PocketEmpires/Player.cpp

596 lines
13 KiB
C++

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