/* ************************************** * 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_ATTACK] = "ATTACK", [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) | (1 << ACTION_ATTACK)), [SOLDIER] = (1 << ACTION_ATTACK), [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 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 // ******************* 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 != 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; } 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) { 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 = (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) { // 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->y; ou.w = UnitGetWidthFromID(ptrOtherUnit->id); ou.h = UnitGetHeightFromID(ptrOtherUnit->id); if (SystemCollisionCheck(&cu, &ou) != false) { //bMoving = false; return; } } } 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]; }