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