Skip to content

Commit

Permalink
Allow multiple preconditions per cheat
Browse files Browse the repository at this point in the history
Each cheat code can have multiple preconditions which all have to be fulfilled
before it can be executed. The default implementation in mupen64plus could not
handle these extra test codes because a failed test only caused a jump over the
next cheatcode (ignoring whether is also a test or a non-test cheatcode).

Therefore, all (negative) results before a non-test cheat code have to be
aggregated. The first non-test cheatcode evaluates the result of the
preconditions and only executes the non-test cheatcode when no precondition
test failed. The earlier results are always dropped after a non-test cheatcode
to allow a fresh start.
  • Loading branch information
ecsv committed Jan 29, 2014
1 parent b0720b5 commit c1636fd
Showing 1 changed file with 34 additions and 50 deletions.
84 changes: 34 additions & 50 deletions src/main/cheat.c
Expand Up @@ -201,8 +201,7 @@ void cheat_apply_cheats(int entry)
{
cheat_t *cheat;
cheat_code_t *code;
int skip;
int execute_next;
int cond_failed;

// If game is Zelda OOT, apply subscreen delay fix
if (entry == ENTRY_VI && strncmp((char *)ROM_HEADER.Name, "THE LEGEND OF ZELDA", 19) == 0) {
Expand Down Expand Up @@ -312,67 +311,52 @@ void cheat_apply_cheats(int entry)
}
break;
case ENTRY_VI:
skip = 0;
execute_next = 0;
list_for_each_entry(code, &cheat->cheat_codes, cheat_code_t, list) {
if (skip) {
skip = 0;
continue;
}
if (execute_next) {
execute_next = 0;

// if code needs GS button pressed, don't save old value
if(((code->address & 0xFF000000) == 0xD8000000 ||
(code->address & 0xFF000000) == 0xD9000000 ||
(code->address & 0xFF000000) == 0xDA000000 ||
(code->address & 0xFF000000) == 0xDB000000))
execute_cheat(code->address, code->value, NULL);
else
execute_cheat(code->address, code->value, &code->old_value);
/* a cheat starts without failed preconditions */
cond_failed = 0;

continue;
}
// conditional cheat codes
list_for_each_entry(code, &cheat->cheat_codes, cheat_code_t, list) {
/* conditional cheat codes */
if((code->address & 0xF0000000) == 0xD0000000)
{
// if code needs GS button pressed and it's not, skip it
/* if code needs GS button pressed and it's not, skip it */
if(((code->address & 0xFF000000) == 0xD8000000 ||
(code->address & 0xFF000000) == 0xD9000000 ||
(code->address & 0xFF000000) == 0xDA000000 ||
(code->address & 0xFF000000) == 0xDB000000) &&
!event_gameshark_active())
{
// skip next code
skip = 1;
/* if condition false, skip next code non-test code */
cond_failed = 1;

/* if condition false, skip next code non-test code */
if (!execute_cheat(code->address, code->value, NULL))
cond_failed = 1;
}
else {
/* preconditions were false for this non-test code
* reset the condition state and skip the cheat
*/
if (cond_failed) {
cond_failed = 0;
continue;
}

if (execute_cheat(code->address, code->value, NULL)) {
// if condition true, execute next cheat code
execute_next = 1;
} else {
// if condition false, skip next code
skip = 1;
continue;
switch (code->address & 0xFF000000) {
/* GS button triggers cheat code */
case 0x88000000:
case 0x89000000:
case 0xA8000000:
case 0xA9000000:
if(event_gameshark_active())
execute_cheat(code->address, code->value, NULL);
break;
/* normal cheat code */
default:
/* exclude boot-time cheat codes */
if((code->address & 0xF0000000) != 0xF0000000)
execute_cheat(code->address, code->value, &code->old_value);
break;
}
}
// GS button triggers cheat code
else if((code->address & 0xFF000000) == 0x88000000 ||
(code->address & 0xFF000000) == 0x89000000 ||
(code->address & 0xFF000000) == 0xA8000000 ||
(code->address & 0xFF000000) == 0xA9000000)
{
if(event_gameshark_active())
execute_cheat(code->address, code->value, NULL);
}
// normal cheat code
else
{
// exclude boot-time cheat codes
if((code->address & 0xF0000000) != 0xF0000000)
execute_cheat(code->address, code->value, &code->old_value);
}
}
break;
default:
Expand Down

3 comments on commit c1636fd

@ecsv
Copy link
Contributor Author

@ecsv ecsv commented on c1636fd Jan 31, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@littleguy77: It seems that this was a bug which a user experience with a "mupen64plus android port" and was submitted to us as issue 598 and may intereset you too. At least when such a bug report exists at your side about some movement hacks in "WWF no mercy". I've checked the cheat file and the only other predefined cheat code using multiple preconditions was for Bomberman Hero (Levitate). There might be more because I've only used a simple regex to grep through the file and did not verify whether this regex was correct.

See https://code.google.com/p/mupen64plus/issues/detail?id=598

@littleguy77
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks Sven. I've already merged this into our version3 (master) branch, but I may try to merge it with our 2.4-bugfixes branch if it's not too hard. Since version3 may still be a ways from publishing, and it's always worth rewarding diligent testers.

For reference, here's the thread where the discussion began:
www.paulscode.com/forum/index.php?topic=1423.msg12505

Tagging @xperia64 on this, as he is probably the best person on our end to track down other games with the issue. And @paulscode as well. I'm least qualified for sure :)

@littleguy77
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pokemon Stadium (E) game difficulty cheat is the only other one I could find. So bottom line, this commit fixes cheats for three games:

  1. WWF No Mercy (lots of cheats)
  2. Bomberman Hero (levitate cheat)
  3. Pokemon Stadium (E) (game difficulty cheat)

Edit: This is the regex I used on mupencheat.txt: D[012389AB][\dA-F]{6} [\dA-F]{4}[\s]*?D[012389AB]

Please sign in to comment.