mirror of
https://github.com/dborth/vbagx.git
synced 2025-07-07 15:05:39 +02:00

* "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
423 lines
12 KiB
C++
423 lines
12 KiB
C++
/****************************************************************************
|
|
* Visual Boy Advance GX
|
|
*
|
|
* Tantric September 2008
|
|
*
|
|
* preferences.cpp
|
|
*
|
|
* Preferences save/load to XML file
|
|
***************************************************************************/
|
|
|
|
#include <gccore.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ogcsys.h>
|
|
#include <mxml.h>
|
|
|
|
#include "vba.h"
|
|
#include "images/saveicon.h"
|
|
#include "menudraw.h"
|
|
#include "memcardop.h"
|
|
#include "fileop.h"
|
|
#include "filesel.h"
|
|
#include "input.h"
|
|
|
|
/****************************************************************************
|
|
* Prepare Preferences Data
|
|
*
|
|
* This sets up the save buffer for saving.
|
|
***************************************************************************/
|
|
static mxml_node_t *xml = NULL;
|
|
static mxml_node_t *data = NULL;
|
|
static mxml_node_t *section = NULL;
|
|
static mxml_node_t *item = NULL;
|
|
static mxml_node_t *elem = NULL;
|
|
|
|
static char temp[20];
|
|
|
|
static const char * toStr(int i)
|
|
{
|
|
sprintf(temp, "%d", i);
|
|
return temp;
|
|
}
|
|
static const char * FtoStr(float i)
|
|
{
|
|
sprintf(temp, "%.2f", i);
|
|
return temp;
|
|
}
|
|
|
|
static void createXMLSection(const char * name, const char * description)
|
|
{
|
|
section = mxmlNewElement(data, "section");
|
|
mxmlElementSetAttr(section, "name", name);
|
|
mxmlElementSetAttr(section, "description", description);
|
|
}
|
|
|
|
static void createXMLSetting(const char * name, const char * description, const char * value)
|
|
{
|
|
item = mxmlNewElement(section, "setting");
|
|
mxmlElementSetAttr(item, "name", name);
|
|
mxmlElementSetAttr(item, "value", value);
|
|
mxmlElementSetAttr(item, "description", description);
|
|
}
|
|
|
|
static void createXMLController(unsigned int controller[], const char * name, const char * description)
|
|
{
|
|
item = mxmlNewElement(section, "controller");
|
|
mxmlElementSetAttr(item, "name", name);
|
|
mxmlElementSetAttr(item, "description", description);
|
|
|
|
// create buttons
|
|
for(int i=0; i < MAXJP; i++)
|
|
{
|
|
elem = mxmlNewElement(item, "button");
|
|
mxmlElementSetAttr(elem, "number", toStr(i));
|
|
mxmlElementSetAttr(elem, "assignment", toStr(controller[i]));
|
|
}
|
|
}
|
|
|
|
static const char * XMLSaveCallback(mxml_node_t *node, int where)
|
|
{
|
|
const char *name;
|
|
|
|
name = node->value.element.name;
|
|
|
|
if(where == MXML_WS_BEFORE_CLOSE)
|
|
{
|
|
if(!strcmp(name, "file") || !strcmp(name, "section"))
|
|
return ("\n");
|
|
else if(!strcmp(name, "controller"))
|
|
return ("\n\t");
|
|
}
|
|
if (where == MXML_WS_BEFORE_OPEN)
|
|
{
|
|
if(!strcmp(name, "file"))
|
|
return ("\n");
|
|
else if(!strcmp(name, "section"))
|
|
return ("\n\n");
|
|
else if(!strcmp(name, "setting") || !strcmp(name, "controller"))
|
|
return ("\n\t");
|
|
else if(!strcmp(name, "button"))
|
|
return ("\n\t\t");
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
static int
|
|
preparePrefsData (int method)
|
|
{
|
|
int offset = 0;
|
|
|
|
// add save icon and comments for Memory Card saves
|
|
if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB)
|
|
{
|
|
offset = sizeof (saveicon);
|
|
|
|
// Copy in save icon
|
|
memcpy (savebuffer, saveicon, offset);
|
|
|
|
// And the comments
|
|
char prefscomment[2][32];
|
|
memset(prefscomment, 0, 64);
|
|
sprintf (prefscomment[0], "%s Prefs", APPNAME);
|
|
sprintf (prefscomment[1], "Preferences");
|
|
memcpy (savebuffer + offset, prefscomment, 64);
|
|
offset += 64;
|
|
}
|
|
|
|
xml = mxmlNewXML("1.0");
|
|
mxmlSetWrapMargin(0); // disable line wrapping
|
|
|
|
data = mxmlNewElement(xml, "file");
|
|
mxmlElementSetAttr(data, "app",APPNAME);
|
|
mxmlElementSetAttr(data, "version",APPVERSION);
|
|
|
|
createXMLSection("File", "File Settings");
|
|
|
|
createXMLSetting("AutoLoad", "Auto Load", toStr(GCSettings.AutoLoad));
|
|
createXMLSetting("AutoSave", "Auto Save", toStr(GCSettings.AutoSave));
|
|
createXMLSetting("LoadMethod", "Load Method", toStr(GCSettings.LoadMethod));
|
|
createXMLSetting("SaveMethod", "Save Method", toStr(GCSettings.SaveMethod));
|
|
createXMLSetting("LoadFolder", "Load Folder", GCSettings.LoadFolder);
|
|
createXMLSetting("SaveFolder", "Save Folder", GCSettings.SaveFolder);
|
|
//createXMLSetting("CheatFolder", "Cheats Folder", GCSettings.CheatFolder);
|
|
createXMLSetting("VerifySaves", "Verify Memory Card Saves", toStr(GCSettings.VerifySaves));
|
|
|
|
createXMLSection("Network", "Network Settings");
|
|
|
|
createXMLSetting("smbip", "Share Computer IP", GCSettings.smbip);
|
|
createXMLSetting("smbshare", "Share Name", GCSettings.smbshare);
|
|
createXMLSetting("smbuser", "Share Username", GCSettings.smbuser);
|
|
createXMLSetting("smbpwd", "Share Password", GCSettings.smbpwd);
|
|
|
|
createXMLSection("Emulation", "Emulation Settings");
|
|
|
|
createXMLSetting("Zoom", "Zoom On/Off", toStr(GCSettings.Zoom));
|
|
createXMLSetting("ZoomLevel", "Zoom Level", FtoStr(GCSettings.ZoomLevel));
|
|
createXMLSetting("render", "Video Filtering", toStr(GCSettings.render));
|
|
createXMLSetting("scaling", "Aspect Ratio Correction", toStr(GCSettings.scaling));
|
|
createXMLSetting("xshift", "Horizontal Video Shift", toStr(GCSettings.xshift));
|
|
createXMLSetting("yshift", "Vertical Video Shift", toStr(GCSettings.yshift));
|
|
|
|
createXMLSection("Controller", "Controller Settings");
|
|
|
|
createXMLSetting("WiiControls", "Match Wii Game", toStr(GCSettings.WiiControls));
|
|
createXMLController(gcpadmap, "gcpadmap", "GameCube Pad");
|
|
createXMLController(wmpadmap, "wmpadmap", "Wiimote");
|
|
createXMLController(ccpadmap, "ccpadmap", "Classic Controller");
|
|
createXMLController(ncpadmap, "ncpadmap", "Nunchuk");
|
|
createXMLController(kbpadmap, "kbpadmap", "Keyboard");
|
|
|
|
int datasize = mxmlSaveString(xml, (char *)savebuffer, SAVEBUFFERSIZE, XMLSaveCallback);
|
|
|
|
mxmlDelete(xml);
|
|
|
|
return datasize;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* loadXMLSetting
|
|
*
|
|
* Load XML elements into variables for an individual variable
|
|
***************************************************************************/
|
|
|
|
static void loadXMLSetting(char * var, const char * name, int maxsize)
|
|
{
|
|
item = mxmlFindElement(xml, xml, "setting", "name", name, MXML_DESCEND);
|
|
if(item)
|
|
{
|
|
const char * tmp = mxmlElementGetAttr(item, "value");
|
|
if(tmp)
|
|
snprintf(var, maxsize, "%s", tmp);
|
|
}
|
|
}
|
|
static void loadXMLSetting(int * var, const char * name)
|
|
{
|
|
item = mxmlFindElement(xml, xml, "setting", "name", name, MXML_DESCEND);
|
|
if(item)
|
|
{
|
|
const char * tmp = mxmlElementGetAttr(item, "value");
|
|
if(tmp)
|
|
*var = atoi(tmp);
|
|
}
|
|
}
|
|
static void loadXMLSetting(float * var, const char * name)
|
|
{
|
|
item = mxmlFindElement(xml, xml, "setting", "name", name, MXML_DESCEND);
|
|
if(item)
|
|
{
|
|
const char * tmp = mxmlElementGetAttr(item, "value");
|
|
if(tmp)
|
|
*var = atof(tmp);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* loadXMLController
|
|
*
|
|
* Load XML elements into variables for a controller mapping
|
|
***************************************************************************/
|
|
|
|
static void loadXMLController(unsigned int controller[], const char * name)
|
|
{
|
|
item = mxmlFindElement(xml, xml, "controller", "name", name, MXML_DESCEND);
|
|
|
|
if(item)
|
|
{
|
|
// populate buttons
|
|
for(int i=0; i < MAXJP; i++)
|
|
{
|
|
elem = mxmlFindElement(item, xml, "button", "number", toStr(i), MXML_DESCEND);
|
|
if(elem)
|
|
{
|
|
const char * tmp = mxmlElementGetAttr(elem, "assignment");
|
|
if(tmp)
|
|
controller[i] = atoi(tmp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* decodePrefsData
|
|
*
|
|
* Decodes preferences - parses XML and loads preferences into the variables
|
|
***************************************************************************/
|
|
|
|
static bool
|
|
decodePrefsData (int method)
|
|
{
|
|
bool result = false;
|
|
int offset = 0;
|
|
|
|
// skip save icon and comments for Memory Card saves
|
|
if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB)
|
|
{
|
|
offset = sizeof (saveicon);
|
|
offset += 64; // sizeof comments
|
|
}
|
|
|
|
xml = mxmlLoadString(NULL, (char *)savebuffer+offset, MXML_TEXT_CALLBACK);
|
|
|
|
if(xml)
|
|
{
|
|
// check settings version
|
|
item = mxmlFindElement(xml, xml, "file", "version", NULL, MXML_DESCEND);
|
|
if(item) // a version entry exists
|
|
{
|
|
const char * version = mxmlElementGetAttr(item, "version");
|
|
|
|
if(version)
|
|
{
|
|
// this code assumes version in format X.X.X
|
|
// XX.X.X, X.XX.X, or X.X.XX will NOT work
|
|
int verMajor = version[0] - '0';
|
|
int verMinor = version[2] - '0';
|
|
int verPoint = version[4] - '0';
|
|
int curMajor = APPVERSION[0] - '0';
|
|
int curMinor = APPVERSION[2] - '0';
|
|
int curPoint = APPVERSION[4] - '0';
|
|
|
|
// first we'll check that the versioning is valid
|
|
if(!(verMajor >= 0 && verMajor <= 9 &&
|
|
verMinor >= 0 && verMinor <= 9 &&
|
|
verPoint >= 0 && verPoint <= 9))
|
|
result = false;
|
|
else if(verPoint < 8 && verMajor == 1) // less than version 1.0.8
|
|
result = false; // reset settings (sorry, should update settings instead)
|
|
else if(verMajor > curMajor || verMinor > curMinor || verPoint > curPoint) // some future version
|
|
result = false; // reset settings
|
|
else
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
if(result)
|
|
{
|
|
// File Settings
|
|
|
|
loadXMLSetting(&GCSettings.AutoLoad, "AutoLoad");
|
|
loadXMLSetting(&GCSettings.AutoSave, "AutoSave");
|
|
loadXMLSetting(&GCSettings.LoadMethod, "LoadMethod");
|
|
loadXMLSetting(&GCSettings.SaveMethod, "SaveMethod");
|
|
loadXMLSetting(GCSettings.LoadFolder, "LoadFolder", sizeof(GCSettings.LoadFolder));
|
|
loadXMLSetting(GCSettings.SaveFolder, "SaveFolder", sizeof(GCSettings.SaveFolder));
|
|
//loadXMLSetting(GCSettings.CheatFolder, "CheatFolder", sizeof(GCSettings.CheatFolder));
|
|
loadXMLSetting(&GCSettings.VerifySaves, "VerifySaves");
|
|
|
|
// Network Settings
|
|
|
|
loadXMLSetting(GCSettings.smbip, "smbip", sizeof(GCSettings.smbip));
|
|
loadXMLSetting(GCSettings.smbshare, "smbshare", sizeof(GCSettings.smbshare));
|
|
loadXMLSetting(GCSettings.smbuser, "smbuser", sizeof(GCSettings.smbuser));
|
|
loadXMLSetting(GCSettings.smbpwd, "smbpwd", sizeof(GCSettings.smbpwd));
|
|
|
|
// Emulation Settings
|
|
|
|
loadXMLSetting(&GCSettings.Zoom, "Zoom");
|
|
loadXMLSetting(&GCSettings.ZoomLevel, "ZoomLevel");
|
|
loadXMLSetting(&GCSettings.render, "render");
|
|
loadXMLSetting(&GCSettings.scaling, "scaling");
|
|
loadXMLSetting(&GCSettings.xshift, "xshift");
|
|
loadXMLSetting(&GCSettings.yshift, "yshift");
|
|
|
|
// Controller Settings
|
|
|
|
loadXMLSetting(&GCSettings.WiiControls, "WiiControls");
|
|
loadXMLController(gcpadmap, "gcpadmap");
|
|
loadXMLController(wmpadmap, "wmpadmap");
|
|
loadXMLController(ccpadmap, "ccpadmap");
|
|
loadXMLController(ncpadmap, "ncpadmap");
|
|
loadXMLController(kbpadmap, "kbpadmap");
|
|
}
|
|
mxmlDelete(xml);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Save Preferences
|
|
***************************************************************************/
|
|
bool
|
|
SavePrefs (bool silent)
|
|
{
|
|
char filepath[1024];
|
|
int datasize;
|
|
int offset = 0;
|
|
|
|
// We'll save using the first available method (probably SD) since this
|
|
// is the method preferences will be loaded from by default
|
|
int method = autoSaveMethod(silent);
|
|
|
|
if(!MakeFilePath(filepath, FILE_PREF, method))
|
|
return false;
|
|
|
|
if (!silent)
|
|
ShowAction ("Saving preferences...");
|
|
|
|
AllocSaveBuffer ();
|
|
datasize = preparePrefsData (method);
|
|
|
|
offset = SaveFile(filepath, datasize, method, silent);
|
|
|
|
FreeSaveBuffer ();
|
|
|
|
if (offset > 0)
|
|
{
|
|
if (!silent)
|
|
WaitPrompt ("Preferences saved");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Load Preferences from specified method
|
|
***************************************************************************/
|
|
bool
|
|
LoadPrefsFromMethod (int method)
|
|
{
|
|
bool retval = false;
|
|
char filepath[1024];
|
|
int offset = 0;
|
|
|
|
if(!MakeFilePath(filepath, FILE_PREF, method))
|
|
return false;
|
|
|
|
AllocSaveBuffer ();
|
|
|
|
offset = LoadFile(filepath, method, SILENT);
|
|
|
|
if (offset > 0)
|
|
retval = decodePrefsData (method);
|
|
|
|
FreeSaveBuffer ();
|
|
|
|
return retval;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Load Preferences
|
|
* Checks sources consecutively until we find a preference file
|
|
***************************************************************************/
|
|
bool LoadPrefs()
|
|
{
|
|
ShowAction ("Loading preferences...");
|
|
bool prefFound = false;
|
|
if(ChangeInterface(METHOD_SD, SILENT))
|
|
prefFound = LoadPrefsFromMethod(METHOD_SD);
|
|
if(!prefFound && ChangeInterface(METHOD_USB, SILENT))
|
|
prefFound = LoadPrefsFromMethod(METHOD_USB);
|
|
if(!prefFound && TestCard(CARD_SLOTA, SILENT))
|
|
prefFound = LoadPrefsFromMethod(METHOD_MC_SLOTA);
|
|
if(!prefFound && TestCard(CARD_SLOTB, SILENT))
|
|
prefFound = LoadPrefsFromMethod(METHOD_MC_SLOTB);
|
|
if(!prefFound && ChangeInterface(METHOD_SMB, SILENT))
|
|
prefFound = LoadPrefsFromMethod(METHOD_SMB);
|
|
|
|
return prefFound;
|
|
}
|