diff --git a/Makefile b/Makefile index d02af909ed..c1aea219a5 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ endif FRONTEND_OBJS = pad.o xparam.o fntsys.o renderman.o menusys.o OSDHistory.o system.o lang.o lang_internal.o config.o hdd.o dialogs.o \ dia.o ioman.o texcache.o themes.o supportbase.o bdmsupport.o ethsupport.o hddsupport.o zso.o lz4.o \ - appsupport.o gui.o guigame.o vmc_groups.o textures.o opl.o atlas.o nbns.o httpclient.o gsm.o cheatman.o sound.o ps2cnf.o + appsupport.o gui.o guigame.o vmc_groups.o textures.o opl.o atlas.o nbns.o httpclient.o gsm.o cheatman.o cheatconfig.o sound.o ps2cnf.o IOP_OBJS = iomanx.o filexio.o ps2fs.o usbd.o bdmevent.o \ bdm.o bdmfs_fatfs.o usbmass_bd.o iLinkman.o IEEE1394_bd.o mx4sio_bd.o \ diff --git a/include/cheatconfig.h b/include/cheatconfig.h new file mode 100644 index 0000000000..97778c8cad --- /dev/null +++ b/include/cheatconfig.h @@ -0,0 +1,15 @@ +#ifndef _CHEATCONFIG_H_ +#define _CHEATCONFIG_H_ + +#include "cheatman.h" + +/* Returns non-zero for standardized required-code headings. */ +int cheatConfigIsMasterCode(const char *name); + +/* Reset optional cheats to off, then restore enabled entries by normalized name. */ +void cheatConfigLoadSelections(config_set_t *configSet); + +/* Save enabled optional cheats as numbered per-game CFG values. */ +void cheatConfigSaveSelections(config_set_t *configSet); + +#endif /* _CHEATCONFIG_H_ */ diff --git a/include/config.h b/include/config.h index 3cf4be790a..ec8c5b952a 100644 --- a/include/config.h +++ b/include/config.h @@ -55,6 +55,7 @@ enum CONFIG_INDEX { #define CONFIG_ITEM_CHEATSSOURCE "$CheatsSource" #define CONFIG_ITEM_ENABLECHEAT "$EnableCheat" #define CONFIG_ITEM_CHEATMODE "$CheatMode" +#define CONFIG_ITEM_CHEAT_SELECTION_PREFIX "$CheatSel" #define CONFIG_ITEM_PADEMUSOURCE "$PADEMUSource" #define CONFIG_ITEM_ENABLEPADEMU "$EnablePadEmu" diff --git a/include/gui.h b/include/gui.h index 44c697409f..40bc74a5c7 100644 --- a/include/gui.h +++ b/include/gui.h @@ -156,6 +156,6 @@ int guiConfirmVideoMode(void); int guiGameShowRemoveSettings(config_set_t *configSet, config_set_t *configGame); -void guiManageCheats(void); +void guiManageCheats(config_set_t *configSet); #endif diff --git a/include/supportbase.h b/include/supportbase.h index 95a57ae023..8d11553d93 100644 --- a/include/supportbase.h +++ b/include/supportbase.h @@ -55,6 +55,6 @@ u32 sbGetISO9660MaxLBA(const char *path); int sbProbeISO9660(const char *path, base_game_info_t *game, u32 layer1_offset); int sbProbeISO9660_64(const char *path, base_game_info_t *game, u32 layer1_offset); -int sbLoadCheats(const char *path, const char *file); +int sbLoadCheats(const char *path, const char *file, config_set_t *configSet); #endif diff --git a/src/bdmsupport.c b/src/bdmsupport.c index b181dec6a0..a8ffdd9d83 100644 --- a/src/bdmsupport.c +++ b/src/bdmsupport.c @@ -492,7 +492,7 @@ void bdmLaunchGame(item_list_t *itemList, int id, config_set_t *configSet) // adjust ZSO cache settings->common.zso_cache = bdmCacheSize; - if ((result = sbLoadCheats(pDeviceData->bdmPrefix, game->startup)) < 0) { + if ((result = sbLoadCheats(pDeviceData->bdmPrefix, game->startup, configSet)) < 0) { if (gAutoLaunchBDMGame == NULL) { switch (result) { case -ENOENT: diff --git a/src/cheatconfig.c b/src/cheatconfig.c new file mode 100644 index 0000000000..f9892816f8 --- /dev/null +++ b/src/cheatconfig.c @@ -0,0 +1,119 @@ +#include "cheatconfig.h" +#include "config.h" + +#include +#include +#include + +#define CHEAT_SELECTION_KEY_MAX CONFIG_KEY_NAME_LEN + +static void normalizeCheatName(const char *source, char *destination, size_t destinationSize) +{ + size_t output = 0; + int pendingSpace = 0; + + if (destinationSize == 0) + return; + + while (*source != NUL && isspace((unsigned char)*source)) + source++; + + while (*source != NUL && output + 1 < destinationSize) { + unsigned char character = (unsigned char)*source++; + + if (isspace(character)) { + pendingSpace = output > 0; + continue; + } + + if (pendingSpace) { + destination[output++] = SPACE; + pendingSpace = 0; + } + + destination[output++] = tolower(character); + } + + destination[output] = NUL; +} + +int cheatConfigIsMasterCode(const char *name) +{ + char normalized[CHEAT_NAME_MAX + 1]; + + normalizeCheatName(name, normalized, sizeof(normalized)); + + return strcmp(normalized, "mastercode") == 0 || + strcmp(normalized, "master code") == 0 || + strcmp(normalized, "enable code (must be on)") == 0; +} + +static int cheatNamesMatch(const char *first, const char *second) +{ + char normalizedFirst[CHEAT_NAME_MAX + 1]; + char normalizedSecond[CHEAT_NAME_MAX + 1]; + + normalizeCheatName(first, normalizedFirst, sizeof(normalizedFirst)); + normalizeCheatName(second, normalizedSecond, sizeof(normalizedSecond)); + + return strcmp(normalizedFirst, normalizedSecond) == 0; +} + +void cheatConfigLoadSelections(config_set_t *configSet) +{ + int cheatIndex; + int selectionIndex; + char key[CHEAT_SELECTION_KEY_MAX]; + char savedName[CONFIG_KEY_VALUE_LEN]; + + /* First use is safe: required code on, every optional code off. */ + for (cheatIndex = 0; cheatIndex < MAX_CODES && gCheats[cheatIndex].name[0] != NUL; cheatIndex++) + gCheats[cheatIndex].enabled = cheatConfigIsMasterCode(gCheats[cheatIndex].name); + + if (configSet == NULL) + return; + + for (selectionIndex = 0; selectionIndex < MAX_CODES; selectionIndex++) { + snprintf(key, sizeof(key), "%s%03d", CONFIG_ITEM_CHEAT_SELECTION_PREFIX, selectionIndex); + + if (!configGetStrCopy(configSet, key, savedName, sizeof(savedName))) + break; + + for (cheatIndex = 0; cheatIndex < MAX_CODES && gCheats[cheatIndex].name[0] != NUL; cheatIndex++) { + if (!cheatConfigIsMasterCode(gCheats[cheatIndex].name) && + cheatNamesMatch(gCheats[cheatIndex].name, savedName)) { + gCheats[cheatIndex].enabled = 1; + break; + } + } + } + + /* Database changes must never leave the required code disabled. */ + for (cheatIndex = 0; cheatIndex < MAX_CODES && gCheats[cheatIndex].name[0] != NUL; cheatIndex++) { + if (cheatConfigIsMasterCode(gCheats[cheatIndex].name)) + gCheats[cheatIndex].enabled = 1; + } +} + +void cheatConfigSaveSelections(config_set_t *configSet) +{ + int cheatIndex; + int selectionIndex = 0; + char key[CHEAT_SELECTION_KEY_MAX]; + + if (configSet == NULL) + return; + + /* Clear stale numbered values from earlier selections. */ + for (cheatIndex = 0; cheatIndex < MAX_CODES; cheatIndex++) { + snprintf(key, sizeof(key), "%s%03d", CONFIG_ITEM_CHEAT_SELECTION_PREFIX, cheatIndex); + configRemoveKey(configSet, key); + } + + for (cheatIndex = 0; cheatIndex < MAX_CODES && gCheats[cheatIndex].name[0] != NUL; cheatIndex++) { + if (gCheats[cheatIndex].enabled && !cheatConfigIsMasterCode(gCheats[cheatIndex].name)) { + snprintf(key, sizeof(key), "%s%03d", CONFIG_ITEM_CHEAT_SELECTION_PREFIX, selectionIndex++); + configSetStr(configSet, key, gCheats[cheatIndex].name); + } + } +} diff --git a/src/cheatman.c b/src/cheatman.c index 5fb538b10d..6c28d00ec7 100644 --- a/src/cheatman.c +++ b/src/cheatman.c @@ -1,3 +1,4 @@ +#include "include/cheatconfig.h" /* * Manage cheat codes * @@ -285,7 +286,7 @@ static int parse_buf(const char *buf) cheat_index++; // Move to the next cheat entry strncpy(gCheats[cheat_index].name, temp_name, CHEAT_NAME_MAX); gCheats[cheat_index].name[CHEAT_NAME_MAX] = NUL; - gCheats[cheat_index].enabled = 1; // Set cheat as enabled + gCheats[cheat_index].enabled = (gCheatMode == 0) || cheatConfigIsMasterCode(gCheats[cheat_index].name); // Auto mode enables all; select mode enables required code only temp_name[0] = NUL; // Clear temp_name after use } // Add the cheat code to the current cheat entry diff --git a/src/ethsupport.c b/src/ethsupport.c index f0462fa42a..5fae09e4f7 100644 --- a/src/ethsupport.c +++ b/src/ethsupport.c @@ -637,7 +637,7 @@ static void ethLaunchGame(item_list_t *itemList, int id, config_set_t *configSet compatmask = sbPrepare(game, configSet, size_smb_cdvdman_irx, smb_cdvdman_irx, &i); - if ((result = sbLoadCheats(ethPrefix, game->startup)) < 0) { + if ((result = sbLoadCheats(ethPrefix, game->startup, configSet)) < 0) { switch (result) { case -ENOENT: guiWarning(_l(_STR_NO_CHEATS_FOUND), 10); diff --git a/src/gui.c b/src/gui.c index 1054228616..86de98df37 100644 --- a/src/gui.c +++ b/src/gui.c @@ -1,3 +1,4 @@ +#include "include/cheatconfig.h" /* Copyright 2010, Volca Licenced under Academic Free License version 3.0 @@ -1845,7 +1846,7 @@ int guiGameShowRemoveSettings(config_set_t *configSet, config_set_t *configGame) return 1; } -void guiManageCheats(void) +void guiManageCheats(config_set_t *configSet) { int offset = 0; int terminate = 0; @@ -1875,7 +1876,7 @@ void guiManageCheats(void) } if (getKeyOn(gSelectButton)) { - if (!(strncasecmp(gCheats[selectedCheat].name, "mastercode", 10) == 0 || strncasecmp(gCheats[selectedCheat].name, "master code", 11) == 0)) + if (!cheatConfigIsMasterCode(gCheats[selectedCheat].name)) gCheats[selectedCheat].enabled = !gCheats[selectedCheat].enabled; } @@ -1896,7 +1897,6 @@ void guiManageCheats(void) continue; int enabled = gCheats[i].enabled; - int boxX = 50; int boxY = 100 + (renderedCheats * 30); int boxWidth = rmWideScale(25); @@ -1909,15 +1909,15 @@ void guiManageCheats(void) u32 textColour = (i == selectedCheat) ? gTheme->selTextColor : gTheme->textColor; fntRenderString(gTheme->fonts[0], boxX + 35, boxY + 3, ALIGN_LEFT, 0, 0, gCheats[i].name, textColour); - renderedCheats++; } guiDrawIconAndText(gSelectButton == KEY_CIRCLE ? CIRCLE_ICON : CROSS_ICON, _STR_SELECT, gTheme->fonts[0], 70, 417, gTheme->selTextColor); guiDrawIconAndText(START_ICON, _STR_RUN, gTheme->fonts[0], 500, 417, gTheme->selTextColor); - guiEndFrame(); } + cheatConfigSaveSelections(configSet); + configWrite(configSet); sfxPlay(SFX_CONFIRM); } diff --git a/src/hddsupport.c b/src/hddsupport.c index 1f3eaefa87..9ce0a27d8c 100644 --- a/src/hddsupport.c +++ b/src/hddsupport.c @@ -557,7 +557,7 @@ void hddLaunchGame(item_list_t *itemList, int id, config_set_t *configSet) sbPrepare(NULL, configSet, size_irx, irx, &i); - if ((result = sbLoadCheats(gHDDPrefix, game->startup)) < 0) { + if ((result = sbLoadCheats(gHDDPrefix, game->startup, configSet)) < 0) { if (gAutoLaunchGame == NULL) { switch (result) { case -ENOENT: diff --git a/src/supportbase.c b/src/supportbase.c index 63cd6ad2e4..badf0d2a2d 100644 --- a/src/supportbase.c +++ b/src/supportbase.c @@ -11,6 +11,7 @@ #include "include/cheatman.h" #include "include/ps2cnf.h" #include "include/gui.h" +#include "include/cheatconfig.h" #define NEWLIB_PORT_AWARE #include // fileXioMount("iso:", ***), fileXioUmount("iso:") @@ -828,7 +829,7 @@ void sbCreateFolders(const char *path, int createDiscImgFolders) sbCreateFoldersFromList(path, discImgFolders); } -int sbLoadCheats(const char *path, const char *file) +int sbLoadCheats(const char *path, const char *file, config_set_t *configSet) { char cheatfile[64]; int cheatMode = 0; @@ -841,8 +842,10 @@ int sbLoadCheats(const char *path, const char *file) LOG("Error: failed to load cheats\n"); else { LOG("Cheats found\n"); - if ((gAutoLaunchGame == NULL) && (gAutoLaunchBDMGame == NULL) && (cheatMode == 1)) - guiManageCheats(); + if (cheatMode == 1) { + cheatConfigLoadSelections(configSet); + guiManageCheats(configSet); + } } }