/* ************************************** * Includes * * **************************************/ #include "Player.h" #include "Pad.h" #include "Unit.h" #include "Gameplay.h" /* ************************************** * Defines * * **************************************/ #define ACCEPT_UNIT_BUILDING_OPTIONS_FRAMES 5 #define MAX_SELECTION_DIST 400 #define NO_SELECTION -1 /* ************************************** * Local variables * * **************************************/ Player::Player(void) { } Player::~Player(void) { } void Player::Init(void) { uint8_t i; unit_i = 0; selectedUnitCandidate = NO_SELECTION; CameraInit(&Camera); UnitInit(); for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { memset(&units[i], 0, sizeof(TYPE_UNIT)); } TYPE_COLLISION_BLOCK cb; Resources.Wood = 25; Resources.Gold = 50; Resources.Food = 75; cb.x = SystemRand(0, 20); cb.y = SystemRand(0, 20); if (createUnit(TOWN_CENTER, cb) == false) { GfxPrintText_Flash(F("Failed to create building!")); } cb.x = SystemRand(48, 56); cb.y = SystemRand(48, 56); cb.w = UnitGetWidthFromID(PEASANT); cb.h = UnitGetHeightFromID(PEASANT); showActionsMenu_counter = 0; showActionsMenu_index = 0; showActionsMenu = false; anyUnitSelected = false; if (createUnit(PEASANT, cb) == false) { GfxPrintText_Flash(F("Failed to create unit!")); } } void Player::showHealth(uint8_t hp) { enum { HP_TEXT_X = 4, HP_TEXT_Y = Y_SCREEN_RESOLUTION - 4, }; char str[8]; GfxFillRectangle(0, Y_SCREEN_RESOLUTION - 5, X_SCREEN_RESOLUTION, 8, GFX_WHITE); snprintf(str, sizeof(str), "HP=%u", hp); GfxPrintTextFont(str, font3x3, HP_TEXT_X, HP_TEXT_Y); } void Player::DrawHandler(void) { enum { PROGRESS_BAR_X = X_SCREEN_RESOLUTION - 16, PROGRESS_BAR_Y = Y_SCREEN_RESOLUTION - 4, PROGRESS_BAR_W = ACCEPT_UNIT_BUILDING_OPTIONS_FRAMES << 1, PROGRESS_BAR_H = 3, }; uint8_t i; bool bAnyoneSelected = false; for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* u = &units[i]; if (u->alive == false) { continue; } bool selected = false; if (selectedUnitCandidate != NO_SELECTION) { selected = (i == selectedUnitCandidate); } UnitDraw(u, &Camera, selected); if ( (u->selected == true) && (bAnyoneSelected == false) ) { bAnyoneSelected = true; showHealth(u->hp); } } if (human == true) { if (bAnyoneSelected == true) { GfxDrawRectangle(PROGRESS_BAR_X, PROGRESS_BAR_Y, PROGRESS_BAR_W, PROGRESS_BAR_H, GFX_BLACK); if (showActionsMenu_counter != 0) { GfxFillRectangle(PROGRESS_BAR_X, PROGRESS_BAR_Y, showActionsMenu_counter << 1, PROGRESS_BAR_H, GFX_BLACK); } } ActionsMenu(); ShowResources(); } } void Player::ShowResources(void) { char str[16]; gb.display.setColor(GFX_WHITE); gb.display.fillRect(0, 0, X_SCREEN_RESOLUTION, 5); snprintf(str, sizeof(str), "W=%d", Resources.Wood); GfxPrintTextFont(str, font3x3, 2, 1); snprintf(str, sizeof(str), "G=%d", Resources.Gold); GfxPrintTextFont(str, font3x3, 22, 1); snprintf(str, sizeof(str), "F=%d", Resources.Food); GfxPrintTextFont(str, font3x3, 42, 1); } bool Player::checkNewBuildingPosition(TYPE_COLLISION_BLOCK * cb) { uint8_t i; TYPE_COLLISION_BLOCK bldgCB; bool success; static uint8_t max_tries = 0; for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* ptrUnit = &units[i]; success = false; if (ptrUnit->building == false) { continue; } bldgCB.x = ptrUnit->x; bldgCB.y = ptrUnit->y; bldgCB.w = UnitGetWidthFromID(ptrUnit->id); bldgCB.h = UnitGetHeightFromID(ptrUnit->id); if (SystemCollisionCheck(*cb, bldgCB) == true) { success = false; } else { success = true; } if (success == false) { cb->x = SystemRand(0, 128); cb->y = SystemRand(0, 128); if (++max_tries < 16) { if (checkNewBuildingPosition(cb) == false) { return false; } else { return true; } } else { return false; } } } max_tries = 0; return true; } bool Player::createUnit(TYPE_UNIT_ID id, TYPE_COLLISION_BLOCK cb) { if (unit_i < PLAYER_MAX_UNITS_BUILDINGS) { TYPE_UNIT* ptrNewUnit = &units[unit_i]; ptrNewUnit->id = id; ptrNewUnit->x = cb.x; ptrNewUnit->y = cb.y; ptrNewUnit->hp = UnitGetHpFromID(id); ptrNewUnit->alive = true; ptrNewUnit->building = (id > MAX_UNIT_ID); unit_i++; return true; } else { return false; } return false; } TYPE_COLLISION_BLOCK Player::GetCursorPos(void) { TYPE_COLLISION_BLOCK cb; cb.x = (X_SCREEN_RESOLUTION >> 1) - 4 - Camera.X_Offset; cb.y = (Y_SCREEN_RESOLUTION >> 1) - 4 - Camera.Y_Offset; cb.w = 8; cb.h = 8; return cb; } void Player::UnitBuildingSelection(void) { uint16_t i; uint32_t nearest_unit_dist = 0xFFFFFFFF; // Set maximum value uint32_t dist; int8_t nearest_unit = NO_SELECTION; for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* u = &units[i]; if ( (u->alive == false) || (u->selected == true) ) { continue; } TYPE_COLLISION_BLOCK cursor_cb = GetCursorPos(); TYPE_COLLISION_BLOCK u_cb = {u->x, u->y, UnitGetWidthFromID(u->id), UnitGetHeightFromID(u->id) }; uint16_t dist_x = (u_cb.x + (u_cb.w >> 1) - cursor_cb.x); uint16_t dist_y = (u_cb.y + (u_cb.h >> 1) - cursor_cb.y); dist = (dist_x * dist_x) + (dist_y * dist_y); if (dist < nearest_unit_dist) { nearest_unit_dist = dist; nearest_unit = (int8_t)i; } } selectedUnitCandidate = nearest_unit; } void Player::ActionsMenu(void) { if (showActionsMenu == true) { for (uint8_t i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* ptrUnit = &units[i]; if (ptrUnit->selected == true) { uint8_t availableActions = UnitGetAvailableActions(ptrUnit); if (!(availableActions & (1 << showActionsMenu_index) ) ) { IncreaseShowActionsMenuIndex(); } UNIT_ACTION action = (UNIT_ACTION)(showActionsMenu_index); const char* str = UnitGetActionString(action); GfxPrintTextFont(str, font3x3, 40, Y_SCREEN_RESOLUTION - 4); break; } } } } void Player::Handler(void) { CameraSetLock(&Camera, showActionsMenu); CameraHandler(&Camera); UnitBuildingSelection(); UnitHandler(units, sizeof(units) / sizeof(units[0])); ButtonHandler(); } void Player::ButtonHandler(void) { if (PadButtonPressed(PAD_A) == true) { ButtonAPressed(); } else if (PadButtonReleased(PAD_A) == true) { ButtonAReleased(); } else if (PadButtonPressed(PAD_B) == true) { ButtonBPressed(); } else if (PadButtonReleased(PAD_B) == true) { ButtonBReleased(); } else if (PadButtonReleased(PAD_LEFT) == true) { ButtonLeftReleased(); } else if (PadButtonReleased(PAD_RIGHT) == true) { ButtonRightReleased(); } } void Player::ButtonAPressed(void) { // Only increase progress bar when any unit has been previously selected if (anyUnitSelected == true) { if (showActionsMenu == false) { if (showActionsMenu_counter < ACCEPT_UNIT_BUILDING_OPTIONS_FRAMES) { showActionsMenu_counter++; } } } } void Player::ButtonAReleased(void) { if (showActionsMenu_counter < ACCEPT_UNIT_BUILDING_OPTIONS_FRAMES) { if (selectedUnitCandidate != NO_SELECTION) { // When actions menu is not active, select unit if // a candidate is present TYPE_UNIT* ptrUnit = &units[selectedUnitCandidate]; ptrUnit->selected = true; anyUnitSelected = true; showActionsMenu_index = 0; } showActionsMenu_counter = 0; } else if (showActionsMenu == true) { uint8_t i = 0; for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* ptrUnit = &units[i]; if (ptrUnit->selected == true) { showActionsMenu_counterLevel1 = 0; switch (showActionsMenu_index) { case ACTION_CREATE_PEASANT: ActionCreateUnit(ptrUnit, PEASANT); break; case ACTION_BUILD_BARRACKS: ActionCreateBuilding(ptrUnit, BARRACKS); break; default: break; } break; } } } showActionsMenu = (showActionsMenu_counter < ACCEPT_UNIT_BUILDING_OPTIONS_FRAMES)? false: true; } void Player::ActionCreateUnit(TYPE_UNIT* ptrUnit, TYPE_UNIT_ID unit) { uint8_t w = UnitGetWidthFromID(ptrUnit->id); uint8_t h = UnitGetHeightFromID(ptrUnit->id); uint8_t new_pos_x = ptrUnit->x + SystemRand(w, w + (w >> 1)); uint8_t new_pos_y = ptrUnit->y + SystemRand(h, h + (h >> 1)); TYPE_COLLISION_BLOCK cb = {.x = new_pos_x, .y = new_pos_y}; createUnit(unit, cb); } void Player::ActionCreateBuilding(TYPE_UNIT* ptrUnit, TYPE_UNIT_ID bldg) { TYPE_COLLISION_BLOCK cb = GetCursorPos(); createUnit(bldg, cb); } void Player::ButtonBPressed(void) { enum { CANCEL_SELECTION_FRAMES = 5 }; if (anyUnitSelected == true) { if (unselectUnits_counter < CANCEL_SELECTION_FRAMES) { unselectUnits_counter++; } else { if (anyUnitSelected == true) { uint8_t i; // Cancel selection of all units for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* ptrUnit = &units[i]; if (ptrUnit->selected == true) { ptrUnit->selected = false; } } // Reset accumulated counter and flags unselectUnits_counter = 0; anyUnitSelected = false; showActionsMenu = false; showActionsMenu_counter = 0; } } } } void Player::ButtonBReleased(void) { if (anyUnitSelected == true) { TYPE_COLLISION_BLOCK cursor = GetCursorPos(); uint8_t i; for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* ptrUnit = &units[i]; if (ptrUnit->selected == true) { UnitMoveTo(ptrUnit, cursor.x, cursor.y); } } } // Reset accumulated counter unselectUnits_counter = 0; } void Player::ButtonLeftReleased(void) { if (showActionsMenu == true) { uint8_t i; for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* ptrUnit = &units[i]; if (ptrUnit->selected == true) { // We need to iterate over all available actions // for current unit. uint8_t availableActions = UnitGetAvailableActions(ptrUnit); for (uint8_t j = showActionsMenu_index - 1; j != showActionsMenu_index ; j--) { if (j > (sizeof(uint8_t) << 3)) { // Maximum index: 7 j = (sizeof(uint8_t) << 3) - 1; } if (availableActions & (1 << j)) { showActionsMenu_index = j; break; } } } } } } void Player::ButtonRightReleased(void) { IncreaseShowActionsMenuIndex(); } void Player::IncreaseShowActionsMenuIndex(void) { if (showActionsMenu == true) { uint8_t i; for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++) { TYPE_UNIT* ptrUnit = &units[i]; if (ptrUnit->selected == true) { // We need to iterate over all available actions // for current unit. uint8_t availableActions = UnitGetAvailableActions(ptrUnit); for (uint8_t j = showActionsMenu_index + 1; j != showActionsMenu_index ; j++) { if (j >= (sizeof(uint8_t) << 3) ) { j = 0; } if (availableActions & (1 << j)) { showActionsMenu_index = j; break; } } } } } }