Kinda improved pathfinding algorithm. Still some work TODO.

Fixed some errors in DEBUG_VAR macro.
Shadows are now drawn before any other object.
Different strings are now shown depending on the number of selected units.
Some work on calculating actions mask when different types of units are selected. Still some work TODO.
This commit is contained in:
XaviDCR92 2017-11-10 00:04:35 +01:00
parent 7b05778e3e
commit d854647815
10 changed files with 1834 additions and 1756 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,8 @@
#define DEBUG_VAR(var, suff, x, y) if (1) \
{ \
char buffer##suff[16]; \
Systemitoa(str, sizeof(buffer##suff[16]), var); \
GfxPrintText(buffer##suff, x - (strlen(buffer##suff)<<3), y); \
Systemitoa(buffer##suff, sizeof(buffer##suff), var); \
GfxPrintText(buffer##suff, x, y); \
}
/* *************************************

View File

@ -98,20 +98,25 @@ void Player::showHealth(uint8_t hp)
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) || (u->building == false) )
{
continue;
}
UnitDrawShadow(u, &Camera);
}
for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* u = &units[i];
TYPE_UNIT *u = &units[i];
if (u->alive == false)
{
@ -130,33 +135,26 @@ void Player::DrawHandler(void)
if ( (u->selected != false) && (bAnyoneSelected == false) )
{
bAnyoneSelected = true;
showHealth(u->hp);
}
}
if (human != false)
{
if (bAnyoneSelected != false)
{
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();
MenuDrawHandler();
}
}
void Player::MenuDrawHandler(void)
{
ActionsMenu();
ShowResources();
}
void Player::ShowResources(void)
{
char str[8];
uint8_t i;
size_t i;
str[1] = '=';
@ -181,22 +179,12 @@ void Player::ShowResources(void)
GfxPrintTextFont(str, font3x3, 42, 1);
Systemitoa(str, 3, getAliveUnits());
for (i = 0; i < 3; i++)
{
if (str[i] == '\0')
{
break;
}
}
i = Systemitoa(str, 3, getAliveUnits());
str[i++] = '/';
Systemitoa(&str[i], sizeof(str) - i, PLAYER_MAX_UNITS_BUILDINGS);
//~ snprintf(str, sizeof(str), "%d/%d", unit_i, PLAYER_MAX_UNITS_BUILDINGS);
GfxPrintTextFont(str, font3x3, 42, 5);
}
@ -210,7 +198,7 @@ bool Player::checkNewBuildingPosition(TYPE_COLLISION_BLOCK * cb)
for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* ptrUnit = &units[i];
TYPE_UNIT *ptrUnit = &units[i];
success = false;
if (ptrUnit->building == false)
@ -338,7 +326,8 @@ void Player::UnitBuildingSelection(void)
{
enum
{
MAX_ALLOWED_DISTANCE = (X_SCREEN_RESOLUTION * X_SCREEN_RESOLUTION) + (Y_SCREEN_RESOLUTION) * (Y_SCREEN_RESOLUTION)
X_MAX_ALLOWED_DISTANCE = X_SCREEN_RESOLUTION >> 1,
Y_MAX_ALLOWED_DISTANCE = Y_SCREEN_RESOLUTION >> 1
};
uint16_t i;
@ -349,7 +338,7 @@ void Player::UnitBuildingSelection(void)
for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* u = &units[i];
TYPE_UNIT *u = &units[i];
if ( (u->alive == false) || (u->selected != false) )
{
@ -359,8 +348,13 @@ void Player::UnitBuildingSelection(void)
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);
int16_t dist_x = (u_cb.x + (u_cb.w >> 1) - cursor_cb.x);
int16_t dist_y = (u_cb.y + (u_cb.h >> 1) - cursor_cb.y);
if ( (abs(dist_x) > X_MAX_ALLOWED_DISTANCE) || (abs(dist_y) > Y_MAX_ALLOWED_DISTANCE) )
{
continue;
}
dist = SystemGetHyp(dist_x, dist_y);
@ -371,41 +365,90 @@ void Player::UnitBuildingSelection(void)
}
}
selectedUnitCandidate = dist < (uint32_t)MAX_ALLOWED_DISTANCE? nearest_unit: NO_SELECTION;
selectedUnitCandidate = nearest_unit;
}
void Player::ActionsMenu(void)
{
if (showActionsMenu != false)
enum
{
for (uint8_t i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
ALL_ACTIONS_MASK = 0xFF
};
uint8_t selectedUnits = 0;
uint8_t availableActions = ALL_ACTIONS_MASK;
TYPE_UNIT *ptrSelectedUnit = NULL;
for (uint8_t i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT *ptrUnit = &units[i];
if (ptrUnit->selected != false)
{
TYPE_UNIT* ptrUnit = &units[i];
if (ptrUnit->selected != false)
{
uint8_t availableActions = UnitGetAvailableActions(ptrUnit);
if (availableActions != 0)
{
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;
}
}
ptrSelectedUnit = ptrUnit;
selectedUnits++;
availableActions &= UnitGetAvailableActions(ptrUnit);
}
}
if (selectedUnits != 0)
{
if (selectedUnits == 1)
{
showHealth(ptrSelectedUnit->hp);
}
else
{
enum
{
UNITS_SELECTED_NUMBER_STR_SIZE = 3 /* "000" */,
UNITS_SELECTED_STR = UNITS_SELECTED_NUMBER_STR_SIZE + 6 /* strlen("units\0") */,
UNITS_SELECTED_TEXT_X = 4,
UNITS_SELECTED_TEXT_Y = Y_SCREEN_RESOLUTION - 4,
};
char unitsSelectedStr[UNITS_SELECTED_STR];
size_t i = Systemitoa(unitsSelectedStr, UNITS_SELECTED_NUMBER_STR_SIZE, selectedUnits);
//~ strcpy(&unitsSelectedStr[i], "units");
memcpy(&unitsSelectedStr[i], "units\0", 6 /* strlen("units")*/);
GfxPrintTextFont(unitsSelectedStr, font3x3, UNITS_SELECTED_TEXT_X, UNITS_SELECTED_TEXT_Y);
}
if ( (availableActions != 0)
&&
(availableActions != ALL_ACTIONS_MASK) )
{
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,
};
if (!(availableActions & (1 << showActionsMenu_index) ) )
{
IncreaseShowActionsMenuIndex();
}
GfxDrawRectangle(PROGRESS_BAR_X, PROGRESS_BAR_Y, PROGRESS_BAR_W, PROGRESS_BAR_H, GFX_BLACK);
GfxFillRectangle(PROGRESS_BAR_X, PROGRESS_BAR_Y, showActionsMenu_counter << 1, PROGRESS_BAR_H, GFX_BLACK);
if (showActionsMenu != false)
{
UNIT_ACTION action = (UNIT_ACTION)(showActionsMenu_index);
const char* str = UnitGetActionString(action);
GfxPrintTextFont(str, font3x3, 40, Y_SCREEN_RESOLUTION - 4);
}
}
}
}
void Player::Handler(void)
@ -472,7 +515,7 @@ void Player::ButtonAReleased(void)
{
// When actions menu is not active, select unit if
// a candidate is present
TYPE_UNIT* ptrUnit = &units[selectedUnitCandidate];
TYPE_UNIT *ptrUnit = &units[selectedUnitCandidate];
ptrUnit->selected = true;
anyUnitSelected = true;
@ -487,7 +530,7 @@ void Player::ButtonAReleased(void)
for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* ptrUnit = &units[i];
TYPE_UNIT *ptrUnit = &units[i];
if (ptrUnit->selected != false)
{
@ -523,7 +566,7 @@ void Player::ButtonAReleased(void)
showActionsMenu = (showActionsMenu_counter < ACCEPT_UNIT_BUILDING_OPTIONS_FRAMES)? false: true;
}
void Player::ActionCreateUnit(TYPE_UNIT* ptrUnit, TYPE_UNIT_ID unit)
void Player::ActionCreateUnit(TYPE_UNIT *ptrUnit, TYPE_UNIT_ID unit)
{
enum
{
@ -594,7 +637,7 @@ void Player::ButtonBPressed(void)
/* Cancel selection of all units */
for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* ptrUnit = &units[i];
TYPE_UNIT *ptrUnit = &units[i];
if (ptrUnit->selected != false)
{
@ -621,7 +664,7 @@ void Player::ButtonBReleased(void)
for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* ptrUnit = &units[i];
TYPE_UNIT *ptrUnit = &units[i];
if (ptrUnit->selected != false)
{
@ -651,7 +694,7 @@ void Player::ButtonLeftReleased(void)
for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* ptrUnit = &units[i];
TYPE_UNIT *ptrUnit = &units[i];
if (ptrUnit->selected != false)
{
@ -692,7 +735,7 @@ void Player::IncreaseShowActionsMenuIndex(void)
for (i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* ptrUnit = &units[i];
TYPE_UNIT *ptrUnit = &units[i];
if (ptrUnit->selected != false)
{

View File

@ -78,6 +78,7 @@ class Player
void showHealth(uint8_t hp);
void ButtonHandler(void);
void ActionsMenu(void);
void MenuDrawHandler(void);
TYPE_COLLISION_BLOCK GetCursorPos(void);
// Unit selection
@ -93,7 +94,7 @@ class Player
void IncreaseShowActionsMenuIndex();
// Action callbacks
void ActionCreateUnit(TYPE_UNIT* ptrUnit, TYPE_UNIT_ID unit);
void ActionCreateUnit(TYPE_UNIT *ptrUnit, TYPE_UNIT_ID unit);
void ActionCreateBuilding(TYPE_UNIT_ID bldg);
// Collision detection

View File

@ -277,13 +277,13 @@ bool SystemCollisionCheck(TYPE_COLLISION_BLOCK* c1, TYPE_COLLISION_BLOCK* c2)
c2->x, c2->y, c2->w, c2->h );
}
bool Systemitoa(char* str, size_t sz, int16_t value)
size_t Systemitoa(char* str, size_t sz, int16_t value)
{
if (sz != 0)
{
bool first_digit_found = false;
uint16_t i;
uint8_t j = 0;
uint8_t bytes_written = 0;
/* Example: 65535 */
/* Another example: -32767 */
@ -291,7 +291,7 @@ bool Systemitoa(char* str, size_t sz, int16_t value)
if (value & 0x8000)
{
/* Sign bit */
str[j++] = '-';
str[bytes_written++] = '-';
}
for (i = 10000; i >= 1; i /= 10)
@ -311,20 +311,20 @@ bool Systemitoa(char* str, size_t sz, int16_t value)
continue;
}
str[j++] = digit + '0';
str[bytes_written++] = digit + '0';
if (j >= (sz - 1))
if (bytes_written >= (sz - 1))
{
return false;
return 0;
}
}
str[j] = '\0';
str[bytes_written] = '\0';
return true;
return bytes_written;
}
return false;
return 0;
}
uint32_t SystemGetHyp(uint16_t x, uint16_t y)

View File

@ -86,7 +86,8 @@ bool SystemArrayCompare(unsigned short * arr1, unsigned short * arr2, size_t sz)
// Checks collision of two objects
bool SystemCollisionCheck(TYPE_COLLISION_BLOCK* c1, TYPE_COLLISION_BLOCK* c2);
// Transforms integer to string. Use this instead of sprintf() as much as possible.
bool Systemitoa(char* str, size_t sz, int16_t value);
// Returns the number of bytes written into "str". In case of error, 0 is returned.
size_t Systemitoa(char* str, size_t sz, int16_t value);
// Return hypothenuse of two points
uint32_t SystemGetHyp(uint16_t x, uint16_t y);

131
Unit.c
View File

@ -135,7 +135,19 @@ void UnitInit(void)
UnitWalkingShadowSprTable[TOWN_CENTER].color = GFX_GRAY;
}
void UnitDraw(TYPE_UNIT* ptrUnit, TYPE_CAMERA* ptrCamera, bool bHighlighted)
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;
@ -213,14 +225,6 @@ void UnitDraw(TYPE_UNIT* ptrUnit, TYPE_CAMERA* ptrCamera, bool bHighlighted)
// *******************
// 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];
}
@ -269,23 +273,23 @@ TYPE_RESOURCES UnitNeededResourcesFromID(TYPE_UNIT_ID id)
return UnitResourcesTable[id];
}
void UnitMoveTo(TYPE_UNIT* ptrUnit, uint16_t x, uint16_t y)
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)
void UnitAttackAccepted(TYPE_UNIT *ptrUnit)
{
ptrUnit->selecting_attack = true;
}
bool UnitCheckCollisionAgainstOtherUnits(TYPE_COLLISION_BLOCK* cb, TYPE_UNIT* ptrUnitArray, TYPE_UNIT* ptrCurrentUnit)
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_UNIT *ptrOtherUnit = &ptrUnitArray[i];
TYPE_COLLISION_BLOCK ocb = {.x = ptrOtherUnit->x,
.y = ptrOtherUnit->y,
.w = UnitGetWidthFromID(ptrOtherUnit->id),
@ -317,46 +321,84 @@ void UnitHandler(TYPE_UNIT* unitArray, size_t sz)
for (i = 0; i < sz; i++)
{
TYPE_UNIT* ptrUnit = &unitArray[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 ( (ptrUnit->x - UnitSpeedTable[ptrUnit->id]) > ptrUnit->target_x)
if ( (uint16_t)abs(x_dist) > (uint16_t)(abs(y_dist) << 2) ) /* Add some hysteresis so unit does not change constantly its direction */
{
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];
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
{
bMoving = false;
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,
@ -366,33 +408,22 @@ void UnitHandler(TYPE_UNIT* unitArray, size_t sz)
if (UnitCheckCollisionAgainstOtherUnits(&cu, unitArray, ptrUnit) == true)
{
uint32_t dist = 0;
uint32_t dist2 = 0;
switch (ptrUnit->dir)
{
case DIRECTION_LEFT:
// Fall through
case DIRECTION_RIGHT:
dist = SystemGetHyp(abs(ptrUnit->x - ptrUnit->target_x), abs((ptrUnit->y + y_d) - ptrUnit->target_y));
dist2 = SystemGetHyp(abs(ptrUnit->x - ptrUnit->target_x), abs((ptrUnit->y - y_d) - ptrUnit->target_y));
y_d = dist < dist2? x_d: -x_d;
ptrUnit->dir = y_d? DIRECTION_DOWN: DIRECTION_UP;
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:
dist = SystemGetHyp(abs((ptrUnit->x - x_d) - ptrUnit->target_x), abs(ptrUnit->y - ptrUnit->target_y));
dist2 = SystemGetHyp(abs((ptrUnit->x + x_d) - ptrUnit->target_x), abs(ptrUnit->y - ptrUnit->target_y));
x_d = dist < dist2? -y_d: -x_d;
ptrUnit->dir = x_d? DIRECTION_RIGHT: DIRECTION_LEFT;
x_d = y_d;
y_d = 0;
ptrUnit->dir = x_d > 0? DIRECTION_RIGHT: DIRECTION_LEFT;
break;
}
}
@ -410,7 +441,7 @@ void UnitHandler(TYPE_UNIT* unitArray, size_t sz)
}
}
uint8_t UnitGetAvailableActions(TYPE_UNIT* ptrUnit)
uint8_t UnitGetAvailableActions(TYPE_UNIT *ptrUnit)
{
return UnitActionsTable[ptrUnit->id];
}

9
Unit.h
View File

@ -100,17 +100,18 @@ void UnitHandler(TYPE_UNIT* unitArray, size_t sz);
uint8_t UnitGetHpFromID(TYPE_UNIT_ID id);
uint8_t UnitGetWidthFromID(TYPE_UNIT_ID id);
uint8_t UnitGetHeightFromID(TYPE_UNIT_ID id);
uint8_t UnitGetAvailableActions(TYPE_UNIT* ptrUnit);
uint8_t UnitGetAvailableActions(TYPE_UNIT *ptrUnit);
TYPE_RESOURCES UnitNeededResourcesFromID(TYPE_UNIT_ID id);
// Rendering
void UnitDraw(TYPE_UNIT* ptrUnit, TYPE_CAMERA* ptrCamera, bool bHighlighted);
void UnitDraw(TYPE_UNIT *ptrUnit, TYPE_CAMERA* ptrCamera, bool bHighlighted);
void UnitDrawShadow(TYPE_UNIT *ptrUnit, TYPE_CAMERA *ptrCamera);
// Movement
void UnitMoveTo(TYPE_UNIT* ptrUnit, uint16_t x, uint16_t y);
void UnitMoveTo(TYPE_UNIT *ptrUnit, uint16_t x, uint16_t y);
// Collision cheking
bool UnitCheckCollisionAgainstOtherUnits(TYPE_COLLISION_BLOCK* cb, TYPE_UNIT* ptrUnitArray, TYPE_UNIT* ptrCurrentUnit);
bool UnitCheckCollisionAgainstOtherUnits(TYPE_COLLISION_BLOCK* cb, TYPE_UNIT *ptrUnitArray, TYPE_UNIT* ptrCurrentUnit);
// Selection index
const char* UnitGetActionString(UNIT_ACTION action);