/* ************************************** * 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]; }