Airport/Source/Aircraft.c
Xavier ASUS 8fcf5bf1f7 Removed SIO interrupt (it caused VBlank ISR not to be triggered).
Added Gfx wait on LoadMenuEnd(). Otherwise, some levels would not start after loading all required files.
Also, added GPU wait on Menu.c before entering the main loop.
An invalid index inside sound table was being accessed when creating an arrival flight. This made the game crash only under real hardware.
Other minor changes and fixes.
2018-11-30 01:34:40 +01:00

937 lines
29 KiB
C

/* *************************************
* Includes
* *************************************/
#include "Aircraft.h"
#include "System.h"
#include "Game.h"
#include "Camera.h"
#include "LoadMenu.h"
/* *************************************
* Defines
* *************************************/
#define AIRCRAFT_SIZE 16
#define AIRCRAFT_SIZE_FIX16 fix16_from_int(AIRCRAFT_SIZE)
#define AIRCRAFT_INVALID_IDX 0xFF
/* *************************************
* Structs and enums
* *************************************/
enum
{
AIRCRAFT_SPRITE_W = 24,
AIRCRAFT_SPRITE_H = 16,
AIRCRAFT_SPRITE_VRAM_X = 800,
AIRCRAFT_SPRITE_VRAM_Y = 256,
};
enum
{
PHX_LIVERY_CLUT_X = 384,
PHX_LIVERY_CLUT_Y = 497,
};
typedef enum t_aircraftSpeeds
{
AIRCRAFT_SPEED_IDLE = 0,
AIRCRAFT_SPEED_GROUND,
AIRCRAFT_SPEED_APPROACH,
AIRCRAFT_SPEED_TAKEOFF,
AIRCRAFT_SPEED_FINAL,
AIRCRAFT_SPEED_FINAL_Z,
}AIRCRAFT_SPEEDS;
/* *************************************
* Local variables
* *************************************/
static TYPE_AIRCRAFT_DATA AircraftData[GAME_MAX_AIRCRAFT];
static uint8_t aircraftIndex;
static GsSprite AircraftSpr;
static GsSprite UpDownArrowSpr;
static GsSprite LeftRightArrowSpr;
static TYPE_ISOMETRIC_POS AircraftCenterIsoPos;
static TYPE_CARTESIAN_POS AircraftCenterPos;
static AIRCRAFT_LIVERY AircraftLiveryTable[] = {AIRCRAFT_LIVERY_0, AIRCRAFT_LIVERY_UNKNOWN};
// Used to quickly link FlightData indexes against AircraftData indexes.
static uint8_t flightDataIdxTable[GAME_MAX_AIRCRAFT];
static const fix16_t AircraftSpeedsTable[] =
{
[AIRCRAFT_SPEED_IDLE] = 0,
[AIRCRAFT_SPEED_GROUND] = 0x9999,
[AIRCRAFT_SPEED_TAKEOFF] = 0x20000,
[AIRCRAFT_SPEED_FINAL] = 0x10000,
[AIRCRAFT_SPEED_FINAL_Z] = 0x3000
};
/* *************************************
* Local prototypes
* *************************************/
static void AircraftDirection(TYPE_AIRCRAFT_DATA* const ptrAircraft);
static AIRCRAFT_LIVERY AircraftLiveryFromFlightNumber(char* strFlightNumber);
static void AircraftAttitude(TYPE_AIRCRAFT_DATA* const ptrAircraft);
static void AircraftUpdateSpriteFromData(TYPE_AIRCRAFT_DATA* const ptrAircraft);
static void AircraftSpeed(TYPE_AIRCRAFT_DATA* const ptrAircraft);
static bool AircraftCheckCollision(const TYPE_AIRCRAFT_DATA* const ptrRefAircraft, const TYPE_AIRCRAFT_DATA* const ptrOtherAircraft);
static bool AircraftCheckPath(TYPE_AIRCRAFT_DATA* ptrAicraft, TYPE_AIRCRAFT_DATA* ptrOtherAircraft);
void AircraftInit(void)
{
static bool initialised;
bzero(AircraftData, GAME_MAX_AIRCRAFT * sizeof (TYPE_AIRCRAFT_DATA));
aircraftIndex = 0;
AircraftSpr.x = 0;
AircraftSpr.y = 0;
AircraftSpr.attribute = COLORMODE(COLORMODE_8BPP);
AircraftSpr.cx = PHX_LIVERY_CLUT_X;
AircraftSpr.cy = PHX_LIVERY_CLUT_Y;
AircraftSpr.w = AIRCRAFT_SPRITE_W;
AircraftSpr.h = AIRCRAFT_SPRITE_H;
GfxTPageOffsetFromVRAMPosition(&AircraftSpr, AIRCRAFT_SPRITE_VRAM_X, AIRCRAFT_SPRITE_VRAM_Y);
AircraftCenterIsoPos.x = AIRCRAFT_SIZE >> 1;
AircraftCenterIsoPos.y = AIRCRAFT_SIZE >> 1;
AircraftCenterIsoPos.z = 0;
AircraftCenterPos = GfxIsometricToCartesian(&AircraftCenterIsoPos);
memset(flightDataIdxTable, AIRCRAFT_INVALID_IDX, sizeof (flightDataIdxTable));
if (initialised == false)
{
static const char* const GameFileList[] =
{
"DATA\\SPRITES\\UDNARROW.TIM",
"DATA\\SPRITES\\LFRARROW.TIM"
};
static void* const GameFileDest[] =
{
&UpDownArrowSpr,
&LeftRightArrowSpr
};
initialised = true;
LOAD_FILES(GameFileList, GameFileDest);
}
}
bool AircraftAddNew( TYPE_FLIGHT_DATA* const ptrFlightData,
uint8_t FlightDataIndex,
uint16_t* targets,
DIRECTION direction )
{
if (aircraftIndex < GAME_MAX_AIRCRAFT)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = &AircraftData[aircraftIndex];
memmove(ptrAircraft->Target, targets, sizeof (uint16_t) * AIRCRAFT_MAX_TARGETS);
ptrAircraft->TargetIdx = 0;
ptrAircraft->Livery = AircraftLiveryFromFlightNumber(ptrFlightData->strFlightNumber[FlightDataIndex]);
ptrAircraft->FlightDataIdx = FlightDataIndex;
Serial_printf("ptrAircraft->FlightDataIdx = %d, FlightDataIndex = %d\n", ptrAircraft->FlightDataIdx, FlightDataIndex);
if (ptrFlightData->FlightDirection[FlightDataIndex] == ARRIVAL)
{
const uint8_t level_columns = GameGetLevelColumns();
switch (direction)
{
case DIR_EAST:
ptrAircraft->IsoPos.x = 0;
ptrAircraft->IsoPos.y = targets[0] / level_columns;
ptrAircraft->IsoPos.y <<= TILE_SIZE_BIT_SHIFT;
ptrAircraft->IsoPos.y += TILE_SIZE >> 1; // Adjust to tile center
ptrAircraft->IsoPos.y = fix16_from_int(ptrAircraft->IsoPos.y);
ptrAircraft->IsoPos.z = targets[0] % level_columns;
ptrAircraft->IsoPos.z <<= TILE_SIZE_BIT_SHIFT - 2;
ptrAircraft->IsoPos.z += 8;
ptrAircraft->IsoPos.z = fix16_from_int(ptrAircraft->IsoPos.z);
break;
case DIR_SOUTH:
ptrAircraft->IsoPos.x = targets[0] % level_columns;
ptrAircraft->IsoPos.x <<= TILE_SIZE_BIT_SHIFT;
ptrAircraft->IsoPos.x += TILE_SIZE >> 1; // Adjust to tile center
ptrAircraft->IsoPos.x = fix16_from_int(ptrAircraft->IsoPos.x);
ptrAircraft->IsoPos.y = 0;
ptrAircraft->IsoPos.z = targets[0] / level_columns;
ptrAircraft->IsoPos.z <<= TILE_SIZE_BIT_SHIFT - 2;
ptrAircraft->IsoPos.z += 8;
ptrAircraft->IsoPos.z = fix16_from_int(ptrAircraft->IsoPos.z);
break;
case NO_DIRECTION:
// Fall through
default:
Serial_printf("Invalid runway direction %d for inbound flight.\n", direction);
return false;
}
}
else if (ptrFlightData->FlightDirection[FlightDataIndex] == DEPARTURE)
{
if (direction == NO_DIRECTION)
{
Serial_printf("Invalid direction for outbound flight.\n");
return false;
}
ptrAircraft->IsoPos.x = GameGetXFromTile(ptrFlightData->Parking[FlightDataIndex]);
ptrAircraft->IsoPos.y = GameGetYFromTile(ptrFlightData->Parking[FlightDataIndex]);
ptrAircraft->IsoPos.z = 0;
}
ptrAircraft->Direction = direction;
ptrAircraft->State = ptrFlightData->State[FlightDataIndex];
flightDataIdxTable[FlightDataIndex] = aircraftIndex;
Serial_printf("\nAircraft Data:\n");
Serial_printf("\tTargets:");
{
uint8_t i;
for (i = 0; i < AIRCRAFT_MAX_TARGETS; i++)
{
if (ptrAircraft->Target[i] == 0)
{
break;
}
Serial_printf(" %d", ptrAircraft->Target[i]);
}
}
Serial_printf("\n\tDirection: %d\n", ptrAircraft->Direction);
Serial_printf("\nLivery: %d\n", ptrAircraft->Livery );
Serial_printf("Aircraft position: {%d, %d, %d}\n",
fix16_to_int(ptrAircraft->IsoPos.x),
fix16_to_int(ptrAircraft->IsoPos.y),
fix16_to_int(ptrAircraft->IsoPos.z) );
aircraftIndex++;
return true;
}
else
{
Serial_printf("Exceeded maximum aircraft capacity!\n");
}
return false;
}
static AIRCRAFT_LIVERY AircraftLiveryFromFlightNumber(char* strFlightNumber)
{
static const char* const AircraftLiveryNamesTable[] =
{
"PHX",
NULL
};
int32_t liveryIndex;
char strLivery[4];
memset(strLivery, 0, ARRAY_SIZE(strLivery) );
strncpy(strLivery, strFlightNumber, 3);
liveryIndex = SystemIndexOfStringArray(strLivery, AircraftLiveryNamesTable);
if (liveryIndex == -1)
{
return AIRCRAFT_LIVERY_UNKNOWN;
}
return AircraftLiveryTable[liveryIndex];
}
bool AircraftRemove(uint8_t aircraftIdx)
{
if (aircraftIdx != AIRCRAFT_INVALID_IDX)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = AircraftFromFlightDataIndex(aircraftIdx);
if (ptrAircraft->State != STATE_IDLE)
{
if (ptrAircraft->FlightDataIdx == aircraftIdx)
{
ptrAircraft->State = STATE_IDLE;
Serial_printf("Flight %d removed\n", ptrAircraft->FlightDataIdx);
return true;
}
}
}
return false;
}
void AircraftHandler(void)
{
uint8_t i;
for (i = 0; i < GAME_MAX_AIRCRAFT; i++)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = &AircraftData[i];
bool collision_warning = false;
if (ptrAircraft->State != STATE_IDLE)
{
uint8_t j;
AircraftDirection(ptrAircraft);
AircraftAttitude(ptrAircraft);
AircraftSpeed(ptrAircraft);
// Check collision against all other aircraft.
for (j = 0; j < GAME_MAX_AIRCRAFT; j++)
{
TYPE_AIRCRAFT_DATA* ptrOtherAircraft = &AircraftData[j];
if (ptrOtherAircraft->State == STATE_IDLE)
{
continue;
}
if (i == j)
{
continue;
}
else
{
// Check whether aircraft should stop in order to avoid collision against
// other aircraft.
// WARNING: only STATE_TAXIING can be used to automatically stop an aircraft
// when calling GameStopFlight() or GameResumeFlightFromAutoStop().
collision_warning |= AircraftCheckPath(ptrAircraft, ptrOtherAircraft);
}
if (j > i)
{
if (AircraftCheckCollision(ptrAircraft, ptrOtherAircraft))
{
GameAircraftCollision(ptrAircraft->FlightDataIdx);
break;
}
}
else
{
// Collision already calculated.
}
}
if (collision_warning)
{
GameStopFlight(ptrAircraft->FlightDataIdx);
}
else
{
GameResumeFlightFromAutoStop(ptrAircraft->FlightDataIdx);
}
ptrAircraft->State = GameGetFlightDataStateFromIdx(ptrAircraft->FlightDataIdx);
}
}
}
static bool AircraftCheckPath(TYPE_AIRCRAFT_DATA* const ptrAircraft, TYPE_AIRCRAFT_DATA* ptrOtherAircraft)
{
const uint16_t currentTile = AircraftGetTileFromFlightDataIndex(ptrAircraft->FlightDataIdx);
uint16_t nextTile; // Keep compiler happy
switch (ptrAircraft->Direction)
{
case DIR_EAST:
nextTile = currentTile + 1;
break;
case DIR_WEST:
nextTile = currentTile - 1;
break;
case DIR_NORTH:
nextTile = currentTile - GameGetLevelColumns();
break;
case DIR_SOUTH:
nextTile = currentTile + GameGetLevelColumns();
break;
case NO_DIRECTION:
// Fall through
default:
Serial_printf("AircraftCheckPath: Undefined direction\n");
return false;
}
{
const uint16_t otherAircraft_currentTile = AircraftGetTileFromFlightDataIndex(ptrOtherAircraft->FlightDataIdx);
if ( (otherAircraft_currentTile == nextTile)
||
(otherAircraft_currentTile == currentTile) )
{
if (ptrOtherAircraft->Speed == 0)
{
// Make ptrAircraft stop if ptrOtherAircraft is nearby and not moving!
return true;
}
}
}
return false;
}
static void AircraftSpeed(TYPE_AIRCRAFT_DATA* const ptrAircraft)
{
switch(ptrAircraft->State)
{
case STATE_FINAL:
ptrAircraft->Speed = AircraftSpeedsTable[AIRCRAFT_SPEED_FINAL];
break;
case STATE_TAKEOFF:
// Fall through
case STATE_CLIMBING:
ptrAircraft->Speed = AircraftSpeedsTable[AIRCRAFT_SPEED_TAKEOFF];
break;
case STATE_TAXIING:
// Fall through
case STATE_ENTERING_RWY:
ptrAircraft->Speed = AircraftSpeedsTable[AIRCRAFT_SPEED_GROUND];
break;
case STATE_USER_STOPPED:
// Fall through
case STATE_AUTO_STOPPED:
// Fall through
case STATE_READY_FOR_TAKEOFF:
// Fall through
case STATE_UNBOARDING:
// Fall through
case STATE_IDLE:
// Fall through
case STATE_LANDED:
// Fall through
case STATE_HOLDING_RWY:
// Fall through
default:
ptrAircraft->Speed = 0;
break;
}
}
void AircraftRender(TYPE_PLAYER* const ptrPlayer, uint8_t aircraftIdx)
{
if (aircraftIdx != AIRCRAFT_INVALID_IDX)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = AircraftFromFlightDataIndex(aircraftIdx);
if (ptrAircraft != NULL)
{
if (ptrAircraft->State != STATE_IDLE)
{
AircraftUpdateSpriteFromData(ptrAircraft);
if (ptrAircraft->IsoPos.z > 0)
{
// Draw aircraft shadow
TYPE_ISOMETRIC_FIX16_POS shadowIsoPos;
shadowIsoPos.x = ptrAircraft->IsoPos.x;
shadowIsoPos.y = ptrAircraft->IsoPos.y;
shadowIsoPos.z = 0;
const TYPE_CARTESIAN_POS shadowCartPos = GfxIsometricFix16ToCartesian(&shadowIsoPos);
// Aircraft position is referred to aircraft center
AircraftSpr.x = shadowCartPos.x - (AircraftSpr.w >> 1);
AircraftSpr.y = shadowCartPos.y - (AircraftSpr.h >> 1);
CameraApplyCoordinatesToSprite(ptrPlayer, &AircraftSpr);
AircraftSpr.r = 0;
AircraftSpr.g = 0;
AircraftSpr.b = 0;
GfxSortSprite(&AircraftSpr);
}
const TYPE_CARTESIAN_POS cartPos = GfxIsometricFix16ToCartesian(&ptrAircraft->IsoPos);
// Aircraft position is referred to aircraft center
AircraftSpr.x = cartPos.x - (AircraftSpr.w >> 1);
AircraftSpr.y = cartPos.y - (AircraftSpr.h >> 1);
CameraApplyCoordinatesToSprite(ptrPlayer, &AircraftSpr);
if ((ptrPlayer->FlightDataSelectedAircraft == aircraftIdx)
&&
(ptrPlayer->ShowAircraftData))
{
static uint8_t aircraft_sine;
static bool aircraft_sine_decrease;
if (aircraft_sine_decrease == false)
{
if (aircraft_sine < 240)
{
aircraft_sine += 24;
}
else
{
aircraft_sine_decrease = true;
}
}
else
{
if (aircraft_sine > 24)
{
aircraft_sine -= 24;
}
else
{
aircraft_sine_decrease = false;
}
}
AircraftSpr.r = NORMAL_LUMINANCE >> 2;
AircraftSpr.g = NORMAL_LUMINANCE >> 2;
AircraftSpr.b = aircraft_sine;
if (GfxIsSpriteInsideScreenArea(&AircraftSpr) == false)
{
bool showLRArrow = false;
bool showUPDNArrow = false;
// When aircraft can't be shown on screen,
// show an arrow indicating its position.
if (AircraftSpr.x < 0)
{
LeftRightArrowSpr.x = 0;
LeftRightArrowSpr.attribute |= H_FLIP;
showLRArrow = true;
}
else if (AircraftSpr.x > X_SCREEN_RESOLUTION)
{
LeftRightArrowSpr.x = X_SCREEN_RESOLUTION - (LeftRightArrowSpr.w << 1);
LeftRightArrowSpr.attribute &= ~(H_FLIP);
showLRArrow = true;
}
else if (AircraftSpr.y < 0)
{
UpDownArrowSpr.y = 0;
UpDownArrowSpr.attribute &= ~(V_FLIP);
showUPDNArrow = true;
}
else if (AircraftSpr.y > Y_SCREEN_RESOLUTION)
{
UpDownArrowSpr.y = Y_SCREEN_RESOLUTION - (UpDownArrowSpr.h);
UpDownArrowSpr.attribute |= V_FLIP;
showUPDNArrow = true;
}
if (showLRArrow)
{
LeftRightArrowSpr.y = AircraftSpr.y;
// First, saturate calculated Y values to {0, Y_SCREEN_RESOLUTION - LeftRightArrowSpr.h}.
if (LeftRightArrowSpr.y < 0)
{
LeftRightArrowSpr.y = 0;
}
else if (LeftRightArrowSpr.y > (Y_SCREEN_RESOLUTION - LeftRightArrowSpr.h) )
{
LeftRightArrowSpr.y = (Y_SCREEN_RESOLUTION - LeftRightArrowSpr.h);
}
GfxSortSprite(&LeftRightArrowSpr);
}
else if (showUPDNArrow)
{
UpDownArrowSpr.x = AircraftSpr.x;
// First, saturate calculated Y values to {0, Y_SCREEN_RESOLUTION - UpDownArrowSpr.h}.
if (UpDownArrowSpr.x < 0)
{
UpDownArrowSpr.x = 0;
}
else if (UpDownArrowSpr.x > (X_SCREEN_RESOLUTION - (UpDownArrowSpr.w << 1) ) )
{
UpDownArrowSpr.x = (UpDownArrowSpr.w << 1);
}
GfxSortSprite(&UpDownArrowSpr);
}
}
}
else
{
AircraftSpr.r = NORMAL_LUMINANCE;
AircraftSpr.g = NORMAL_LUMINANCE;
AircraftSpr.b = NORMAL_LUMINANCE;
}
GfxSortSprite(&AircraftSpr);
}
}
}
}
static void AircraftDirection(TYPE_AIRCRAFT_DATA* const ptrAircraft)
{
TYPE_ISOMETRIC_FIX16_POS targetPos;
if (ptrAircraft->State != STATE_CLIMBING)
{
if (ptrAircraft->Target[ptrAircraft->TargetIdx] == 0)
{
return;
}
targetPos.x = GameGetXFromTile(ptrAircraft->Target[ptrAircraft->TargetIdx]);
targetPos.y = GameGetYFromTile(ptrAircraft->Target[ptrAircraft->TargetIdx]);
targetPos.z = 0;
ptrAircraft->TargetReached = false;
if (targetPos.y == ptrAircraft->IsoPos.y)
{
if (targetPos.x > ptrAircraft->IsoPos.x)
{
if (targetPos.x <= (ptrAircraft->IsoPos.x + ptrAircraft->Speed) )
{
ptrAircraft->TargetReached = true;
}
else
{
ptrAircraft->Direction = DIR_EAST;
ptrAircraft->IsoPos.x += ptrAircraft->Speed;
}
}
else if (targetPos.x < ptrAircraft->IsoPos.x)
{
if (targetPos.x >= (ptrAircraft->IsoPos.x - ptrAircraft->Speed) )
{
ptrAircraft->TargetReached = true;
}
else
{
ptrAircraft->Direction = DIR_WEST;
ptrAircraft->IsoPos.x -= ptrAircraft->Speed;
}
}
else
{
ptrAircraft->TargetReached = true;
}
}
else if (targetPos.x == ptrAircraft->IsoPos.x)
{
if (targetPos.y > ptrAircraft->IsoPos.y)
{
if (targetPos.y <= (ptrAircraft->IsoPos.y + ptrAircraft->Speed) )
{
ptrAircraft->TargetReached = true;
}
else
{
ptrAircraft->Direction = DIR_SOUTH;
ptrAircraft->IsoPos.y += ptrAircraft->Speed;
}
}
else if (targetPos.y < ptrAircraft->IsoPos.y)
{
if (targetPos.y >= (ptrAircraft->IsoPos.y - ptrAircraft->Speed) )
{
ptrAircraft->TargetReached = true;
}
else
{
ptrAircraft->Direction = DIR_NORTH;
ptrAircraft->IsoPos.y -= ptrAircraft->Speed;
}
}
else
{
ptrAircraft->TargetReached = true;
}
}
if (ptrAircraft->TargetReached)
{
ptrAircraft->IsoPos.x = targetPos.x;
ptrAircraft->IsoPos.y = targetPos.y;
if (ptrAircraft->Target[++ptrAircraft->TargetIdx] == 0)
{
Serial_printf("All targets reached!\n");
ptrAircraft->State = GameTargetsReached(ptrAircraft->Target[0], ptrAircraft->FlightDataIdx);
memset(ptrAircraft->Target, 0, AIRCRAFT_MAX_TARGETS);
}
}
}
else
{
// STATE_CLIMBING
switch(ptrAircraft->Direction)
{
case DIR_EAST:
ptrAircraft->IsoPos.x += ptrAircraft->Speed;
break;
case DIR_WEST:
ptrAircraft->IsoPos.x -= ptrAircraft->Speed;
break;
case DIR_NORTH:
ptrAircraft->IsoPos.y -= ptrAircraft->Speed;
break;
case DIR_SOUTH:
ptrAircraft->IsoPos.y += ptrAircraft->Speed;
break;
case NO_DIRECTION:
// Fall through
default:
return;
}
ptrAircraft->IsoPos.z += AircraftSpeedsTable[AIRCRAFT_SPEED_FINAL_Z];
if (GameInsideLevelFromIsoPos(&ptrAircraft->IsoPos) == false)
{
GameRemoveFlight(ptrAircraft->FlightDataIdx, true);
// Deactivate TYPE_AIRCRAFT instance.
ptrAircraft->State = STATE_IDLE;
}
}
}
static void AircraftUpdateSpriteFromData(TYPE_AIRCRAFT_DATA* const ptrAircraft)
{
switch(ptrAircraft->Livery)
{
case AIRCRAFT_LIVERY_0:
AircraftSpr.cx = PHX_LIVERY_CLUT_X;
AircraftSpr.cy = PHX_LIVERY_CLUT_Y;
break;
case AIRCRAFT_LIVERY_UNKNOWN:
// Fall through
default:
Serial_printf("Unknown livery %d!\n", ptrAircraft->Livery);
break;
}
// Reset TPAGE and {U, V} offset first.
GfxTPageOffsetFromVRAMPosition(&AircraftSpr, AIRCRAFT_SPRITE_VRAM_X, AIRCRAFT_SPRITE_VRAM_Y);
switch(ptrAircraft->Direction)
{
case DIR_NORTH:
AircraftSpr.v += AircraftSpr.h;
AircraftSpr.attribute |= H_FLIP;
break;
case DIR_SOUTH:
AircraftSpr.v += 0;
AircraftSpr.attribute |= H_FLIP;
break;
case DIR_EAST:
AircraftSpr.v += 0;
AircraftSpr.attribute &= ~(H_FLIP);
break;
case DIR_WEST:
AircraftSpr.v += AircraftSpr.h;
AircraftSpr.attribute &= ~(H_FLIP);
break;
case NO_DIRECTION:
// Fall through
default:
break;
}
}
static void AircraftAttitude(TYPE_AIRCRAFT_DATA* const ptrAircraft)
{
if (ptrAircraft->State == STATE_FINAL)
{
if (ptrAircraft->IsoPos.z > 0)
{
ptrAircraft->IsoPos.z -= AircraftSpeedsTable[AIRCRAFT_SPEED_FINAL_Z];
}
}
}
TYPE_ISOMETRIC_POS AircraftGetIsoPos(const uint8_t FlightDataIdx)
{
TYPE_ISOMETRIC_POS retIsoPos = {0};
if (FlightDataIdx != AIRCRAFT_INVALID_IDX)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = AircraftFromFlightDataIndex(FlightDataIdx);
if (ptrAircraft != NULL)
{
// Aircraft position data is stored in fix16_t data type instead of "short" data type.
// So we must perform a conversion first for convenience.
const TYPE_ISOMETRIC_FIX16_POS fix16IsoPos = ptrAircraft->IsoPos;
retIsoPos.x = (short)fix16_to_int(fix16IsoPos.x);
retIsoPos.y = (short)fix16_to_int(fix16IsoPos.y);
retIsoPos.z = (short)fix16_to_int(fix16IsoPos.z);
}
}
return retIsoPos;
}
void AircraftAddTargets(TYPE_AIRCRAFT_DATA* const ptrAircraft, const uint16_t* const targets)
{
memmove(ptrAircraft->Target, targets, sizeof (uint16_t) * AIRCRAFT_MAX_TARGETS);
ptrAircraft->TargetIdx = 0;
}
uint16_t AircraftGetTileFromFlightDataIndex(const uint8_t index)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = AircraftFromFlightDataIndex(index);
if (ptrAircraft != NULL)
{
if (ptrAircraft->State != STATE_IDLE)
{
TYPE_ISOMETRIC_POS isoPos = AircraftGetIsoPos(index);
return GameGetTileFromIsoPosition(&isoPos);
}
}
return 0;
}
TYPE_AIRCRAFT_DATA* AircraftFromFlightDataIndex(const uint8_t index)
{
if ((index != AIRCRAFT_INVALID_IDX)
&&
(index < GAME_MAX_AIRCRAFT))
{
const uint8_t idx = flightDataIdxTable[index];
if (idx != AIRCRAFT_INVALID_IDX)
{
return &AircraftData[idx];
}
}
return NULL;
}
void AircraftFromFlightDataIndexAddTargets(const uint8_t index, const uint16_t* const targets)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = AircraftFromFlightDataIndex(index);
if (ptrAircraft != NULL)
{
AircraftAddTargets(ptrAircraft, targets);
}
}
DIRECTION AircraftGetDirection(TYPE_AIRCRAFT_DATA* const ptrAircraft)
{
return ptrAircraft->Direction;
}
const uint16_t* AircraftGetTargets(uint8_t index)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = AircraftFromFlightDataIndex(index);
if (ptrAircraft != NULL)
{
return ptrAircraft->Target;
}
return NULL;
}
uint8_t AircraftGetTargetIdx(uint8_t index)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = AircraftFromFlightDataIndex(index);
if (ptrAircraft != NULL)
{
return ptrAircraft->TargetIdx;
}
return 0;
}
bool AircraftMoving(uint8_t index)
{
TYPE_AIRCRAFT_DATA* const ptrAircraft = AircraftFromFlightDataIndex(index);
if (ptrAircraft != NULL)
{
return (bool)ptrAircraft->Speed;
}
return false;
}
static bool AircraftCheckCollision(const TYPE_AIRCRAFT_DATA* const ptrRefAircraft, const TYPE_AIRCRAFT_DATA* const ptrOtherAircraft)
{
// Here I have used an old macro that I found on nextvolume's source code for "A Small Journey", IIRC.
// Totally fool-proof, so I dint' want to complicate things!
#define check_bb_collision(x1,y1,w1,h1,x2,y2,w2,h2) (!( ((x1)>=(x2)+(w2)) || ((x2)>=(x1)+(w1)) || \
((y1)>=(y2)+(h2)) || ((y2)>=(y1)+(h1)) ))
if (check_bb_collision( ptrRefAircraft->IsoPos.x,
ptrRefAircraft->IsoPos.y,
AIRCRAFT_SIZE_FIX16,
AIRCRAFT_SIZE_FIX16,
ptrOtherAircraft->IsoPos.x,
ptrOtherAircraft->IsoPos.y,
AIRCRAFT_SIZE_FIX16,
AIRCRAFT_SIZE_FIX16 ) != 0)
{
if (ptrRefAircraft->IsoPos.z == ptrOtherAircraft->IsoPos.z)
{
return true;
}
}
return false;
#undef check_bb_collision
}