/**************************************************************************** * Visual Boy Advance GX * * Tantric September 2008 * * preferences.cpp * * Preferences save/load to XML file ***************************************************************************/ #include #include #include #include #include #include #include "vba.h" #include "menu.h" #include "fileop.h" #include "filebrowser.h" #include "input.h" #include "button_mapping.h" #include "gamesettings.h" struct SGCSettings GCSettings; static gamePalette *palettes = NULL; static int loadedPalettes = 0; /**************************************************************************** * 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 mxml_node_t *mxmlFindNewElement(mxml_node_t *parent, const char *nodename, const char *attr=NULL, const char *value=NULL) { mxml_node_t *node = mxmlFindElement(parent, xml, nodename, attr, value, MXML_DESCEND); if (!node) { node = mxmlNewElement(parent, nodename); if (attr && value) mxmlElementSetAttr(node, attr, value); } return node; } static char temp[20]; static const char * toStr(int i) { sprintf(temp, "%d", i); return temp; } static const char * toHex(u32 i) { sprintf(temp, "0x%06X", 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 const char * XMLSavePalCallback(mxml_node_t *node, int where) { const char *name; name = node->value.element.name; if(where == MXML_WS_BEFORE_CLOSE) { if(!strcmp(name, "palette") || !strcmp(name, "game")) return ("\n"); else if(!strcmp(name, "bkgr") || !strcmp(name, "wind") || !strcmp(name, "obj0") || !strcmp(name, "obj1")) return ("\n\t"); } if (where == MXML_WS_BEFORE_OPEN) { if(!strcmp(name, "palette")) return ("\n"); else if(!strcmp(name, "game")) return ("\n\n"); else if(!strcmp(name, "bkgr") || !strcmp(name, "wind") || !strcmp(name, "obj0") || !strcmp(name, "obj1")) return ("\n\t"); } return (NULL); } static int preparePrefsData () { 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); 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("Video", "Video Settings"); createXMLSetting("videomode", "Video Mode", toStr(GCSettings.videomode)); createXMLSetting("gbaZoomHor", "GBA Horizontal Zoom Level", FtoStr(GCSettings.gbaZoomHor)); createXMLSetting("gbaZoomVert", "GBA Vertical Zoom Level", FtoStr(GCSettings.gbaZoomVert)); createXMLSetting("gbZoomHor", "GB Horizontal Zoom Level", FtoStr(GCSettings.gbZoomHor)); createXMLSetting("gbZoomVert", "GB Vertical Zoom Level", FtoStr(GCSettings.gbZoomVert)); 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)); createXMLSetting("colorize", "Colorize Mono Gameboy", toStr(GCSettings.colorize)); createXMLSection("Menu", "Menu Settings"); createXMLSetting("WiimoteOrientation", "Wiimote Orientation", toStr(GCSettings.WiimoteOrientation)); createXMLSetting("ExitAction", "Exit Action", toStr(GCSettings.ExitAction)); createXMLSetting("MusicVolume", "Music Volume", toStr(GCSettings.MusicVolume)); createXMLSetting("SFXVolume", "Sound Effects Volume", toStr(GCSettings.SFXVolume)); createXMLSetting("Rumble", "Rumble", toStr(GCSettings.Rumble)); createXMLSetting("language", "Language", toStr(GCSettings.language)); createXMLSection("Controller", "Controller Settings"); createXMLSetting("WiiControls", "Match Wii Game", toStr(GCSettings.WiiControls)); createXMLController(btnmap[CTRLR_GCPAD], "gcpadmap", "GameCube Pad"); createXMLController(btnmap[CTRLR_WIIMOTE], "wmpadmap", "Wiimote"); createXMLController(btnmap[CTRLR_CLASSIC], "ccpadmap", "Classic Controller"); createXMLController(btnmap[CTRLR_NUNCHUK], "ncpadmap", "Nunchuk"); createXMLController(btnmap[CTRLR_KEYBOARD], "kbpadmap", "Keyboard"); int datasize = mxmlSaveString(xml, (char *)savebuffer, SAVEBUFFERSIZE, XMLSaveCallback); mxmlDelete(xml); return datasize; } static void createXMLPalette(gamePalette *p, bool overwrite, const char *newname = NULL) { if (!newname) newname = p->gameName; section = mxmlFindElement(xml, xml, "game", "name", newname, MXML_DESCEND); if (section && !overwrite) { return; } else if (!section) { section = mxmlNewElement(data, "game"); } mxmlElementSetAttr(section, "name", newname); mxmlElementSetAttr(section, "use", "1"); item = mxmlFindNewElement(section, "bkgr"); mxmlElementSetAttr(item, "c0", toHex(p->palette[0])); mxmlElementSetAttr(item, "c1", toHex(p->palette[1])); mxmlElementSetAttr(item, "c2", toHex(p->palette[2])); mxmlElementSetAttr(item, "c3", toHex(p->palette[3])); item = mxmlFindNewElement(section, "wind"); mxmlElementSetAttr(item, "c0", toHex(p->palette[4])); mxmlElementSetAttr(item, "c1", toHex(p->palette[5])); mxmlElementSetAttr(item, "c2", toHex(p->palette[6])); mxmlElementSetAttr(item, "c3", toHex(p->palette[7])); item = mxmlFindNewElement(section, "obj0"); mxmlElementSetAttr(item, "c0", toHex(p->palette[8])); mxmlElementSetAttr(item, "c1", toHex(p->palette[9])); mxmlElementSetAttr(item, "c2", toHex(p->palette[10])); item = mxmlFindNewElement(section, "obj1"); mxmlElementSetAttr(item, "c0", toHex(p->palette[11])); mxmlElementSetAttr(item, "c1", toHex(p->palette[12])); mxmlElementSetAttr(item, "c2", toHex(p->palette[13])); } static int preparePalData (gamePalette pals[], int palCount) { xml = mxmlNewXML("1.0"); mxmlSetWrapMargin(0); // disable line wrapping data = mxmlNewElement(xml, "palette"); mxmlElementSetAttr(data, "app", APPNAME); mxmlElementSetAttr(data, "version", APPVERSION); for (int i=0; i= 0 && verMajor <= 9 && verMinor >= 0 && verMinor <= 9 && verPoint >= 0 && verPoint <= 9)) result = false; else if(verMajor < 2) // less than version 2.0.0 result = false; // reset settings (sorry, should update settings instead) else if((verMajor*100 + verMinor*10 + verPoint) > (curMajor*100 + curMinor*10 + 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)); // 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)); // Video Settings loadXMLSetting(&GCSettings.videomode, "videomode"); loadXMLSetting(&GCSettings.gbaZoomHor, "gbaZoomHor"); loadXMLSetting(&GCSettings.gbaZoomVert, "gbaZoomVert"); loadXMLSetting(&GCSettings.gbZoomHor, "gbZoomHor"); loadXMLSetting(&GCSettings.gbZoomVert, "gbZoomVert"); loadXMLSetting(&GCSettings.render, "render"); loadXMLSetting(&GCSettings.scaling, "scaling"); loadXMLSetting(&GCSettings.xshift, "xshift"); loadXMLSetting(&GCSettings.yshift, "yshift"); loadXMLSetting(&GCSettings.colorize, "colorize"); // Menu Settings loadXMLSetting(&GCSettings.WiimoteOrientation, "WiimoteOrientation"); loadXMLSetting(&GCSettings.ExitAction, "ExitAction"); loadXMLSetting(&GCSettings.MusicVolume, "MusicVolume"); loadXMLSetting(&GCSettings.SFXVolume, "SFXVolume"); loadXMLSetting(&GCSettings.Rumble, "Rumble"); loadXMLSetting(&GCSettings.language, "language"); // Controller Settings loadXMLSetting(&GCSettings.WiiControls, "WiiControls"); loadXMLController(btnmap[CTRLR_GCPAD], "gcpadmap"); loadXMLController(btnmap[CTRLR_WIIMOTE], "wmpadmap"); loadXMLController(btnmap[CTRLR_CLASSIC], "ccpadmap"); loadXMLController(btnmap[CTRLR_NUNCHUK], "ncpadmap"); loadXMLController(btnmap[CTRLR_KEYBOARD], "kbpadmap"); } mxmlDelete(xml); } return result; } static bool decodePalsData () { bool result = false; xml = mxmlLoadString(NULL, (char *) savebuffer, MXML_TEXT_CALLBACK); if (xml) { // count number of palettes in file loadedPalettes = 0; item = mxmlFindElement(xml, xml, "palette", NULL, NULL, MXML_DESCEND); for (section = mxmlFindElement(item, xml, "game", NULL, NULL, MXML_DESCEND); section; section = mxmlFindElement(section, xml, "game", NULL, NULL, MXML_NO_DESCEND)) { loadedPalettes++; } // Allocate enough memory for all palettes in file, plus all hardcoded palettes, // plus one new palette if (palettes) free(palettes); palettes = (gamePalette *)malloc(sizeof(gamePalette)*loadedPalettes); // Load all palettes in file, hardcoded palettes are added later int i = 0; for (section = mxmlFindElement(item, xml, "game", NULL, NULL, MXML_DESCEND); section; section = mxmlFindElement(section, xml, "game", NULL, NULL, MXML_NO_DESCEND)) { loadXMLPaletteFromSection(palettes[i]); i++; } mxmlDelete(xml); } return result; } /**************************************************************************** * FixInvalidSettings * * Attempts to correct at least some invalid settings - the ones that * might cause crashes ***************************************************************************/ void FixInvalidSettings() { if(GCSettings.LoadMethod > 4) GCSettings.LoadMethod = DEVICE_AUTO; if(GCSettings.SaveMethod > 4) GCSettings.SaveMethod = DEVICE_AUTO; if(!(GCSettings.gbaZoomHor > 0.5 && GCSettings.gbaZoomHor < 1.5)) GCSettings.gbaZoomHor = 1.0; if(!(GCSettings.gbaZoomVert > 0.5 && GCSettings.gbaZoomVert < 1.5)) GCSettings.gbaZoomVert = 1.0; if(!(GCSettings.gbZoomHor > 0.5 && GCSettings.gbZoomHor < 1.5)) GCSettings.gbZoomHor = 1.0; if(!(GCSettings.gbZoomVert > 0.5 && GCSettings.gbZoomVert < 1.5)) GCSettings.gbZoomVert = 1.0; if(!(GCSettings.xshift > -50 && GCSettings.xshift < 50)) GCSettings.xshift = 0; if(!(GCSettings.yshift > -50 && GCSettings.yshift < 50)) GCSettings.yshift = 0; if(!(GCSettings.MusicVolume >= 0 && GCSettings.MusicVolume <= 100)) GCSettings.MusicVolume = 40; if(!(GCSettings.SFXVolume >= 0 && GCSettings.SFXVolume <= 100)) GCSettings.SFXVolume = 40; if(GCSettings.language < 0 || GCSettings.language > LANG_KOREAN) GCSettings.language = LANG_ENGLISH; if(!(GCSettings.render >= 0 && GCSettings.render < 3)) GCSettings.render = 1; if(!(GCSettings.videomode >= 0 && GCSettings.videomode < 5)) GCSettings.videomode = 0; } /**************************************************************************** * DefaultSettings * * Sets all the defaults! ***************************************************************************/ void DefaultSettings () { memset (&GCSettings, 0, sizeof (GCSettings)); ResetControls(); // controller button mappings GCSettings.LoadMethod = DEVICE_AUTO; // Auto, SD, DVD, USB, Network (SMB) GCSettings.SaveMethod = DEVICE_AUTO; // Auto, SD, USB, Network (SMB) sprintf (GCSettings.LoadFolder, "%s/roms", APPFOLDER); // Path to game files sprintf (GCSettings.SaveFolder, "%s/saves", APPFOLDER); // Path to save files sprintf (GCSettings.CheatFolder, "%s/cheats", APPFOLDER); // Path to cheat files GCSettings.AutoLoad = 1; GCSettings.AutoSave = 1; GCSettings.WiimoteOrientation = 0; GCSettings.gbaZoomHor = 1.0; // GBA horizontal zoom level GCSettings.gbaZoomVert = 1.0; // GBA vertical zoom level GCSettings.gbZoomHor = 1.0; // GBA horizontal zoom level GCSettings.gbZoomVert = 1.0; // GBA vertical zoom level GCSettings.videomode = 0; // automatic video mode detection GCSettings.render = 1; // Filtered GCSettings.scaling = 1; // partial stretch GCSettings.WiiControls = false; // Match Wii Game GCSettings.xshift = 0; // horizontal video shift GCSettings.yshift = 0; // vertical video shift GCSettings.colorize = 0; // Colorize mono gameboy games GCSettings.WiimoteOrientation = 0; GCSettings.ExitAction = 0; GCSettings.MusicVolume = 40; GCSettings.SFXVolume = 40; GCSettings.Rumble = 1; GCSettings.language = CONF_GetLanguage(); } /**************************************************************************** * Save Preferences ***************************************************************************/ static char prefpath[MAXPATHLEN] = { 0 }; bool SavePrefs (bool silent) { char filepath[MAXPATHLEN]; int datasize; int offset = 0; int device = 0; if(prefpath[0] != 0) { sprintf(filepath, "%s/%s", prefpath, PREF_FILE_NAME); FindDevice(filepath, &device); } else if(appPath[0] != 0) { sprintf(filepath, "%s/%s", appPath, PREF_FILE_NAME); strcpy(prefpath, appPath); FindDevice(filepath, &device); } else { device = autoSaveMethod(silent); if(device == 0) return false; sprintf(filepath, "%s%s", pathPrefix[device], APPFOLDER); if (!diropen(filepath)) { mkdir(filepath, 0777); sprintf(filepath, "%s%s/roms", pathPrefix[device], APPFOLDER); mkdir(filepath, 0777); sprintf(filepath, "%s%s/saves", pathPrefix[device], APPFOLDER); mkdir(filepath, 0777); } sprintf(filepath, "%s%s/%s", pathPrefix[device], APPFOLDER, PREF_FILE_NAME); sprintf(prefpath, "%s%s", pathPrefix[device], APPFOLDER); } if(device == 0) return false; if (!silent) ShowAction ("Saving preferences..."); FixInvalidSettings(); AllocSaveBuffer (); datasize = preparePrefsData (); offset = SaveFile(filepath, datasize, silent); FreeSaveBuffer (); CancelAction(); if (offset > 0) { if (!silent) InfoPrompt("Preferences saved"); return true; } return false; } /**************************************************************************** * Load Preferences from specified filepath ***************************************************************************/ bool LoadPrefsFromMethod (char * path) { bool retval = false; int offset = 0; char filepath[MAXPATHLEN]; sprintf(filepath, "%s/%s", path, PREF_FILE_NAME); AllocSaveBuffer (); offset = LoadFile(filepath, SILENT); if (offset > 0) retval = decodePrefsData (); FreeSaveBuffer (); if(retval) { strcpy(prefpath, path); if(appPath[0] == 0) strcpy(appPath, prefpath); } return retval; } /**************************************************************************** * Load Preferences * Checks sources consecutively until we find a preference file ***************************************************************************/ static bool prefLoaded = false; bool LoadPrefs() { if(prefLoaded) // already attempted loading return true; bool prefFound = false; char filepath[4][MAXPATHLEN]; int numDevices; #ifdef HW_RVL numDevices = 5; sprintf(filepath[0], "%s", appPath); sprintf(filepath[1], "sd:/apps/%s", APPFOLDER); sprintf(filepath[2], "usb:/apps/%s", APPFOLDER); sprintf(filepath[3], "sd:/%s", APPFOLDER); sprintf(filepath[4], "usb:/%s", APPFOLDER); #else numDevices = 2; sprintf(filepath[0], "carda:/%s", APPFOLDER); sprintf(filepath[1], "cardb:/%s", APPFOLDER); #endif for(int i=0; i 0) { if (!silent) InfoPrompt("Palette saved"); return true; } return false; } static void AddPalette(gamePalette pal, const char *gameName, bool overwrite) { for (int i=0; i < loadedPalettes; i++) if (strcmp(palettes[i].gameName, gameName)==0) { if (overwrite) { palettes[i] = pal; strncpy(palettes[i].gameName, gameName, 17); return; } else { return; } } palettes = (gamePalette *)realloc(palettes, sizeof(gamePalette)*(loadedPalettes+1)); palettes[loadedPalettes] = pal; strncpy(palettes[loadedPalettes].gameName, gameName, 17); loadedPalettes++; } bool SavePaletteAs(bool silent, const char *name) { AddPalette(CurrentPalette, name, true); return SavePalettes(silent); } /**************************************************************************** * Load Palettes ***************************************************************************/ bool LoadPalettes() { bool retval = false; int offset = 0; char filepath[MAXPATHLEN]; AllocSaveBuffer (); sprintf(filepath, "%s/%s", prefpath, PAL_FILE_NAME); offset = LoadFile(filepath, SILENT); if (offset > 0) retval = decodePalsData (); FreeSaveBuffer (); // add hard-coded palettes for (int i=0; i= 0) { CurrentPalette = palettes[snum]; } else // no match, use the default palette { for (int i = 0; i < loadedPalettes; i++) { if(strcmp(gameName, "default")==0) { snum = i; break; } } if(snum >= 0) { CurrentPalette = palettes[snum]; } else { CurrentPalette = palettes[0]; } // DON'T add this game to the palette list } }