1879 lines
43 KiB
C
1879 lines
43 KiB
C
/* *************************************
|
|
* Includes
|
|
* *************************************/
|
|
|
|
#include "Game.h"
|
|
|
|
/* *************************************
|
|
* Defines
|
|
* *************************************/
|
|
|
|
#define GAME_MAX_MAP_SIZE 0x400
|
|
#define GAME_MAX_RUNWAYS 16
|
|
#define GAME_MAX_RWY_LENGTH 16
|
|
|
|
#define MIN_MAP_COLUMNS 8
|
|
#define MAX_MAP_COLUMNS 32
|
|
|
|
#define LEVEL_HEADER_SIZE 64
|
|
#define COLUMNS_PER_TILESET 4
|
|
#define ROWS_PER_TILESET COLUMNS_PER_TILESET
|
|
#define LEVEL_MAGIC_NUMBER_SIZE 3
|
|
#define LEVEL_MAGIC_NUMBER_STRING "ATC"
|
|
#define LEVEL_TITLE_SIZE 24
|
|
#define TILE_MIRROR_FLAG ( (uint8_t)0x80 )
|
|
|
|
#define GAME_INVALID_TILE_SELECTION ( (uint16_t)0xFFFF )
|
|
|
|
/* **************************************
|
|
* Structs and enums *
|
|
* *************************************/
|
|
|
|
enum
|
|
{
|
|
TILE_GRASS = 0,
|
|
TILE_ASPHALT_WITH_BORDERS,
|
|
TILE_WATER,
|
|
TILE_ASPHALT,
|
|
TILE_HANGAR,
|
|
TILE_ILS,
|
|
TILE_ATC_TOWER,
|
|
TILE_ATC_LOC,
|
|
TILE_RWY_MID,
|
|
TILE_RWY_START_1,
|
|
TILE_RWY_START_2,
|
|
TILE_PARKING,
|
|
TILE_RESERVED_1,
|
|
TILE_TAXIWAY_INTERSECT_GRASS,
|
|
TILE_TAXIWAY_GRASS,
|
|
TILE_TAXIWAY_CORNER_GRASS,
|
|
|
|
LAST_TILE_TILESET1 = TILE_TAXIWAY_CORNER_GRASS
|
|
};
|
|
|
|
enum
|
|
{
|
|
TILE_HALF_WATER_1 = LAST_TILE_TILESET1 + 1,
|
|
TILE_HALF_WATER_2,
|
|
TILE_RESERVED_2,
|
|
TILE_RESERVED_3,
|
|
TILE_AIRPORT_BUILDING,
|
|
TILE_PLANE,
|
|
TILE_RESERVED_4,
|
|
TILE_RESERVED_5,
|
|
TILE_RWY_EXIT,
|
|
TILE_GATE,
|
|
TILE_RESERVED_6,
|
|
TILE_RESERVED_7,
|
|
TILE_TAXIWAY_CORNER_GRASS_2,
|
|
|
|
LAST_TILE_TILESET2 = TILE_TAXIWAY_CORNER_GRASS_2,
|
|
|
|
TILE_NOTHING = 0xFF
|
|
};
|
|
|
|
enum
|
|
{
|
|
MOUSE_W = 8,
|
|
MOUSE_H = 8,
|
|
MOUSE_X = (X_SCREEN_RESOLUTION >> 1),
|
|
MOUSE_Y = (Y_SCREEN_RESOLUTION >> 1),
|
|
MOUSE_X_2PLAYER = (X_SCREEN_RESOLUTION >> 2),
|
|
MOUSE_Y_2PLAYER = (Y_SCREEN_RESOLUTION >> 1)
|
|
};
|
|
|
|
/* *************************************
|
|
* Local Prototypes
|
|
* *************************************/
|
|
|
|
static void GameInit(void);
|
|
static void GameLoadLevel(void);
|
|
static bool GamePause(void);
|
|
static void GameEmergencyMode(void);
|
|
static void GameCalculations(void);
|
|
static void GamePlayerHandler(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData);
|
|
static void GamePlayerAddWaypoint(TYPE_PLAYER* ptrPlayer);
|
|
static void GamePlayerAddWaypoint_Ex(TYPE_PLAYER* ptrPlayer, uint16_t tile);
|
|
static void GameGraphics(void);
|
|
static void GameRenderLevel(TYPE_PLAYER* ptrPlayer);
|
|
//static void GameLoadPilots(char * strPath);
|
|
static void GameClock(void);
|
|
static void GameClockFlights(void);
|
|
static void GameAircraftState(void);
|
|
static void GameActiveAircraft(void);
|
|
static void GameStateShowAircraft(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData);
|
|
static void GameFirstLastAircraftIndex(void);
|
|
static void GameSelectAircraftFromList(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData);
|
|
static void GameStateSelectRunway(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData);
|
|
static void GameStateSelectTaxiwayRunway(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData);
|
|
static void GameStateSelectTaxiwayParking(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData);
|
|
static void GameStateLockTarget(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFlightData);
|
|
static void GameSelectAircraft(TYPE_PLAYER* ptrPlayer);
|
|
static void GameGetRunwayArray(void);
|
|
static void GameGetSelectedRunwayArray(uint16_t rwyHeader);
|
|
static void GameAssignRunwaytoAircraft(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData);
|
|
static bool GamePathToTile(TYPE_PLAYER* ptrPlayer);
|
|
static void GameDrawMouse(TYPE_PLAYER* ptrPlayer);
|
|
|
|
/* *************************************
|
|
* Global Variables
|
|
* *************************************/
|
|
|
|
bool GameStartupFlag;
|
|
|
|
/* *************************************
|
|
* Local Variables
|
|
* *************************************/
|
|
|
|
static GsSprite GameTilesetSpr;
|
|
static GsSprite GameTileset2Spr;
|
|
static GsSprite GamePlaneSpr;
|
|
static GsSprite GameMouseSpr;
|
|
static uint16_t GameRwy[GAME_MAX_RUNWAYS];
|
|
static TYPE_FLIGHT_DATA FlightData;
|
|
static uint16_t GameRwyArray[GAME_MAX_RWY_LENGTH];
|
|
static uint16_t GameUsedRwy[GAME_MAX_RUNWAYS];
|
|
static uint16_t GameSelectedTile;
|
|
|
|
// Instances for player-specific data
|
|
TYPE_PLAYER PlayerData[MAX_PLAYERS];
|
|
|
|
static char * GameFileList[] = { "cdrom:\\DATA\\SPRITES\\TILESET1.TIM;1" ,
|
|
"cdrom:\\DATA\\SPRITES\\TILESET2.TIM;1" ,
|
|
"cdrom:\\DATA\\LEVELS\\LEVEL1.PLT;1" ,
|
|
"cdrom:\\DATA\\SPRITES\\GAMEPLN.TIM;1" ,
|
|
"cdrom:\\DATA\\SPRITES\\PLNBLUE.CLT;1" ,
|
|
"cdrom:\\DATA\\SPRITES\\MOUSE.TIM;1" };
|
|
|
|
static void * GameFileDest[] = { (GsSprite*)&GameTilesetSpr ,
|
|
(GsSprite*)&GameTileset2Spr ,
|
|
(TYPE_FLIGHT_DATA*)&FlightData ,
|
|
(GsSprite*)&GamePlaneSpr ,
|
|
NULL ,
|
|
(GsSprite*)&GameMouseSpr };
|
|
|
|
static char * GameLevelList[] = { "cdrom:\\DATA\\LEVELS\\LEVEL1.LVL;1"};
|
|
static uint8_t GameLevelBuffer[GAME_MAX_MAP_SIZE];
|
|
|
|
static uint8_t GameLevelColumns;
|
|
static uint8_t GameLevelSize;
|
|
|
|
static char GameLevelTitle[LEVEL_TITLE_SIZE];
|
|
|
|
//Game local time
|
|
static uint8_t GameHour;
|
|
static uint8_t GameMinutes;
|
|
|
|
//Local flag for two-player game mode. Obtained from Menu
|
|
static bool TwoPlayersActive;
|
|
//Index for first non-idle aircraft on list
|
|
static uint8_t firstActiveAircraft;
|
|
//Index for last non-idle aircraft on list
|
|
static uint8_t lastActiveAircraft;
|
|
|
|
void Game(bool two_players)
|
|
{
|
|
TwoPlayersActive = two_players;
|
|
GameInit();
|
|
|
|
while(1)
|
|
{
|
|
if(GamePause() == true)
|
|
{
|
|
// Exit game
|
|
break;
|
|
}
|
|
|
|
GameEmergencyMode();
|
|
|
|
GameCalculations();
|
|
|
|
GameGraphics();
|
|
|
|
if(GameStartupFlag == true)
|
|
{
|
|
GameStartupFlag = false;
|
|
}
|
|
}
|
|
|
|
GfxDisableSplitScreen();
|
|
|
|
EndAnimation();
|
|
|
|
SfxPlayTrack(INTRO_TRACK);
|
|
}
|
|
|
|
bool GamePause(void)
|
|
{
|
|
TYPE_PLAYER* ptrPlayer;
|
|
uint8_t i;
|
|
bool pause_flag = false;
|
|
|
|
if(GameStartupFlag == true)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for(i = 0 ; i < MAX_PLAYERS ; i++)
|
|
{
|
|
ptrPlayer = &PlayerData[i];
|
|
// Run player-specific functions for each player
|
|
if(ptrPlayer->Active == true)
|
|
{
|
|
//dprintf("Released callback = 0x%08X\n", ptrPlayer->PadKeySinglePress_Callback);
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_START) == true)
|
|
{
|
|
dprintf("Player %d set pause_flag to true!\n",i);
|
|
pause_flag = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pause_flag == true)
|
|
{
|
|
// Blocking function:
|
|
// * Returns true if player pointed to by ptrPlayer wants to exit game
|
|
// * Returns false if player pointed to by ptrPlayer wants to resume game
|
|
return GameGuiPauseDialog(ptrPlayer);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void GameInit(void)
|
|
{
|
|
uint8_t i;
|
|
uint32_t track;
|
|
|
|
GameStartupFlag = true;
|
|
|
|
LoadMenu( GameFileList,
|
|
GameFileDest,
|
|
sizeof(GameFileList) / sizeof(char*),
|
|
sizeof(GameFileDest) /sizeof(void*) );
|
|
|
|
GameLoadLevel();
|
|
|
|
GameGuiInit();
|
|
|
|
memset(GameRwy,0,GAME_MAX_RUNWAYS * sizeof(uint16_t) );
|
|
|
|
memset(GameUsedRwy,0,GAME_MAX_RUNWAYS * sizeof(uint16_t) );
|
|
|
|
PlayerData[PLAYER_ONE].Active = true;
|
|
PlayerData[PLAYER_ONE].PadKeyPressed_Callback = &PadOneKeyPressed;
|
|
PlayerData[PLAYER_ONE].PadKeyReleased_Callback = &PadOneKeyReleased;
|
|
PlayerData[PLAYER_ONE].PadKeySinglePress_Callback = &PadOneKeySinglePress;
|
|
PlayerData[PLAYER_ONE].PadDirectionKeyPressed_Callback = &PadOneDirectionKeyPressed;
|
|
PlayerData[PLAYER_ONE].FlightDataPage = 0;
|
|
|
|
PlayerData[PLAYER_TWO].Active = TwoPlayersActive? true : false;
|
|
|
|
if(PlayerData[PLAYER_TWO].Active == true)
|
|
{
|
|
PlayerData[PLAYER_TWO].PadKeyPressed_Callback = &PadTwoKeyPressed;
|
|
PlayerData[PLAYER_TWO].PadKeyReleased_Callback = &PadTwoKeyReleased;
|
|
PlayerData[PLAYER_TWO].PadDirectionKeyPressed_Callback = &PadTwoDirectionKeyPressed;
|
|
PlayerData[PLAYER_TWO].FlightDataPage = 0;
|
|
PlayerData[PLAYER_TWO].PadKeySinglePress_Callback = &PadTwoKeySinglePress;
|
|
|
|
// On 2-player mode, one player controls departure flights and
|
|
// other player controls arrival flights.
|
|
PlayerData[PLAYER_ONE].FlightDirection = DEPARTURE;
|
|
PlayerData[PLAYER_TWO].FlightDirection = ARRIVAL;
|
|
}
|
|
else
|
|
{
|
|
PlayerData[PLAYER_ONE].FlightDirection = DEPARTURE | ARRIVAL;
|
|
}
|
|
|
|
for(i = 0; i < MAX_PLAYERS ; i++)
|
|
{
|
|
CameraInit(&PlayerData[i]);
|
|
PlayerData[i].ShowAircraftData = false;
|
|
PlayerData[i].SelectRunway = false;
|
|
PlayerData[i].SelectTaxiwayRunway = false;
|
|
PlayerData[i].LockTarget = false;
|
|
PlayerData[i].SelectedAircraft = 0;
|
|
PlayerData[i].FlightDataPage = 0;
|
|
memset(&PlayerData[i].Waypoints, 0, sizeof(uint16_t) * PLAYER_MAX_WAYPOINTS);
|
|
PlayerData[i].WaypointIdx = 0;
|
|
PlayerData[i].LastWaypointIdx = 0;
|
|
}
|
|
|
|
firstActiveAircraft = 0;
|
|
lastActiveAircraft = 0;
|
|
|
|
if(GameTwoPlayersActive() == true)
|
|
{
|
|
GameMouseSpr.x = MOUSE_X_2PLAYER;
|
|
GameMouseSpr.y = MOUSE_Y_2PLAYER;
|
|
}
|
|
else
|
|
{
|
|
GameMouseSpr.x = MOUSE_X;
|
|
GameMouseSpr.y = MOUSE_Y;
|
|
}
|
|
|
|
GameMouseSpr.w = MOUSE_W;
|
|
GameMouseSpr.h = MOUSE_H;
|
|
GameMouseSpr.attribute = COLORMODE(COLORMODE_16BPP);
|
|
GameMouseSpr.r = NORMAL_LUMINANCE;
|
|
GameMouseSpr.g = NORMAL_LUMINANCE;
|
|
GameMouseSpr.b = NORMAL_LUMINANCE;
|
|
|
|
GameGetRunwayArray();
|
|
|
|
GameSelectedTile = 0;
|
|
|
|
AircraftInit();
|
|
|
|
LoadMenuEnd();
|
|
|
|
GfxSetGlobalLuminance(0);
|
|
|
|
track = SystemRand(GAMEPLAY_FIRST_TRACK,GAMEPLAY_LAST_TRACK);
|
|
|
|
SfxPlayTrack(track);
|
|
}
|
|
|
|
void GameEmergencyMode(void)
|
|
{
|
|
enum
|
|
{
|
|
ERROR_RECT_X = 32,
|
|
ERROR_RECT_W = X_SCREEN_RESOLUTION - (ERROR_RECT_X << 1),
|
|
|
|
ERROR_RECT_Y = 16,
|
|
ERROR_RECT_H = Y_SCREEN_RESOLUTION - (ERROR_RECT_Y << 1),
|
|
|
|
ERROR_RECT_R = 0,
|
|
ERROR_RECT_G = 32,
|
|
ERROR_RECT_B = NORMAL_LUMINANCE
|
|
};
|
|
|
|
GsRectangle errorRct;
|
|
|
|
bzero((GsRectangle*)&errorRct, sizeof(GsRectangle));
|
|
|
|
while(SystemGetEmergencyMode() == true)
|
|
{
|
|
// Pad one has been disconnected during gameplay
|
|
// Show an error screen until it is disconnected again.
|
|
|
|
GsSortCls(0,0,0);
|
|
|
|
errorRct.x = ERROR_RECT_X;
|
|
errorRct.w = ERROR_RECT_W;
|
|
errorRct.y = ERROR_RECT_Y;
|
|
errorRct.h = ERROR_RECT_H;
|
|
|
|
errorRct.r = ERROR_RECT_R;
|
|
errorRct.g = ERROR_RECT_G;
|
|
errorRct.b = ERROR_RECT_B;
|
|
|
|
GsSortRectangle(&errorRct);
|
|
GfxDrawScene();
|
|
}
|
|
}
|
|
|
|
void GameCalculations(void)
|
|
{
|
|
uint8_t i;
|
|
|
|
GameClock();
|
|
GameAircraftState();
|
|
GameActiveAircraft();
|
|
GameFirstLastAircraftIndex();
|
|
AircraftHandler();
|
|
|
|
for(i = 0 ; i < MAX_PLAYERS ; i++)
|
|
{
|
|
// Run player-specific functions for each player
|
|
if(PlayerData[i].Active == true)
|
|
{
|
|
GamePlayerHandler(&PlayerData[i], &FlightData);
|
|
}
|
|
}
|
|
|
|
if(PadOneKeyReleased(PAD_CIRCLE) == true)
|
|
{
|
|
for(i = 0; i < FlightData.nAircraft ; i++)
|
|
{
|
|
/*typedef struct
|
|
{
|
|
FL_DIR FlightDirection[GAME_MAX_AIRCRAFT];
|
|
char strFlightNumber[GAME_MAX_AIRCRAFT][GAME_MAX_CHARACTERS];
|
|
uint8_t Passengers[GAME_MAX_AIRCRAFT];
|
|
uint8_t Hours[GAME_MAX_AIRCRAFT];
|
|
uint8_t Minutes[GAME_MAX_AIRCRAFT];
|
|
uint8_t Parking[GAME_MAX_AIRCRAFT];
|
|
}TYPE_FLIGHT_DATA;*/
|
|
|
|
dprintf("\n*****************\n");
|
|
dprintf("\tAIRCRAFT %d\n",i);
|
|
dprintf("*****************\n");
|
|
|
|
if(FlightData.FlightDirection[i] == ARRIVAL)
|
|
{
|
|
dprintf("Direction: %s\n","Arrival");
|
|
}
|
|
else if(FlightData.FlightDirection[i] == DEPARTURE)
|
|
{
|
|
dprintf("Direction: %s\n","Arrival");
|
|
}
|
|
|
|
dprintf("Time: %d:%d\n",FlightData.Hours[i],FlightData.Minutes[i]);
|
|
|
|
dprintf("State: ");
|
|
|
|
switch(FlightData.State[i])
|
|
{
|
|
case STATE_APPROACH:
|
|
dprintf("Approach");
|
|
break;
|
|
|
|
case STATE_TAXIING:
|
|
dprintf("Taxiing");
|
|
break;
|
|
|
|
case STATE_FINAL:
|
|
dprintf("Final");
|
|
break;
|
|
|
|
case STATE_IDLE:
|
|
dprintf("Idle");
|
|
break;
|
|
|
|
case STATE_PARKED:
|
|
dprintf("Parked");
|
|
break;
|
|
|
|
case STATE_LANDED:
|
|
dprintf("Landed");
|
|
break;
|
|
|
|
case STATE_TAKEOFF:
|
|
dprintf("Takeoff");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
dprintf("\n");
|
|
}
|
|
|
|
dprintf("Active aircraft: %d\n",FlightData.ActiveAircraft);
|
|
}
|
|
|
|
}
|
|
|
|
void GameFirstLastAircraftIndex(void)
|
|
{
|
|
bool first_set = false;
|
|
uint8_t i;
|
|
|
|
for(i = 0; i < GAME_MAX_AIRCRAFT ; i++)
|
|
{
|
|
if(FlightData.State[i] != STATE_IDLE)
|
|
{
|
|
if(first_set == false)
|
|
{
|
|
firstActiveAircraft = i;
|
|
first_set = true;
|
|
}
|
|
lastActiveAircraft = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t GameGetFirstActiveAircraft(void)
|
|
{
|
|
return firstActiveAircraft;
|
|
}
|
|
|
|
uint8_t GameGetLastActiveAircraft(void)
|
|
{
|
|
return lastActiveAircraft;
|
|
}
|
|
|
|
void GamePlayerHandler(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData)
|
|
{
|
|
ptrPlayer->SelectedTile = 0; // Reset selected tile if no states
|
|
// which use this are currently active.
|
|
ptrPlayer->InvalidPath = false; // Do the same thing for "InvalidPath".
|
|
|
|
GameStateLockTarget(ptrPlayer, ptrFlightData);
|
|
GameStateSelectRunway(ptrPlayer, ptrFlightData);
|
|
GameStateSelectTaxiwayRunway(ptrPlayer, ptrFlightData);
|
|
GameStateSelectTaxiwayParking(ptrPlayer, ptrFlightData);
|
|
GameStateShowAircraft(ptrPlayer, ptrFlightData);
|
|
CameraHandler(ptrPlayer);
|
|
GameGuiActiveAircraftList(ptrPlayer, ptrFlightData);
|
|
GameGuiActiveAircraftPage(ptrPlayer, ptrFlightData);
|
|
GameSelectAircraftFromList(ptrPlayer, ptrFlightData);
|
|
}
|
|
|
|
void GameClock(void)
|
|
{
|
|
if(System1SecondTick() == true)
|
|
{
|
|
GameMinutes++;
|
|
|
|
if(GameMinutes >= 60)
|
|
{
|
|
GameHour++;
|
|
GameMinutes = 0;
|
|
}
|
|
|
|
if(GameHour >= 24)
|
|
{
|
|
GameHour = 0;
|
|
}
|
|
}
|
|
|
|
GameClockFlights();
|
|
}
|
|
|
|
void GameClockFlights(void)
|
|
{
|
|
uint8_t i;
|
|
|
|
for(i = 0; i < FlightData.nAircraft ; i++)
|
|
{
|
|
if(System1SecondTick() == true)
|
|
{
|
|
if( (FlightData.Minutes[i] == 0)
|
|
&&
|
|
(FlightData.Hours[i] > 0) )
|
|
{
|
|
FlightData.Minutes[i] = 60;
|
|
FlightData.Hours[i]--;
|
|
}
|
|
|
|
if(FlightData.Minutes[i] > 0)
|
|
{
|
|
FlightData.Minutes[i]--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameGraphics(void)
|
|
{
|
|
int i;
|
|
bool split_screen = false;
|
|
|
|
while(GfxIsGPUBusy() == true);
|
|
|
|
if(TwoPlayersActive == true)
|
|
{
|
|
split_screen = true;
|
|
}
|
|
|
|
if(GfxGetGlobalLuminance() < NORMAL_LUMINANCE)
|
|
{
|
|
// Fading from black effect on startup.
|
|
GfxIncreaseGlobalLuminance(1);
|
|
}
|
|
|
|
for(i = 0; i < MAX_PLAYERS ; i++)
|
|
{
|
|
if(PlayerData[i].Active == true)
|
|
{
|
|
if(split_screen == true)
|
|
{
|
|
GfxSetSplitScreen(i);
|
|
}
|
|
|
|
// Draw half split screen for each player
|
|
// only if 2-player mode is active. Else, render
|
|
// the whole screen as usual.
|
|
|
|
GsSortCls(0,0,GfxGetGlobalLuminance() >> 1);
|
|
|
|
GameRenderLevel(&PlayerData[i]);
|
|
|
|
AircraftRender(&PlayerData[i]);
|
|
|
|
GameGuiAircraftList(&PlayerData[i], &FlightData);
|
|
|
|
GameDrawMouse(&PlayerData[i]);
|
|
}
|
|
}
|
|
|
|
// Avoid changing drawing environment twice on 1-player mode
|
|
// as it doesn't make any sense.
|
|
if(split_screen == true)
|
|
{
|
|
GfxDisableSplitScreen();
|
|
}
|
|
|
|
// Draw common elements for both players (messages, clock...)
|
|
|
|
GameGuiAircraftNotificationRequest(&FlightData);
|
|
|
|
GameGuiBubble(&FlightData);
|
|
|
|
GameGuiClock(GameHour,GameMinutes);
|
|
|
|
GfxDrawScene();
|
|
}
|
|
|
|
void GameLoadLevel(void)
|
|
{
|
|
uint8_t i = 0;
|
|
uint8_t* ptrBuffer;
|
|
char LevelHeader[LEVEL_MAGIC_NUMBER_SIZE + 1];
|
|
|
|
/* TODO - Very important */
|
|
// Map contents (that means, without header) should be copied to GameLevelBuffer
|
|
// Header treatment (magic number, map size, map title...) should be done
|
|
// using System's file buffer.
|
|
|
|
if(SystemLoadFile(GameLevelList[0]) == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ptrBuffer = SystemGetBufferAddress();
|
|
|
|
//SystemLoadFileToBuffer(GameLevelList[0],GameLevelBuffer,GAME_MAX_MAP_SIZE);
|
|
|
|
memset(LevelHeader,0, LEVEL_MAGIC_NUMBER_SIZE + 1);
|
|
|
|
memcpy(LevelHeader,ptrBuffer,LEVEL_MAGIC_NUMBER_SIZE);
|
|
|
|
LevelHeader[LEVEL_MAGIC_NUMBER_SIZE] = '\0';
|
|
|
|
dprintf("Level header: %s\n",LevelHeader);
|
|
|
|
if(strncmp(LevelHeader,LEVEL_MAGIC_NUMBER_STRING,LEVEL_MAGIC_NUMBER_SIZE) != 0)
|
|
{
|
|
dprintf("Invalid level header! Read \"%s\" instead of \"ATC\"\n",LevelHeader);
|
|
return;
|
|
}
|
|
|
|
i += LEVEL_MAGIC_NUMBER_SIZE;
|
|
|
|
GameLevelColumns = ptrBuffer[i++];
|
|
|
|
dprintf("Level size: %d\n",GameLevelColumns);
|
|
|
|
if( (GameLevelColumns < MIN_MAP_COLUMNS)
|
|
||
|
|
(GameLevelColumns > MAX_MAP_COLUMNS) )
|
|
{
|
|
dprintf("Invalid map size! Value: %d\n",GameLevelColumns);
|
|
return;
|
|
}
|
|
|
|
GameLevelSize = GameLevelColumns * GameLevelColumns;
|
|
|
|
memset(GameLevelTitle,0,LEVEL_TITLE_SIZE);
|
|
|
|
memcpy(GameLevelTitle,&ptrBuffer[i],LEVEL_TITLE_SIZE);
|
|
|
|
dprintf("Game level title: %s\n",GameLevelTitle);
|
|
|
|
i += LEVEL_TITLE_SIZE;
|
|
|
|
memset(GameLevelBuffer,0,GAME_MAX_MAP_SIZE);
|
|
|
|
i = LEVEL_HEADER_SIZE;
|
|
|
|
memcpy(GameLevelBuffer,&ptrBuffer[i],GameLevelSize);
|
|
|
|
}
|
|
|
|
char* GetGameLevelTitle(void)
|
|
{
|
|
return GameLevelTitle;
|
|
}
|
|
|
|
void GameAircraftState(void)
|
|
{
|
|
uint8_t i;
|
|
uint16_t target[2] = {0};
|
|
// Arrays are copied to AircraftAddNew, so we create a first and only
|
|
// target which is the parking tile itself, and the second element
|
|
// is just the NULL character.
|
|
// Not an ideal solution, but the best one currently available.
|
|
|
|
for(i = 0; i < FlightData.nAircraft ; i++)
|
|
{
|
|
if( (FlightData.Hours[i] == 0)
|
|
&&
|
|
(FlightData.Minutes[i] == 0)
|
|
&&
|
|
(FlightData.State[i] == STATE_IDLE) )
|
|
{
|
|
if(FlightData.FlightDirection[i] == DEPARTURE)
|
|
{
|
|
FlightData.State[i] = STATE_PARKED;
|
|
|
|
target[0] = FlightData.Parking[i];
|
|
|
|
dprintf("Target assigned = %d", target[0]);
|
|
|
|
if(AircraftAddNew(&FlightData, i, target) == false)
|
|
{
|
|
dprintf("Exceeded maximum aircraft number!\n");
|
|
return;
|
|
}
|
|
}
|
|
else if(FlightData.FlightDirection[i] == ARRIVAL)
|
|
{
|
|
FlightData.State[i] = STATE_APPROACH;
|
|
}
|
|
|
|
// Create notification request for incoming aircraft
|
|
FlightData.NotificationRequest[i] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void GameRenderLevel(TYPE_PLAYER* ptrPlayer)
|
|
{
|
|
uint16_t i;
|
|
uint16_t j;
|
|
uint8_t columns = 0;
|
|
uint8_t rows = 0;
|
|
bool flip_id;
|
|
bool used_rwy;
|
|
uint8_t aux_id;
|
|
GsSprite * ptrTileset;
|
|
static unsigned char rwy_sine = 0;
|
|
static bool rwy_sine_decrease = false;
|
|
TYPE_ISOMETRIC_POS tileIsoPos;
|
|
TYPE_CARTESIAN_POS tileCartPos;
|
|
|
|
// Prepare runway to be painted in blue if player is on runway selection mode
|
|
if(ptrPlayer->SelectRunway == true)
|
|
{
|
|
GameGetSelectedRunwayArray(GameRwy[ptrPlayer->SelectedRunway]);
|
|
/*dprintf("Runway array:\n");
|
|
|
|
for(j = 0; j < GAME_MAX_RWY_LENGTH; j++)
|
|
{
|
|
dprintf("%d ",GameRwyArray[j]);
|
|
}
|
|
|
|
dprintf("\n");*/
|
|
}
|
|
|
|
for(i = 0 ; i < GameLevelSize; i++)
|
|
{
|
|
// Flipped tiles have bit 7 enabled
|
|
if(GameLevelBuffer[i] & TILE_MIRROR_FLAG)
|
|
{
|
|
flip_id = true;
|
|
aux_id = GameLevelBuffer[i];
|
|
GameLevelBuffer[i] &= ~(TILE_MIRROR_FLAG);
|
|
}
|
|
else
|
|
{
|
|
flip_id = false;
|
|
}
|
|
|
|
if(GameLevelBuffer[i] == TILE_NOTHING)
|
|
{
|
|
// Skip empty tiles
|
|
continue;
|
|
}
|
|
|
|
if(GameLevelBuffer[i] <= LAST_TILE_TILESET1)
|
|
{
|
|
// Draw using GameTilesetSpr
|
|
ptrTileset = &GameTilesetSpr;
|
|
}
|
|
else if( (GameLevelBuffer[i] > LAST_TILE_TILESET1)
|
|
&&
|
|
(GameLevelBuffer[i] <= LAST_TILE_TILESET2) )
|
|
{
|
|
// Draw using GameTileset2Spr
|
|
ptrTileset = &GameTileset2Spr;
|
|
}
|
|
else
|
|
{
|
|
ptrTileset = NULL;
|
|
|
|
if(flip_id == false)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ptrTileset->w = TILE_SIZE;
|
|
ptrTileset->h = TILE_SIZE;
|
|
|
|
used_rwy = false;
|
|
|
|
if( (ptrPlayer->SelectRunway == true)
|
|
&&
|
|
(i != 0)
|
|
&&
|
|
(SystemContains_u16(i, GameRwyArray, GAME_MAX_RWY_LENGTH) == true) )
|
|
{
|
|
for(j = 0; j < GAME_MAX_RUNWAYS; j++)
|
|
{
|
|
if(GameUsedRwy[j] != 0)
|
|
{
|
|
if(SystemContains_u16(GameUsedRwy[j], GameRwyArray, GAME_MAX_RWY_LENGTH) == true)
|
|
{
|
|
used_rwy = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(used_rwy == true)
|
|
{
|
|
ptrTileset->r = rwy_sine;
|
|
ptrTileset->b = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->g = NORMAL_LUMINANCE >> 2;
|
|
}
|
|
else
|
|
{
|
|
ptrTileset->r = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->g = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->b = rwy_sine;
|
|
}
|
|
}
|
|
else if( ( (ptrPlayer->SelectTaxiwayParking == true)
|
|
||
|
|
(ptrPlayer->SelectTaxiwayRunway == true) )
|
|
&&
|
|
(i != 0)
|
|
&&
|
|
( (SystemContains_u16(i, ptrPlayer->Waypoints, PLAYER_MAX_WAYPOINTS) == true)
|
|
||
|
|
(i == ptrPlayer->SelectedTile) )
|
|
&&
|
|
(ptrPlayer->SelectedTile != GAME_INVALID_TILE_SELECTION) )
|
|
{
|
|
if(ptrPlayer->InvalidPath == true)
|
|
{
|
|
ptrTileset->r = rwy_sine;
|
|
ptrTileset->b = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->g = NORMAL_LUMINANCE >> 2;
|
|
}
|
|
else
|
|
{
|
|
ptrTileset->r = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->g = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->b = rwy_sine;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptrTileset->r = NORMAL_LUMINANCE;
|
|
ptrTileset->g = NORMAL_LUMINANCE;
|
|
ptrTileset->b = NORMAL_LUMINANCE;
|
|
}
|
|
|
|
if(System100msTick() == true)
|
|
{
|
|
if(rwy_sine_decrease == false)
|
|
{
|
|
if(rwy_sine < 255)
|
|
{
|
|
rwy_sine++;
|
|
}
|
|
else
|
|
{
|
|
rwy_sine_decrease = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(rwy_sine > (NORMAL_LUMINANCE >> 2))
|
|
{
|
|
rwy_sine--;
|
|
}
|
|
else
|
|
{
|
|
rwy_sine_decrease = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Isometric -> Cartesian conversion
|
|
tileIsoPos.x = columns << (TILE_SIZE_BIT_SHIFT);
|
|
tileIsoPos.y = rows << (TILE_SIZE_BIT_SHIFT);
|
|
tileIsoPos.z = 0;
|
|
|
|
tileCartPos = GfxIsometricToCartesian(&tileIsoPos);
|
|
|
|
ptrTileset->x = tileCartPos.x;
|
|
ptrTileset->y = tileCartPos.y;
|
|
|
|
// Set coordinate origin to left upper corner
|
|
ptrTileset->x -= TILE_SIZE >> 1;
|
|
ptrTileset->y -= TILE_SIZE >> 2;
|
|
|
|
/*ptrTileset->x = columns << (TILE_SIZE_BIT_SHIFT - 1);
|
|
ptrTileset->x -= rows << (TILE_SIZE_BIT_SHIFT - 1);
|
|
|
|
ptrTileset->y = rows << (TILE_SIZE_BIT_SHIFT - 2);
|
|
ptrTileset->y += columns << (TILE_SIZE_BIT_SHIFT - 2);*/
|
|
|
|
if(columns < GameLevelColumns -1 )
|
|
{
|
|
columns++;
|
|
}
|
|
else
|
|
{
|
|
rows++;
|
|
columns = 0;
|
|
}
|
|
|
|
if(ptrTileset != NULL)
|
|
{
|
|
if(flip_id == true)
|
|
{
|
|
ptrTileset->attribute |= H_FLIP;
|
|
}
|
|
}
|
|
|
|
ptrTileset->u = (short)(GameLevelBuffer[i] % COLUMNS_PER_TILESET)<<TILE_SIZE_BIT_SHIFT;
|
|
ptrTileset->v = (short)(GameLevelBuffer[i] / COLUMNS_PER_TILESET)<<TILE_SIZE_BIT_SHIFT;
|
|
|
|
if(flip_id == true)
|
|
{
|
|
flip_id = false;
|
|
GameLevelBuffer[i] = aux_id;
|
|
}
|
|
|
|
// dprintf("Tile %d, attribute 0x%X\n",i,ptrTileset->attribute);
|
|
|
|
CameraApplyCoordinatesToSprite(ptrPlayer, ptrTileset);
|
|
GfxSortSprite(ptrTileset);
|
|
|
|
if(ptrTileset->attribute & H_FLIP)
|
|
{
|
|
ptrTileset->attribute &= ~(H_FLIP);
|
|
}
|
|
}
|
|
|
|
/*if(PadOneKeyReleased(PAD_CROSS) == true)
|
|
{
|
|
for(i = 0; i < GameLevelSize; i++)
|
|
{
|
|
dprintf("Tile number %d, ID: %d\n",i,GameLevelBuffer[i]);
|
|
}
|
|
}*/
|
|
}
|
|
|
|
void GameSetTime(uint8_t hour, uint8_t minutes)
|
|
{
|
|
GameHour = hour;
|
|
GameMinutes = minutes;
|
|
}
|
|
|
|
void GameActiveAircraft(void)
|
|
{
|
|
uint8_t i;
|
|
|
|
FlightData.ActiveAircraft = 0;
|
|
|
|
for(i = 0 ; i < FlightData.nAircraft ; i++)
|
|
{
|
|
if(FlightData.State[i] != STATE_IDLE)
|
|
{
|
|
FlightData.ActiveAircraft++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameStateShowAircraft(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData)
|
|
{
|
|
if(ptrPlayer->ShowAircraftData == true)
|
|
{
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_TRIANGLE) == true)
|
|
{
|
|
ptrPlayer->ShowAircraftData = false;
|
|
}
|
|
}
|
|
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_CIRCLE) == true)
|
|
{
|
|
if(GameGuiShowAircraftDataSpecialConditions(ptrPlayer) == false)
|
|
{
|
|
//Invert ptrPlayer->ShowAircraftData value
|
|
ptrPlayer->ShowAircraftData = ptrPlayer->ShowAircraftData ? false : true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameStateLockTarget(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFlightData)
|
|
{
|
|
uint8_t AircraftIdx = ptrPlayer->ActiveAircraftList[ptrPlayer->SelectedAircraft];
|
|
|
|
if(ptrPlayer->LockTarget == true)
|
|
{
|
|
CameraMoveToIsoPos(ptrPlayer, AircraftGetIsoPos(ptrPlayer->LockedAircraft) );
|
|
}
|
|
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_SQUARE) == true)
|
|
{
|
|
if(ptrPlayer->LockTarget == false)
|
|
{
|
|
if( (ptrFlightData->State[AircraftIdx] != STATE_IDLE)
|
|
&&
|
|
(ptrFlightData->State[AircraftIdx] != STATE_APPROACH) )
|
|
{
|
|
ptrPlayer->LockTarget = true;
|
|
ptrPlayer->LockedAircraft = AircraftIdx;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptrPlayer->LockTarget = false;
|
|
ptrPlayer->LockedAircraft = 0;
|
|
}
|
|
}
|
|
else if(ptrPlayer->PadDirectionKeyPressed_Callback() == true)
|
|
{
|
|
if( (ptrPlayer->LockTarget == true)
|
|
&&
|
|
(ptrPlayer->ShowAircraftData == false) )
|
|
{
|
|
ptrPlayer->LockTarget = false;
|
|
ptrPlayer->LockedAircraft = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameStateSelectTaxiwayRunway(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData)
|
|
{
|
|
TYPE_ISOMETRIC_POS IsoPos = CameraGetIsoPos(ptrPlayer);
|
|
uint8_t i;
|
|
uint16_t target_tile;
|
|
|
|
/*dprintf("Camera is pointing to {%d,%d}\n",IsoPos.x, IsoPos.y);*/
|
|
|
|
if(ptrPlayer->SelectTaxiwayRunway == true)
|
|
{
|
|
// Under this mode, always reset locking target.
|
|
ptrPlayer->LockTarget = false;
|
|
ptrPlayer->LockedAircraft = 0;
|
|
|
|
ptrPlayer->SelectedTile = GameGetTileFromIsoPosition(&IsoPos);
|
|
|
|
if(GamePathToTile(ptrPlayer) == false)
|
|
{
|
|
ptrPlayer->InvalidPath = true;
|
|
}
|
|
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_TRIANGLE) == true)
|
|
{
|
|
// State exit.
|
|
ptrPlayer->SelectTaxiwayRunway = false;
|
|
// Clear waypoints array.
|
|
memset(ptrPlayer->Waypoints, 0, sizeof(uint16_t) * PLAYER_MAX_WAYPOINTS);
|
|
ptrPlayer->WaypointIdx = 0;
|
|
ptrPlayer->LastWaypointIdx = 0;
|
|
}
|
|
else if(ptrPlayer->PadKeySinglePress_Callback(PAD_CROSS) == true)
|
|
{
|
|
if(ptrPlayer->InvalidPath == false)
|
|
{
|
|
for(i = 0; i < PLAYER_MAX_WAYPOINTS; i++)
|
|
{
|
|
if(ptrPlayer->Waypoints[i] == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ptrPlayer->LastWaypointIdx = i;
|
|
}
|
|
|
|
target_tile = GameLevelBuffer[ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx]];
|
|
|
|
switch(target_tile)
|
|
{
|
|
case TILE_RWY_START_1:
|
|
// Fall through
|
|
case TILE_RWY_START_1 | TILE_MIRROR_FLAG:
|
|
// Fall through
|
|
case TILE_RWY_START_2:
|
|
// Fall through
|
|
case TILE_RWY_START_2 | TILE_MIRROR_FLAG:
|
|
AircraftFromFlightDataIndexAddTargets(ptrPlayer->LockedAircraft, ptrPlayer->Waypoints);
|
|
dprintf("Added these targets to aircraft %d:\n", ptrPlayer->LockedAircraft);
|
|
|
|
for(i = 0; i < PLAYER_MAX_WAYPOINTS; i++)
|
|
{
|
|
dprintf("%d ",ptrPlayer->Waypoints[i]);
|
|
}
|
|
|
|
dprintf("\n");
|
|
|
|
ptrPlayer->SelectTaxiwayParking = false;
|
|
// Clear waypoints array.
|
|
memset(ptrPlayer->Waypoints, 0, sizeof(uint16_t) * PLAYER_MAX_WAYPOINTS);
|
|
ptrPlayer->WaypointIdx = 0;
|
|
ptrPlayer->LastWaypointIdx = 0;
|
|
|
|
ptrFlightData->State[ptrPlayer->LockedAircraft] = STATE_TAXIING;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameStateSelectTaxiwayParking(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData)
|
|
{
|
|
TYPE_ISOMETRIC_POS IsoPos = CameraGetIsoPos(ptrPlayer);
|
|
uint8_t i;
|
|
uint16_t target_tile;
|
|
|
|
if(ptrPlayer->SelectTaxiwayParking == true)
|
|
{
|
|
// Under this mode, always reset locking target.
|
|
ptrPlayer->LockTarget = false;
|
|
ptrPlayer->LockedAircraft = 0;
|
|
|
|
ptrPlayer->SelectedTile = GameGetTileFromIsoPosition(&IsoPos);
|
|
|
|
if(GamePathToTile(ptrPlayer) == false)
|
|
{
|
|
ptrPlayer->InvalidPath = true;
|
|
}
|
|
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_TRIANGLE) == true)
|
|
{
|
|
// State exit.
|
|
ptrPlayer->SelectTaxiwayParking = false;
|
|
// Clear waypoints array.
|
|
memset(ptrPlayer->Waypoints, 0, sizeof(uint16_t) * PLAYER_MAX_WAYPOINTS);
|
|
ptrPlayer->WaypointIdx = 0;
|
|
ptrPlayer->LastWaypointIdx = 0;
|
|
}
|
|
else if(ptrPlayer->PadKeySinglePress_Callback(PAD_CROSS) == true)
|
|
{
|
|
if(ptrPlayer->InvalidPath == false)
|
|
{
|
|
for(i = 0; i < PLAYER_MAX_WAYPOINTS; i++)
|
|
{
|
|
if(ptrPlayer->Waypoints[i] == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ptrPlayer->LastWaypointIdx = i;
|
|
}
|
|
|
|
target_tile = GameLevelBuffer[ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx]];
|
|
|
|
dprintf("ptrPlayer->LastWaypointIdx = %d\n",
|
|
ptrPlayer->LastWaypointIdx);
|
|
|
|
dprintf("target_tile = %d, TILE_PARKING = %d\n",
|
|
target_tile,
|
|
TILE_PARKING);
|
|
|
|
if( (target_tile == TILE_PARKING)
|
|
||
|
|
(target_tile == (TILE_PARKING | TILE_MIRROR_FLAG) ) )
|
|
{
|
|
// TODO: Assign path to aircraft
|
|
AircraftFromFlightDataIndexAddTargets(ptrPlayer->LockedAircraft, ptrPlayer->Waypoints);
|
|
|
|
dprintf("Added these targets to aircraft %d:\n", ptrPlayer->LockedAircraft);
|
|
|
|
for(i = 0; i < PLAYER_MAX_WAYPOINTS; i++)
|
|
{
|
|
dprintf("%d ",ptrPlayer->Waypoints[i]);
|
|
}
|
|
|
|
dprintf("\n");
|
|
|
|
ptrPlayer->SelectTaxiwayParking = false;
|
|
// Clear waypoints array.
|
|
memset(ptrPlayer->Waypoints, 0, sizeof(uint16_t) * PLAYER_MAX_WAYPOINTS);
|
|
ptrPlayer->WaypointIdx = 0;
|
|
ptrPlayer->LastWaypointIdx = 0;
|
|
|
|
ptrFlightData->State[ptrPlayer->LockedAircraft] = STATE_TAXIING;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameStateSelectRunway(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData)
|
|
{
|
|
uint8_t i;
|
|
bool success;
|
|
TYPE_ISOMETRIC_POS IsoPos = { GameGetXFromTile_short(GameRwy[ptrPlayer->SelectedRunway]),
|
|
GameGetYFromTile_short(GameRwy[ptrPlayer->SelectedRunway]),
|
|
0 };
|
|
|
|
if(ptrPlayer->SelectRunway == true)
|
|
{
|
|
// Under this mode, always reset locking target.
|
|
ptrPlayer->LockTarget = false;
|
|
ptrPlayer->LockedAircraft = 0;
|
|
|
|
CameraMoveToIsoPos(ptrPlayer, IsoPos);
|
|
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_TRIANGLE) == true)
|
|
{
|
|
ptrPlayer->SelectRunway = false;
|
|
}
|
|
else if(ptrPlayer->PadKeySinglePress_Callback(PAD_CROSS) == true)
|
|
{
|
|
ptrPlayer->SelectRunway = false;
|
|
|
|
dprintf("ptrPlayer->SelectedRunway = %d\n", GameRwy[ptrPlayer->SelectedRunway]);
|
|
if(SystemContains_u16(GameRwy[ptrPlayer->SelectedRunway], GameUsedRwy, GAME_MAX_RUNWAYS) == false)
|
|
{
|
|
ptrPlayer->SelectRunway = false;
|
|
dprintf("Player selected runway %d!\n",GameRwy[ptrPlayer->SelectedRunway]);
|
|
|
|
success = false;
|
|
|
|
for(i = 0; i < GAME_MAX_RUNWAYS; i++)
|
|
{
|
|
if(GameUsedRwy[i] == 0)
|
|
{
|
|
GameAssignRunwaytoAircraft(ptrPlayer, ptrFlightData);
|
|
success = true;
|
|
GameUsedRwy[i] = GameRwy[ptrPlayer->SelectedRunway];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(success == false)
|
|
{
|
|
dprintf("No available runways!\n");
|
|
}
|
|
}
|
|
}
|
|
else if(ptrPlayer->PadKeySinglePress_Callback(PAD_LEFT) == true)
|
|
{
|
|
if(ptrPlayer->SelectedRunway != 0)
|
|
{
|
|
ptrPlayer->SelectedRunway--;
|
|
}
|
|
}
|
|
else if(ptrPlayer->PadKeySinglePress_Callback(PAD_RIGHT) == true)
|
|
{
|
|
if(ptrPlayer->SelectedRunway < (GAME_MAX_RUNWAYS - 1))
|
|
{
|
|
if(GameRwy[ptrPlayer->SelectedRunway + 1] != 0)
|
|
{
|
|
ptrPlayer->SelectedRunway++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameGetRunwayArray(void)
|
|
{
|
|
uint8_t i;
|
|
uint8_t j = 0;
|
|
|
|
for(i = 0; i < GameLevelSize; i++)
|
|
{
|
|
if(GameLevelBuffer[i] == TILE_RWY_START_1)
|
|
{
|
|
if(SystemContains_u8(i, GameLevelBuffer, GAME_MAX_RUNWAYS) == false)
|
|
{
|
|
GameRwy[j++] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
dprintf("GameRwy = ");
|
|
|
|
for(i = 0; i < GAME_MAX_RUNWAYS; i++)
|
|
{
|
|
if(GameRwy[i] == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
dprintf("%d ", GameRwy[i]);
|
|
}
|
|
|
|
dprintf("\n");
|
|
}
|
|
|
|
void GameSelectAircraftFromList(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData)
|
|
{
|
|
uint8_t AircraftIdx = ptrPlayer->ActiveAircraftList[ptrPlayer->SelectedAircraft];
|
|
FL_STATE aircraftState = ptrFlightData->State[AircraftIdx];
|
|
|
|
if(ptrPlayer->ShowAircraftData == true)
|
|
{
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_CROSS) == true)
|
|
{
|
|
if(ptrPlayer->ActiveAircraft != 0)
|
|
{
|
|
ptrPlayer->ShowAircraftData = false;
|
|
|
|
switch(aircraftState)
|
|
{
|
|
case STATE_APPROACH:
|
|
ptrPlayer->SelectRunway = true;
|
|
break;
|
|
|
|
case STATE_PARKED:
|
|
ptrPlayer->SelectTaxiwayRunway = true;
|
|
GameSelectAircraft(ptrPlayer);
|
|
break;
|
|
|
|
case STATE_LANDED:
|
|
ptrPlayer->SelectTaxiwayParking = true;
|
|
// Move camera to selected aircraft and add first waypoint.
|
|
GameSelectAircraft(ptrPlayer);
|
|
break;
|
|
|
|
default:
|
|
dprintf("Incompatible state %d!\n",aircraftState);
|
|
// States remain unchanged
|
|
ptrPlayer->SelectRunway = false;
|
|
ptrPlayer->SelectTaxiwayRunway = false;
|
|
ptrPlayer->ShowAircraftData = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
dprintf("aircraftState = %d\n", aircraftState);
|
|
dprintf("AircraftIdx = %d\n", AircraftIdx);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameGetSelectedRunwayArray(uint16_t rwyHeader)
|
|
{
|
|
typedef enum t_rwydir
|
|
{
|
|
RWY_DIR_EAST = 0,
|
|
RWY_DIR_WEST,
|
|
RWY_DIR_NORTH,
|
|
RWY_DIR_SOUTH,
|
|
}RWY_DIR;
|
|
|
|
static uint16_t last_tile = 0;
|
|
static uint8_t i = 0;
|
|
static RWY_DIR dir;
|
|
|
|
if(rwyHeader != 0)
|
|
{
|
|
// This function is called recursively.
|
|
// Since 0 is not a valid value (it's not allowed to place
|
|
// a runway header on first tile), it is used to determine
|
|
// when to start creating the array.
|
|
memset(GameRwyArray, 0, GAME_MAX_RWY_LENGTH * sizeof(uint16_t));
|
|
last_tile = rwyHeader;
|
|
i = 0;
|
|
|
|
switch(GameLevelBuffer[rwyHeader])
|
|
{
|
|
case TILE_RWY_START_1:
|
|
dir = RWY_DIR_EAST;
|
|
break;
|
|
case TILE_RWY_START_2:
|
|
dir = RWY_DIR_WEST;
|
|
break;
|
|
case TILE_RWY_START_1 | TILE_MIRROR_FLAG:
|
|
dir = RWY_DIR_SOUTH;
|
|
case TILE_RWY_START_2 | TILE_MIRROR_FLAG:
|
|
dir = RWY_DIR_NORTH;
|
|
default:
|
|
dprintf("Unknown direction for tile %d\n",rwyHeader);
|
|
return;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (GameLevelBuffer[last_tile] == TILE_RWY_START_1)
|
|
||
|
|
(GameLevelBuffer[last_tile] == TILE_RWY_START_2)
|
|
||
|
|
(GameLevelBuffer[last_tile] == (TILE_RWY_START_1 | TILE_MIRROR_FLAG) )
|
|
||
|
|
(GameLevelBuffer[last_tile] == (TILE_RWY_START_2 | TILE_MIRROR_FLAG) ) )
|
|
{
|
|
// Runway end found
|
|
GameRwyArray[i++] = last_tile;
|
|
return;
|
|
}
|
|
}
|
|
|
|
GameRwyArray[i++] = last_tile;
|
|
|
|
switch(dir)
|
|
{
|
|
case RWY_DIR_EAST:
|
|
last_tile++;
|
|
break;
|
|
case RWY_DIR_WEST:
|
|
last_tile--;
|
|
case RWY_DIR_NORTH:
|
|
last_tile -= GameLevelColumns;
|
|
case RWY_DIR_SOUTH:
|
|
last_tile += GameLevelColumns;
|
|
}
|
|
|
|
GameGetSelectedRunwayArray(0);
|
|
}
|
|
|
|
void GameAssignRunwaytoAircraft(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA * ptrFlightData)
|
|
{
|
|
uint16_t assignedRwy = GameRwy[ptrPlayer->SelectedRunway];
|
|
uint8_t aircraftIndex = ptrPlayer->SelectedAircraft;
|
|
uint16_t rwyExit;
|
|
uint32_t i;
|
|
uint16_t targets[AIRCRAFT_MAX_TARGETS];
|
|
uint8_t rwyTiles[GAME_MAX_RWY_LENGTH];
|
|
|
|
memset(targets, 0, sizeof(uint16_t) * AIRCRAFT_MAX_TARGETS);
|
|
|
|
// Remember that ptrPlayer->SelectedAircraft contains an index to
|
|
// be used with ptrFlightData.
|
|
|
|
/*typedef enum t_flstate
|
|
{
|
|
STATE_IDLE = 0,
|
|
STATE_PARKED,
|
|
STATE_TAXIING,
|
|
STATE_APPROACH,
|
|
STATE_FINAL
|
|
}FL_STATE;*/
|
|
|
|
dprintf("aircraftIndex = %d\n",aircraftIndex);
|
|
|
|
if(ptrFlightData->State[aircraftIndex] == STATE_APPROACH)
|
|
{
|
|
ptrFlightData->State[aircraftIndex] = STATE_FINAL;
|
|
|
|
GameGetSelectedRunwayArray(assignedRwy);
|
|
|
|
for(i = 0; i < GAME_MAX_RWY_LENGTH; i++)
|
|
{
|
|
rwyTiles[i] = GameLevelBuffer[GameRwyArray[i]];
|
|
}
|
|
|
|
i = SystemIndexOf_U8((uint8_t)TILE_RWY_EXIT, rwyTiles, 0, GAME_MAX_RWY_LENGTH);
|
|
|
|
if(i == -1)
|
|
{
|
|
dprintf("ERROR: Could not find TILE_RWY_EXIT for runway header %d.\n", assignedRwy);
|
|
return;
|
|
}
|
|
|
|
i = SystemIndexOf_U8((uint8_t)TILE_RWY_EXIT, rwyTiles, i + 1, GAME_MAX_RWY_LENGTH);
|
|
|
|
if(i == -1)
|
|
{
|
|
dprintf("ERROR: Could not find second TILE_RWY_EXIT for runway header %d.\n", assignedRwy);
|
|
return;
|
|
}
|
|
|
|
rwyExit = GameRwyArray[i];
|
|
|
|
targets[0] = assignedRwy;
|
|
targets[1] = rwyExit;
|
|
|
|
if( AircraftAddNew(ptrFlightData,
|
|
aircraftIndex,
|
|
targets ) == false)
|
|
{
|
|
dprintf("Exceeded maximum aircraft number!\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
short GameGetXFromTile_short(uint16_t tile)
|
|
{
|
|
short retVal;
|
|
|
|
tile %= GameLevelColumns;
|
|
|
|
retVal = (fix16_t)(tile << TILE_SIZE_BIT_SHIFT);
|
|
|
|
// Always point to tile center
|
|
retVal += TILE_SIZE >> 1;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
short GameGetYFromTile_short(uint16_t tile)
|
|
{
|
|
short retVal;
|
|
|
|
tile /= GameLevelColumns;
|
|
|
|
retVal = (fix16_t)(tile << TILE_SIZE_BIT_SHIFT);
|
|
|
|
// Always point to tile center
|
|
retVal += TILE_SIZE >> 1;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
fix16_t GameGetXFromTile(uint16_t tile)
|
|
{
|
|
return fix16_from_int(GameGetXFromTile_short(tile));
|
|
}
|
|
|
|
fix16_t GameGetYFromTile(uint16_t tile)
|
|
{
|
|
return fix16_from_int(GameGetYFromTile_short(tile));
|
|
}
|
|
|
|
FL_STATE GameTargetsReached(uint8_t index)
|
|
{
|
|
FL_STATE retState = STATE_IDLE;
|
|
|
|
switch(FlightData.State[index])
|
|
{
|
|
case STATE_FINAL:
|
|
FlightData.State[index] = STATE_LANDED;
|
|
break;
|
|
|
|
case STATE_TAXIING:
|
|
FlightData.State[index] = STATE_UNBOARDING;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return retState;
|
|
}
|
|
|
|
uint16_t GameGetTileFromIsoPosition(TYPE_ISOMETRIC_POS * IsoPos)
|
|
{
|
|
uint16_t tile;
|
|
|
|
if(IsoPos == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( (IsoPos->x < 0) || (IsoPos->y < 0) )
|
|
{
|
|
return GAME_INVALID_TILE_SELECTION; // Invalid XYZ position
|
|
}
|
|
|
|
tile = IsoPos->x >> TILE_SIZE_BIT_SHIFT;
|
|
tile += (IsoPos->y >> TILE_SIZE_BIT_SHIFT) * GameLevelColumns;
|
|
|
|
/*dprintf("Returning tile %d from position {%d, %d, %d}\n",
|
|
tile,
|
|
IsoPos->x,
|
|
IsoPos->y,
|
|
IsoPos->z );*/
|
|
|
|
return tile;
|
|
}
|
|
|
|
uint8_t GameGetLevelColumns(void)
|
|
{
|
|
return GameLevelColumns;
|
|
}
|
|
|
|
void GamePlayerAddWaypoint(TYPE_PLAYER* ptrPlayer)
|
|
{
|
|
GamePlayerAddWaypoint_Ex(ptrPlayer, ptrPlayer->SelectedTile);
|
|
}
|
|
|
|
void GamePlayerAddWaypoint_Ex(TYPE_PLAYER* ptrPlayer, uint16_t tile)
|
|
{
|
|
// "_Ex" function allow selecting a certain tile, whereas the other one
|
|
// is a particulare case of "_Ex" for tile = ptrPlayer->SelectedTIle.
|
|
|
|
if(ptrPlayer->WaypointIdx >= PLAYER_MAX_WAYPOINTS)
|
|
{
|
|
dprintf("No available waypoints for this player!\n");
|
|
return;
|
|
}
|
|
|
|
/*dprintf("Added tile %d to ptrPlayer->Waypoints[%d]\n",
|
|
tile,
|
|
ptrPlayer->WaypointIdx);*/
|
|
|
|
ptrPlayer->Waypoints[ptrPlayer->WaypointIdx++] = tile;
|
|
}
|
|
|
|
bool GamePathToTile(TYPE_PLAYER* ptrPlayer)
|
|
{
|
|
// Given an input TYPE_PLAYER structure and a selected tile,
|
|
// it updates current Waypoints array with all tiles between two points.
|
|
// If one of these tiles do not belong to desired tiles (i.e.: grass,
|
|
// water, buildings...), then false is returned.
|
|
|
|
uint8_t AcceptedTiles[] = { TILE_ASPHALT, TILE_ASPHALT_WITH_BORDERS,
|
|
TILE_PARKING, TILE_RWY_START_1,
|
|
TILE_RWY_START_2, TILE_RWY_MID,
|
|
TILE_RWY_EXIT, TILE_TAXIWAY_CORNER_GRASS,
|
|
TILE_TAXIWAY_CORNER_GRASS_2, TILE_TAXIWAY_GRASS,
|
|
TILE_TAXIWAY_INTERSECT_GRASS};
|
|
|
|
uint8_t i;
|
|
uint8_t j;
|
|
|
|
uint16_t x_diff;
|
|
uint16_t y_diff;
|
|
uint16_t temp_tile;
|
|
|
|
if(ptrPlayer->SelectedTile == GAME_INVALID_TILE_SELECTION)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for(i = (ptrPlayer->LastWaypointIdx + 1); i < PLAYER_MAX_WAYPOINTS; i++)
|
|
{
|
|
ptrPlayer->Waypoints[i] = 0;
|
|
}
|
|
|
|
ptrPlayer->WaypointIdx = ptrPlayer->LastWaypointIdx + 1;
|
|
|
|
x_diff = (uint16_t)abs( (ptrPlayer->SelectedTile % GameLevelColumns) -
|
|
(ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx] % GameLevelColumns) );
|
|
|
|
y_diff = (uint16_t)abs( (ptrPlayer->SelectedTile / GameLevelColumns) -
|
|
(ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx] / GameLevelColumns) );
|
|
|
|
/*dprintf("SelectedTile = %d, ptrPlayer->Waypoints[%d] = %d\n",
|
|
ptrPlayer->SelectedTile,
|
|
0,
|
|
ptrPlayer->Waypoints[0] );
|
|
|
|
dprintf("X = abs(%d - %d)\n",
|
|
ptrPlayer->SelectedTile % GameLevelColumns,
|
|
(ptrPlayer->Waypoints[0] % GameLevelColumns) );
|
|
|
|
dprintf("Y = abs(%d - %d)\n",
|
|
ptrPlayer->SelectedTile / GameLevelColumns,
|
|
(ptrPlayer->Waypoints[0] / GameLevelColumns) );
|
|
|
|
dprintf("Diff = {%d, %d}\n", x_diff, y_diff);*/
|
|
|
|
// At this point, we have to update current waypoints list.
|
|
// ptrPlayer->Waypoints[ptrPlayer->WaypointIdx - 1] points to the last inserted point,
|
|
// so now we have to determine how many points need to be created.
|
|
|
|
temp_tile = ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx];
|
|
|
|
if(x_diff >= y_diff)
|
|
{
|
|
while( (x_diff--) > 0)
|
|
{
|
|
if( (ptrPlayer->SelectedTile % GameLevelColumns) >
|
|
(ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx] % GameLevelColumns) )
|
|
{
|
|
temp_tile++;
|
|
}
|
|
else
|
|
{
|
|
temp_tile--;
|
|
}
|
|
|
|
if(SystemContains_u16(temp_tile, ptrPlayer->Waypoints, PLAYER_MAX_WAYPOINTS) == false)
|
|
{
|
|
for(i = 0; i < GAME_MAX_AIRCRAFT; i++)
|
|
{
|
|
if(temp_tile == AircraftGetTileFromFlightDataIndex(i))
|
|
{
|
|
return false; // Check pending!
|
|
}
|
|
}
|
|
|
|
GamePlayerAddWaypoint_Ex(ptrPlayer, temp_tile);
|
|
}
|
|
else
|
|
{
|
|
return false; // Tile is already included in the list of temporary tiles?
|
|
}
|
|
}
|
|
|
|
while( (y_diff--) > 0)
|
|
{
|
|
if( (ptrPlayer->SelectedTile / GameLevelColumns) >
|
|
(ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx] / GameLevelColumns) )
|
|
{
|
|
temp_tile += GameLevelColumns;
|
|
}
|
|
else
|
|
{
|
|
temp_tile -= GameLevelColumns;
|
|
}
|
|
|
|
if(SystemContains_u16(temp_tile, ptrPlayer->Waypoints, PLAYER_MAX_WAYPOINTS) == false)
|
|
{
|
|
for(i = 0; i < GAME_MAX_AIRCRAFT; i++)
|
|
{
|
|
if(temp_tile == AircraftGetTileFromFlightDataIndex(i))
|
|
{
|
|
return false; // Check pending!
|
|
}
|
|
}
|
|
|
|
GamePlayerAddWaypoint_Ex(ptrPlayer, temp_tile);
|
|
}
|
|
else
|
|
{
|
|
// TEST - Check pending!
|
|
return false; // Tile is already included in the list of temporary tiles?
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while( (y_diff--) > 0)
|
|
{
|
|
if( (ptrPlayer->SelectedTile / GameLevelColumns) >
|
|
(ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx] / GameLevelColumns) )
|
|
{
|
|
temp_tile += GameLevelColumns;
|
|
}
|
|
else
|
|
{
|
|
temp_tile -= GameLevelColumns;
|
|
}
|
|
|
|
if(SystemContains_u16(temp_tile, ptrPlayer->Waypoints, PLAYER_MAX_WAYPOINTS) == false)
|
|
{
|
|
for(i = 0; i < GAME_MAX_AIRCRAFT; i++)
|
|
{
|
|
if(temp_tile == AircraftGetTileFromFlightDataIndex(i))
|
|
{
|
|
return false; // Check pending!
|
|
}
|
|
}
|
|
|
|
GamePlayerAddWaypoint_Ex(ptrPlayer, temp_tile);
|
|
}
|
|
else
|
|
{
|
|
// TEST - Check pending!
|
|
return false; // Tile is already included in the list of temporary tiles?
|
|
}
|
|
}
|
|
|
|
while( (x_diff--) > 0)
|
|
{
|
|
if( (ptrPlayer->SelectedTile % GameLevelColumns) >
|
|
(ptrPlayer->Waypoints[ptrPlayer->LastWaypointIdx] % GameLevelColumns) )
|
|
{
|
|
temp_tile++;
|
|
}
|
|
else
|
|
{
|
|
temp_tile--;
|
|
}
|
|
|
|
if(SystemContains_u16(temp_tile, ptrPlayer->Waypoints, PLAYER_MAX_WAYPOINTS) == false)
|
|
{
|
|
for(i = 0; i < GAME_MAX_AIRCRAFT; i++)
|
|
{
|
|
if(temp_tile == AircraftGetTileFromFlightDataIndex(i))
|
|
{
|
|
return false; // Check pending!
|
|
}
|
|
}
|
|
|
|
GamePlayerAddWaypoint_Ex(ptrPlayer, temp_tile);
|
|
}
|
|
else
|
|
{
|
|
// TEST - Check pending!
|
|
return false; // Tile is already included in the list of temporary tiles?
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now at this point, we have prepared our array.
|
|
|
|
for(i = 0; i < PLAYER_MAX_WAYPOINTS; i++)
|
|
{
|
|
if(ptrPlayer->Waypoints[i] == 0)
|
|
{
|
|
// We have found empty waypoints. Exit loop
|
|
break;
|
|
}
|
|
|
|
if(SystemContains_u8( GameLevelBuffer[ptrPlayer->Waypoints[i]],
|
|
AcceptedTiles,
|
|
sizeof(AcceptedTiles) ) == false)
|
|
{
|
|
// Now try again with mirrored tiles, just in case!
|
|
|
|
for(j = 0; j < (sizeof(AcceptedTiles) * sizeof(uint8_t) ); j++)
|
|
{
|
|
AcceptedTiles[j] |= TILE_MIRROR_FLAG;
|
|
}
|
|
|
|
if(SystemContains_u8( GameLevelBuffer[ptrPlayer->Waypoints[i]],
|
|
AcceptedTiles,
|
|
sizeof(AcceptedTiles) ) == false)
|
|
{
|
|
// Both cases have failed. Return from function.
|
|
return false;
|
|
}
|
|
|
|
// Reverse mirror flag.
|
|
|
|
for(j = 0; j < (sizeof(AcceptedTiles) * sizeof(uint8_t) ); j++)
|
|
{
|
|
AcceptedTiles[j] &= ~(TILE_MIRROR_FLAG);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void GameSelectAircraft(TYPE_PLAYER* ptrPlayer)
|
|
{
|
|
uint8_t AircraftIdx = ptrPlayer->ActiveAircraftList[ptrPlayer->SelectedAircraft];
|
|
TYPE_ISOMETRIC_POS IsoPos = AircraftGetIsoPos(AircraftIdx);
|
|
|
|
CameraMoveToIsoPos(ptrPlayer, IsoPos);
|
|
|
|
ptrPlayer->SelectedTile = GameGetTileFromIsoPosition(&IsoPos);
|
|
|
|
GamePlayerAddWaypoint(ptrPlayer);
|
|
}
|
|
|
|
bool GameTwoPlayersActive(void)
|
|
{
|
|
return TwoPlayersActive;
|
|
}
|
|
|
|
void GameDrawMouse(TYPE_PLAYER* ptrPlayer)
|
|
{
|
|
if( (ptrPlayer->SelectTaxiwayParking == true)
|
|
||
|
|
(ptrPlayer->SelectTaxiwayRunway == true) )
|
|
{
|
|
GfxSortSprite(&GameMouseSpr);
|
|
}
|
|
}
|
|
|
|
FL_STATE GameGetFlightDataStateFromIdx(uint8_t FlightDataIdx)
|
|
{
|
|
if(FlightDataIdx >= GAME_MAX_AIRCRAFT)
|
|
{
|
|
return STATE_IDLE; // Error: could cause buffer overrun
|
|
}
|
|
|
|
return FlightData.State[FlightDataIdx];
|
|
}
|