PocketEmpires/UnitOld.c

453 lines
16 KiB
C

/* **************************************
* Includes *
* **************************************/
#include "Unit.h"
/* Units sprite data */
#include "PeasantSpr.i"
#include "SoldierSpr.i"
/* Buildings sprite data */
#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,
[SOLDIER] = 80,
[BARRACKS] = 100,
[TOWN_CENTER] = 200 };
static TYPE_RESOURCES const UnitResourcesTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = {.Wood = 0, .Gold = 0, .Food = 50},
[SOLDIER] = {.Wood = 25, .Gold = 10, .Food = 50},
[BARRACKS] = {.Wood = 100, .Gold = 0, .Food = 0},
[TOWN_CENTER] = {.Wood = 200, .Gold = 0, .Food = 0} };
static uint8_t const UnitSpeedTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = 1,
[SOLDIER] = 1,
[BARRACKS] = 0,
[TOWN_CENTER] = 0 };
static const char* const UnitActionsTable_Level[MAX_ACTIONS] = { [ACTION_BUILD_BARRACKS] = "B.BARR",
[ACTION_CREATE_PEASANT] = "C.PEAS.",
[ACTION_CREATE_SOLDIER] = "C.SLDR.",
[ACTION_BUILD_TOWER_CENTER] = "C.TWNC."};
static uint8_t const UnitActionsTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = ((1 << ACTION_BUILD_BARRACKS) | (1 << ACTION_BUILD_TOWER_CENTER)),
[SOLDIER] = 0,
[BARRACKS] = (1 << ACTION_CREATE_SOLDIER),
[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)
{
/* ***********************************
* Unit sprite data init
* ***********************************/
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;
UnitSprTable[SOLDIER].Data = SoldierSprData;
UnitSprTable[SOLDIER].w = GfxGetWidthFromSpriteData(SoldierSprData);
UnitSprTable[SOLDIER].h = GfxGetHeightFromSpriteData(SoldierSprData);
UnitSprTable[SOLDIER].flip = 0;
UnitSprTable[SOLDIER].rotation = 0;
UnitSprTable[SOLDIER].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;
UnitWalkingShadowSprTable[SOLDIER].Data = SoldierSprData_Walking;
UnitWalkingShadowSprTable[SOLDIER].w = GfxGetWidthFromSpriteData(SoldierSprData_Walking);
UnitWalkingShadowSprTable[SOLDIER].h = GfxGetHeightFromSpriteData(SoldierSprData_Walking);
UnitWalkingShadowSprTable[SOLDIER].flip = 0;
UnitWalkingShadowSprTable[SOLDIER].rotation = 0;
UnitWalkingShadowSprTable[SOLDIER].color = GFX_BLACK;
/* ***********************************
* Buildings sprite data init
* ***********************************/
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 UnitDrawShadow(TYPE_UNIT *ptrUnit, TYPE_CAMERA *ptrCamera)
{
uint8_t id = ptrUnit->id;
CameraApplyCoordinatesToSprite( ptrCamera,
&UnitWalkingShadowSprTable[id],
ptrUnit->x + UnitShadowOffsetTable[id - FIRST_BUILDING_ID].x,
ptrUnit->y + UnitShadowOffsetTable[id - FIRST_BUILDING_ID].y );
GfxDrawSprite(&UnitWalkingShadowSprTable[id]);
}
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 != false)
{
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 != false)
{
ptrSpr->flip |= GFX_FLIPH;
}
break;
case DIRECTION_DOWN:
if (ptrUnit->mirror != false)
{
ptrSpr->flip |= GFX_FLIPH;
}
break;
case DIRECTION_LEFT:
ptrSpr->rotation = GFX_ROTCCW;
ptrSpr->flip |= GFX_FLIPH;
if (ptrUnit->mirror != false)
{
ptrSpr->flip |= GFX_FLIPV;
}
break;
case DIRECTION_RIGHT:
ptrSpr->rotation = GFX_ROTCCW;
if (ptrUnit->mirror != false)
{
ptrSpr->flip |= GFX_FLIPV;
}
break;
}
}
else
{
/* *******************. */
/* Buildings. */
/* *******************. */
ptrSpr = &UnitSprTable[id];
}
CameraApplyCoordinatesToSprite( ptrCamera,
ptrSpr,
ptrUnit->x,
ptrUnit->y );
GfxDrawSprite(ptrSpr);
if ( (bHighlighted != false) || (ptrUnit->selected != false) )
{
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 != false)
{
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(TYPE_UNIT_ID id)
{
return GfxGetWidthFromSpriteData(UnitSprTable[id].Data);
}
uint8_t UnitGetHeightFromID(TYPE_UNIT_ID id)
{
return GfxGetHeightFromSpriteData(UnitSprTable[id].Data);
}
uint8_t UnitGetHpFromID(TYPE_UNIT_ID id)
{
return UnitHPTable[id];
}
TYPE_RESOURCES UnitNeededResourcesFromID(TYPE_UNIT_ID id)
{
return UnitResourcesTable[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;
}
bool UnitCheckCollisionAgainstOtherUnits(TYPE_COLLISION_BLOCK* cb, TYPE_UNIT *ptrUnitArray, TYPE_UNIT* ptrCurrentUnit)
{
for (uint8_t i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT *ptrOtherUnit = &ptrUnitArray[i];
TYPE_COLLISION_BLOCK ocb = {.x = ptrOtherUnit->x,
.y = ptrOtherUnit->y,
.w = UnitGetWidthFromID(ptrOtherUnit->id),
.h = UnitGetHeightFromID(ptrOtherUnit->id)};
if (ptrOtherUnit->alive == false)
{
continue;
}
if (ptrOtherUnit == ptrCurrentUnit)
{
/* We are referring to the same TYPE_UNIT instance. Discard. */
continue;
}
if (SystemCollisionCheck(cb, &ocb) != false)
{
return true;
}
}
return false;
}
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 != false)
{
int16_t x_dist = ptrUnit->target_x - (ptrUnit->x + (UnitGetWidthFromID(ptrUnit->id) >> 1));
int16_t y_dist = ptrUnit->target_y - (ptrUnit->y + (UnitGetHeightFromID(ptrUnit->id) >> 1));
uint8_t unit_speed = UnitSpeedTable[ptrUnit->id];
int8_t x_d = 0;
int8_t y_d = 0;
if ( (uint16_t)abs(x_dist) > (uint16_t)(abs(y_dist) << 2) ) /* Add some hysteresis so unit does not change constantly its direction */
{
if (x_dist >= (int16_t)unit_speed)
{
x_d = unit_speed;
ptrUnit->dir = DIRECTION_RIGHT;
}
else if (x_dist <= (int16_t)-unit_speed)
{
x_d = (int8_t)-unit_speed;
ptrUnit->dir = DIRECTION_LEFT;
}
else
{
bMoving = false;
}
}
else
{
if (y_dist >= (int16_t)unit_speed)
{
y_d = unit_speed;
ptrUnit->dir = DIRECTION_DOWN;
}
else if (y_dist <= (int16_t)-unit_speed)
{
y_d = (int8_t)-unit_speed;
ptrUnit->dir = DIRECTION_UP;
}
else
{
bMoving = false;
}
}
/* ~ if ( (ptrUnit->x - UnitSpeedTable[ptrUnit->id]) > ptrUnit->target_x). */
/* ~ {. */
/* ~ ptrUnit->dir = DIRECTION_LEFT;. */
/* ~ x_d = (int8_t)-UnitSpeedTable[ptrUnit->id];. */
/* ~ }. */
/* ~ else if ( (ptrUnit->x + UnitSpeedTable[ptrUnit->id]) < ptrUnit->target_x). */
/* ~ {. */
/* ~ ptrUnit->dir = DIRECTION_RIGHT;. */
/* ~ x_d = (int8_t)UnitSpeedTable[ptrUnit->id];. */
/* ~ }. */
/* ~ else if ( (ptrUnit->y - UnitSpeedTable[ptrUnit->id]) > ptrUnit->target_y). */
/* ~ {. */
/* ~ ptrUnit->dir = DIRECTION_UP;. */
/* ~ y_d = (int8_t)-UnitSpeedTable[ptrUnit->id];. */
/* ~ }. */
/* ~ else if ( (ptrUnit->y + UnitSpeedTable[ptrUnit->id]) < ptrUnit->target_y). */
/* ~ {. */
/* ~ ptrUnit->dir = DIRECTION_DOWN;. */
/* ~ y_d = (int8_t)UnitSpeedTable[ptrUnit->id];. */
/* ~ }. */
/* ~ else. */
/* ~ {. */
/* ~ bMoving = false;. */
/* ~ }. */
if (ptrUnit->walking != false)
{
TYPE_COLLISION_BLOCK cu = { .x = ptrUnit->x + x_d,
.y = ptrUnit->y + y_d,
.w = UnitGetWidthFromID(ptrUnit->id),
.h = UnitGetHeightFromID(ptrUnit->id) };
if (UnitCheckCollisionAgainstOtherUnits(&cu, unitArray, ptrUnit) == true)
{
switch (ptrUnit->dir)
{
case DIRECTION_LEFT:
/* Fall through. */
case DIRECTION_RIGHT:
y_d = -x_d;
x_d = 0;
ptrUnit->dir = y_d > 0? DIRECTION_DOWN: DIRECTION_UP;
break;
case DIRECTION_UP:
/* Fall through. */
case DIRECTION_DOWN:
x_d = y_d;
y_d = 0;
ptrUnit->dir = x_d > 0? DIRECTION_RIGHT: DIRECTION_LEFT;
break;
}
}
}
ptrUnit->walking = bMoving;
if (ptrUnit->walking != false)
{
/* 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];
}