/**************************************************************************** * FCE Ultra 0.98.12 * Nintendo Wii/Gamecube Port * * Tantric September 2008 * * menu.c * * Main menu flow control ****************************************************************************/ #include #include #include #include #include #include #ifdef WII_DVD #include #endif #include "common.h" #include "fceuconfig.h" #include "pad.h" #include "button_mapping.h" #include "filesel.h" #include "gcunzip.h" #include "smbop.h" #include "memcardop.h" #include "fileop.h" #include "dvd.h" #include "menudraw.h" #include "fceustate.h" #include "gcvideo.h" #include "preferences.h" #include "fceuram.h" #include "fceuload.h" extern void ResetNES(void); extern void FCEU_ResetPalette(void); extern int menu; extern bool romLoaded; #define SOFTRESET_ADR ((volatile u32*)0xCC003024) /**************************************************************************** * Reboot / Exit ****************************************************************************/ #ifndef HW_RVL #define PSOSDLOADID 0x7c6000a6 int *psoid = (int *) 0x80001800; void (*PSOReload) () = (void (*)()) 0x80001800; #endif void Reboot() { #ifdef HW_RVL SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); #else #define SOFTRESET_ADR ((volatile u32*)0xCC003024) *SOFTRESET_ADR = 0x00000000; #endif } /**************************************************************************** * Load Manager ****************************************************************************/ int LoadManager () { int loadROM = OpenROM(GCSettings.LoadMethod); if ( loadROM == 1 ) // if ROM was loaded { // load the RAM if (GCSettings.AutoLoad == 1) LoadRAM(GCSettings.SaveMethod, SILENT); else if (GCSettings.AutoLoad == 2) LoadState(GCSettings.SaveMethod, SILENT); ResetNES(); } return loadROM; } /**************************************************************************** * Emulator Menu ****************************************************************************/ static int emulatormenuCount = 6; static char emulatormenu[][50] = { "Screen Scaler", "Palette", "8 Sprite Limit", "Timing", "Save Preferences", "Back to Main Menu" }; void EmulatorMenu () { int ret = 0; int quit = 0; int oldmenu = menu; menu = 0; while (quit == 0) { sprintf (emulatormenu[0], "Screen Scaler - %s", (GCSettings.screenscaler == 0) ? "2x" : (GCSettings.screenscaler == 1) ? "Cheesy" : "GX"); sprintf (emulatormenu[1], "Palette - %s", GCSettings.currpal ? palettes[GCSettings.currpal-1].name : "Default"); sprintf (emulatormenu[2], "8 Sprite Limit - %s", GCSettings.slimit == true ? " ON" : "OFF"); sprintf (emulatormenu[3], "Timing - %s", GCSettings.timing == true ? " PAL" : "NTSC"); ret = RunMenu (emulatormenu, emulatormenuCount, (char*)"Emulator Options", 16, -1); switch (ret) { case 0: // screen scaler if (++GCSettings.screenscaler > 2) GCSettings.screenscaler = 0; break; case 1: // palette if ( ++GCSettings.currpal > MAXPAL ) GCSettings.currpal = 0; if ( GCSettings.currpal == 0 ) { // Do palette reset FCEU_ResetPalette(); } else { // Now setup this palette unsigned char i,r,g,b; for ( i = 0; i < 64; i++ ) { r = palettes[GCSettings.currpal-1].data[i] >> 16; g = ( palettes[GCSettings.currpal-1].data[i] & 0xff00 ) >> 8; b = ( palettes[GCSettings.currpal-1].data[i] & 0xff ); FCEUD_SetPalette( i, r, g, b); FCEUD_SetPalette( i+64, r, g, b); FCEUD_SetPalette( i+128, r, g, b); FCEUD_SetPalette( i+192, r, g, b); } } break; case 2: // 8 sprite limit GCSettings.slimit ^=1; FCEUI_DisableSpriteLimitation(GCSettings.slimit); break; case 3: // timing GCSettings.timing ^= 1; FCEUI_SetVidSystem(GCSettings.timing); break; case 4: SavePrefs(GCSettings.SaveMethod, NOTSILENT); break; case -1: // Button B case 5: quit = 1; break; } } menu = oldmenu; } /**************************************************************************** * Preferences Menu ****************************************************************************/ static int prefmenuCount = 9; static char prefmenu[][50] = { "Load Method", "Load Folder", "Save Method", "Save Folder", "Auto Load", "Auto Save", "Verify MC Saves", "Save Preferences", "Back to Main Menu" }; void PreferencesMenu () { int ret = 0; int quit = 0; int oldmenu = menu; menu = 0; while (quit == 0) { // some load/save methods are not implemented - here's where we skip them // they need to be skipped in the order they were enumerated in snes9xGX.h // no USB ports on GameCube #ifndef HW_RVL if(GCSettings.LoadMethod == METHOD_USB) GCSettings.LoadMethod++; if(GCSettings.SaveMethod == METHOD_USB) GCSettings.SaveMethod++; #endif // saving to DVD is impossible if(GCSettings.SaveMethod == METHOD_DVD) GCSettings.SaveMethod++; // disable SMB in GC mode (stalls out) #ifndef HW_RVL if(GCSettings.LoadMethod == METHOD_SMB) GCSettings.LoadMethod++; if(GCSettings.SaveMethod == METHOD_SMB) GCSettings.SaveMethod++; #endif // disable MC saving in Wii mode - does not work for some reason! #ifdef HW_RVL if(GCSettings.SaveMethod == METHOD_MC_SLOTA) GCSettings.SaveMethod++; if(GCSettings.SaveMethod == METHOD_MC_SLOTB) GCSettings.SaveMethod++; prefmenu[6][0] = '\0'; #else sprintf (prefmenu[6], "Verify MC Saves %s", GCSettings.VerifySaves == true ? " ON" : "OFF"); #endif // correct load/save methods out of bounds if(GCSettings.LoadMethod > 4) GCSettings.LoadMethod = 0; if(GCSettings.SaveMethod > 6) GCSettings.SaveMethod = 0; if (GCSettings.LoadMethod == METHOD_AUTO) sprintf (prefmenu[0],"Load Method AUTO"); else if (GCSettings.LoadMethod == METHOD_SD) sprintf (prefmenu[0],"Load Method SD"); else if (GCSettings.LoadMethod == METHOD_USB) sprintf (prefmenu[0],"Load Method USB"); else if (GCSettings.LoadMethod == METHOD_DVD) sprintf (prefmenu[0],"Load Method DVD"); else if (GCSettings.LoadMethod == METHOD_SMB) sprintf (prefmenu[0],"Load Method Network"); sprintf (prefmenu[1], "Load Folder %s", GCSettings.LoadFolder); if (GCSettings.SaveMethod == METHOD_AUTO) sprintf (prefmenu[2],"Save Method AUTO"); else if (GCSettings.SaveMethod == METHOD_SD) sprintf (prefmenu[2],"Save Method SD"); else if (GCSettings.SaveMethod == METHOD_USB) sprintf (prefmenu[2],"Save Method USB"); else if (GCSettings.SaveMethod == METHOD_SMB) sprintf (prefmenu[2],"Save Method Network"); else if (GCSettings.SaveMethod == METHOD_MC_SLOTA) sprintf (prefmenu[2],"Save Method MC Slot A"); else if (GCSettings.SaveMethod == METHOD_MC_SLOTB) sprintf (prefmenu[2],"Save Method MC Slot B"); sprintf (prefmenu[3], "Save Folder %s", GCSettings.SaveFolder); // disable changing load/save directories for now prefmenu[1][0] = '\0'; prefmenu[3][0] = '\0'; if (GCSettings.AutoLoad == 0) sprintf (prefmenu[4],"Auto Load OFF"); else if (GCSettings.AutoLoad == 1) sprintf (prefmenu[4],"Auto Load RAM"); else if (GCSettings.AutoLoad == 2) sprintf (prefmenu[4],"Auto Load STATE"); if (GCSettings.AutoSave == 0) sprintf (prefmenu[5],"Auto Save OFF"); else if (GCSettings.AutoSave == 1) sprintf (prefmenu[5],"Auto Save RAM"); else if (GCSettings.AutoSave == 2) sprintf (prefmenu[5],"Auto Save STATE"); else if (GCSettings.AutoSave == 3) sprintf (prefmenu[5],"Auto Save BOTH"); ret = RunMenu (prefmenu, prefmenuCount, (char*)"Preferences", 16, -1); switch (ret) { case 0: GCSettings.LoadMethod ++; break; case 1: break; case 2: GCSettings.SaveMethod ++; break; case 3: break; case 4: GCSettings.AutoLoad ++; if (GCSettings.AutoLoad > 2) GCSettings.AutoLoad = 0; break; case 5: GCSettings.AutoSave ++; if (GCSettings.AutoSave > 3) GCSettings.AutoSave = 0; break; case 6: GCSettings.VerifySaves ^= 1; break; case 7: SavePrefs(GCSettings.SaveMethod, NOTSILENT); break; case -1: // Button B case 8: quit = 1; break; } } menu = oldmenu; } /**************************************************************************** * Game Options Menu ****************************************************************************/ int GameMenu () { int gamemenuCount = 8; char gamemenu[][50] = { "Return to Game", "Reset Game", "ROM Information", "Load RAM", "Save RAM", "Load State", "Save State", "Back to Main Menu" }; int ret, retval = 0; int quit = 0; int oldmenu = menu; menu = 0; while (quit == 0) { if(nesGameType == 4) // FDS game { // disable RAM saving/loading gamemenu[3][0] = '\0'; gamemenu[4][0] = '\0'; // disable ROM Information gamemenu[2][0] = '\0'; } // disable RAM/STATE saving/loading if AUTO is on if (GCSettings.AutoLoad == 1) // Auto Load RAM gamemenu[3][0] = '\0'; else if (GCSettings.AutoLoad == 2) // Auto Load STATE gamemenu[5][0] = '\0'; if (GCSettings.AutoSave == 1) // Auto Save RAM gamemenu[4][0] = '\0'; else if (GCSettings.AutoSave == 2) // Auto Save STATE gamemenu[6][0] = '\0'; else if (GCSettings.AutoSave == 3) // Auto Save BOTH { gamemenu[4][0] = '\0'; gamemenu[6][0] = '\0'; } ret = RunMenu (gamemenu, gamemenuCount, (char*)"Game Menu", 20, -1); switch (ret) { case 0: // Return to Game quit = retval = 1; break; case 1: // Reset Game ResetNES(); quit = retval = 1; break; case 2: // ROM Information RomInfo(); WaitButtonA (); break; case 3: // Load RAM quit = retval = LoadRAM(GCSettings.SaveMethod, NOTSILENT); break; case 4: // Save RAM SaveRAM(GCSettings.SaveMethod, NOTSILENT); break; case 5: // Load State quit = retval = LoadState(GCSettings.SaveMethod, NOTSILENT); break; case 6: // Save State SaveState(GCSettings.SaveMethod, NOTSILENT); break; case -1: // Button B case 7: // Return to previous menu retval = 0; quit = 1; break; } } menu = oldmenu; return retval; } /**************************************************************************** * Controller Configuration * * Snes9x 1.50 uses a cmd system to work out which button has been pressed. * Here, I simply move the designated value to the gcpadmaps array, which saves * on updating the cmd sequences. ****************************************************************************/ u32 GetInput (u16 ctrlr_type) { //u32 exp_type; u32 pressed; pressed=0; s8 gc_px = 0; while( PAD_ButtonsHeld(0) #ifdef HW_RVL | WPAD_ButtonsHeld(0) #endif ) VIDEO_WaitVSync(); // button 'debounce' while (pressed == 0) { VIDEO_WaitVSync(); // get input based on controller type if (ctrlr_type == CTRLR_GCPAD) { pressed = PAD_ButtonsHeld (0); gc_px = PAD_SubStickX (0); } #ifdef HW_RVL else { // if ( WPAD_Probe( 0, &exp_type) == 0) // check wiimote and expansion status (first if wiimote is connected & no errors) // { pressed = WPAD_ButtonsHeld (0); // if (ctrlr_type != CTRLR_WIIMOTE && exp_type != ctrlr_type+1) // if we need input from an expansion, and its not connected... // pressed = 0; // } } #endif /*** check for exit sequence (c-stick left OR home button) ***/ if ( (gc_px < -70) || (pressed & WPAD_BUTTON_HOME) || (pressed & WPAD_CLASSIC_BUTTON_HOME) ) return 0; } // end while while( pressed == (PAD_ButtonsHeld(0) #ifdef HW_RVL | WPAD_ButtonsHeld(0) #endif ) ) VIDEO_WaitVSync(); return pressed; } // end GetInput() int cfg_text_count = 7; char cfg_text[][50] = { "Remapping ", "Press Any Button", "on the", " ", // identify controller " ", "Press C-Left or", "Home to exit" }; u32 GetButtonMap(u16 ctrlr_type, char* btn_name) { u32 pressed, previous; char temp[50] = ""; uint k; pressed = 0; previous = 1; switch (ctrlr_type) { case CTRLR_NUNCHUK: strncpy (cfg_text[3], (char*)"NUNCHUK", 7); break; case CTRLR_CLASSIC: strncpy (cfg_text[3], (char*)"CLASSIC", 7); break; case CTRLR_GCPAD: strncpy (cfg_text[3], (char*)"GC PAD", 7); break; case CTRLR_WIIMOTE: strncpy (cfg_text[3], (char*)"WIIMOTE", 7); break; }; /*** note which button we are remapping ***/ sprintf (temp, (char*)"Remapping "); for (k=0; k<9-strlen(btn_name); k++) strcat(temp, " "); // add whitespace padding to align text strncat (temp, btn_name, 9); // nes button we are remapping strncpy (cfg_text[0], temp, 19); // copy this all back to the text we wish to display DrawMenu(&cfg_text[0], NULL, cfg_text_count, 1, 20, -1); // display text // while (previous != pressed && pressed == 0); // get two consecutive button presses (which are the same) // { // previous = pressed; // VIDEO_WaitVSync(); // slow things down a bit so we don't overread the pads pressed = GetInput(ctrlr_type); // } return pressed; } // end getButtonMap() int cfg_btns_count = 10; char cfg_btns_menu[][50] = { "B - ", "A - ", "SELECT - ", "START - ", "UP - ", "DOWN - ", "LEFT - ", "RIGHT - ", "SPECIAL - ", "Return to previous" }; extern unsigned int gcpadmap[]; extern unsigned int wmpadmap[]; extern unsigned int ccpadmap[]; extern unsigned int ncpadmap[]; void ConfigureButtons (u16 ctrlr_type) { int quit = 0; int ret = 0; int oldmenu = menu; menu = 0; char* menu_title = NULL; u32 pressed; unsigned int* currentpadmap = 0; char temp[50] = ""; int i, j; uint k; /*** Update Menu Title (based on controller we're configuring) ***/ switch (ctrlr_type) { case CTRLR_NUNCHUK: menu_title = (char*)"NES - NUNCHUK"; currentpadmap = ncpadmap; break; case CTRLR_CLASSIC: menu_title = (char*)"NES - CLASSIC"; currentpadmap = ccpadmap; break; case CTRLR_GCPAD: menu_title = (char*)"NES - GC PAD"; currentpadmap = gcpadmap; break; case CTRLR_WIIMOTE: menu_title = (char*)"NES - WIIMOTE"; currentpadmap = wmpadmap; break; }; while (quit == 0) { /*** Update Menu with Current ButtonMap ***/ for (i=0; i= 0) { ret = selectedMenu; selectedMenu = -1; // default back to main menu } else { ret = RunMenu (menuitems, menucount, (char*)"Main Menu", 20, -1); } switch (ret) { case 0: // Load ROM Menu quit = LoadManager (); break; case 1: // Configure Controllers ConfigureControllers (); break; case 2: // Emulator Options EmulatorMenu (); break; case 3: // Preferences PreferencesMenu (); break; case 4: // Game Options quit = GameMenu (); break; case 5: // Credits Credits (); WaitButtonA (); break; case 6: // Reset the Gamecube/Wii Reboot(); break; case 7: // Exit to Loader #ifdef HW_RVL #ifdef WII_DVD DI_Close(); #endif exit(0); #else // gamecube if (psoid[0] == PSOSDLOADID) PSOReload (); #endif break; case -1: // Button B // Return to Game if(romLoaded) quit = 1; break; } } // Wait for buttons to be released int count = 0; // how long we've been waiting for the user to release the button while(count < 50 && ( PAD_ButtonsHeld(0) #ifdef HW_RVL || WPAD_ButtonsHeld(0) #endif )) { VIDEO_WaitVSync(); count++; } }