PocketEmpires/Unit.c

358 lines
11 KiB
C

/* **************************************
* Includes *
* **************************************/
#include "Unit.h"
#include "PeasantSpr.i"
#include "BarracksSpr.i"
#include "TownCentre.i"
/* **************************************
* Defines *
* **************************************/
/* **************************************
* Structs and enums *
* **************************************/
struct t_coordinates
{
int8_t x;
int8_t y;
};
/* **************************************
* Local prototypes *
* **************************************/
/* **************************************
* Local variables *
* **************************************/
/* Tables */
static uint8_t const UnitHPTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = 25 ,
[BARRACKS] = 100,
[TOWN_CENTER] = 200 };
static uint8_t const UnitSpeedTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = 1,
[BARRACKS] = 0,
[TOWN_CENTER] = 0 };
static const char* const UnitActionsTable_Level[MAX_ACTIONS] = { [ACTION_BUILD_BARRACKS] = "B.BARR",
[ACTION_ATTACK] = "ATTACK",
[ACTION_CREATE_PEASANT] = "C.PEAS."};
static uint8_t const UnitActionsTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = ((1 << ACTION_BUILD_BARRACKS) | (1 << ACTION_ATTACK)),
[BARRACKS] = (1 << ACTION_CREATE_PEASANT),
[TOWN_CENTER] = (1 << ACTION_CREATE_PEASANT) };
// **************
// Sprite tables
// **************
static TYPE_SPRITE UnitSprTable[MAX_UNITS_BUILDINGS];
static TYPE_SPRITE UnitWalkingShadowSprTable[MAX_UNITS_BUILDINGS];
static const struct t_coordinates UnitShadowOffsetTable[MAX_BUILDING_ID - FIRST_BUILDING_ID] = { [BARRACKS - FIRST_BUILDING_ID] = {.x = -6, .y = 0},
[TOWN_CENTER - FIRST_BUILDING_ID] = {.x = -3, .y = 0} };
void UnitInit(void)
{
UnitSprTable[PEASANT].Data = Peasant_SprData;
UnitSprTable[PEASANT].w = GfxGetWidthFromSpriteData(Peasant_SprData);
UnitSprTable[PEASANT].h = GfxGetHeightFromSpriteData(Peasant_SprData);
UnitSprTable[PEASANT].flip = 0;
UnitSprTable[PEASANT].rotation = 0;
UnitSprTable[PEASANT].color = GFX_BLACK;
UnitWalkingShadowSprTable[PEASANT].Data = Peasant_Walking_SprData;
UnitWalkingShadowSprTable[PEASANT].w = GfxGetWidthFromSpriteData(Peasant_Walking_SprData);
UnitWalkingShadowSprTable[PEASANT].h = GfxGetHeightFromSpriteData(Peasant_Walking_SprData);
UnitWalkingShadowSprTable[PEASANT].flip = 0;
UnitWalkingShadowSprTable[PEASANT].rotation = 0;
UnitWalkingShadowSprTable[PEASANT].color = GFX_BLACK;
UnitSprTable[BARRACKS].Data = BarracksSpr_Data;
UnitSprTable[BARRACKS].w = GfxGetWidthFromSpriteData(BarracksSpr_Data);
UnitSprTable[BARRACKS].h = GfxGetHeightFromSpriteData(BarracksSpr_Data);
UnitSprTable[BARRACKS].flip = 0;
UnitSprTable[BARRACKS].rotation = 0;
UnitSprTable[BARRACKS].color = GFX_BLACK;
UnitSprTable[TOWN_CENTER].Data = TownCentreSprData;
UnitSprTable[TOWN_CENTER].w = GfxGetWidthFromSpriteData(TownCentreSprData);
UnitSprTable[TOWN_CENTER].h = GfxGetHeightFromSpriteData(TownCentreSprData);
UnitSprTable[TOWN_CENTER].flip = 0;
UnitSprTable[TOWN_CENTER].rotation = 0;
UnitSprTable[TOWN_CENTER].color = GFX_BLACK;
UnitWalkingShadowSprTable[BARRACKS].Data = BarracksShadowSpr_Data;
UnitWalkingShadowSprTable[BARRACKS].w = GfxGetWidthFromSpriteData(BarracksShadowSpr_Data);
UnitWalkingShadowSprTable[BARRACKS].h = GfxGetHeightFromSpriteData(BarracksShadowSpr_Data);
UnitWalkingShadowSprTable[BARRACKS].flip = 0;
UnitWalkingShadowSprTable[BARRACKS].rotation = 0;
UnitWalkingShadowSprTable[BARRACKS].color = GFX_GRAY;
UnitWalkingShadowSprTable[TOWN_CENTER].Data = TownCentreShadowSprData;
UnitWalkingShadowSprTable[TOWN_CENTER].w = GfxGetWidthFromSpriteData(TownCentreShadowSprData);
UnitWalkingShadowSprTable[TOWN_CENTER].h = GfxGetHeightFromSpriteData(TownCentreShadowSprData);
UnitWalkingShadowSprTable[TOWN_CENTER].flip = 0;
UnitWalkingShadowSprTable[TOWN_CENTER].rotation = 0;
UnitWalkingShadowSprTable[TOWN_CENTER].color = GFX_GRAY;
}
void UnitDraw(TYPE_UNIT* ptrUnit, TYPE_CAMERA* ptrCamera, bool bHighlighted)
{
uint8_t id = ptrUnit->id;
TYPE_SPRITE* ptrSpr;
if (ptrUnit->alive == false)
{
return;
}
if (ptrUnit->building == false)
{
enum
{
WALK_FRAMES = 4
};
// ***************
// Units
// ***************
ptrSpr = ptrUnit->walking ? &UnitWalkingShadowSprTable[id] : &UnitSprTable[id];
ptrSpr->rotation = GFX_NOROT;
ptrSpr->flip = GFX_NOFLIP;
if (ptrUnit->walking == true)
{
if (++ptrUnit->walk_counter > WALK_FRAMES)
{
ptrUnit->walk_counter = 0;
ptrUnit->mirror = ptrUnit->mirror ? false : true;
}
}
switch (ptrUnit->dir)
{
case DIRECTION_UP:
ptrSpr->flip |= GFX_FLIPV;
if (ptrUnit->mirror == true)
{
ptrSpr->flip |= GFX_FLIPH;
}
break;
case DIRECTION_DOWN:
if (ptrUnit->mirror == true)
{
ptrSpr->flip |= GFX_FLIPH;
}
break;
case DIRECTION_LEFT:
ptrSpr->rotation = GFX_ROTCCW;
ptrSpr->flip |= GFX_FLIPH;
if (ptrUnit->mirror == true)
{
ptrSpr->flip |= GFX_FLIPV;
}
break;
case DIRECTION_RIGHT:
ptrSpr->rotation = GFX_ROTCCW;
if (ptrUnit->mirror == true)
{
ptrSpr->flip |= GFX_FLIPV;
}
break;
}
}
else
{
// *******************
// Buildings
// *******************
CameraApplyCoordinatesToSprite( ptrCamera,
&UnitWalkingShadowSprTable[id],
ptrUnit->x + UnitShadowOffsetTable[id - FIRST_BUILDING_ID].x,
ptrUnit->y + UnitShadowOffsetTable[id - FIRST_BUILDING_ID].y );
GfxDrawSprite(&UnitWalkingShadowSprTable[id]);
ptrSpr = &UnitSprTable[id];
}
CameraApplyCoordinatesToSprite( ptrCamera,
ptrSpr,
ptrUnit->x,
ptrUnit->y );
GfxDrawSprite(ptrSpr);
if ( (bHighlighted == true) || (ptrUnit->selected == true) )
{
TYPE_COLLISION_BLOCK cb = CameraApplyCoordinatesToCoordinates(ptrCamera, ptrUnit->x, ptrUnit->y);
int8_t colour = ptrUnit->selected? GFX_BLACK : GFX_GRAY;
uint8_t w = UnitGetWidthFromID(id);
uint8_t h = UnitGetHeightFromID(id);
if (ptrUnit->building == true)
{
GfxDrawRectangle(cb.x - (w >> 3), cb.y - (h >> 3), w + (w >> 2), h + (h >> 2), colour);
}
else
{
GfxDrawCircle(cb.x + (w >> 1), cb.y + (h >> 1), w, colour);
}
}
}
uint8_t UnitGetWidthFromID(uint8_t id)
{
return GfxGetWidthFromSpriteData(UnitSprTable[id].Data);
}
uint8_t UnitGetHeightFromID(uint8_t id)
{
return GfxGetHeightFromSpriteData(UnitSprTable[id].Data);
}
uint8_t UnitGetHpFromID(uint8_t id)
{
return UnitHPTable[id];
}
void UnitMoveTo(TYPE_UNIT* ptrUnit, uint16_t x, uint16_t y)
{
ptrUnit->target_x = x;
ptrUnit->target_y = y;
ptrUnit->walking = true;
}
void UnitAttackAccepted(TYPE_UNIT* ptrUnit)
{
ptrUnit->selecting_attack = true;
}
void UnitHandler(TYPE_UNIT* unitArray, size_t sz)
{
size_t i;
for (i = 0; i < sz; i++)
{
TYPE_UNIT* ptrUnit = &unitArray[i];
if (ptrUnit->alive == false)
{
continue;
}
bool bMoving = true;
if (ptrUnit->walking == true)
{
int8_t x_d = 0;
int8_t y_d = 0;
if ( (ptrUnit->x - UnitSpeedTable[ptrUnit->id]) > ptrUnit->target_x)
{
ptrUnit->dir = DIRECTION_LEFT;
x_d = -UnitSpeedTable[ptrUnit->id];
//~ ptrUnit->x -= UnitSpeedTable[ptrUnit->id];
}
else if ( (ptrUnit->x + UnitSpeedTable[ptrUnit->id]) < ptrUnit->target_x)
{
ptrUnit->dir = DIRECTION_RIGHT;
x_d = UnitSpeedTable[ptrUnit->id];
//~ ptrUnit->x += UnitSpeedTable[ptrUnit->id];
}
if ( (ptrUnit->y - UnitSpeedTable[ptrUnit->id]) > ptrUnit->target_y)
{
ptrUnit->dir = DIRECTION_UP;
y_d = -UnitSpeedTable[ptrUnit->id];
//~ ptrUnit->y -= UnitSpeedTable[ptrUnit->id];
}
else if ( (ptrUnit->y + UnitSpeedTable[ptrUnit->id]) < ptrUnit->target_y)
{
ptrUnit->dir = DIRECTION_DOWN;
y_d = UnitSpeedTable[ptrUnit->id];
//~ ptrUnit->y += UnitSpeedTable[ptrUnit->id];
}
else
{
x_d = ptrUnit->x - ptrUnit->target_x;
y_d = ptrUnit->y - ptrUnit->target_y;
bMoving = false;
}
ptrUnit->walking = bMoving;
if (ptrUnit->walking == true)
{
// If player is still walking, check collisions
// against all other active units.
size_t j;
for (j = 0; j < sz; j++)
{
TYPE_UNIT* ptrOtherUnit = &unitArray[j];
TYPE_COLLISION_BLOCK cu = { .x = ptrUnit->x + x_d,
.y = ptrUnit->y + y_d,
.w = UnitGetWidthFromID(ptrUnit->id),
.h = UnitGetHeightFromID(ptrUnit->id) };
TYPE_COLLISION_BLOCK ou;
if (ptrOtherUnit->alive == false)
{
continue;
}
if (j == i)
{
// Do not compare against itself!
continue;
}
ou.x = ptrOtherUnit->x;
ou.y = ptrOtherUnit->x;
ou.w = UnitGetWidthFromID(ptrOtherUnit->id);
ou.h = UnitGetHeightFromID(ptrOtherUnit->id);
if (SystemCollisionCheck(cu, ou) == true)
{
ptrUnit->walking = false;
break;
}
}
}
if (ptrUnit->walking == true)
{
// If no collision is detected, keep moving to the new position
ptrUnit->x += x_d;
ptrUnit->y += y_d;
}
}
}
}
uint8_t UnitGetAvailableActions(TYPE_UNIT* ptrUnit)
{
return UnitActionsTable[ptrUnit->id];
}
const char* UnitGetActionString(UNIT_ACTION action)
{
return UnitActionsTable_Level[action];
}