2679 lines
62 KiB
C
2679 lines
62 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 )
|
|
|
|
#define GAME_MINIMUM_PARKING_SPAWN_TIME 20 // 2 seconds
|
|
|
|
/* **************************************
|
|
* Structs and enums *
|
|
* *************************************/
|
|
|
|
typedef struct t_rwyentrydata
|
|
{
|
|
AIRCRAFT_DIRECTION Direction;
|
|
uint16_t rwyEntryTile;
|
|
int8_t rwyStep;
|
|
uint16_t rwyHeader;
|
|
}TYPE_RWY_ENTRY_DATA;
|
|
|
|
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)
|
|
};
|
|
|
|
enum
|
|
{
|
|
LOST_FLIGHT_PENALTY = 4000,
|
|
SCORE_REWARD_TAXIING = 200,
|
|
SCORE_REWARD_FINAL = 400,
|
|
SCORE_REWARD_UNLOADING = 300,
|
|
SCORE_REWARD_TAKEOFF = 200,
|
|
SCORE_REWARD_FINISH_FLIGHT = 1000
|
|
};
|
|
|
|
enum
|
|
{
|
|
UNBOARDING_KEY_SEQUENCE_EASY = 4,
|
|
UNBOARDING_KEY_SEQUENCE_MEDIUM = 6,
|
|
UNBOARDING_KEY_SEQUENCE_HARD = GAME_MAX_SEQUENCE_KEYS,
|
|
UNBOARDING_PASSENGERS_PER_SEQUENCE = 100
|
|
};
|
|
|
|
enum
|
|
{
|
|
BUILDING_HANGAR = 0,
|
|
BUILDING_ILS,
|
|
BUILDING_ATC_TOWER,
|
|
BUILDING_ATC_LOC,
|
|
BUILDING_TERMINAL,
|
|
BUILDING_TERMINAL_2,
|
|
BUILDING_GATE,
|
|
|
|
LAST_BUILDING = BUILDING_GATE
|
|
};
|
|
|
|
enum
|
|
{
|
|
TILE_GRASS = 0,
|
|
TILE_ASPHALT_WITH_BORDERS,
|
|
TILE_WATER,
|
|
TILE_ASPHALT,
|
|
|
|
TILE_RWY_MID,
|
|
TILE_RWY_START_1,
|
|
TILE_RWY_START_2,
|
|
TILE_PARKING,
|
|
|
|
TILE_PARKING_2,
|
|
TILE_TAXIWAY_INTERSECT_GRASS,
|
|
TILE_TAXIWAY_GRASS,
|
|
TILE_TAXIWAY_CORNER_GRASS,
|
|
|
|
TILE_HALF_WATER_1,
|
|
TILE_HALF_WATER_2,
|
|
TILE_RWY_HOLDING_POINT,
|
|
TILE_RWY_HOLDING_POINT_2,
|
|
|
|
TILE_RWY_EXIT,
|
|
TILE_TAXIWAY_CORNER_GRASS_2,
|
|
|
|
LAST_TILE_TILESET1 = TILE_TAXIWAY_CORNER_GRASS_2
|
|
};
|
|
|
|
enum
|
|
{
|
|
LAST_TILE_TILESET2 = LAST_TILE_TILESET1
|
|
};
|
|
|
|
/* *************************************
|
|
* Local Prototypes
|
|
* *************************************/
|
|
|
|
static void GameInit(void);
|
|
static void GameLoadLevel(void);
|
|
static bool GamePause(void);
|
|
static bool GameFinished(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 TYPE_ISOMETRIC_POS GameSelectAircraft(TYPE_PLAYER* ptrPlayer);
|
|
static void GameSelectAircraftWaypoint(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, TYPE_FLIGHT_DATA* ptrFlightData);
|
|
static void GameDrawMouse(TYPE_PLAYER* ptrPlayer);
|
|
static void GameStateUnboarding(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFlightData);
|
|
static void GameGenerateUnboardingSequence(TYPE_PLAYER* ptrPlayer);
|
|
static void GameCreateTakeoffWaypoints(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFlightData, uint8_t aircraftIdx);
|
|
static void GameGetRunwayEntryTile(uint8_t aircraftIdx, TYPE_RWY_ENTRY_DATA* ptrRwyEntry);
|
|
static void GameActiveAircraftList(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFlightData);
|
|
static void GameRemainingAircraft(void);
|
|
static void GameMinimumSpawnTimeout(void);
|
|
|
|
/* *************************************
|
|
* Global Variables
|
|
* *************************************/
|
|
|
|
bool GameStartupFlag;
|
|
uint32_t GameScore;
|
|
|
|
/* *************************************
|
|
* 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;
|
|
static bool firstLevelRender; // Used to avoid reentrance issues on GameRenderLevel()
|
|
static TYPE_TIMER* GameSpawnMinTime;
|
|
static bool spawnMinTimeFlag;
|
|
static bool GameAircraftCreatedFlag;
|
|
static bool GameAircraftCollisionFlag;
|
|
static uint8_t GameAircraftCollisionIdx;
|
|
|
|
// Instances for player-specific data
|
|
TYPE_PLAYER PlayerData[MAX_PLAYERS];
|
|
|
|
static char* GameFileList[] = { "cdrom:\\DATA\\SPRITES\\TILESET1.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 ,
|
|
(TYPE_FLIGHT_DATA*)&FlightData ,
|
|
(GsSprite*)&GamePlaneSpr ,
|
|
NULL ,
|
|
(GsSprite*)&GameMouseSpr };
|
|
|
|
static char* GameLevelList[] = { "cdrom:\\DATA\\LEVELS\\LEVEL1.LVL;1"};
|
|
static uint16_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(GameFinished() == true)
|
|
{
|
|
// Exit game on level finished.
|
|
break;
|
|
}
|
|
|
|
if(GamePause() == true)
|
|
{
|
|
// Exit game if player desires to exit.
|
|
break;
|
|
}
|
|
|
|
if(GameAircraftCollisionFlag == true)
|
|
{
|
|
GameGuiAircraftCollision(&PlayerData[PLAYER_ONE]);
|
|
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].PadLastKeySinglePressed_Callback = &PadOneGetLastKeySinglePressed;
|
|
PlayerData[PLAYER_ONE].FlightDataPage = 0;
|
|
PlayerData[PLAYER_ONE].UnboardingSequenceIdx = 0;
|
|
|
|
memset(PlayerData[PLAYER_ONE].UnboardingSequence, 0, GAME_MAX_SEQUENCE_KEYS * sizeof(unsigned short) );
|
|
|
|
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;
|
|
PlayerData[PLAYER_TWO].PadLastKeySinglePressed_Callback = &PadTwoGetLastKeySinglePressed;
|
|
PlayerData[PLAYER_TWO].UnboardingSequenceIdx = 0;
|
|
|
|
memset(PlayerData[PLAYER_TWO].UnboardingSequence, 0, GAME_MAX_SEQUENCE_KEYS * sizeof(unsigned short) );
|
|
|
|
// 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;
|
|
GameAircraftCreatedFlag = false;
|
|
GameAircraftCollisionFlag = false;
|
|
GameAircraftCollisionIdx = 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;
|
|
|
|
GameSpawnMinTime = SystemCreateTimer(GAME_MINIMUM_PARKING_SPAWN_TIME, false, &GameMinimumSpawnTimeout);
|
|
|
|
spawnMinTimeFlag = false;
|
|
|
|
GameScore = 0;
|
|
|
|
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();
|
|
GameGuiCalculateSlowScore();
|
|
GameRemainingAircraft();
|
|
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++)
|
|
{
|
|
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;
|
|
|
|
case STATE_UNBOARDING:
|
|
dprintf("Unboarding");
|
|
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 < FlightData.nAircraft ; 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".
|
|
|
|
ptrPlayer->FlightDataSelectedAircraft = ptrPlayer->ActiveAircraftList[ptrPlayer->SelectedAircraft];
|
|
|
|
if(GameAircraftCollisionFlag == true)
|
|
{
|
|
TYPE_ISOMETRIC_POS IsoPos = AircraftGetIsoPos(GameAircraftCollisionIdx);
|
|
CameraMoveToIsoPos(ptrPlayer, IsoPos);
|
|
}
|
|
|
|
GameActiveAircraftList(ptrPlayer, ptrFlightData);
|
|
GameStateUnboarding(ptrPlayer, ptrFlightData);
|
|
GameStateLockTarget(ptrPlayer, ptrFlightData);
|
|
GameStateSelectRunway(ptrPlayer, ptrFlightData);
|
|
GameStateSelectTaxiwayRunway(ptrPlayer, ptrFlightData);
|
|
GameStateSelectTaxiwayParking(ptrPlayer, ptrFlightData);
|
|
GameStateShowAircraft(ptrPlayer, ptrFlightData);
|
|
CameraHandler(ptrPlayer);
|
|
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]--;
|
|
}
|
|
|
|
if( (FlightData.State[i] != STATE_IDLE)
|
|
&&
|
|
(FlightData.RemainingTime[i] > 0) )
|
|
{
|
|
FlightData.RemainingTime[i]--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameGraphics(void)
|
|
{
|
|
int i;
|
|
bool split_screen = false;
|
|
|
|
while( (SystemRefreshNeeded() == false) || (GfxIsGPUBusy() == true) );
|
|
|
|
if(TwoPlayersActive == true)
|
|
{
|
|
split_screen = true;
|
|
}
|
|
|
|
if(GfxGetGlobalLuminance() < NORMAL_LUMINANCE)
|
|
{
|
|
// Fading from black effect on startup.
|
|
GfxIncreaseGlobalLuminance(1);
|
|
}
|
|
|
|
firstLevelRender = true;
|
|
|
|
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]);
|
|
|
|
GameGuiDrawUnboardingSequence(&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...)
|
|
|
|
GameGuiBubble(&FlightData);
|
|
|
|
GameGuiClock(GameHour,GameMinutes);
|
|
|
|
GameGuiShowScore();
|
|
|
|
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 * sizeof(uint16_t)); // 2 bytes per tile
|
|
}
|
|
|
|
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.Finished[i] == false)
|
|
{
|
|
if( (FlightData.Hours[i] == 0)
|
|
&&
|
|
(FlightData.Minutes[i] == 0)
|
|
&&
|
|
(FlightData.State[i] == STATE_IDLE)
|
|
&&
|
|
(FlightData.RemainingTime[i] > 0)
|
|
&&
|
|
(spawnMinTimeFlag == false) )
|
|
{
|
|
if( (FlightData.FlightDirection[i] == DEPARTURE)
|
|
&&
|
|
(FlightData.Parking[i] != 0) )
|
|
{
|
|
uint8_t j;
|
|
bool bParkingBusy = false;
|
|
|
|
for(j = 0; j < FlightData.nAircraft; j++)
|
|
{
|
|
if(AircraftFromFlightDataIndex(j)->State != STATE_IDLE)
|
|
{
|
|
uint16_t tile = AircraftGetTileFromFlightDataIndex(j);
|
|
uint16_t* targets = AircraftGetTargets(j);
|
|
|
|
if(tile == FlightData.Parking[i])
|
|
{
|
|
bParkingBusy = true;
|
|
}
|
|
|
|
if(SystemContains_u16(FlightData.Parking[i], targets, AIRCRAFT_MAX_TARGETS) == true)
|
|
{
|
|
bParkingBusy = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bParkingBusy == false)
|
|
{
|
|
FlightData.State[i] = STATE_PARKED;
|
|
|
|
GameAircraftCreatedFlag = true;
|
|
|
|
// Create notification request for incoming aircraft
|
|
GameGuiBubbleShow();
|
|
|
|
target[0] = FlightData.Parking[i];
|
|
|
|
dprintf("Target assigned = %d\n", target[0]);
|
|
|
|
dprintf("2\n");
|
|
|
|
if(AircraftAddNew(&FlightData, i, target) == false)
|
|
{
|
|
dprintf("Exceeded maximum aircraft number!\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if(FlightData.FlightDirection[i] == ARRIVAL)
|
|
{
|
|
dprintf("Flight %d set to STATE_APPROACH.\n", i);
|
|
FlightData.State[i] = STATE_APPROACH;
|
|
GameAircraftCreatedFlag = true;
|
|
|
|
// Create notification request for incoming aircraft
|
|
GameGuiBubbleShow();
|
|
}
|
|
}
|
|
|
|
if( (FlightData.State[i] != STATE_IDLE)
|
|
&&
|
|
(FlightData.RemainingTime[i] == 0) )
|
|
{
|
|
// Player(s) lost a flight!
|
|
GameRemoveFlight(i, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
const uint8_t rwy_sine_step = 24;
|
|
static unsigned char rwy_sine = rwy_sine_step;
|
|
static bool rwy_sine_decrease = false;
|
|
TYPE_ISOMETRIC_POS tileIsoPos;
|
|
TYPE_CARTESIAN_POS tileCartPos;
|
|
GsRectangle rct = {0};
|
|
|
|
// 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");*/
|
|
}
|
|
|
|
if(firstLevelRender == true)
|
|
{
|
|
// Avoid re-entrance.
|
|
|
|
firstLevelRender = false;
|
|
|
|
if(rwy_sine_decrease == false)
|
|
{
|
|
if(rwy_sine < 240)
|
|
{
|
|
rwy_sine += rwy_sine_step;
|
|
}
|
|
else
|
|
{
|
|
rwy_sine_decrease = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(rwy_sine > rwy_sine_step)
|
|
{
|
|
rwy_sine -= rwy_sine_step;
|
|
}
|
|
else
|
|
{
|
|
rwy_sine_decrease = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i = 0 ; i < GameLevelSize; i++)
|
|
{
|
|
// GameLevelBuffer bits explanation:
|
|
// X X X X X X X X
|
|
// | | | | | | | |
|
|
// | | | | | | | V
|
|
// | | | | | | V Tile, bit 0
|
|
// | | | | | V Tile, bit 1
|
|
// | | | | V Tile, bit 2
|
|
// | | | V Tile, bit 3
|
|
// | | V Tile, bit 4
|
|
// | V Tile, bit 5
|
|
// V Tile, bit 6
|
|
// Tile mirror flag
|
|
|
|
uint8_t CurrentTile = (uint8_t)(GameLevelBuffer[i] & 0x00FF);
|
|
|
|
// Flipped tiles have bit 7 enabled
|
|
if(CurrentTile & TILE_MIRROR_FLAG)
|
|
{
|
|
flip_id = true;
|
|
aux_id = CurrentTile;
|
|
CurrentTile &= ~(TILE_MIRROR_FLAG);
|
|
}
|
|
else
|
|
{
|
|
flip_id = false;
|
|
}
|
|
|
|
if(CurrentTile <= LAST_TILE_TILESET1)
|
|
{
|
|
// Draw using GameTilesetSpr
|
|
ptrTileset = &GameTilesetSpr;
|
|
}
|
|
else if( (CurrentTile > LAST_TILE_TILESET1)
|
|
&&
|
|
(CurrentTile <= LAST_TILE_TILESET2) )
|
|
{
|
|
// Draw using GameTileset2Spr
|
|
ptrTileset = &GameTileset2Spr;
|
|
}
|
|
else
|
|
{
|
|
ptrTileset = NULL;
|
|
|
|
continue;
|
|
|
|
// if(flip_id == false)
|
|
// {
|
|
// continue;
|
|
// }
|
|
}
|
|
|
|
ptrTileset->w = TILE_SIZE;
|
|
ptrTileset->h = TILE_SIZE_H;
|
|
|
|
used_rwy = false;
|
|
|
|
ptrTileset->r = NORMAL_LUMINANCE;
|
|
ptrTileset->g = NORMAL_LUMINANCE;
|
|
ptrTileset->b = NORMAL_LUMINANCE;
|
|
|
|
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) )
|
|
{
|
|
if(( (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 if( (ptrPlayer->SelectTaxiwayRunway == true)
|
|
&&
|
|
( (CurrentTile == TILE_RWY_HOLDING_POINT)
|
|
||
|
|
(CurrentTile == TILE_RWY_HOLDING_POINT_2) ) )
|
|
{
|
|
uint16_t aircraftTile;
|
|
bool bHoldingRwyBusy = false;
|
|
|
|
for(j = 0; j < FlightData.nAircraft; j++)
|
|
{
|
|
uint16_t* targets = AircraftGetTargets(j);
|
|
aircraftTile = AircraftGetTileFromFlightDataIndex(j);
|
|
uint16_t lastTarget = 0;
|
|
uint8_t k;
|
|
|
|
for(k = 0; k < AIRCRAFT_MAX_TARGETS; k++)
|
|
{
|
|
if(targets[k] == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
lastTarget = targets[k];
|
|
}
|
|
|
|
if( (i == aircraftTile)
|
|
||
|
|
(i == lastTarget) )
|
|
{
|
|
bHoldingRwyBusy = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(bHoldingRwyBusy == true)
|
|
{
|
|
ptrTileset->r = rwy_sine;
|
|
ptrTileset->g = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->b = NORMAL_LUMINANCE >> 2;
|
|
}
|
|
else
|
|
{
|
|
ptrTileset->r = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->g = rwy_sine;
|
|
ptrTileset->b = NORMAL_LUMINANCE >> 2;
|
|
}
|
|
}
|
|
else if( (ptrPlayer->SelectTaxiwayParking == true)
|
|
&&
|
|
( (CurrentTile == TILE_PARKING)
|
|
||
|
|
(CurrentTile == TILE_PARKING_2) ) )
|
|
{
|
|
uint16_t aircraftTile;
|
|
bool bParkingBusy = false;
|
|
|
|
for(j = 0; j < FlightData.nAircraft; j++)
|
|
{
|
|
aircraftTile = AircraftGetTileFromFlightDataIndex(j);
|
|
|
|
if(i == aircraftTile)
|
|
{
|
|
bParkingBusy = true;
|
|
}
|
|
}
|
|
|
|
if(bParkingBusy == true)
|
|
{
|
|
ptrTileset->r = rwy_sine;
|
|
ptrTileset->g = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->b = NORMAL_LUMINANCE >> 2;
|
|
}
|
|
else
|
|
{
|
|
ptrTileset->r = NORMAL_LUMINANCE >> 2;
|
|
ptrTileset->g = rwy_sine;
|
|
ptrTileset->b = NORMAL_LUMINANCE >> 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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_H >> 2;
|
|
|
|
rct.x = tileCartPos.x;
|
|
rct.y = tileCartPos.y;
|
|
rct.r = NORMAL_LUMINANCE;
|
|
rct.g = 0;
|
|
rct.b = 0;
|
|
rct.w = rct.h = 2;
|
|
|
|
if(columns < (GameLevelColumns - 1) )
|
|
{
|
|
columns++;
|
|
}
|
|
else
|
|
{
|
|
rows++;
|
|
columns = 0;
|
|
}
|
|
|
|
if(ptrTileset != NULL)
|
|
{
|
|
if(flip_id == true)
|
|
{
|
|
ptrTileset->attribute |= H_FLIP;
|
|
}
|
|
}
|
|
|
|
ptrTileset->u = (short)(CurrentTile % COLUMNS_PER_TILESET) << TILE_SIZE_BIT_SHIFT;
|
|
ptrTileset->v = (short)(CurrentTile / COLUMNS_PER_TILESET) * TILE_SIZE_H;
|
|
|
|
ptrTileset->mx = ptrTileset->u + (TILE_SIZE >> 1);
|
|
ptrTileset->my = ptrTileset->v + (TILE_SIZE_H >> 1);
|
|
|
|
if(flip_id == true)
|
|
{
|
|
flip_id = false;
|
|
CurrentTile = aux_id;
|
|
}
|
|
|
|
// dprintf("Tile %d, attribute 0x%X\n",i,ptrTileset->attribute);
|
|
|
|
CameraApplyCoordinatesToSprite(ptrPlayer, ptrTileset);
|
|
GfxSortSprite(ptrTileset);
|
|
|
|
CameraApplyCoordinatesToRectangle(ptrPlayer, &rct);
|
|
GsSortRectangle(&rct);
|
|
|
|
if(ptrTileset->attribute & H_FLIP)
|
|
{
|
|
ptrTileset->attribute &= ~(H_FLIP);
|
|
}
|
|
}
|
|
}
|
|
|
|
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->FlightDataSelectedAircraft;
|
|
|
|
if(ptrPlayer->LockTarget == true)
|
|
{
|
|
CameraMoveToIsoPos(ptrPlayer, AircraftGetIsoPos(ptrPlayer->LockedAircraft) );
|
|
}
|
|
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_SQUARE) == true)
|
|
{
|
|
if(ptrPlayer->LockTarget == false)
|
|
{
|
|
if(ptrPlayer->ShowAircraftData == true)
|
|
{
|
|
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, ptrFlightData) == 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_HOLDING_POINT:
|
|
// Fall through
|
|
case TILE_RWY_HOLDING_POINT | TILE_MIRROR_FLAG:
|
|
// Fall through
|
|
case TILE_RWY_HOLDING_POINT_2:
|
|
// Fall through
|
|
case TILE_RWY_HOLDING_POINT_2 | TILE_MIRROR_FLAG:
|
|
AircraftFromFlightDataIndexAddTargets(ptrPlayer->FlightDataSelectedAircraft, ptrPlayer->Waypoints);
|
|
dprintf("Added these targets to aircraft %d:\n", ptrPlayer->FlightDataSelectedAircraft);
|
|
|
|
for(i = 0; i < PLAYER_MAX_WAYPOINTS; i++)
|
|
{
|
|
dprintf("%d ",ptrPlayer->Waypoints[i]);
|
|
}
|
|
|
|
dprintf("\n");
|
|
|
|
// Clear waypoints array.
|
|
memset(ptrPlayer->Waypoints, 0, sizeof(uint16_t) * PLAYER_MAX_WAYPOINTS);
|
|
|
|
// Reset state and auxiliar variables
|
|
ptrPlayer->WaypointIdx = 0;
|
|
ptrPlayer->LastWaypointIdx = 0;
|
|
ptrPlayer->LockedAircraft = 0;
|
|
ptrPlayer->LockTarget = false;
|
|
ptrPlayer->SelectTaxiwayRunway = false;
|
|
|
|
ptrFlightData->State[ptrPlayer->FlightDataSelectedAircraft] = STATE_TAXIING;
|
|
GameScore += SCORE_REWARD_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, ptrFlightData) == 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))
|
|
||
|
|
(target_tile == TILE_PARKING_2)
|
|
||
|
|
(target_tile == (TILE_PARKING_2 | TILE_MIRROR_FLAG) ) )
|
|
{
|
|
// TODO: Assign path to aircraft
|
|
AircraftFromFlightDataIndexAddTargets(ptrPlayer->FlightDataSelectedAircraft, ptrPlayer->Waypoints);
|
|
|
|
dprintf("Added these targets to aircraft %d:\n", ptrPlayer->FlightDataSelectedAircraft);
|
|
|
|
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->FlightDataSelectedAircraft] = STATE_TAXIING;
|
|
GameScore += SCORE_REWARD_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;
|
|
|
|
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(ptrFlightData->State[ptrPlayer->FlightDataSelectedAircraft] == STATE_APPROACH)
|
|
{
|
|
if(ptrPlayer->SelectedRunway != 0)
|
|
{
|
|
ptrPlayer->SelectedRunway--;
|
|
}
|
|
}
|
|
}
|
|
else if(ptrPlayer->PadKeySinglePress_Callback(PAD_RIGHT) == true)
|
|
{
|
|
if(ptrFlightData->State[ptrPlayer->FlightDataSelectedAircraft] == STATE_APPROACH)
|
|
{
|
|
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_u16(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->FlightDataSelectedAircraft;
|
|
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;
|
|
// Move camera to selected aircraft and add first waypoint.
|
|
GameSelectAircraftWaypoint(ptrPlayer);
|
|
break;
|
|
|
|
case STATE_LANDED:
|
|
ptrPlayer->SelectTaxiwayParking = true;
|
|
// Move camera to selected aircraft and add first waypoint.
|
|
GameSelectAircraftWaypoint(ptrPlayer);
|
|
break;
|
|
|
|
case STATE_UNBOARDING:
|
|
ptrPlayer->Unboarding = true;
|
|
// Move camera to selected aircraft.
|
|
GameSelectAircraft(ptrPlayer);
|
|
// Generate first unboarding key sequence
|
|
GameGenerateUnboardingSequence(ptrPlayer);
|
|
break;
|
|
|
|
case STATE_READY_FOR_TAKEOFF:
|
|
ptrFlightData->State[AircraftIdx] = STATE_TAKEOFF;
|
|
GameCreateTakeoffWaypoints(ptrPlayer, ptrFlightData, AircraftIdx);
|
|
break;
|
|
|
|
case STATE_HOLDING_RWY:
|
|
{
|
|
TYPE_RWY_ENTRY_DATA rwyEntryData = {0};
|
|
uint8_t i;
|
|
|
|
ptrPlayer->SelectRunway = true;
|
|
GameGetRunwayEntryTile(AircraftIdx, &rwyEntryData);
|
|
|
|
for(i = 0; GameRwy[i] != 0 && (i < (sizeof(GameRwy) / sizeof(GameRwy[0]))); i++)
|
|
{
|
|
if(GameRwy[i] == rwyEntryData.rwyHeader)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ptrPlayer->SelectedRunway = i;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dprintf("Incompatible state %d!\n",aircraftState);
|
|
// States remain unchanged
|
|
ptrPlayer->SelectRunway = false;
|
|
ptrPlayer->SelectTaxiwayRunway = false;
|
|
ptrPlayer->ShowAircraftData = true;
|
|
ptrPlayer->Unboarding = false;
|
|
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->FlightDataSelectedAircraft;
|
|
uint16_t rwyExit;
|
|
uint32_t i;
|
|
uint16_t targets[AIRCRAFT_MAX_TARGETS] = {0};
|
|
uint8_t rwyTiles[GAME_MAX_RWY_LENGTH] = {0};
|
|
|
|
// 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;
|
|
GameScore += SCORE_REWARD_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;
|
|
|
|
dprintf("1\n");
|
|
|
|
if( AircraftAddNew(ptrFlightData,
|
|
aircraftIndex,
|
|
targets ) == false)
|
|
{
|
|
dprintf("Exceeded maximum aircraft number!\n");
|
|
return;
|
|
}
|
|
}
|
|
else if(ptrFlightData->State[aircraftIndex] == STATE_HOLDING_RWY)
|
|
{
|
|
TYPE_RWY_ENTRY_DATA rwyEntryData;
|
|
uint8_t i;
|
|
|
|
GameGetRunwayEntryTile(aircraftIndex, &rwyEntryData);
|
|
|
|
targets[0] = rwyEntryData.rwyEntryTile;
|
|
targets[1] = targets[0] + rwyEntryData.rwyStep;
|
|
|
|
dprintf("Added the following targets = ");
|
|
|
|
for(i = 0; i < (sizeof(targets) / sizeof(targets[0])); i++)
|
|
{
|
|
dprintf("%d ", targets[i]);
|
|
}
|
|
|
|
dprintf("\n");
|
|
|
|
AircraftAddTargets(AircraftFromFlightDataIndex(aircraftIndex), targets);
|
|
|
|
ptrFlightData->State[aircraftIndex] = STATE_ENTERING_RWY;
|
|
|
|
/*uint16_t i;
|
|
|
|
|
|
i = rwyEntryData.rwyEntryTile;
|
|
|
|
DEBUG_PRINT_VAR(rwyEntryData.rwyEntryTile);
|
|
DEBUG_PRINT_VAR(rwyEntryData.rwyStep);
|
|
|
|
while(GameLevelBuffer[i] != TILE_RWY_START_1)
|
|
{
|
|
if(i > rwyEntryData.rwyStep)
|
|
{
|
|
i -= rwyEntryData.rwyStep;
|
|
}
|
|
}
|
|
|
|
GameGetSelectedRunwayArray(i);*/
|
|
}
|
|
}
|
|
|
|
short GameGetXFromTile_short(uint16_t tile)
|
|
{
|
|
short retVal;
|
|
|
|
tile %= GameLevelColumns;
|
|
|
|
retVal = (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);
|
|
retVal = (tile << TILE_SIZE_BIT_SHIFT);
|
|
|
|
// Always point to tile center
|
|
//retVal += TILE_SIZE >> 1;
|
|
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(uint16_t firstTarget, uint8_t index)
|
|
{
|
|
FL_STATE retState = STATE_IDLE;
|
|
uint8_t i;
|
|
|
|
switch(FlightData.State[index])
|
|
{
|
|
case STATE_FINAL:
|
|
FlightData.State[index] = STATE_LANDED;
|
|
|
|
for(i = 0; i < GAME_MAX_RUNWAYS; i++)
|
|
{
|
|
if(GameUsedRwy[i] == firstTarget)
|
|
{
|
|
GameUsedRwy[i] = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATE_TAXIING:
|
|
if(FlightData.FlightDirection[index] == DEPARTURE)
|
|
{
|
|
FlightData.State[index] = STATE_HOLDING_RWY;
|
|
}
|
|
else if(FlightData.FlightDirection[index] == ARRIVAL)
|
|
{
|
|
FlightData.State[index] = STATE_UNBOARDING;
|
|
}
|
|
break;
|
|
|
|
case STATE_TAKEOFF:
|
|
FlightData.State[index] = STATE_CLIMBING;
|
|
break;
|
|
|
|
case STATE_ENTERING_RWY:
|
|
FlightData.State[index] = STATE_READY_FOR_TAKEOFF;
|
|
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, TYPE_FLIGHT_DATA* ptrFlightData)
|
|
{
|
|
// 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_WITH_BORDERS,
|
|
TILE_PARKING, TILE_RWY_MID,
|
|
TILE_RWY_EXIT, TILE_TAXIWAY_CORNER_GRASS,
|
|
TILE_TAXIWAY_CORNER_GRASS_2, TILE_TAXIWAY_GRASS,
|
|
TILE_TAXIWAY_INTERSECT_GRASS,
|
|
TILE_RWY_HOLDING_POINT, TILE_RWY_HOLDING_POINT_2 };
|
|
|
|
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 < FlightData.nAircraft; i++)
|
|
{
|
|
if( (ptrFlightData->State[i] != STATE_IDLE)
|
|
&&
|
|
(AircraftMoving(i) == false) )
|
|
{
|
|
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 < FlightData.nAircraft; i++)
|
|
{
|
|
if( (ptrFlightData->State[i] != STATE_IDLE)
|
|
&&
|
|
(AircraftMoving(i) == false) )
|
|
{
|
|
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 < FlightData.nAircraft; i++)
|
|
{
|
|
if( (ptrFlightData->State[i] != STATE_IDLE)
|
|
&&
|
|
(AircraftMoving(i) == false) )
|
|
{
|
|
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 < FlightData.nAircraft; i++)
|
|
{
|
|
if( (ptrFlightData->State[i] != STATE_IDLE)
|
|
&&
|
|
(AircraftMoving(i) == false) )
|
|
{
|
|
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;
|
|
}
|
|
|
|
TYPE_ISOMETRIC_POS GameSelectAircraft(TYPE_PLAYER* ptrPlayer)
|
|
{
|
|
uint8_t AircraftIdx = ptrPlayer->FlightDataSelectedAircraft;
|
|
TYPE_ISOMETRIC_POS IsoPos = AircraftGetIsoPos(AircraftIdx);
|
|
|
|
CameraMoveToIsoPos(ptrPlayer, IsoPos);
|
|
|
|
return IsoPos;
|
|
}
|
|
|
|
void GameSelectAircraftWaypoint(TYPE_PLAYER* ptrPlayer)
|
|
{
|
|
TYPE_ISOMETRIC_POS IsoPos = GameSelectAircraft(ptrPlayer);
|
|
|
|
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 >= FlightData.nAircraft)
|
|
{
|
|
return STATE_IDLE; // Error: could cause buffer overrun
|
|
}
|
|
|
|
return FlightData.State[FlightDataIdx];
|
|
}
|
|
|
|
uint32_t GameGetScore(void)
|
|
{
|
|
return GameScore;
|
|
}
|
|
|
|
void GameStateUnboarding(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFlightData)
|
|
{
|
|
if(ptrPlayer->Unboarding == true)
|
|
{
|
|
if(ptrPlayer->PadKeySinglePress_Callback(PAD_CIRCLE) == true)
|
|
{
|
|
ptrPlayer->Unboarding = false;
|
|
ptrPlayer->UnboardingSequenceIdx = 0; // Player will need to repeat sequence
|
|
// if he/she decides to leave without finishing
|
|
}
|
|
|
|
ptrPlayer->LockTarget = true;
|
|
ptrPlayer->LockedAircraft = ptrPlayer->FlightDataSelectedAircraft;
|
|
|
|
if(ptrPlayer->PadLastKeySinglePressed_Callback() == ptrPlayer->UnboardingSequence[ptrPlayer->UnboardingSequenceIdx])
|
|
{
|
|
if(++ptrPlayer->UnboardingSequenceIdx >= UNBOARDING_KEY_SEQUENCE_MEDIUM)
|
|
{
|
|
if(ptrFlightData->Passengers[ptrPlayer->FlightDataSelectedAircraft] > UNBOARDING_PASSENGERS_PER_SEQUENCE)
|
|
{
|
|
// Player has entered correct sequence. Unboard UNBOARDING_PASSENGERS_PER_SEQUENCE passengers.
|
|
|
|
ptrFlightData->Passengers[ptrPlayer->FlightDataSelectedAircraft] -= UNBOARDING_PASSENGERS_PER_SEQUENCE;
|
|
GameScore += SCORE_REWARD_UNLOADING;
|
|
|
|
ptrPlayer->PassengersLeftSelectedAircraft = ptrFlightData->Passengers[ptrPlayer->FlightDataSelectedAircraft];
|
|
|
|
GameGenerateUnboardingSequence(ptrPlayer);
|
|
}
|
|
else
|
|
{
|
|
// Flight has finished. Remove aircraft and set finished flag
|
|
ptrPlayer->Unboarding = false;
|
|
GameRemoveFlight(ptrPlayer->FlightDataSelectedAircraft, true);
|
|
}
|
|
|
|
ptrPlayer->UnboardingSequenceIdx = 0;
|
|
}
|
|
|
|
dprintf("ptrPlayer->UnboardingSequenceIdx = %d\n", ptrPlayer->UnboardingSequenceIdx);
|
|
}
|
|
else if(ptrPlayer->PadLastKeySinglePressed_Callback() != 0)
|
|
{
|
|
ptrPlayer->UnboardingSequenceIdx = 0; // Player has committed a mistake while entering the sequence. Repeat it!
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameGenerateUnboardingSequence(TYPE_PLAYER* ptrPlayer)
|
|
{
|
|
uint8_t i;
|
|
unsigned short keyTable[] = { PAD_CROSS, PAD_SQUARE, PAD_TRIANGLE };
|
|
|
|
memset(ptrPlayer->UnboardingSequence, 0, sizeof(ptrPlayer->UnboardingSequence) );
|
|
|
|
ptrPlayer->UnboardingSequenceIdx = 0;
|
|
|
|
dprintf("Key sequence generated: ");
|
|
|
|
// Only medium level implemented. TODO: Implement other levels
|
|
for(i = 0; i < UNBOARDING_KEY_SEQUENCE_MEDIUM; i++)
|
|
{
|
|
uint8_t randIdx = SystemRand(0, (sizeof(keyTable) / sizeof(keyTable[0])) - 1);
|
|
|
|
ptrPlayer->UnboardingSequence[i] = keyTable[randIdx];
|
|
|
|
dprintf("idx = %d, 0x%04X ", randIdx, ptrPlayer->UnboardingSequence[i]);
|
|
}
|
|
|
|
dprintf("\n");
|
|
}
|
|
|
|
void GameCreateTakeoffWaypoints(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFlightData, uint8_t aircraftIdx)
|
|
{
|
|
// Look for aircraft direction by searching TILE_RWY_EXIT
|
|
//uint16_t currentTile = AircraftGetTileFromFlightDataIndex(aircraftIdx);
|
|
//uint8_t targetsIdx = 0;
|
|
AIRCRAFT_DIRECTION aircraftDir = AircraftGetDirection(AircraftFromFlightDataIndex(aircraftIdx));
|
|
int8_t rwyStep = 0;
|
|
uint16_t currentTile = 0;
|
|
uint16_t targets[AIRCRAFT_MAX_TARGETS] = {0};
|
|
uint8_t i;
|
|
|
|
switch(aircraftDir)
|
|
{
|
|
case AIRCRAFT_DIR_EAST:
|
|
dprintf("EAST\n");
|
|
rwyStep = 1;
|
|
break;
|
|
|
|
case AIRCRAFT_DIR_WEST:
|
|
dprintf("WEST\n");
|
|
rwyStep = -1;
|
|
break;
|
|
|
|
case AIRCRAFT_DIR_NORTH:
|
|
dprintf("NORTH\n");
|
|
rwyStep = -GameLevelColumns;
|
|
break;
|
|
|
|
case AIRCRAFT_DIR_SOUTH:
|
|
dprintf("SOUTH\n");
|
|
rwyStep = GameLevelColumns;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
for(currentTile = (AircraftGetTileFromFlightDataIndex(aircraftIdx) + rwyStep);
|
|
(GameLevelBuffer[currentTile] != TILE_RWY_START_1)
|
|
&&
|
|
(GameLevelBuffer[currentTile] != TILE_RWY_START_2);
|
|
currentTile -= rwyStep )
|
|
{
|
|
|
|
}
|
|
|
|
for(i = 0; i < GAME_MAX_RUNWAYS; i++)
|
|
{
|
|
if(GameUsedRwy[i] == currentTile)
|
|
{
|
|
GameUsedRwy[i] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(currentTile = (AircraftGetTileFromFlightDataIndex(aircraftIdx) + rwyStep);
|
|
GameLevelBuffer[currentTile] != TILE_RWY_EXIT;
|
|
currentTile += rwyStep )
|
|
{
|
|
|
|
}
|
|
|
|
targets[0] = currentTile;
|
|
|
|
AircraftAddTargets(AircraftFromFlightDataIndex(aircraftIdx), targets);
|
|
}
|
|
|
|
void GameGetRunwayEntryTile(uint8_t aircraftIdx, TYPE_RWY_ENTRY_DATA* ptrRwyEntry)
|
|
{
|
|
// Look for aircraft direction by searching TILE_RWY_EXIT
|
|
uint16_t currentTile = AircraftGetTileFromFlightDataIndex(aircraftIdx);
|
|
int16_t step = 0;
|
|
uint16_t i;
|
|
|
|
if( (currentTile >= GameLevelColumns)
|
|
&&
|
|
( (currentTile + GameLevelColumns) < GameLevelSize) )
|
|
{
|
|
if(GameLevelBuffer[currentTile + 1] == TILE_RWY_EXIT)
|
|
{
|
|
ptrRwyEntry->Direction = AIRCRAFT_DIR_EAST;
|
|
ptrRwyEntry->rwyStep = GameLevelColumns;
|
|
step = -1;
|
|
}
|
|
else if(GameLevelBuffer[currentTile - 1] == TILE_RWY_EXIT)
|
|
{
|
|
ptrRwyEntry->Direction = AIRCRAFT_DIR_WEST;
|
|
ptrRwyEntry->rwyStep = -GameLevelColumns;
|
|
step = 1;
|
|
}
|
|
else if(GameLevelBuffer[currentTile + GameLevelColumns] == TILE_RWY_EXIT)
|
|
{
|
|
ptrRwyEntry->Direction = AIRCRAFT_DIR_SOUTH;
|
|
ptrRwyEntry->rwyStep = 1;
|
|
step = GameLevelColumns;
|
|
}
|
|
else if(GameLevelBuffer[currentTile - GameLevelColumns] == TILE_RWY_EXIT)
|
|
{
|
|
ptrRwyEntry->Direction = AIRCRAFT_DIR_NORTH;
|
|
ptrRwyEntry->rwyStep = -1;
|
|
step = -GameLevelColumns;
|
|
}
|
|
else
|
|
{
|
|
ptrRwyEntry->rwyEntryTile = 0;
|
|
ptrRwyEntry->Direction = AIRCRAFT_DIR_NO_DIRECTION;
|
|
ptrRwyEntry->rwyStep = 0;
|
|
dprintf("GameCreateTakeoffWaypoints(): could not determine aircraft direction.\n");
|
|
return;
|
|
}
|
|
|
|
ptrRwyEntry->rwyEntryTile = currentTile + step;
|
|
|
|
i = ptrRwyEntry->rwyEntryTile;
|
|
|
|
while( (GameLevelBuffer[i] != TILE_RWY_START_1)
|
|
&&
|
|
(GameLevelBuffer[i] != TILE_RWY_START_2)
|
|
&&
|
|
(i > ptrRwyEntry->rwyStep)
|
|
&&
|
|
((i - ptrRwyEntry->rwyStep) < GameLevelSize ) )
|
|
{
|
|
i -= ptrRwyEntry->rwyStep;
|
|
}
|
|
|
|
ptrRwyEntry->rwyHeader = i;
|
|
|
|
DEBUG_PRINT_VAR(ptrRwyEntry->rwyHeader);
|
|
}
|
|
else
|
|
{
|
|
dprintf("GameCreateTakeoffWaypoints(): Invalid index for tile.\n");
|
|
}
|
|
}
|
|
|
|
bool GameInsideLevelFromIsoPos(TYPE_ISOMETRIC_FIX16_POS* ptrIsoPos)
|
|
{
|
|
short x = (short)fix16_to_int(ptrIsoPos->x);
|
|
short y = (short)fix16_to_int(ptrIsoPos->y);
|
|
|
|
if(x < 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if(x > (GameLevelColumns << TILE_SIZE_BIT_SHIFT))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if(y < 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if(y > (GameLevelColumns << TILE_SIZE_BIT_SHIFT) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void GameRemoveFlight(uint8_t idx, bool successful)
|
|
{
|
|
uint8_t i;
|
|
|
|
for(i = PLAYER_ONE; i < MAX_PLAYERS; i++)
|
|
{
|
|
TYPE_PLAYER* ptrPlayer = &PlayerData[i];
|
|
uint8_t j;
|
|
|
|
for(j = 0; j < ptrPlayer->ActiveAircraft; j++)
|
|
{
|
|
uint8_t k;
|
|
|
|
if(FlightData.State[ptrPlayer->ActiveAircraftList[j]] != STATE_IDLE)
|
|
{
|
|
if(ptrPlayer->ActiveAircraftList[j] == idx)
|
|
{
|
|
if(ptrPlayer == &PlayerData[PLAYER_ONE])
|
|
{
|
|
dprintf("Player one\n");
|
|
}
|
|
else if(ptrPlayer == &PlayerData[PLAYER_TWO])
|
|
{
|
|
dprintf("Player two\n");
|
|
}
|
|
|
|
memset(ptrPlayer->UnboardingSequence, 0, GAME_MAX_SEQUENCE_KEYS);
|
|
ptrPlayer->UnboardingSequenceIdx = 0;
|
|
|
|
/*DEBUG_PRINT_VAR(ptrPlayer);
|
|
DEBUG_PRINT_VAR(&PlayerData[PLAYER_ONE]);
|
|
DEBUG_PRINT_VAR(&PlayerData[PLAYER_TWO]);*/
|
|
|
|
for(k = 0; k < GAME_MAX_RUNWAYS; k++)
|
|
{
|
|
uint16_t* targets = AircraftGetTargets(ptrPlayer->ActiveAircraftList[j]);
|
|
|
|
if(SystemContains_u16(GameUsedRwy[k], targets, AIRCRAFT_MAX_TARGETS) == true)
|
|
{
|
|
GameUsedRwy[k] = 0;
|
|
}
|
|
}
|
|
|
|
if(FlightData.State[ptrPlayer->ActiveAircraftList[j]] != STATE_APPROACH)
|
|
{
|
|
if(AircraftRemove(idx) == false)
|
|
{
|
|
dprintf("Something went wrong when removing aircraft!\n");
|
|
}
|
|
}
|
|
|
|
ptrPlayer->LockTarget = false;
|
|
ptrPlayer->LockedAircraft = 0;
|
|
|
|
if(successful == true)
|
|
{
|
|
GameScore += SCORE_REWARD_FINISH_FLIGHT;
|
|
}
|
|
else
|
|
{
|
|
GameScore = (GameScore < LOST_FLIGHT_PENALTY)? 0 : (GameScore - LOST_FLIGHT_PENALTY);
|
|
}
|
|
|
|
if(ptrPlayer->SelectedAircraft >= j)
|
|
{
|
|
ptrPlayer->SelectedAircraft--; // Check pending
|
|
}
|
|
|
|
FlightData.Passengers[ptrPlayer->ActiveAircraftList[j]] = 0;
|
|
FlightData.State[ptrPlayer->ActiveAircraftList[j]] = STATE_IDLE;
|
|
FlightData.Finished[ptrPlayer->ActiveAircraftList[j]] = true;
|
|
|
|
spawnMinTimeFlag = true;
|
|
SystemTimerRestart(GameSpawnMinTime);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Usually called in PlayerHandler(), but now
|
|
// force active aircraft list update.
|
|
GameActiveAircraftList(ptrPlayer, &FlightData);
|
|
}
|
|
}
|
|
|
|
void GameActiveAircraftList(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFlightData)
|
|
{
|
|
uint8_t i;
|
|
uint8_t j = 0;
|
|
|
|
uint8_t currentFlightDataIdx;
|
|
uint8_t lastFlightDataIdx;
|
|
|
|
// Clear all pointers for aircraft data first.
|
|
// Then, rebuild aircraft list for player.
|
|
|
|
lastFlightDataIdx = ptrPlayer->ActiveAircraftList[ptrPlayer->SelectedAircraft];
|
|
|
|
memset(ptrPlayer->ActiveAircraftList, 0, GAME_MAX_AIRCRAFT);
|
|
ptrPlayer->ActiveAircraft = 0;
|
|
|
|
for(i = 0; i < GAME_MAX_AIRCRAFT; i++)
|
|
{
|
|
if( (ptrFlightData->State[i] != STATE_IDLE)
|
|
&&
|
|
(ptrFlightData->FlightDirection[i] & ptrPlayer->FlightDirection) )
|
|
{
|
|
ptrPlayer->ActiveAircraftList[j++] = i;
|
|
ptrPlayer->ActiveAircraft++;
|
|
}
|
|
}
|
|
|
|
currentFlightDataIdx = ptrPlayer->ActiveAircraftList[ptrPlayer->SelectedAircraft];
|
|
|
|
if(GameAircraftCreatedFlag == true)
|
|
{
|
|
GameAircraftCreatedFlag = false;
|
|
|
|
if(ptrPlayer->ActiveAircraft > 1)
|
|
{
|
|
if(currentFlightDataIdx != lastFlightDataIdx)
|
|
{
|
|
for(ptrPlayer->SelectedAircraft = 0; ptrPlayer->SelectedAircraft < GAME_MAX_AIRCRAFT; ptrPlayer->SelectedAircraft++)
|
|
{
|
|
if(ptrPlayer->ActiveAircraftList[ptrPlayer->SelectedAircraft] == lastFlightDataIdx)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameRemainingAircraft(void)
|
|
{
|
|
uint8_t i;
|
|
FlightData.nRemainingAircraft = FlightData.nAircraft;
|
|
|
|
for(i = 0; i < FlightData.nAircraft; i++)
|
|
{
|
|
if(FlightData.Finished[i] == true)
|
|
{
|
|
FlightData.nRemainingAircraft--;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool GameFinished(void)
|
|
{
|
|
uint8_t i;
|
|
|
|
for(i = 0; i < FlightData.nAircraft; i++)
|
|
{
|
|
if(FlightData.Finished[i] == false)
|
|
{
|
|
// At least one aircraft still not finished
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return GameGuiFinishedDialog(&PlayerData[PLAYER_ONE]);
|
|
}
|
|
|
|
void GameMinimumSpawnTimeout(void)
|
|
{
|
|
spawnMinTimeFlag = false;
|
|
}
|
|
|
|
void GameAircraftCollision(uint8_t AircraftIdx)
|
|
{
|
|
GameAircraftCollisionFlag = true;
|
|
GameAircraftCollisionIdx = AircraftIdx;
|
|
}
|