diff options
| author | Xavier Del Campo <xavi.dcr@gmail.com> | 2017-02-04 14:49:08 +0100 |
|---|---|---|
| committer | Xavier Del Campo <xavi.dcr@gmail.com> | 2017-02-04 14:49:08 +0100 |
| commit | 189ecf754d0c8131464bfdff98fb56e7752556b1 (patch) | |
| tree | 89e7d02128bbc7b2d3f5c19a3da14ec14291982a /Source/Game.c | |
| download | airport-189ecf754d0c8131464bfdff98fb56e7752556b1.tar.gz | |
Initial commit
Diffstat (limited to 'Source/Game.c')
| -rwxr-xr-x | Source/Game.c | 1727 |
1 files changed, 1727 insertions, 0 deletions
diff --git a/Source/Game.c b/Source/Game.c new file mode 100755 index 0000000..88d2b75 --- /dev/null +++ b/Source/Game.c @@ -0,0 +1,1727 @@ +/* ************************************* + * 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 - (X_SCREEN_RESOLUTION >> 1), + MOUSE_Y = Y_SCREEN_RESOLUTION - (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); +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 GameGuiShowAircraftDataSpecialConditions(TYPE_PLAYER * ptrPlayer); +static uint16_t GameGetTileFromIsoPosition(TYPE_ISOMETRIC_POS * IsoPos); +static bool GamePathToTile(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; + } + } + + 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->PadKeyReleased_Callback); + if(ptrPlayer->PadKeyReleased_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].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; + + // 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; + + 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); + 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; + + while( (GfxIsGPUBusy() == true) + || + (SystemRefreshNeeded() == false) ); + + GsSortCls(0,0,NORMAL_LUMINANCE >> 1); + + if(GfxGetGlobalLuminance() < NORMAL_LUMINANCE) + { + GfxIncreaseGlobalLuminance(1); + } + + for(i = 0; i < MAX_PLAYERS ; i++) + { + if(PlayerData[i].Active == true) + { + GameRenderLevel(&PlayerData[i]); + AircraftRender(&PlayerData[i]); + } + } + + GameGuiAircraftNotificationRequest(&FlightData); + + GameGuiBubble(&FlightData); + + GameGuiClock(GameHour,GameMinutes); + + for(i = 0; i < MAX_PLAYERS ; i++) + { + GameGuiAircraftList(&PlayerData[i], &FlightData); + } + + 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; + + 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; + } + 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( (ptrPlayer->SelectTaxiwayParking == true) + || + (ptrPlayer->SelectTaxiwayRunway == true) ) + { + GfxSortSprite(&GameMouseSpr); + } + + /*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->PadKeyReleased_Callback(PAD_TRIANGLE) == true) + { + ptrPlayer->ShowAircraftData = false; + } + else if(ptrPlayer->PadKeyReleased_Callback(PAD_SQUARE) == true) + { + dprintf("Aircraft state = %d. STATE_IDLE = %d\n", + ptrFlightData->State[ptrPlayer->SelectedAircraft], + STATE_IDLE); + + if(ptrFlightData->State[ptrPlayer->SelectedAircraft] != STATE_IDLE) + { + ptrPlayer->LockTarget = true; + ptrPlayer->LockedAircraft = ptrPlayer->SelectedAircraft; + } + } + } + + if(ptrPlayer->PadKeyReleased_Callback(PAD_CIRCLE) == true) + { + if(GameGuiShowAircraftDataSpecialConditions(ptrPlayer) == false) + { + //Invert ptrPlayer->ShowAircraftData value + ptrPlayer->ShowAircraftData = ptrPlayer->ShowAircraftData ? false : true; + } + } +} + +void GameStateLockTarget(TYPE_PLAYER * ptrPlayer) +{ + if(ptrPlayer->LockTarget == true) + { + CameraMoveToIsoPos(ptrPlayer, AircraftGetIsoPos(ptrPlayer->LockedAircraft) ); + + if(ptrPlayer->PadKeyReleased_Callback(PAD_SQUARE) == true) + { + 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->PadKeyReleased_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->PadKeyReleased_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]]; + + if( (target_tile == TILE_RWY_START_1) + || + (target_tile == (TILE_RWY_START_1 | TILE_MIRROR_FLAG) ) + || + (target_tile == TILE_RWY_START_2) + || + (target_tile == (TILE_RWY_START_2 | 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 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->PadKeyReleased_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->PadKeyReleased_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; + + if(ptrPlayer->SelectRunway == true) + { + // Under this mode, always reset locking target. + ptrPlayer->LockTarget = false; + ptrPlayer->LockedAircraft = 0; + + if(ptrPlayer->PadKeyReleased_Callback(PAD_TRIANGLE) == true) + { + ptrPlayer->SelectRunway = false; + } + else if(ptrPlayer->PadKeyReleased_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->PadKeyReleased_Callback(PAD_LEFT) == true) + { + if(ptrPlayer->SelectedRunway != 0) + { + ptrPlayer->SelectedRunway--; + } + } + else if(ptrPlayer->PadKeyReleased_Callback(PAD_RIGHT) == true) + { + if(ptrPlayer->SelectedRunway < GAME_MAX_RUNWAYS) + { + 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) +{ + FL_STATE aircraftState = ptrFlightData->State[ptrPlayer->SelectedAircraft]; + + if(ptrPlayer->ShowAircraftData == true) + { + if(ptrPlayer->PadKeyReleased_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; + } + } + } + } +} + +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; + } + } +} + +fix16_t GameGetXFromTile(uint16_t tile) +{ + fix16_t retVal; + + tile %= GameLevelColumns; + + retVal = (fix16_t)(tile << TILE_SIZE_BIT_SHIFT); + + // Always point to tile center + retVal += TILE_SIZE >> 1; + + retVal = fix16_from_int(retVal); + + return retVal; +} + +fix16_t GameGetYFromTile(uint16_t tile) +{ + fix16_t retVal; + + tile /= GameLevelColumns; + + retVal = (fix16_t)(tile << TILE_SIZE_BIT_SHIFT); + + // Always point to tile center + retVal += TILE_SIZE >> 1; + + retVal = fix16_from_int(retVal); + + return retVal; +} + +void GameTargetsReached(uint8_t index) +{ + switch(FlightData.State[index]) + { + case STATE_FINAL: + FlightData.State[index] = STATE_LANDED; + break; + + default: + break; + } +} + +bool GameGuiShowAircraftDataSpecialConditions(TYPE_PLAYER * ptrPlayer) +{ + // Aircraft list data cannot be shown under these conditions. + + if( (ptrPlayer->SelectRunway == true) + || + (ptrPlayer->SelectTaxiwayParking == true) + || + (ptrPlayer->SelectTaxiwayRunway == true) ) + { + return true; + } + + return false; +} + +uint16_t GameGetTileFromIsoPosition(TYPE_ISOMETRIC_POS * IsoPos) +{ + uint16_t tile; + + 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) + { + GamePlayerAddWaypoint_Ex(ptrPlayer, temp_tile); + } + } + + 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) + { + GamePlayerAddWaypoint_Ex(ptrPlayer, temp_tile); + } + } + } + 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) + { + GamePlayerAddWaypoint_Ex(ptrPlayer, temp_tile); + } + } + + 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) + { + GamePlayerAddWaypoint_Ex(ptrPlayer, temp_tile); + } + } + } + + // 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) +{ + TYPE_ISOMETRIC_POS IsoPos = AircraftGetIsoPos(ptrPlayer->SelectedAircraft); + + CameraMoveToIsoPos(ptrPlayer, IsoPos); + + ptrPlayer->SelectedTile = GameGetTileFromIsoPosition(&IsoPos); + + GamePlayerAddWaypoint(ptrPlayer); +} |
