Files
vbagx/source/ngc/menu.cpp
dborth 2d9b7ef1f9 [1.0.8 - April 4, 2009]
* "Match Wii Game" controls option! Games that have a Wii equivalent can be
  played using the controls for that Wii game. For example all Zelda games
  can be played with Twilight Princess controls. See the Instructions section
  below for important details.
* Rotation/Tilt sensor games all work
* Solar sensors (Boktai 1/2/3)
* Rumble (except for games that rely on Gameboy Player)
* Keyboard
* PAL support, finally!
* New scaling options, choose how much stretching you want
* Colourised games now partially work but still have distortion
* "Corvette" no longer has a screwed up palette (but still crashes)
* Triggers net reconnection on SMB failure
* Source code refactored, and project file added
* Instructions section added to this readme file
2009-04-10 03:16:28 +00:00

827 lines
19 KiB
C++

/****************************************************************************
* Visual Boy Advance GX
*
* Tantric September 2008
*
* menu.cpp
*
* Menu flow routines - handles all menu logic
***************************************************************************/
#include <gccore.h>
#include <ogcsys.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiiuse/wpad.h>
#ifdef HW_RVL
extern "C" {
#include <di/di.h>
}
#endif
#include "vba.h"
#include "vbasupport.h"
#include "audio.h"
#include "video.h"
#include "filesel.h"
#include "gcunzip.h"
#include "networkop.h"
#include "memcardop.h"
#include "fileop.h"
#include "dvd.h"
#include "preferences.h"
#include "button_mapping.h"
#include "menudraw.h"
#include "input.h"
#include "vbaconfig.h"
#include "wiiusbsupport.h"
extern "C"
{
#include "tbtime.h"
}
extern int menu;
extern bool ROMLoaded;
extern char DebugStr[50];
/****************************************************************************
* Load Manager
***************************************************************************/
static int
LoadManager ()
{
int loadROM = OpenROM(GCSettings.LoadMethod);
/***
* check for autoload battery / state
***/
if ( loadROM == 1 ) // if ROM was loaded, load the battery / state
{
if (GCSettings.AutoLoad == 1)
LoadBatteryOrState(GCSettings.SaveMethod, FILE_SRAM, SILENT); // load battery
else if (GCSettings.AutoLoad == 2)
LoadBatteryOrState(GCSettings.SaveMethod, FILE_SNAPSHOT, SILENT); // load state
}
return loadROM;
}
/****************************************************************************
* Preferences Menu
***************************************************************************/
static void
PreferencesMenu ()
{
int prefmenuCount = 12;
char prefmenu[][50] = {
"Load Method",
"Load Folder",
"Save Method",
"Save Folder",
"Auto Load",
"Auto Save",
"Verify MC Saves",
"Enable Zooming",
"Video Rendering",
"Video Scaling",
"Reset Preferences",
"Back to Main Menu"
};
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 vba.h
// no USB ports on GameCube
#ifdef HW_DOL
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 DVD in GC mode (not implemented)
#ifdef HW_DOL
if(GCSettings.LoadMethod == METHOD_DVD)
GCSettings.LoadMethod++;
#endif
// disable SMB in GC mode (stalls out)
#ifdef HW_DOL
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
// disable Widescreen correction in Wii mode - determined automatically
#ifdef HW_RVL
if(GCSettings.scaling == 3)
GCSettings.scaling = 0;
#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 SRAM");
else if (GCSettings.AutoLoad == 2) sprintf (prefmenu[4],"Auto Load SNAPSHOT");
if (GCSettings.AutoSave == 0) sprintf (prefmenu[5],"Auto Save OFF");
else if (GCSettings.AutoSave == 1) sprintf (prefmenu[5],"Auto Save SRAM");
else if (GCSettings.AutoSave == 2) sprintf (prefmenu[5],"Auto Save SNAPSHOT");
else if (GCSettings.AutoSave == 3) sprintf (prefmenu[5],"Auto Save BOTH");
sprintf (prefmenu[7], "Enable Zooming %s",
GCSettings.Zoom == true ? " ON" : "OFF");
// original mode not implemented
if(GCSettings.render == 0)
GCSettings.render++;
if (GCSettings.render == 0)
sprintf (prefmenu[8], "Video Rendering Original");
if (GCSettings.render == 1)
sprintf (prefmenu[8], "Video Rendering Filtered");
if (GCSettings.render == 2)
sprintf (prefmenu[8], "Video Rendering Unfiltered");
if (GCSettings.scaling == 0)
sprintf (prefmenu[9], "Video Scaling Maintain Aspect Ratio");
else if (GCSettings.scaling == 1)
sprintf (prefmenu[9], "Video Scaling Partial Stretch");
else if (GCSettings.scaling == 2)
sprintf (prefmenu[9], "Video Scaling Stretch to Fit");
else if (GCSettings.scaling == 3)
sprintf (prefmenu[9], "Video Scaling 16:9 Correction");
ret = RunMenu (prefmenu, prefmenuCount, "Preferences", 16);
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:
GCSettings.Zoom ^= 1;
break;
case 8:
GCSettings.render++;
if (GCSettings.render > 2)
GCSettings.render = 0;
// reset zoom
zoom_reset ();
break;
case 9:
GCSettings.scaling++;
if (GCSettings.scaling > 3)
GCSettings.scaling = 0;
break;
case 10:
DefaultSettings ();
WaitPrompt("Preferences Reset");
break;
case 11:
case -1: /*** Button B ***/
SavePrefs(SILENT);
quit = 1;
break;
}
}
menu = oldmenu;
}
/****************************************************************************
* Game Options Menu
***************************************************************************/
static int
GameMenu ()
{
int gamemenuCount = 10;
char gamemenu[][50] = {
"Return to Game",
"Reset Game",
"Load SRAM", "Save SRAM",
"Load Game Snapshot", "Save Game Snapshot",
"Reset Zoom",
"Weather: 100% sun",
"Back to Main Menu",
""
};
int ret, retval = 0;
int quit = 0;
int oldmenu = menu;
menu = 0;
while (quit == 0)
{
// disable SRAM/SNAPSHOT saving/loading if AUTO is on
if (GCSettings.AutoLoad == 1) // Auto Load SRAM
gamemenu[2][0] = '\0';
else if (GCSettings.AutoLoad == 2) // Auto Load SNAPSHOT
gamemenu[4][0] = '\0';
if (GCSettings.AutoSave == 1) // Auto Save SRAM
gamemenu[3][0] = '\0';
else if (GCSettings.AutoSave == 2) // Auto Save SNAPSHOT
gamemenu[5][0] = '\0';
else if (GCSettings.AutoSave == 3) // Auto Save BOTH
{
gamemenu[3][0] = '\0';
gamemenu[5][0] = '\0';
}
// disable Reset Zoom if Zooming is off
if(!GCSettings.Zoom)
gamemenu[6][0] = '\0';
// Weather menu if a game with Boktai solar sensor
if ((RomIdCode & 0xFF)=='U')
sprintf(gamemenu[7], "Weather: %d%% sun", SunBars*10);
else
gamemenu[7][0] = '\0';
sprintf(gamemenu[9], "%s", DebugStr);
ret = RunMenu (gamemenu, gamemenuCount, "Game Menu");
switch (ret)
{
case 0: // Return to Game
quit = retval = 1;
break;
case 1: // Reset Game
emulator.emuReset();
quit = retval = 1;
break;
case 2: // Load Battery
quit = retval = LoadBatteryOrState(GCSettings.SaveMethod, FILE_SRAM, NOTSILENT);
emulator.emuReset();
break;
case 3: // Save Battery
SaveBatteryOrState(GCSettings.SaveMethod, FILE_SRAM, NOTSILENT);
break;
case 4: // Load State
quit = retval = LoadBatteryOrState(GCSettings.SaveMethod, FILE_SNAPSHOT, NOTSILENT);
break;
case 5: // Save State
SaveBatteryOrState(GCSettings.SaveMethod, FILE_SNAPSHOT, NOTSILENT);
break;
case 6: // Reset Zoom
zoom_reset ();
quit = retval = 1;
break;
case 7: // Weather
SunBars++;
if (SunBars>10) SunBars=0;
break;
case -1: // Button B
case 8: // Return to previous menu
retval = 0;
quit = 1;
break;
}
}
menu = oldmenu;
return retval;
}
/****************************************************************************
* Controller Configuration
***************************************************************************/
static 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)
| AnyKeyDown()
#endif
) {
updateRumbleFrame();
VIDEO_WaitVSync(); // button 'debounce'
}
while (pressed == 0 && !AnyKeyDown())
{
updateRumbleFrame();
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
{
// also needed for keyboard read, to prevent infinite wait when no keyboard
pressed = WPAD_ButtonsHeld (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;
if (DownUsbKeys[KB_ESC]) return 0;
if (ctrlr_type == CTRLR_KEYBOARD)
pressed = 0;
} // end while
if (DownUsbKeys[KB_ESC]) return 0;
if (!pressed) {
for (int i=4; i<=231; i++) {
if (DownUsbKeys[i]) {
while (DownUsbKeys[i]) {
updateRumbleFrame();
VIDEO_WaitVSync();
}
return i;
}
}
}
while( pressed == (PAD_ButtonsHeld(0)
#ifdef HW_RVL
| WPAD_ButtonsHeld(0)
#endif
) ) {
updateRumbleFrame();
VIDEO_WaitVSync();
}
return pressed;
} // end GetInput()
static u32
GetButtonMap(u16 ctrlr_type, char* btn_name)
{
int cfg_text_count = 7;
char cfg_text[][50] = {
"Remapping ",
"Press Any Button",
"on the",
" ", // identify controller (must be at least 8 spaces for "keyboard")
" ",
"Press C-Left or",
"Home to exit"
};
u32 pressed, previous;
char temp[50] = "";
uint k;
pressed = 0; previous = 1;
switch (ctrlr_type) {
case CTRLR_NUNCHUK:
strncpy (cfg_text[3], "NUNCHUK", 8); // 8 spaces in "identify controller" above
break;
case CTRLR_CLASSIC:
strncpy (cfg_text[3], "CLASSIC", 8);
break;
case CTRLR_GCPAD:
strncpy (cfg_text[3], "GC PAD", 8);
break;
case CTRLR_WIIMOTE:
strncpy (cfg_text[3], "WIIMOTE", 8);
break;
case CTRLR_KEYBOARD:
strncpy (cfg_text[3], "KEYBOARD", 8);
};
/*** note which button we are remapping ***/
sprintf (temp, "Remapping ");
for (k=0; k<9-strlen(btn_name); k++) strcat(temp, " "); // add whitespace padding to align text
strncat (temp, btn_name, 9); // snes 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); // display text
pressed = GetInput(ctrlr_type);
return pressed;
} // end getButtonMap()
static void
ConfigureButtons (u16 ctrlr_type)
{
int cfg_btns_count = 11;
char cfg_btns_menu[][50] = {
"B - ",
"A - ",
"SELECT - ",
"START - ",
"UP - ",
"DOWN - ",
"LEFT - ",
"RIGHT - ",
"L TRIG - ",
"R TRIG - ",
"Return to previous"
};
int quit = 0;
int ret = 0;
int oldmenu = menu;
menu = 0;
char menu_title[50];
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:
sprintf(menu_title, "VBA - NUNCHUK");
currentpadmap = ncpadmap;
break;
case CTRLR_CLASSIC:
sprintf(menu_title, "VBA - CLASSIC");
currentpadmap = ccpadmap;
break;
case CTRLR_GCPAD:
sprintf(menu_title, "VBA - GC PAD");
currentpadmap = gcpadmap;
break;
case CTRLR_WIIMOTE:
sprintf(menu_title, "VBA - WIIMOTE");
currentpadmap = wmpadmap;
break;
case CTRLR_KEYBOARD:
sprintf(menu_title, "VBA - KEYBOARD");
currentpadmap = kbpadmap;
break;
};
while (quit == 0)
{
/*** Update Menu with Current ButtonMap ***/
for (i=0; i<10; i++) // vba pad has 10 buttons to config (go thru them)
{
// get current padmap button name to display
for ( j=0;
j < ctrlr_def[ctrlr_type].num_btns &&
currentpadmap[i] != ctrlr_def[ctrlr_type].map[j].btn // match padmap button press with button names
; j++ );
memset (temp, 0, sizeof(temp));
strncpy (temp, cfg_btns_menu[i], 12); // copy vba button information
if (currentpadmap[i] == ctrlr_def[ctrlr_type].map[j].btn) // check if a match was made
{
for (k=0; k<7-strlen(ctrlr_def[ctrlr_type].map[j].name) ;k++) strcat(temp, " "); // add whitespace padding to align text
strncat (temp, ctrlr_def[ctrlr_type].map[j].name, 6); // update button map display
}
else
strcat (temp, "---"); // otherwise, button is 'unmapped'
strncpy (cfg_btns_menu[i], temp, 19); // move back updated information
}
ret = RunMenu (cfg_btns_menu, cfg_btns_count, menu_title, 16);
switch (ret)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
/*** Change button map ***/
// wait for input
memset (temp, 0, sizeof(temp));
strncpy(temp, cfg_btns_menu[ret], 6); // get the name of the vba button we're changing
pressed = GetButtonMap(ctrlr_type, temp); // get a button selection from user
// FIX: check if input is valid for this controller
if (pressed != 0) // check if a the button was configured, or if the user exited.
currentpadmap[ret] = pressed; // update mapping
break;
case -1: /*** Button B ***/
case 10:
/*** Return ***/
quit = 1;
break;
}
}
menu = oldmenu;
} // end configurebuttons()
void
ConfigureControllers ()
{
int ctlrmenucount = 8;
char ctlrmenu[][50] = {
"Match Wii Game",
"Nunchuk",
"Classic Controller",
"Wiimote",
"Gamecube Pad",
"Keyboard",
"Save Preferences",
"Go Back"
};
int quit = 0;
int ret = 0;
int oldmenu = menu;
menu = 0;
// disable unavailable controller options if in GC mode
#ifndef HW_RVL
ctlrmenu[1][0] = 0;
ctlrmenu[2][0] = 0;
ctlrmenu[3][0] = 0;
ctlrmenu[5][0] = 0;
#endif
while (quit == 0)
{
#ifdef HW_RVL
sprintf (ctlrmenu[0], "Match Wii Game: %s",
GCSettings.WiiControls == true ? " ON" : "OFF");
#else
sprintf (ctlrmenu[0], "Match Gamecube Game: %s",
GCSettings.WiiControls == true ? " ON" : "OFF");
#endif
/*** Controller Config Menu ***/
ret = RunMenu (ctlrmenu, ctlrmenucount, "Configure Controllers");
switch (ret)
{
case 0:
GCSettings.WiiControls ^= 1;
break;
case 1:
/*** Configure Nunchuk ***/
ConfigureButtons (CTRLR_NUNCHUK);
break;
case 2:
/*** Configure Classic ***/
ConfigureButtons (CTRLR_CLASSIC);
break;
case 3:
/*** Configure Wiimote ***/
ConfigureButtons (CTRLR_WIIMOTE);
break;
case 4:
/*** Configure GC Pad ***/
ConfigureButtons (CTRLR_GCPAD);
break;
case 5:
/*** Configure Keyboard ***/
ConfigureButtons (CTRLR_KEYBOARD);
break;
case 6:
/*** Save Preferences Now ***/
SavePrefs(NOTSILENT);
break;
case -1: /*** Button B ***/
case 7:
/*** Return ***/
quit = 1;
break;
}
}
menu = oldmenu;
}
/****************************************************************************
* Main Menu
***************************************************************************/
void
MainMenu (int selectedMenu)
{
int menucount = 8;
char menuitems[][50] = {
"Choose Game",
"Controller Configuration",
"Preferences",
"Game Menu",
"Credits",
"DVD Motor Off",
"Reset System",
"Return to Loader"
};
tb_t start,end;
mftb(&start);
int quit = 0;
int ret;
#ifdef HW_RVL
// don't show dvd motor off on the wii
menuitems[5][0] = 0;
// rename reset/exit items
sprintf (menuitems[6], "Return to Wii Menu");
sprintf (menuitems[7], "Return to Homebrew Channel");
#endif
// disable game-specific menu items if a ROM isn't loaded
if (!ROMLoaded)
menuitems[3][0] = '\0';
else
sprintf (menuitems[3], "Game Menu");
updateRumbleFrame();
VIDEO_WaitVSync ();
while (quit == 0)
{
if(selectedMenu >= 0)
{
ret = selectedMenu;
selectedMenu = -1; // default back to main menu
}
else
{
ret = RunMenu (menuitems, menucount, "Main Menu");
}
switch (ret)
{
case 0:
// Load ROM Menu
quit = LoadManager ();
break;
case 1:
// Configure Controllers
ConfigureControllers ();
break;
case 2:
// Preferences
PreferencesMenu ();
break;
case 3:
// Game Options
quit = GameMenu ();
break;
case 4:
// Credits
Credits ();
WaitButtonA ();
break;
case 5:
// turn the dvd motor off (GC only)
#ifdef HW_DOL
dvd_motor_off ();
#endif
break;
case 6:
// Reset the Gamecube/Wii
Reboot();
break;
case 7:
ExitToLoader();
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
))
{
updateRumbleFrame();
VIDEO_WaitVSync();
count++;
}
mftb(&end);
loadtimeradjust += tb_diff_msec(&end, &start);
}