Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cheatman: Add user cheat selection #1364

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,25 @@ that contains the preferred partition name (for example `__common`).
</p>
</details>

<details>
<summary> <b> Cheats </b> </summary>
<p>

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.

</p>
</details>

<details>
<summary> <b> NBD Server </b> </summary>
<p>
Expand Down
2 changes: 1 addition & 1 deletion ee_core/include/coreconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 15 additions & 4 deletions include/cheatman.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@
#include <ctype.h>
#include <string.h>

#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
Expand All @@ -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_ */
2 changes: 2 additions & 0 deletions include/gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,6 @@ int guiConfirmVideoMode(void);

int guiGameShowRemoveSettings(config_set_t *configSet, config_set_t *configGame);

void guiManageCheats(void);

#endif
2 changes: 2 additions & 0 deletions lng_tmpl/_base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -690,3 +690,5 @@ gui_strings:
string: Analog Y-Axis Sensitivity
- label: FILE_COUNT
string: 'Files found: %i'
- label: CHEAT_SELECTION
string: Cheat Selection
112 changes: 84 additions & 28 deletions src/cheatman.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}

Expand All @@ -304,30 +319,38 @@ 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) {
lseek(fd, 0, SEEK_SET);
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;
}

Expand All @@ -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
}
}
77 changes: 77 additions & 0 deletions src/gui.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Loading