From cc4844cff64b902d46ca99af1f16e34fbf9cd7e1 Mon Sep 17 00:00:00 2001 From: KrahJohlito Date: Mon, 21 Oct 2024 18:05:47 +1030 Subject: [PATCH 1/2] cheatman: add user cheat selection at launch and clean some stuff up --- ee_core/include/coreconfig.h | 2 +- include/cheatman.h | 19 ++++-- include/gui.h | 2 + lng_tmpl/_base.yml | 2 + src/cheatman.c | 112 ++++++++++++++++++++++++++--------- src/gui.c | 77 ++++++++++++++++++++++++ src/supportbase.c | 25 +++----- src/system.c | 7 ++- 8 files changed, 196 insertions(+), 50 deletions(-) diff --git a/ee_core/include/coreconfig.h b/ee_core/include/coreconfig.h index b3d6a0a77..eac6e6ab2 100644 --- a/ee_core/include/coreconfig.h +++ b/ee_core/include/coreconfig.h @@ -45,7 +45,7 @@ struct EECoreConfig_t char g_ps2_gateway[16]; unsigned char g_ps2_ETHOpMode; - unsigned int *gCheatList; // Store hooks/codes addr+val pairs + u32 *gCheatList; // Store hooks/codes addr+val pairs void *eeloadCopy; void *initUserMemory; diff --git a/include/cheatman.h b/include/cheatman.h index 2068a1736..7d828e4f3 100644 --- a/include/cheatman.h +++ b/include/cheatman.h @@ -34,11 +34,12 @@ #include #include -#define CHEAT_VERSION "0.5.3.65.g774d1" +#define CHEAT_VERSION "0.5.3.7" -#define MAX_HOOKS 5 -#define MAX_CODES 250 -#define MAX_CHEATLIST (MAX_HOOKS * 2 + MAX_CODES * 2) +#define MAX_HOOKS 5 +#define MAX_CODES 250 +#define MAX_CHEATLIST (MAX_HOOKS * 2 + MAX_CODES * 2) +#define CHEAT_NAME_MAX 128 /* Some character defines */ #define NUL 0x00 @@ -59,9 +60,19 @@ typedef struct u32 val; } code_t; +typedef struct +{ + char name[CHEAT_NAME_MAX + 1]; + code_t codes[MAX_CHEATLIST]; + int enabled; +} cheat_entry_t; + +extern cheat_entry_t gCheats[MAX_CODES]; + void InitCheatsConfig(config_set_t *configSet); int GetCheatsEnabled(void); const u32 *GetCheatsList(void); int load_cheats(const char *cheatfile); +void set_cheats_list(void); #endif /* _CHEATMAN_H_ */ diff --git a/include/gui.h b/include/gui.h index 7b51cb4d6..44c697409 100644 --- a/include/gui.h +++ b/include/gui.h @@ -156,4 +156,6 @@ int guiConfirmVideoMode(void); int guiGameShowRemoveSettings(config_set_t *configSet, config_set_t *configGame); +void guiManageCheats(void); + #endif diff --git a/lng_tmpl/_base.yml b/lng_tmpl/_base.yml index 2ad5f52d0..c1edbcd19 100644 --- a/lng_tmpl/_base.yml +++ b/lng_tmpl/_base.yml @@ -690,3 +690,5 @@ gui_strings: string: Analog Y-Axis Sensitivity - label: FILE_COUNT string: 'Files found: %i' +- label: CHEAT_SELECTION + string: Cheat Selection diff --git a/src/cheatman.c b/src/cheatman.c index 22cea59f5..5fb538b10 100644 --- a/src/cheatman.c +++ b/src/cheatman.c @@ -30,6 +30,7 @@ static int gEnableCheat; // Enables PS2RD Cheat Engine - 0 for Off, 1 for On static int gCheatMode; // Cheat Mode - 0 Enable all cheats, 1 Cheats selected by user static u32 gCheatList[MAX_CHEATLIST]; // Store hooks/codes addr+val pairs +cheat_entry_t gCheats[MAX_CODES]; void InitCheatsConfig(config_set_t *configSet) { @@ -39,7 +40,6 @@ void InitCheatsConfig(config_set_t *configSet) gCheatSource = 0; gEnableCheat = 0; gCheatMode = 0; - memset(gCheatList, 0, sizeof(gCheatList)); if (configGetInt(configSet, CONFIG_ITEM_CHEATSSOURCE, &gCheatSource)) { // Load the rest of the per-game CHEAT configuration if CHEAT is enabled. @@ -80,6 +80,8 @@ static code_t make_code(const char *s) s++; } + digits[i] = '\0'; + sscanf(digits, "%08X %08X", &address, &value); // Return Code Address and Value @@ -244,17 +246,18 @@ static int parse_buf(const char *buf) code_t code; char line[CHEAT_LINE_MAX + 1]; int linenumber = 1; + int cheat_index = -1; // Starts at -1.. indicating no cheat being processed yet + int code_index = 0; + char temp_name[CHEAT_NAME_MAX + 1] = {0}; if (buf == NULL) return -1; - int i = 0; - while (*buf) { /* Scanner */ int len = chr_idx(buf, LF); if (len < 0) - len = strlen(line); + len = strlen(buf); else if (len > CHEAT_LINE_MAX) len = CHEAT_LINE_MAX; @@ -266,23 +269,35 @@ static int parse_buf(const char *buf) term_str(line, is_cmt_str); trim_str(line); - /* Parser */ - code = parse_line(line, linenumber); - if (!((code.addr == 0) && (code.val == 0))) { - gCheatList[i] = code.addr; - i++; - gCheatList[i] = code.val; - i++; + // Check if the line is a cheat name + if (!is_cheat_code(line) && strlen(line) > 0) { + // Store the cheat name temporarily + strncpy(temp_name, line, CHEAT_NAME_MAX); + temp_name[CHEAT_NAME_MAX] = NUL; + // Reset code index in case this is a new cheat + code_index = 0; + } else { + /* Parser */ + code = parse_line(line, linenumber); + if (!(code.addr == 0 && code.val == 0)) { + // Only add the cheat entry if we have a valid cheat name in temp_name + if (cheat_index < MAX_CODES && temp_name[0] != NUL) { + 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 + temp_name[0] = NUL; // Clear temp_name after use + } + // Add the cheat code to the current cheat entry + if (cheat_index >= 0 && code_index < MAX_CHEATLIST) + gCheats[cheat_index].codes[code_index++] = code; + } } } linenumber++; buf += len + 1; } - gCheatList[i] = 0; - i++; - gCheatList[i] = 0; - return 0; } @@ -304,15 +319,23 @@ static inline char *read_text_file(const char *filename, int maxsize) } filesize = lseek(fd, 0, SEEK_END); - if (maxsize && filesize > maxsize) { + if (filesize < 0) { + LOG("%s: Can't seek in text file %s\n", __FUNCTION__, filename); + close(fd); + return NULL; + } + + if (maxsize > 0 && filesize > maxsize) { LOG("%s: Text file too large: %i bytes, max: %i bytes\n", __FUNCTION__, filesize, maxsize); - goto end; + close(fd); + return NULL; } buf = malloc(filesize + 1); if (buf == NULL) { LOG("%s: Unable to allocate %i bytes\n", __FUNCTION__, filesize + 1); - goto end; + close(fd); + return NULL; } if (filesize > 0) { @@ -320,14 +343,14 @@ static inline char *read_text_file(const char *filename, int maxsize) if (read(fd, buf, filesize) != filesize) { LOG("%s: Can't read from text file %s\n", __FUNCTION__, filename); free(buf); - buf = NULL; - goto end; + close(fd); + return NULL; } } buf[filesize] = '\0'; -end: close(fd); + return buf; } @@ -339,19 +362,52 @@ int load_cheats(const char *cheatfile) char *buf = NULL; int ret; - memset(gCheatList, 0, sizeof(gCheatList)); + memset(gCheats, 0, sizeof(gCheats)); - LOG("%s: Reading cheat file '%s'...", __FUNCTION__, cheatfile); + LOG("%s: Reading cheat file '%s'...\n", __FUNCTION__, cheatfile); buf = read_text_file(cheatfile, 0); if (buf == NULL) { - LOG("\n%s: Could not read cheats file '%s'\n", __FUNCTION__, cheatfile); + LOG("%s: Could not read cheats file '%s'\n", __FUNCTION__, cheatfile); return -1; } - LOG("Ok!\n"); + ret = parse_buf(buf); free(buf); + if (ret < 0) - return -1; - else - return 0; + return ret; + + return (gCheatMode == 0) ? 0 : 1; +} + +void set_cheats_list(void) +{ + int cheatCount = 0; + + memset((void *)gCheatList, 0, sizeof(gCheatList)); + + // Populate the cheat list + for (int i = 0; i < MAX_CODES; ++i) { + if (gCheats[i].enabled) { + for (int j = 0; j < MAX_CHEATLIST && gCheats[i].codes[j].addr != 0; ++j) { + if (cheatCount + 2 <= MAX_CHEATLIST) { + // Store the address and value in gCheatList + gCheatList[cheatCount++] = gCheats[i].codes[j].addr; + gCheatList[cheatCount++] = gCheats[i].codes[j].val; + LOG("%s: Setting cheat for eecore:\n%s\n%08X %08X\n", __FUNCTION__, gCheats[i].name, gCheats[i].codes[j].addr, gCheats[i].codes[j].val); + } else + break; + } + } + } + + // Append a blank cheat entry if theres space + if (cheatCount < MAX_CHEATLIST) { + gCheatList[cheatCount++] = 0; // addr + gCheatList[cheatCount++] = 0; // val + } else { + // Overwrite the last cheat with a blank cheat if we are at max + gCheatList[cheatCount - 2] = 0; // addr + gCheatList[cheatCount - 1] = 0; // val + } } diff --git a/src/gui.c b/src/gui.c index e200d4c6f..a8ed33f73 100644 --- a/src/gui.c +++ b/src/gui.c @@ -1837,3 +1837,80 @@ int guiGameShowRemoveSettings(config_set_t *configSet, config_set_t *configGame) return 1; } + +void guiManageCheats(void) +{ + int offset = 0; + int terminate = 0; + int cheatCount = 0; + int selectedCheat = 0; + int visibleCheats = 10; // Maximum number of cheats visible on screen + + while (cheatCount < MAX_CODES && strlen(gCheats[cheatCount].name) > 0) + cheatCount++; + + sfxPlay(SFX_MESSAGE); + + while (!terminate) { + guiStartFrame(); + readPads(); + + if (getKeyOn(KEY_UP) && selectedCheat > 0) { + selectedCheat -= 1; + if (selectedCheat < offset) + offset = selectedCheat; + } + + if (getKeyOn(KEY_DOWN) && selectedCheat < cheatCount - 1) { + selectedCheat += 1; + if (selectedCheat >= offset + visibleCheats) + offset = selectedCheat - visibleCheats + 1; + } + + if (getKeyOn(gSelectButton)) { + if (!(strncasecmp(gCheats[selectedCheat].name, "mastercode", 10) == 0 || strncasecmp(gCheats[selectedCheat].name, "master code", 11) == 0)) + gCheats[selectedCheat].enabled = !gCheats[selectedCheat].enabled; + } + + if (getKeyOn(KEY_START)) + terminate = 1; + + guiShow(); + + rmDrawRect(0, 0, screenWidth, screenHeight, gColDarker); + rmDrawLine(50, 75, screenWidth - 50, 75, gColWhite); + rmDrawLine(50, 410, screenWidth - 50, 410, gColWhite); + + fntRenderString(gTheme->fonts[0], screenWidth >> 1, 60, ALIGN_CENTER, 0, 0, _l(_STR_CHEAT_SELECTION), gTheme->textColor); + + int renderedCheats = 0; + for (int i = offset; renderedCheats < visibleCheats && i < cheatCount; i++) { + if (strlen(gCheats[i].name) == 0) + continue; + + int enabled = gCheats[i].enabled; + + int boxX = 50; + int boxY = 100 + (renderedCheats * 30); + int boxWidth = rmWideScale(25); + int boxHeight = 17; + + if (enabled) { + rmDrawRect(boxX, boxY + 3, boxWidth, boxHeight, gTheme->textColor); + rmDrawRect(boxX + 2, boxY + 5, boxWidth - 4, boxHeight - 4, gTheme->selTextColor); + } + + 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(); + } + + sfxPlay(SFX_CONFIRM); +} diff --git a/src/supportbase.c b/src/supportbase.c index e3c9366a8..b7df52908 100644 --- a/src/supportbase.c +++ b/src/supportbase.c @@ -10,6 +10,7 @@ #include "include/pggsm.h" #include "include/cheatman.h" #include "include/ps2cnf.h" +#include "include/gui.h" #define NEWLIB_PORT_AWARE #include // fileXioMount("iso:", ***), fileXioUmount("iso:") @@ -838,28 +839,20 @@ void sbCreateFolders(const char *path, int createDiscImgFolders) int sbLoadCheats(const char *path, const char *file) { char cheatfile[64]; - const u32 *cheatList; - int result; + int cheatMode = 0; if (GetCheatsEnabled()) { snprintf(cheatfile, sizeof(cheatfile), "%sCHT/%s.cht", path, file); LOG("Loading Cheat File %s\n", cheatfile); - if ((result = load_cheats(cheatfile)) < 0) { - LOG("Error: failed to load cheats\n"); - } else { - cheatList = GetCheatsList(); - if (!((cheatList[0] == 0) && (cheatList[1] == 0))) { - LOG("Cheats found\n"); - result = 0; - } else { - LOG("No cheats found\n"); - result = -ENOENT; - } + if ((cheatMode = load_cheats(cheatfile)) < 0) + LOG("Error: failed to load cheats\n"); + else { + LOG("Cheats found\n"); + if ((gAutoLaunchGame == NULL) && (gAutoLaunchBDMGame == NULL) && (cheatMode == 1)) + guiManageCheats(); } - } else { - result = 0; } - return result; + return cheatMode; } diff --git a/src/system.c b/src/system.c index bd85b8035..c5216dac1 100644 --- a/src/system.c +++ b/src/system.c @@ -900,9 +900,14 @@ void sysLaunchLoaderElf(const char *filename, const char *mode_str, int size_cdv config->EnableDebug = gEnableDebug; config->HDDSpindown = gHDDSpindown; - config->gCheatList = GetCheatsEnabled() ? (unsigned int *)GetCheatsList() : NULL; config->g_ps2_ETHOpMode = gETHOpMode; + if (GetCheatsEnabled()) { + set_cheats_list(); + config->gCheatList = GetCheatsList(); + } else + config->gCheatList = NULL; + sprintf(config->g_ps2_ip, "%u.%u.%u.%u", local_ip_address[0], local_ip_address[1], local_ip_address[2], local_ip_address[3]); sprintf(config->g_ps2_netmask, "%u.%u.%u.%u", local_netmask[0], local_netmask[1], local_netmask[2], local_netmask[3]); sprintf(config->g_ps2_gateway, "%u.%u.%u.%u", local_gateway[0], local_gateway[1], local_gateway[2], local_gateway[3]); From fdd6be868de0802a51072232d0370ee04c06d92f Mon Sep 17 00:00:00 2001 From: KrahJohlito Date: Mon, 18 Nov 2024 11:31:30 +1030 Subject: [PATCH 2/2] add a readme entry for cheats --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 6ec751c64..7ae1af1be 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,25 @@ that contains the preferred partition name (for example `__common`).

+
+ Cheats +

+ +OPL accepts `.cht` files in PS2RD format. Each cheat file corresponds to a specific game and must be stored in the `CHT` directory on your device. +Cheats are structured as hexadecimal codes, with proper headers as descriptions to identify their function. +You can activate cheats via OPL's graphical interface. Navigate to a games settings, enable cheats and select the desired mode. + +### cheat modes + + * Auto Select Cheats: +This mode will enable and apply all cheat codes in your `.cht` file to your game automatically. + + * Select Game Cheats: +When enabled a cheat selection menu will appear when you launch a game. You can navigate the menu and disable undesired cheats for this launch session. `Mastercode`s cannot be disabled as they are required for any other cheats to be applied. + +

+
+
NBD Server