/** * Menu.c handles all the menu operations, including drawing and ship selection. * It mainly consists of a finite state machine, which displays a bunch of given * options to the user, collects the user's input, and configure the system * correspondingly. * * @author Joran Siu, Allen Chang. * @version 1.1 * @date May 4, 2004 */ #include "menu.h" // Menu Header #include "ships.h" // Ship Parameters #include "display.h" // Display Drawing Code #include "ports.h" // For gettign user input #include "game.h" // Game Ship #include "letter.h" // Draw Letters #include #define BUTTON_DELAY 20 // Amount of Delay for button debouncing. #define GAME_START_DELAY 100 // Amoutn of delay bfore game starts. #pragma regalloc- ShipInfoDesc* ship1; // p1 ship ShipInfoDesc* ship2; // p2 ship char gameOverSelection; // Stores the current selection. char _menuState; // state of Menu FSM. char shipSelection1, shipSelection2; // Ship Selection bits. unsigned int counter; // Temporary counters used by fsm unsigned int counter2; char shipDesc[26]; // Ship Description message. #pragma regalloc+ char str[20]; // str for outputting to screen /** * Initializes Menu parameters. */ void initializeMenu(ShipInfoDesc* player1, ShipInfoDesc* player2) { // Load initialized selection. shipSelection1 = ship1->type; shipSelection2 = ship2->type; // Save the ship variables. ship1 = player1; ship2 = player2; // Game starts in GAME_START State _menuState = START_SCREEN; // Clear the screen clearScreen(); displayStartScreen(); } /** * Process next State for Menu selection. (Call by main loop once a frame, * until this returns true. * @return non-zero when we can enter game mode. */ char nextMenuState() { // Decrement Our Counters. if (counter >0) counter--; if (counter2 > 0) counter2--; switch (_menuState) { case START_SCREEN: // Start screen, press button b to start. // If button B is pressed on either controller. if (counter == 0 && (P1_PIN & GEN_W1 || P2_PIN & GEN_W1)) { clearScreen(); displayShipSelectScreen(); // Load initialized selection. shipSelection1 = ship1->type; shipSelection2 = ship2->type; updateSelectScreen(0); updateSelectScreen(1); // Button Debounce counter = BUTTON_DELAY; counter2 = BUTTON_DELAY; zoomDisable(); _menuState = SELECT_SCREEN; } break; case SELECT_SCREEN: // Select ship screen. // Debouncer. // Each user can use left and right to select their ship. // 0-2 are Ships 0, 1, 2 // 3 is the Start. // 4 is processed - Ready to Start // Move Left if(P1_PIN & GEN_LEFT) { if (counter == 0 && shipSelection1 >= 0 && shipSelection1 < 3) { // Select a ship to the left (or wrap around on the left). shipSelection1 = (shipSelection1 == 0)?2:shipSelection1-1; counter = BUTTON_DELAY; updateSelectScreen(0); } } // Move Right if (P1_PIN & GEN_RIGHT) { if (counter == 0 && shipSelection1 <= 2) { // Select a ship to the right (or wrap around on the right). shipSelection1 = (shipSelection1 == 2)?0:shipSelection1+1; counter = BUTTON_DELAY; updateSelectScreen(0); } } // B Button - Start if (P1_PIN & GEN_W1) { // Received "Ok" button press. if (counter == 0 && shipSelection1 < 3) { // Go to "start" button state. ship1->type = shipSelection1; shipSelection1 = 3; counter = BUTTON_DELAY; updateSelectScreen(0); } else if (counter == 0 && shipSelection1 == 3) { // At "start" state, and confirm. Go into Ready mode. shipSelection1 = 4; counter = BUTTON_DELAY; updateSelectScreen(0); } } // C Button - Cancel if (P1_PIN & GEN_W2) { if (counter == 0 && shipSelection1 == 3) { // At "start" state, but not confirm. Return to selection. shipSelection1 = ship1->type; counter = BUTTON_DELAY; updateSelectScreen(0); } } // Player 2 Selection // Move Left if(P2_PIN & GEN_LEFT) { if (counter2 == 0 && shipSelection2 >= 0 && shipSelection2 < 3) { // Select a ship to the left (or wrap around on the left). shipSelection2 = (shipSelection2 == 0)?2:shipSelection2-1; counter2 = BUTTON_DELAY; updateSelectScreen(1); } } // Move Right if (P2_PIN & GEN_RIGHT) { if (counter2 == 0 && shipSelection2 <= 2) { shipSelection2 = (shipSelection2 == 2)?0:shipSelection2+1; counter2 = BUTTON_DELAY; updateSelectScreen(1); } } // B Button - Start if (P2_PIN & GEN_W1) { // Received "Ok" button press. if (counter2 == 0 && shipSelection2 < 3) { // Go to "start" button state. ship2->type = shipSelection2; shipSelection2 = 3; counter2 = BUTTON_DELAY; updateSelectScreen(1); } else if (counter2 == 0 && shipSelection2 == 3) { // At "start" state, and confirm. Go into Ready mode. shipSelection2 = 4; counter2 = BUTTON_DELAY; updateSelectScreen(1); } } // C Button - Cancel if (P2_PIN & GEN_W2) { if (counter2 == 0 && shipSelection2 == 3) { // At "start" state, but not confirm. Return to selection. shipSelection2 = ship2->type; counter2 = BUTTON_DELAY; updateSelectScreen(1); } } // Both are Ready! Start Game. if (shipSelection1 == 4 && shipSelection2 == 4) { clearScreen(); displayBattleMessage(); _menuState = GAME_START; counter = GAME_START_DELAY; } break; case GAME_START: // Starting Game Screen. if (counter <= 0) { // Countdown complete. Start Game!. _menuState = GAME_OVER_DRAW; clearScreen(); return 1; } break; case GAME_OVER_DRAW: // Game Over Screen. // Show option for new game. clearScreen(); _menuState = GAME_OVER; counter = GAME_START_DELAY; sprintf(str,"CONTINUE"); video_putsmalls(24,70,str); sprintf(str,"NEW GAME"); video_putsmalls(72,70,str); gameOverSelection = 0; updateGameOverSelection(gameOverSelection); break; case GAME_OVER: // Go to continue state if (counter == 0) { _menuState = CONTINUE; } case CONTINUE: // Continue Screen. if(P1_PIN & GEN_LEFT || P2_PIN & GEN_LEFT) { // Selected Continue. gameOverSelection = 0; updateGameOverSelection(0); } else if (P1_PIN & GEN_RIGHT || P2_PIN & GEN_RIGHT) { // Selected New Game. gameOverSelection = 1; updateGameOverSelection(1); } else if (P1_PIN & GEN_W1 || P2_PIN & GEN_W1) { // Select an option if (gameOverSelection == 0){ // Continue Selected. clearScreen(); displayBattleMessage(); _menuState = GAME_START; counter = GAME_START_DELAY; } else if (gameOverSelection == 1) { // Load initialized selection. shipSelection1 = ship1->type; shipSelection2 = ship2->type; // Game starts in GAME_START State _menuState = START_SCREEN; // Debounce Button. counter = BUTTON_DELAY; // Clear the screen clearScreen(); displayStartScreen(); } } break; } return 0; } /** * Displays the Start Screen. */ void displayStartScreen() { // Display our bitmap graphic. register int index; register int i; register char j; zoomEnable(32,18); // Logo index = (LOGO_Y_CENTER - 6)* 16 + 5; i = index; j = 0; // Copy logo to screen buffer. for (;i < index + 176; i = i + 16) { screen[i] = logo[j][0]; screen[i+1] = logo[j][1]; j++; } // Start at our precalculated index. index = (TITLE_Y_CENTER - 4) * 16 + 6; i = index; // Draw the Title. j = 0; // Copy title to screen buffer. for (;i < index + 128; i = i + 16) { screen[i] = title[j][0]; screen[i+1] = title[j][1]; screen[i+2] = title[j][2]; screen[i+3] = title[j][3]; screen[i+4] = title[j][4]; j++; } // Display start message. sprintf(str,"PRESS B TO START"); video_putsmalls(32,58,str); } /** * Display the Ship Selection Screen. */ void displayShipSelectScreen() { // This is the horizontal spacing for our ships. // <-8->8<-S1->24<-8->32<-S2->48<-8->56<-S3->72<-8->80<-START->115<-13-> // Player 0 drawBigShips(12,20,0); drawBigShips(36,20,1); drawBigShips(60,20,2); sprintf(str,"START"); video_putsmalls(88,20,str); // Player 0 drawBigShips(12,68,0); drawBigShips(36,68,1); drawBigShips(60,68,2); video_putsmalls(88,68,str); sprintf(str, "SELECT SHIP"); video_putsmalls(20,44,str); } /** * Update Selection Bars. */ void updateSelectScreen(char player) { char i; char draw; // Player 0. if (player == 0) { // Clear our bars first. for(i = 0; i < 11; i++) { screen[240+(int)i] = 0x00; screen[528+(int)i] = 0x00; } screen[299] = screen[300] = 0x00; screen[443] = screen[444] = 0X00; screen[301] = screen[445] = 0X00; // Select the ship to draw bars over. if (shipSelection1 < 3) draw = shipSelection1; else draw = ship1->type; // Draw the ship bars if (draw == 0) { // Line @ X: 8->24 Y:15 & 33 // Ship 1 screen[241] = screen[242] = 0xFF; screen[529] = screen[530] = 0xFF; sprintf(shipDesc,"W1:BULLETS W2:BOOST "); video_putsmalls(12,8,shipDesc); } else if (draw == 1) { // Ship 2 screen[244] = screen[245] = 0xFF; screen[532] = screen[533] = 0xFF; sprintf(shipDesc,"W1:SMART BOMB W2:REPAIR"); video_putsmalls(12,8,shipDesc); } else if (draw == 2) { // Ship 3 screen[247] = screen[248] = 0xFF; screen[535] = screen[536] = 0xFF; sprintf(shipDesc,"W1:TORPEDO W2:HOMING"); video_putsmalls(12,8,shipDesc); } // Draw bars over Start. if (shipSelection1 == 3 ) { screen[299] = screen[300] = 0xFF; screen[443] = screen[444] = 0XFF; screen[301] = screen[445] = 0XF0; } else if (shipSelection1 == 4){ sprintf(str,"READY"); video_putsmalls(88,20,str); } } else { // Clear the bars screen[1067] = screen[1068] = 0x00; screen[1211] = screen[1212] = 0x00; screen[1069] = screen[1213] = 0x00; for(i = 0; i < 10; i++) { screen[1008+i] = 0x00; screen[1296+i] = 0x00; } // Select the ship to draw bars over. if (shipSelection2 < 3) draw = shipSelection2; else draw = ship2->type; // Draw the ship bars if (draw == 0) { // Line @ X: 8->24 Y:63 & 81 // Ship 1. screen[1009] = screen[1010] = 0xFF; screen[1297] = screen[1298] = 0xFF; sprintf(shipDesc,"W1:BULLETS W2:BOOST "); video_putsmalls(12,87,shipDesc); } else if (draw == 1) { // Ship 2 screen[1012] = screen[1013] = 0xFF; screen[1300] = screen[1301] = 0xFF; sprintf(shipDesc,"W1:SMART BOMB W2:REPAIR"); video_putsmalls(12,87,shipDesc); } else if (draw == 2) { // Ship 3 screen[1015] = screen[1016] = 0xFF; screen[1303] = screen[1304] = 0xFF; sprintf(shipDesc,"W1:TORPEDO W2:HOMING"); video_putsmalls(12,87,shipDesc); } // Draw bars over Start. if (shipSelection2 == 3 ) { screen[1067] = screen[1068] = 0xFF; screen[1211] = screen[1212] = 0xFF; screen[1069] = screen[1213] = 0XF0; } else if (shipSelection2 == 4){ sprintf(str,"READY"); video_putsmalls(88,68,str); } } } /** * Update the Game Over Selection Choices */ void updateGameOverSelection(char type) { // Game over selection bars. if (type == 0) { // Continue y= 68 screen[1091] = screen[1092] = screen[1093] = screen[1094] = 0xFF; screen[1097] = screen[1098] = screen[1099] = screen[1100] = 0x00; screen[1219] = screen[1220] = screen[1221] = screen[1222] = 0xFF; screen[1225] = screen[1226] = screen[1227] = screen[1228] = 0x00; } else { // New Game y= 76 screen[1091] = screen[1092] = screen[1093] = screen[1094] = 0x00; screen[1097] = screen[1098] = screen[1099] = screen[1100] = 0xFF; screen[1219] = screen[1220] = screen[1221] = screen[1222] = 0x00; screen[1225] = screen[1226] = screen[1227] = screen[1228] = 0xFF; } } /** * Display the Battle Message. */ void displayBattleMessage() { sprintf(str,"BATTLE"); video_putsmalls(44,30,str); }