/* * "RADIATE.C" * * Source code for tile based two-player game * * * Author: ScoTT Campbell * Started: 21/9/98 * * */ #include "..\escpslib\escpslib.h" #include "radiate.h" #include /*************************** Image related definitions ******************************/ #define TILE_ADDRESS (0x80090000) // used in map #define BACKGROUND_ADDRESS (0x80091D00) // used in background #define STATION_ADDRESS (0x80093A00) // used in background #define COVER_SPRITE_ADDRESS (0x80094400) // Sprite used in status bar #define PLAYER1_SPRITE_ADDRESS (0x800944C0) // Sprites used for player 1 #define PLAYER2_SPRITE_ADDRESS (0x800946A0) // Sprites used for player 2 #define ITEM_SPRITE_ADDRESS (0x80094890) // Sprites used for collectable items #define MENU_TEXT_ADDRESS (0x80095000) // Main menu text #define SUBMENU_TEXT_ADDRESS (0x80096C00) // Sub menus text #define TITLE_ADDRESS (0x8009D000) // Game title #define ESCOTIA_ADDRESS (0x800A1C00) // Escotia Logo #define FLAME_IMAGE_ADDRESS (0x800A2500) // Used in end routines #define EXPLOSION_VH_ADDRESS (0x800A3200) #define EXPLOSION_VB_ADDRESS (0x800A4000) #define CORRECT_BUTTON_VH_ADDRESS (0x800B8600) #define CORRECT_BUTTON_VB_ADDRESS (0x800B9220) #define WRONG_BUTTON_VH_ADDRESS (0x800CD900) #define WRONG_BUTTON_VB_ADDRESS (0x800CE600) #define ITEM_COLLECT_VH_ADDRESS (0x800E2D00) #define ITEM_COLLECT_VB_ADDRESS (0x800E3930) #define AMOUNT_FLAME_IMAGES (5) /************************************************************************************/ /****************************** Global variables ************************************/ /* Menu */ GsSPRITE title, escotia; EsGBOXF titlebg; GsSPRITE* menuSpriteArray, *submenuSpriteArray; GsSPRITE* mapSpriteArray, *bgSpriteArray; menu_type mainMenu, mapSubMenu, bgSubMenu; /* Background */ GsSPRITE* stationImages; GsSPRITE* backgroundImages; GsOT* background; /* Explosion */ GsSPRITE* flames; /* Players */ player_type player1, player2; /* World collision map */ tile_map_header* oTileMap; collision_map_header* objectCollisionMap; /* Items */ GsSPRITE* itemSprites; tile_map_header* gTileMap; item_map_header* itemMap; /* Sounds */ int explosionSound; int wrongButtonSound; int correctButtonSound; int itemCollectedSound; /* Maps */ map_array* maps[AMOUNT_MAPS]; // For storing pointers to each of the maps // Initialised in InitGame() /* Tiles */ GsSPRITE* tiles[AMOUNT_BACKGROUNDS]; // For storing pointers to each of the background tiles // Initialised in InitMap() /* Power bar */ int powerTotal; // Value updating the status bar with status_bar bar; const int WRONG_BUTTON_PENALTY = 10; // Value removed if wrong button pressed char quit; // 0 when the game is running; set to 1 if the player wants to quit /************************************************************************************/ /*************************** Fuction prototypes *************************************/ void InitGame(); /* Initialise structures ready for game start */ void InitSounds(); /* Initialise the sounds used in the game */ void UpdateScreen(); /* Create the drawing commands and send OT to GPU */ void DealWithPlayer1Input(void); /* Checks the current value of the pads and deals with them */ void DealWithPlayer2Input(void); /* Checks the current value of the pads and deals with them */ void UpdateGame(); /* Update any values within the game that need to change */ void CheckButtonsOff(); /* Sets players padClearFlag to 0 if none of the PAD, SQUARE, CROSS, or TRIANGLE buttons being pressed */ void CleanUp(long int videoMode); /* Clean up before quitting, setting the video mode to videoMode */ void CleanUpGame(); /* Free the memory allocated in InitNewGame */ void InitNewGame(map_array* currentMap, GsSPRITE* currentTiles); /* Reset any globals and create the structures necessary for each new game */ void Player1Win(); /* Player 1 win routine */ void Player2Win(); /* Player 2 win routine */ void MovePastTopCollision(player_type* player, int x, int y); /* Stop 'sticky' collisions */ void MovePastBottomCollision(player_type* player, int x, int y); /* Stop 'sticky' collisions */ void MovePastLeftCollision(player_type* player, int x, int y); /* Stop 'sticky' collisions */ void MovePastRightCollision(player_type* player, int x, int y); /* Stop 'sticky' collisions */ /************************************************************************************/ /******************************** Local functions ***********************************/ int main(void) { int menuDelay = 0; int menuChoice; unsigned long int pad; long int initialVideoMode = GetVideoMode(); quit = 0; InitGraphics(); /* Clear the screen to black every frame */ GsDRAWENV.r0 = GsDRAWENV.g0 = GsDRAWENV.b0 = 0; GsDRAWENV.isbg = 1; /* Initialise the global OTs */ InitWorldOTs(); /* Set up the controllers */ InitControllers(); /* Set up the game structures and graphics */ InitGame(); /* Set up the menu */ InitMenu(); /* Set up the game sounds */ InitSounds(); for(;;) { pad = ReadControllers(); menuChoice = mainMenu->size; if(!menuDelay) { if(pad) { menuChoice = UpdateMenu(mainMenu, pad); /* Waste some time since the for loop will be very quick */ menuDelay = 6; } } else menuDelay--; switch(menuChoice) { case 0: /* Set up a new game */ InitNewGame(maps[GetSubMenu(&mainMenu->menuArray[MAP_MENU_POSITION])->current], tiles[GetSubMenu(&mainMenu->menuArray[BACKGROUND_MENU_POSITION])->current]); while(!quit) { DealWithPlayer1Input(); DealWithPlayer2Input(); UpdateGame(); UpdateScreen(); } if(quit == 1) Player1Win(); else if(quit == 2) Player2Win(); else { //Do nothing } /* Clean up the current game */ CleanUpGame(); /* Reset quit flag */ quit = 0; break; case 3: printf("Options\n"); break; case 4: printf("Quit\n"); CleanUp(initialVideoMode); return 0; break; default: DisplayMenu(mainMenu); break; } /* Change the colours of the title */ SetGBoxFColours(&titlebg, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255); } /* If it ever reaches here something's gone very wrong */ return 1; }/* main */ void InitGame() { /* Initialise the background */ InitMapImages(); InitStatusBar(&bar); /* Initialise the explosion images */ flames = (GsSPRITE*) calloc(AMOUNT_FLAME_IMAGES, sizeof(GsSPRITE)); InitVerticalSpriteSet(flames, FLAME_IMAGE_ADDRESS, AMOUNT_FLAME_IMAGES, TILE_HEIGHT, stationImages[0].x + stationImages[0].mx, stationImages[0].y + stationImages[0].my); /* Initialise the players */ InitPlayer(&player1, PLAYER1_SPRITE_ADDRESS, MAP_LEFT_X + ((TILE_WIDTH - PLAYER_SPRITE_WIDTH)/2), MAP_TOP_Y + ((TILE_WIDTH - PLAYER_SPRITE_WIDTH)/2)); InitPlayer(&player2, PLAYER2_SPRITE_ADDRESS, (MAP_RIGHT_X - TILE_WIDTH) + ((TILE_WIDTH - PLAYER_SPRITE_WIDTH)/2), (MAP_BOTTOM_Y - TILE_HEIGHT) + ((TILE_WIDTH - PLAYER_SPRITE_WIDTH)/2)); /* Initialise the collectable items */ itemSprites = InitItemImages(ITEM_SPRITE_ADDRESS, AMOUNT_ITEM_IMAGES); /* Set up pointers to each of the maps */ maps[0] = &map1; maps[1] = &map2; maps[2] = &map3; maps[3] = &map4; maps[4] = &map5; }/* InitGame */ void InitNewGame(map_array* currentMap, GsSPRITE* currentTiles) { if( (background = CreateMap(*currentMap, currentTiles)) == NULL) quit = 3; /* Create all the bounding boxes within the map */ oTileMap = CreateTileMap(*currentMap, 'o'); objectCollisionMap = CreateCollisionMap(oTileMap, TILE_WIDTH, TILE_HEIGHT); DestroyTileMap(oTileMap); /* Set up the collectable items */ gTileMap = CreateTileMap(*currentMap, 'g'); itemMap = CreateItemMap(gTileMap); DestroyTileMap(gTileMap); AddItemsToItemMap(itemMap, itemSprites, (rand() % 10)); ResetStatusBar(&bar); ResetPlayer(&player1, MAP_LEFT_X + ((TILE_WIDTH - PLAYER_SPRITE_WIDTH)/2), MAP_TOP_Y + ((TILE_WIDTH - PLAYER_SPRITE_WIDTH)/2)); ResetPlayer(&player2, (MAP_RIGHT_X - TILE_WIDTH) + ((TILE_WIDTH - PLAYER_SPRITE_WIDTH)/2), (MAP_BOTTOM_Y - TILE_HEIGHT) + ((TILE_WIDTH - PLAYER_SPRITE_WIDTH)/2)); /* Reset the value used to update the status bar */ powerTotal = 0; /* Check for no buttons being pressed every VSync */ VSyncCallback(CheckButtonsOff); }/* InitNewGame */ void CleanUpGame() { /* Destroy the current background */ DestroyMap(background); /* Destroy the current collision map */ DestroyCollisionMap(objectCollisionMap); /* Destroy the current item map */ DestroyItemMap(itemMap); /* Switch off Callbacks */ VSyncCallback((void*)0); }/* CleanUpGame */ void InitSounds() { explosionSound = InitialiseSound(EXPLOSION_VH_ADDRESS, EXPLOSION_VB_ADDRESS); wrongButtonSound = InitialiseSound(WRONG_BUTTON_VH_ADDRESS, WRONG_BUTTON_VB_ADDRESS); correctButtonSound = InitialiseSound(CORRECT_BUTTON_VH_ADDRESS, CORRECT_BUTTON_VB_ADDRESS); itemCollectedSound = InitialiseSound(ITEM_COLLECT_VH_ADDRESS, ITEM_COLLECT_VB_ADDRESS); }/* InitSounds */ void UpdateScreen() { unsigned char vTime; int activeBuffer = GsGetActiveBuff(); // Find out which buffer we want to draw in GsSetWorkBase((PACKET*)packetArray[activeBuffer]); // Set drawing command storage address GsClearOt(0,0,&worldOT[activeBuffer]); // Clear the current ordering table DrawStatusBar(&bar, activeBuffer); DrawPlayer(&player1, activeBuffer); DrawPlayer(&player2, activeBuffer); DrawItems(itemMap, activeBuffer); if(!INTERLACE_MODE) // Check if we are in interlace mode DrawSync(0); // Wait for current drawing to finish vTime = VSync(0); // Wait for screen to finish drawing //printf("VSYNC = %d\n", vTime); FntFlush(-1); GsSwapDispBuff(); // Swap drawing buffer with display buffer DrawMap(background); // Draw the background GsDrawOt(&worldOT[activeBuffer]); // Draw the OT we just processed }/* UpdateScreen */ void CleanUp(long int videoMode) { // Need to add destroy images // and add in a mode reset also ResetGraph(1); /* Free memory used for menus */ DestroyMenu(mapSubMenu); DestroyMenu(bgSubMenu); free((void*)submenuSpriteArray); DestroyMenu(mainMenu); free((void*)menuSpriteArray); /* Free memory used for images */ free((void*) stationImages); free((void*) backgroundImages); free((void*) itemSprites); free((void*) tiles); free((void*) flames); /* Free memory used for sounds */ SsVabClose(explosionSound); SsVabClose(wrongButtonSound); SetVideoMode(videoMode); } void Player1Win() { int i = 0, j = 0, k; int loopCounter = 0; int activeBuffer; int explosionFinished = 0; int scale = ONE/2; GsSPRITE* currentStation, *currentFlame; /* Set images to position of player 1's station */ /* Need to include correction for using GsSortFastSprite */ for(k=0;k (5 * ONE) ) scale = 5 * ONE; SetSpriteSize(currentFlame, scale); } else SetSpriteSize(currentFlame, scale); GsSortFastSprite(currentStation, &worldOT[activeBuffer], 1); GsSortSprite(currentFlame, &worldOT[activeBuffer], 0); DrawStatusBar(&bar, activeBuffer); DrawPlayer(&player1, activeBuffer); DrawSync(0); // Wait for drawing of other buffer to stop VSync(0); // Wait for screen to stop drawing GsSwapDispBuff(); // Start displaying other buffer GsSortClear(0, 0, 0, &worldOT[activeBuffer]); // Insert a screen clear command into the OT DrawMap(background); GsDrawOt(&worldOT[activeBuffer]); // Draw OT into buffer activeBuffer loopCounter++; } }/* Player1Win */ void Player2Win() { int i = 0, j = 0, k; int loopCounter =0; int activeBuffer; int explosionFinished = 0; int scale = ONE/2; GsSPRITE* currentStation, *currentFlame; /* Set images to position of player 1's station */ /* Need to include correction for using GsSortFastSprite */ for(k=0;k (5 * ONE) ) scale = 5 * ONE; SetSpriteSize(currentFlame, scale); } else SetSpriteSize(currentFlame, scale); GsSortFastSprite(currentStation, &worldOT[activeBuffer], 1); GsSortSprite(currentFlame, &worldOT[activeBuffer], 0); DrawStatusBar(&bar, activeBuffer); DrawPlayer(&player2, activeBuffer); DrawSync(0); // Wait for drawing of other buffer to stop VSync(0); // Wait for screen to stop drawing GsSwapDispBuff(); // Start displaying other buffer GsSortClear(0, 0, 0, &worldOT[activeBuffer]); // Insert a screen clear command into the OT DrawMap(background); GsDrawOt(&worldOT[activeBuffer]); // Draw OT into buffer activeBuffer loopCounter++; } }/* Player2Win */ void DealWithPlayer1Input() { int x, y; button_type currentItem; static button_type lastItem; unsigned long int padValue = ReadControllers(); if(padValue & PAD1_SELECT) quit = 3; if(padValue & PAD1_L1) UpdateStatusBar(&bar, -1); if(padValue & PAD1_R1) UpdateStatusBar(&bar, 1); if(padValue & PAD1_LEFT){ player1.currentX -= PLAYER_SPEED; if(CheckLeftCollision(&player1, &x, &y)) MovePastLeftCollision(&player1, x, y); } if(padValue & PAD1_RIGHT){ player1.currentX += PLAYER_SPEED; if(CheckRightCollision(&player1, &x, &y)) MovePastRightCollision(&player1, x, y); } if(padValue & PAD1_UP){ player1.currentY -= PLAYER_SPEED; if(CheckTopCollision(&player1, &x, &y)) MovePastTopCollision(&player1, x, y); } if(padValue & PAD1_DOWN){ player1.currentY += PLAYER_SPEED; if(CheckBottomCollision(&player1, &x, &y)) MovePastBottomCollision(&player1, x, y); } //FntPrint("Length = %d\n", player1.itemList->length); // Print out the length of players list if(!player1.padClearFlag) // Check pad has cleared at some point { if(player1.itemList->length > 0) // check the player has items left to use { if(Collision(MAP_LEFT_X, MAP_TOP_Y, TILE_WIDTH, TILE_HEIGHT, player1.currentX, player1.currentY, player1.width, player1.height)) { if(padValue & PAD1_CROSS) { BLGetFront(player1.itemList, ¤tItem); if(player1.itemValue) { if(currentItem != lastItem) player1.itemValue = (player1.itemValue) * 2; } if(currentItem == CROSS) { if(player1.itemValue < 1) player1.itemValue = 1; SsUtKeyOn(correctButtonSound, 0, 0, 60, 0, 127,127); player1.powerValue += player1.itemValue; lastItem = currentItem; } else { SsUtKeyOn(wrongButtonSound, 0, 0, 60, 0, 127,127); player1.powerValue -= WRONG_BUTTON_PENALTY; player1.itemValue = 0; } player1.padClearFlag++; } if(padValue & PAD1_SQUARE) { BLGetFront(player1.itemList, ¤tItem); if(player1.itemValue) { if(currentItem != lastItem) player1.itemValue = (player1.itemValue) * 2; } if(currentItem == SQUARE) { if(player1.itemValue < 1) player1.itemValue = 1; SsUtKeyOn(correctButtonSound, 0, 0, 60, 0, 127,127); player1.powerValue += player1.itemValue; lastItem = currentItem; } else { SsUtKeyOn(wrongButtonSound, 0, 0, 60, 0, 127,127); player1.powerValue -= WRONG_BUTTON_PENALTY; player1.itemValue = 0; } player1.padClearFlag++; } if(padValue & PAD1_TRIANGLE) { BLGetFront(player1.itemList, ¤tItem); if(player1.itemValue) { if(currentItem != lastItem) player1.itemValue = (player1.itemValue) * 2; } if(currentItem == TRIANGLE) { if(player1.itemValue < 1) player1.itemValue = 1; SsUtKeyOn(correctButtonSound, 0, 0, 60, 0, 127,127); player1.powerValue += player1.itemValue; lastItem = currentItem; } else { SsUtKeyOn(wrongButtonSound, 0, 0, 60, 0, 127,127); player1.powerValue -= WRONG_BUTTON_PENALTY; player1.itemValue = 0; } player1.padClearFlag++; } if(padValue & PAD1_CIRCLE) { BLGetFront(player1.itemList, ¤tItem); if(player1.itemValue) { if(currentItem != lastItem) player1.itemValue = (player1.itemValue) * 2; } if(currentItem == CIRCLE) { if(player1.itemValue < 1) player1.itemValue = 1; SsUtKeyOn(correctButtonSound, 0, 0, 60, 0, 127,127); player1.powerValue += player1.itemValue; lastItem = currentItem; } else { SsUtKeyOn(wrongButtonSound, 0, 0, 60, 0, 127,127); player1.powerValue -= WRONG_BUTTON_PENALTY; player1.itemValue = 0; } player1.padClearFlag++; } } } } //FntPrint("Player1 power = %d\n", player1.powerValue); }/* DealWithPlayer1Input */ void DealWithPlayer2Input() { int x, y; button_type currentItem; static button_type lastItem; unsigned long int padValue = ReadControllers(); if(padValue & PAD2_SELECT) quit = 1; if(padValue & PAD2_L1) UpdateStatusBar(&bar, -1); if(padValue & PAD2_R1) UpdateStatusBar(&bar, 1); if(padValue & PAD2_LEFT){ player2.currentX -= PLAYER_SPEED; if(CheckLeftCollision(&player2, &x, &y)) MovePastLeftCollision(&player2, x, y); } if(padValue & PAD2_RIGHT){ player2.currentX += PLAYER_SPEED; if(CheckRightCollision(&player2, &x, &y)) MovePastRightCollision(&player2, x, y); } if(padValue & PAD2_UP){ player2.currentY -= PLAYER_SPEED; if(CheckTopCollision(&player2, &x, &y)) MovePastTopCollision(&player2, x, y); } if(padValue & PAD2_DOWN){ player2.currentY += PLAYER_SPEED; if(CheckBottomCollision(&player2, &x, &y)) MovePastBottomCollision(&player2, x, y); } //FntPrint("Length = %d\n", player2.itemList->length); // Print out the length of players list if(!player2.padClearFlag) // Check pad has cleared at some point { if(player2.itemList->length > 0) // check the player has items left to use { if(Collision(MAP_RIGHT_X - TILE_WIDTH, MAP_BOTTOM_Y - TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT, player2.currentX, player2.currentY, player2.width, player2.height)) { if(padValue & PAD2_CROSS) { BLGetFront(player2.itemList, ¤tItem); if(player2.itemValue) { if(currentItem != lastItem) player2.itemValue = (player2.itemValue) * 2; } if(currentItem == CROSS) { if(player2.itemValue < 1) player2.itemValue = 1; SsUtKeyOn(correctButtonSound, 0, 0, 60, 0, 127,127); player2.powerValue += player2.itemValue; lastItem = currentItem; } else { SsUtKeyOn(wrongButtonSound, 0, 0, 60, 0, 127,127); player2.powerValue -= WRONG_BUTTON_PENALTY; player2.itemValue = 0; } player2.padClearFlag++; } if(padValue & PAD2_SQUARE) { BLGetFront(player2.itemList, ¤tItem); if(player2.itemValue) { if(currentItem != lastItem) player2.itemValue = (player2.itemValue) * 2; } if(currentItem == SQUARE) { if(player2.itemValue < 1) player2.itemValue = 1; SsUtKeyOn(correctButtonSound, 0, 0, 60, 0, 127,127); player2.powerValue += player2.itemValue; lastItem = currentItem; } else { SsUtKeyOn(wrongButtonSound, 0, 0, 60, 0, 127,127); player2.powerValue -= WRONG_BUTTON_PENALTY; player2.itemValue = 0; } player2.padClearFlag++; } if(padValue & PAD2_TRIANGLE) { BLGetFront(player2.itemList, ¤tItem); if(player2.itemValue) { if(currentItem != lastItem) player2.itemValue = (player2.itemValue) * 2; } if(currentItem == TRIANGLE) { if(player2.itemValue < 1) player2.itemValue = 1; SsUtKeyOn(correctButtonSound, 0, 0, 60, 0, 127,127); player2.powerValue += player2.itemValue; lastItem = currentItem; } else { SsUtKeyOn(wrongButtonSound, 0, 0, 60, 0, 127,127); player2.powerValue -= WRONG_BUTTON_PENALTY; player2.itemValue = 0; } player2.padClearFlag++; } if(padValue & PAD2_CIRCLE) { BLGetFront(player2.itemList, ¤tItem); if(player2.itemValue) { if(currentItem != lastItem) player2.itemValue = (player2.itemValue) * 2; } if(currentItem == CIRCLE) { if(player2.itemValue < 1) player2.itemValue = 1; SsUtKeyOn(correctButtonSound, 0, 0, 60, 0, 127,127); player2.powerValue += player2.itemValue; lastItem = currentItem; } else { SsUtKeyOn(wrongButtonSound, 0, 0, 60, 0, 127,127); player2.powerValue -= WRONG_BUTTON_PENALTY; player2.itemValue = 0; } player2.padClearFlag++; } } } } FntPrint("Player2 power = %d\n", player2.powerValue); }/* DealWithPlayer2Input */ void UpdateGame() { static dropInitFlag = 0; static unsigned int nextDrop; /* Initialise value used to determine when items are to be added to maze */ if(!dropInitFlag) { nextDrop = rand() % GetItemMapActiveCount(itemMap); dropInitFlag = 1; } /* Add player 1's power value if they have left station or have used all items*/ if( (!(BLLength(player1.itemList))) || (!(Collision(MAP_LEFT_X, MAP_TOP_Y, TILE_WIDTH, TILE_HEIGHT, player1.currentX, player1.currentY, player1.width, player1.height))) ) { powerTotal += player1.powerValue; player1.powerValue = 0; player1.itemValue = 0; } /* Add player 2's power value if they have left station or have used all items*/ if( (!(BLLength(player2.itemList))) || (!(Collision(MAP_RIGHT_X-TILE_WIDTH, MAP_BOTTOM_Y-TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT, player2.currentX, player2.currentY, player2.width, player2.height))) ) { powerTotal -= player2.powerValue; player2.powerValue = 0; player2.itemValue = 0; } /* Status bar animation */ if(powerTotal > 0) { if(UpdateStatusBar(&bar, 1)) quit = 1; powerTotal--; } else if(powerTotal < 0) { if(UpdateStatusBar(&bar, -1)) quit = 2; powerTotal++; } /* Add more items to the map if needed */ if(itemMap->activeCount <= nextDrop) { nextDrop = rand() % 10; AddItemsToItemMap(itemMap, itemSprites, rand()%10); } }/* UpdateGame */ void CheckButtonsOff() { unsigned long int padValue = ReadControllers(); /* Check player 1's pad */ if( (!(padValue & PAD1_SQUARE)) && (!(padValue & PAD1_TRIANGLE)) && (!(padValue & PAD1_CIRCLE)) && (!(padValue & PAD1_CROSS)) ) player1.padClearFlag = 0; /* Check player 2's pad */ if( (!(padValue & PAD2_SQUARE)) && (!(padValue & PAD2_TRIANGLE)) && (!(padValue & PAD2_CIRCLE)) && (!(padValue & PAD2_CROSS)) ) player2.padClearFlag = 0; }/* CheckButtonsOff */ void MovePastTopCollision(player_type* player, int x, int y) { if(!((x == -1) && (y == -1))) { if(player->currentX < x) player->currentX -= 1; else player->currentX += 1; } }/* MovePastCollision */ void MovePastBottomCollision(player_type* player, int x, int y) { if(!((x == -1) && (y == -1))) { if(player->currentX < x) player->currentX -= 1; else player->currentX += 1; } }/* MovePastCollision */ void MovePastLeftCollision(player_type* player, int x, int y) { if(!((x == -1) && (y == -1))) { if(player->currentY < y) player->currentY -= 1; else player->currentY += 1; } }/* MovePastCollision */ void MovePastRightCollision(player_type* player, int x, int y) { if(!((x == -1) && (y == -1))) { if(player->currentY < y) player->currentY -= 1; else player->currentY += 1; } }/* MovePastCollision */ /************************************************************************************/ /***************************** Map related functions ********************************/ void InitMapImages() { int i; GsSPRITE* tileImages; if( !(tileImages = (GsSPRITE*) calloc(AMOUNT_TILE_IMAGES * AMOUNT_BACKGROUNDS, sizeof(GsSPRITE))) ) return; if( !(stationImages = (GsSPRITE*) calloc(AMOUNT_STATION_IMAGES*2, sizeof(GsSPRITE))) ) return; if( !(backgroundImages = (GsSPRITE*) calloc(AMOUNT_BACKGROUND_IMAGES, sizeof(GsSPRITE))) ) return; InitSpriteSet(tileImages, TILE_ADDRESS, AMOUNT_TILE_IMAGES * AMOUNT_BACKGROUNDS, TILE_WIDTH, TILE_HEIGHT, 0, 0); InitHorizontalSpriteSet(stationImages, STATION_ADDRESS, AMOUNT_STATION_IMAGES*2, TILE_WIDTH, 0, 0); InitSpriteSet(backgroundImages, BACKGROUND_ADDRESS, AMOUNT_BACKGROUND_IMAGES, TILE_WIDTH, TILE_HEIGHT, 0, 0); /* Keep pointers to the tiles */ for(i=0; iorg = (GsOT_TAG*) calloc((1<org); free((void*)mapOT); return (GsOT*)NULL; } mapOT->length = MAP_OT_LENGTH; GsClearOt(0, 0, mapOT); GsSetWorkBase((PACKET*) mapPackets); for(height=0;heightorg) free((void*)mapOT->org); free((void*)mapOT); mapOT = NULL; return 0; }/* DestroyMap */ /************************************************************************************/ /**************************** Status bar related functions **************************/ void InitStatusBar(status_bar* statusBar) { InitGBoxF(&statusBar->left, BAR_LEFT_START_X, BAR_Y, BAR_START_WIDTH, BAR_HEIGHT); InitGBoxF(&statusBar->right, BAR_RIGHT_START_X, BAR_Y, BAR_START_WIDTH, BAR_HEIGHT); SetGBoxFColours(&statusBar->left, 255, 0, 0, 255, 255, 255, 255, 0, 0, 255, 0, 0); SetGBoxFColours(&statusBar->right, 255, 0, 0, 255, 0, 0, 255, 255, 255, 255, 0, 0); InitSprite(&statusBar->cover, COVER_SPRITE_ADDRESS, COVER_START_X, COVER_Y); statusBar->coverPosition = COVER_START_X; }/* InitStatusBar */ int UpdateStatusBar(status_bar* statusBar, int value) { statusBar->coverPosition += value; if(statusBar->coverPosition <= BAR_LEFT_END) /* Player1 has lost */ { statusBar->coverPosition = BAR_LEFT_END; SetSpriteXPosition(&statusBar->cover, BAR_LEFT_END); SetGBoxFWidth(&statusBar->left, 0); SetGBoxFXPosition(&statusBar->right, BAR_LEFT_END + COVER_SPRITE_WIDTH); SetGBoxFWidth(&statusBar->right, TOTAL_BAR_WIDTH - COVER_SPRITE_WIDTH); return 1; } else if(statusBar->coverPosition >= BAR_RIGHT_END) /* Player2 has lost */ { statusBar->coverPosition = BAR_RIGHT_END; SetSpriteXPosition(&statusBar->cover, BAR_RIGHT_END); SetGBoxFWidth(&statusBar->left, TOTAL_BAR_WIDTH - COVER_SPRITE_WIDTH); SetGBoxFWidth(&statusBar->right, 0); return 1; } else /* Game on */ { SetSpriteXPosition(&statusBar->cover, statusBar->coverPosition); SetGBoxFWidth(&statusBar->left, statusBar->coverPosition - BAR_LEFT_START_X); SetGBoxFXPosition(&statusBar->right, statusBar->coverPosition + COVER_SPRITE_WIDTH); SetGBoxFWidth(&statusBar->right, BAR_RIGHT_END - statusBar->coverPosition); return 0; } }/* UpdateStatusBar */ void ResetStatusBar(status_bar* statusBar) { InitGBoxF(&statusBar->left, BAR_LEFT_START_X, BAR_Y, BAR_START_WIDTH, BAR_HEIGHT); InitGBoxF(&statusBar->right, BAR_RIGHT_START_X, BAR_Y, BAR_START_WIDTH, BAR_HEIGHT); SetGBoxFColours(&statusBar->left, 255, 0, 0, 255, 255, 255, 255, 0, 0, 255, 0, 0); SetGBoxFColours(&statusBar->right, 255, 0, 0, 255, 0, 0, 255, 255, 255, 255, 0, 0); SetSpritePosition(&statusBar->cover, COVER_START_X, COVER_Y); statusBar->coverPosition = COVER_START_X; }/* ResetStatusBar */ void DrawStatusBar(status_bar* statusBar, int buffer) { EsSortGBoxFill(&statusBar->left, &worldOT[buffer], 0); EsSortGBoxFill(&statusBar->right, &worldOT[buffer], 0); GsSortFastSprite(&statusBar->cover, &worldOT[buffer], 0); }/* DrawStatusBar */ /************************************************************************************/ /****************************** Player related functions ****************************/ int InitPlayer(player_type* player, unsigned long int spriteAddress, int xStart, int yStart) { //player->spriteArray = (GsSPRITE*) calloc(AMOUNT_PLAYER_IMAGES, sizeof(GsSPRITE)); InitSprite(&player->playerSprite, spriteAddress, xStart, yStart); player->currentX = xStart; player->currentY = yStart; player->width = PLAYER_SPRITE_WIDTH; player->height = PLAYER_SPRITE_HEIGHT; if( (player->itemList = CreateButtonList()) == NULL_BUTTON_LIST ) return 1; player->powerValue = 0; player->padClearFlag = 0; DrawSync(0); return 0; }/* InitPlayerImages */ void ResetPlayer(player_type* player, int xStart, int yStart) { player->currentX = xStart; player->currentY = yStart; player->powerValue = 0; /* player->itemValue may not have been reset before game ended so do it here */ player->itemValue = 0; /* Clear the item list of any unused items */ BLClear(player->itemList); }/* ResetPlayer */ void DrawPlayer(player_type* player, int buffer) { //SetSpritePosition(&player->playerSprite[player->currentSprite], currentX, currentY); //GsSortFastSprite(&player->playerSprite[player->currentSprite], &worldOT[buffer], 1); SetSpritePosition(&player->playerSprite, player->currentX, player->currentY); GsSortFastSprite(&player->playerSprite, &worldOT[buffer], 1); }/* DrawPlayers */ /************************************************************************************/ /***************************** Collision related functions **************************/ /* * TEMPORARY COLLISION DETECTION */ int CheckTopCollision(player_type* player, int* x, int* y) { unsigned long int i; *x = *y = -1; /* Check player is not out of bounds */ if(player->currentY < MAP_TOP_Y) { player->currentY = MAP_TOP_Y; return 1; } if(objectCollisionMap != NULL) { /* Stop player walking through map objects */ for(i=0;icount;i++) { if(Collision(player->currentX, player->currentY, player->width, player->height, objectCollisionMap->boxArray[i].x, objectCollisionMap->boxArray[i].y, objectCollisionMap->boxArray[i].width, objectCollisionMap->boxArray[i].height)) { *x = objectCollisionMap->boxArray[i].x; *y = objectCollisionMap->boxArray[i].y; player->currentY += PLAYER_SPEED; return 1; } } } /* See if player has collected any items */ for(i=0; icount; i++) { if(itemMap->itemArray[i].active) { if(Collision(player->currentX, player->currentY, player->width, player->height, itemMap->itemArray[i].box.x, itemMap->itemArray[i].box.y, itemMap->itemArray[i].box.width, itemMap->itemArray[i].box.height)) { SsUtKeyOn(itemCollectedSound, 0, 0, 60, 0, 127,127); BLAddBack(player->itemList, GetItemFromItemMap(itemMap, i)); return 1; } } } return 0; }/* CheckTopCollision */ int CheckBottomCollision(player_type* player, int* x, int* y) { unsigned long int i; *x = *y = -1; /* Check player is not out of bounds */ if((player->currentY + PLAYER_SPRITE_HEIGHT) > MAP_BOTTOM_Y) { player->currentY = MAP_BOTTOM_Y - PLAYER_SPRITE_HEIGHT; return 1; } if(objectCollisionMap != NULL) { /* Stop player walking through map objects */ for(i=0;icount;i++) { if(Collision(player->currentX, player->currentY, player->width, player->height, objectCollisionMap->boxArray[i].x, objectCollisionMap->boxArray[i].y, objectCollisionMap->boxArray[i].width, objectCollisionMap->boxArray[i].height)) { *x = objectCollisionMap->boxArray[i].x; *y = objectCollisionMap->boxArray[i].y; player->currentY -= PLAYER_SPEED; return 1; } } } /* See if player has collected any items */ for(i=0; icount; i++) { if(itemMap->itemArray[i].active) { if(Collision(player->currentX, player->currentY, player->width, player->height, itemMap->itemArray[i].box.x, itemMap->itemArray[i].box.y, itemMap->itemArray[i].box.width, itemMap->itemArray[i].box.height)) { SsUtKeyOn(itemCollectedSound, 0, 0, 60, 0, 127,127); BLAddBack(player->itemList, GetItemFromItemMap(itemMap, i)); return 1; } } } return 0; }/* CheckBottomCollision */ int CheckLeftCollision(player_type* player, int* x, int* y) { unsigned long int i; *x = *y = -1; /* Check player is not out of bounds */ if(player->currentX < MAP_LEFT_X) { player->currentX = MAP_LEFT_X; return 1; } if(objectCollisionMap != NULL) { /* Stop player walking through map objects */ for(i=0;icount;i++) { if(Collision(player->currentX, player->currentY, player->width, player->height, objectCollisionMap->boxArray[i].x, objectCollisionMap->boxArray[i].y, objectCollisionMap->boxArray[i].width, objectCollisionMap->boxArray[i].height)) { *x = objectCollisionMap->boxArray[i].x; *y = objectCollisionMap->boxArray[i].y; player->currentX += PLAYER_SPEED; return 1; } } } /* See if player has collected any items */ for(i=0; icount; i++) { if(itemMap->itemArray[i].active) { if(Collision(player->currentX, player->currentY, player->width, player->height, itemMap->itemArray[i].box.x, itemMap->itemArray[i].box.y, itemMap->itemArray[i].box.width, itemMap->itemArray[i].box.height)) { SsUtKeyOn(itemCollectedSound, 0, 0, 60, 0, 127,127); BLAddBack(player->itemList, GetItemFromItemMap(itemMap, i)); return 1; } } } return 0; }/* CheckLeftCollision */ int CheckRightCollision(player_type* player, int* x, int* y) { unsigned long int i; *x = *y = -1; /* Check player is not out of bounds */ if((player->currentX + PLAYER_SPRITE_WIDTH) > (MAP_RIGHT_X-2)) { player->currentX = (MAP_RIGHT_X-2) - PLAYER_SPRITE_WIDTH; return 1; } if(objectCollisionMap != NULL) { /* Stop player walking through map objects */ for(i=0;icount;i++) { if(Collision(player->currentX, player->currentY, player->width, player->height, objectCollisionMap->boxArray[i].x, objectCollisionMap->boxArray[i].y, objectCollisionMap->boxArray[i].width, objectCollisionMap->boxArray[i].height)) { *x = objectCollisionMap->boxArray[i].x; *y = objectCollisionMap->boxArray[i].y; player->currentX -= PLAYER_SPEED; return 1; } } } /* See if player has collected any items */ for(i=0; icount; i++) { if(itemMap->itemArray[i].active) { if(Collision(player->currentX, player->currentY, player->width, player->height, itemMap->itemArray[i].box.x, itemMap->itemArray[i].box.y, itemMap->itemArray[i].box.width, itemMap->itemArray[i].box.height)) { SsUtKeyOn(itemCollectedSound, 0, 0, 60, 0, 127,127); BLAddBack(player->itemList, GetItemFromItemMap(itemMap, i)); return 1; } } } return 0; }/* CheckRightCollision */ int Collision(int x1, int y1, unsigned int width1, unsigned int height1, int x2, int y2, unsigned int width2, unsigned int height2) { int dx, dy; unsigned int boxWidth = (width1 + width2) / 2; unsigned int boxHeight = (height1 + height2) / 2; x1 += ((signed)width1 - (signed)boxWidth) / 2; y1 += ((signed)height1 - (signed)boxHeight) / 2; x2 += ((signed)width2 - (signed)boxWidth) / 2; y2 += ((signed)height2 - (signed)boxHeight) / 2; dx = abs(x2 - x1); dy = abs(y2 - y1); if( (dx < boxWidth) && (dy < boxHeight) ) return 1; else return 0; }/* Collision */ collision_map_header* CreateCollisionMap(tile_map_header* tileMap, int width, int height) { int i; int xCorrection = (TILE_WIDTH - width)/2; int yCorrection = (TILE_HEIGHT - height)/2; // To center box on object tile_map_node* currentNode; collision_map_header* header; if((tileMap == NULL) || (!tileMap->count) || (width == 0) || (height == 0)) return NULL; if( !(header = (collision_map_header*) malloc(sizeof(collision_map_header))) ) return NULL; if( !(header->boxArray = (bounding_box*) calloc(tileMap->count, sizeof(bounding_box))) ) return NULL; currentNode = tileMap->front; header->count = tileMap->count; for(i=0; icount; i++) { header->boxArray[i].x = currentNode->x + xCorrection; header->boxArray[i].y = currentNode->y + yCorrection; header->boxArray[i].width = width; header->boxArray[i].height = height; currentNode = currentNode->next; } return header; }/* CreateCollisionMap */ int DestroyCollisionMap(collision_map_header* collisionMap) { if(collisionMap == NULL) return 1; if( !(collisionMap->boxArray == NULL) ) free((void*)collisionMap->boxArray); free((void*)collisionMap); collisionMap = NULL; return 0; }/* DestroyItemMap */ /************************************************************************************/ /**************************** Tile map related functions ****************************/ tile_map_header* CreateTileMap(map_array map, int tile) { tile_map_header* header; tile_map_node* newNode; tile_map_node* tempNode; unsigned char mapHeight, mapWidth; unsigned int mapX = DISPLAY_X_OFFSET; unsigned int mapY = DISPLAY_Y_OFFSET; if( !(header = (tile_map_header*) malloc(sizeof(tile_map_header))) ) return NULL; else { header->front = tempNode = NULL; header->count = 0; } for(mapHeight=0; mapHeightnext = NULL; newNode->x = mapX; newNode->y = mapY; if(header->count) { tempNode->next = newNode; tempNode = newNode; } else tempNode = header->front = newNode; header->count++; } } mapX += TILE_WIDTH; } mapX = DISPLAY_X_OFFSET; mapY += TILE_HEIGHT; } return header; }/* CreateTileMap */ int DestroyTileMap(tile_map_header* header) { tile_map_node* tempNode; if(header == NULL) return 1; else { while(header->count) { tempNode = header->front; header->front = header->front->next; free(tempNode); header->count--; } } free((void*)header); header = NULL; return 0; }/* DestroyTileMap */ /************************************************************************************/ /******************************* Item related functions *****************************/ GsSPRITE* InitItemImages(unsigned long int address, unsigned int amount) { GsSPRITE* itemArray; if(amount == 0) return NULL; if( !(itemArray = (GsSPRITE*) calloc(amount, sizeof(GsSPRITE))) ) return NULL; InitVerticalSpriteSet(itemArray, address, amount, ITEM_HEIGHT, 0, 0); return itemArray; }/* InitItemImages */ item_map_header* CreateItemMap(tile_map_header* tileMap) { int i; item_map_header* newItemMap; tile_map_node* currentMapNode; if(tileMap == NULL) return NULL; if( !(newItemMap = (item_map_header*) malloc(sizeof(item_map_header))) ) return NULL; if( !(newItemMap->itemArray = (item_type*) calloc(tileMap->count, sizeof(item_type))) ) { free((void*)itemMap); return NULL; } currentMapNode = tileMap->front; // Initialise the item map newItemMap->count = tileMap->count; newItemMap->activeCount = 0; for(i=0; icount; i++) { newItemMap->itemArray[i].active = 0; newItemMap->itemArray[i].box.x = currentMapNode->x + ((TILE_WIDTH-ITEM_WIDTH)/2); newItemMap->itemArray[i].box.y = currentMapNode->y + ((TILE_HEIGHT-ITEM_HEIGHT)/2); newItemMap->itemArray[i].box.width = ITEM_WIDTH; newItemMap->itemArray[i].box.height = ITEM_HEIGHT; currentMapNode = currentMapNode->next; } return newItemMap; }/* CreateItemMap */ int GetItemMapActiveCount(item_map_header* itemMap) { return itemMap->activeCount; }/* GetItemMapActiveCount */ button_type GetItemFromItemMap(item_map_header* itemMap, unsigned int position) { itemMap->itemArray[position].active = 0; itemMap->activeCount--; return(itemMap->itemArray[position].itemID); }/* GetItemFromItemMap */ void AddItemsToItemMap(item_map_header* itemMap, GsSPRITE* itemSpriteArray, unsigned int numberOfItems) /* Need to add checks to this to stop items being placed onto players */ { unsigned char item; // item to be added unsigned int position; // position for item to be added in itemMap unsigned int itemsAdded = numberOfItems; if( (itemMap == NULL) || (itemSpriteArray == NULL) ) return; while(numberOfItems != 0) { item = rand() % AMOUNT_ITEM_IMAGES; position = rand() % itemMap->count; if(!(itemMap->itemArray[position].active)) { // Set the relevent values in itemMap CopySprite(&itemSpriteArray[item], &itemMap->itemArray[position].itemSprite); itemMap->itemArray[position].itemID = item; itemMap->itemArray[position].active = 1; numberOfItems--; } } itemMap->activeCount += itemsAdded; }/* AddItemsToItemMap */ void DrawItems(item_map_header* itemMap, unsigned char buffer) { unsigned int i; for(i=0; i<(itemMap->count); i++) { if((itemMap->itemArray[i].active) == 1) { // Set sprites position ready to draw SetSpritePosition(&itemMap->itemArray[i].itemSprite, itemMap->itemArray[i].box.x, itemMap->itemArray[i].box.y); // Create packets and insert into worldOT[buffer] GsSortFastSprite(&itemMap->itemArray[i].itemSprite, &worldOT[buffer], 0); } } }/* DrawItems */ int DestroyItemMap(item_map_header* itemMap) { if(itemMap == NULL) return 1; if( !(itemMap->itemArray == NULL) ) free((void*)itemMap->itemArray); free((void*)itemMap); itemMap = NULL; return 0; }/* DestroyItemMap */ /************************************************************************************/ /******************************* Menu related functions *****************************/ void InitMenu() { int i; /* Set up the games title */ InitSprite(&title, TITLE_ADDRESS, 0, 0); SetSpritePosition(&title, SCREEN_WIDTH/2, title.h/2 + 20); InitGBoxF(&titlebg, 0, 0, 250, 75); SetGBoxFPosition(&titlebg, SCREEN_WIDTH/2 - title.w/2, 20); /* Set up the Escotia logo */ InitSprite(&escotia, ESCOTIA_ADDRESS, 0, 0); SetSpritePosition(&escotia, SCREEN_WIDTH/2, 450); /* Create main menu */ mainMenu = CreateMenu(AMOUNT_MAIN_MENU_ITEMS, 0, 0, 0); menuSpriteArray = (GsSPRITE*) calloc(AMOUNT_MAIN_MENU_ITEMS, sizeof(GsSPRITE)); InitVerticalSpriteSet(menuSpriteArray, MENU_TEXT_ADDRESS, AMOUNT_MAIN_MENU_ITEMS, MENU_TEXT_HEIGHT, 0, 0); for(i=0; i