GBA Cheats: Implement "never" type codes (closes #915)

This commit is contained in:
Vicki Pfau 2022-02-22 19:40:21 -08:00
parent 7d71396968
commit 64d8dd1b69
5 changed files with 146 additions and 5 deletions

View File

@ -48,6 +48,7 @@ Misc:
- GB Video: Add default SGB border
- GBA: Automatically skip BIOS if ROM has invalid logo
- GBA: Refine multiboot detection (fixes mgba.io/i/2192)
- GBA Cheats: Implement "never" type codes (closes mgba.io/i/915)
- GBA DMA: Enhanced logging (closes mgba.io/i/2454)
- GBA Video: Implement layer placement for OpenGL renderer (fixes mgba.io/i/1962)
- mGUI: Add margin to right-aligned menu text (fixes mgba.io/i/871)

View File

@ -31,6 +31,7 @@ enum mCheatType {
CHEAT_IF_LAND,
CHEAT_IF_NAND,
CHEAT_IF_BUTTON,
CHEAT_NEVER,
};
struct mCheat {

View File

@ -741,6 +741,12 @@ void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
negativeConditionRemaining = cheat->negativeRepeat;
operationsRemaining = 1;
break;
case CHEAT_NEVER:
condition = false;
conditionRemaining = cheat->repeat;
negativeConditionRemaining = cheat->negativeRepeat;
operationsRemaining = 1;
break;
}
if (performAssignment) {

View File

@ -72,12 +72,9 @@ static void _parElseBlock(struct GBACheatSet* cheats) {
static bool _addPAR3Cond(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
enum GBAActionReplay3Condition condition = op1 & PAR3_COND;
int width = 1 << ((op1 & PAR3_WIDTH) >> PAR3_WIDTH_BASE);
if (width > 4) {
// TODO: Always false conditions
return false;
}
if ((op1 & PAR3_ACTION) == PAR3_ACTION_DISABLE) {
// TODO: Codes that disable
mLOG(CHEATS, STUB, "Disable-type PARv3 codes not yet supported");
return false;
}
@ -136,6 +133,11 @@ static bool _addPAR3Cond(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2)
cheat->type = CHEAT_IF_AND;
break;
}
if (width > 4) {
cheat->width = 0;
cheat->type = CHEAT_NEVER;
}
return true;
}

View File

@ -1051,6 +1051,133 @@ M_TEST_DEFINE(doPARv3IfButton) {
mCheatSetDeinit(set);
}
M_TEST_DEFINE(doPARv3Never1) {
struct mCore* core = *state;
struct mCheatDevice* device = core->cheatDevice(core);
assert_non_null(device);
struct mCheatSet* set = device->createSet(device, NULL);
assert_non_null(set);
GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW);
assert_true(set->addLine(set, "00300001 00000011", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "0E300000 00000000", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300001 00000012", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300000 00000001", GBA_CHEAT_PRO_ACTION_REPLAY));
core->reset(core);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0);
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
core->reset(core);
core->rawWrite8(core, 0x03000000, -1, 0x1);
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
mCheatSetDeinit(set);
}
M_TEST_DEFINE(doPARv3Never2) {
struct mCore* core = *state;
struct mCheatDevice* device = core->cheatDevice(core);
assert_non_null(device);
struct mCheatSet* set = device->createSet(device, NULL);
assert_non_null(set);
GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW);
assert_true(set->addLine(set, "00300001 00000011", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300002 00000021", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "4E300000 00000000", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300001 00000012", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300002 00000022", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300000 00000001", GBA_CHEAT_PRO_ACTION_REPLAY));
core->reset(core);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0);
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0);
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21);
core->reset(core);
core->rawWrite8(core, 0x03000000, -1, 0x1);
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21);
mCheatSetDeinit(set);
}
M_TEST_DEFINE(doPARv3NeverX) {
struct mCore* core = *state;
struct mCheatDevice* device = core->cheatDevice(core);
assert_non_null(device);
struct mCheatSet* set = device->createSet(device, NULL);
assert_non_null(set);
GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW);
assert_true(set->addLine(set, "00300001 00000011", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "8E300000 00000000", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300001 00000012", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00000000 40000000", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300000 00000001", GBA_CHEAT_PRO_ACTION_REPLAY));
core->reset(core);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0);
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
core->reset(core);
core->rawWrite8(core, 0x03000000, -1, 0x1);
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
mCheatSetDeinit(set);
}
M_TEST_DEFINE(doPARv3NeverXElse) {
struct mCore* core = *state;
struct mCheatDevice* device = core->cheatDevice(core);
assert_non_null(device);
struct mCheatSet* set = device->createSet(device, NULL);
assert_non_null(set);
GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW);
assert_true(set->addLine(set, "00300001 00000011", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300002 00000021", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "8E300000 00000000", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300001 00000012", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00000000 60000000", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300002 00000022", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00000000 40000000", GBA_CHEAT_PRO_ACTION_REPLAY));
assert_true(set->addLine(set, "00300000 00000001", GBA_CHEAT_PRO_ACTION_REPLAY));
core->reset(core);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0);
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0);
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x22);
core->reset(core);
core->rawWrite8(core, 0x03000000, -1, 0x1);
mCheatRefresh(device, set);
assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);
assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11);
assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x22);
mCheatSetDeinit(set);
}
M_TEST_SUITE_DEFINE(GBACheats,
cmocka_unit_test_setup_teardown(createSet, cheatsSetup, cheatsTeardown),
cmocka_unit_test_setup_teardown(addRawPARv3, cheatsSetup, cheatsTeardown),
@ -1072,4 +1199,8 @@ M_TEST_SUITE_DEFINE(GBACheats,
cmocka_unit_test_setup_teardown(doPARv3IfXContain1Else, cheatsSetup, cheatsTeardown),
cmocka_unit_test_setup_teardown(doPARv3IfXElseContain1, cheatsSetup, cheatsTeardown),
cmocka_unit_test_setup_teardown(doPARv3IfXContain1ElseContain1, cheatsSetup, cheatsTeardown),
cmocka_unit_test_setup_teardown(doPARv3IfButton, cheatsSetup, cheatsTeardown))
cmocka_unit_test_setup_teardown(doPARv3IfButton, cheatsSetup, cheatsTeardown),
cmocka_unit_test_setup_teardown(doPARv3Never1, cheatsSetup, cheatsTeardown),
cmocka_unit_test_setup_teardown(doPARv3Never2, cheatsSetup, cheatsTeardown),
cmocka_unit_test_setup_teardown(doPARv3NeverX, cheatsSetup, cheatsTeardown),
cmocka_unit_test_setup_teardown(doPARv3NeverXElse, cheatsSetup, cheatsTeardown))