all repos — mgba @ 18c6e6c330749abe3105a24cbe6571a85bbb2de4

mGBA Game Boy Advance Emulator

GBA Cheats: Better autodetection
Jeffrey Pfau jeffrey@endrift.com
Wed, 12 Oct 2016 22:14:22 -0700
commit

18c6e6c330749abe3105a24cbe6571a85bbb2de4

parent

ac0238ef07dff044b90894ea8ec858eed6b3a26f

M CHANGESCHANGES

@@ -1,6 +1,7 @@

0.6.0: (Future) Features: - GBA: Support printing debug strings from inside a game + - GBA: Better cheat type autodetection Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior
M src/gba/cheats.csrc/gba/cheats.c

@@ -138,19 +138,26 @@ uint32_t o2 = op2;

char line[18] = "XXXXXXXX XXXXXXXX"; snprintf(line, sizeof(line), "%08X %08X", op1, op2); + int gsaP, parP; switch (set->gsaVersion) { case 0: // Try to detect GameShark version GBACheatDecryptGameShark(&o1, &o2, GBACheatGameSharkSeeds); - if ((o1 & 0xF0000000) == 0xF0000000 && !(o2 & 0xFFFFFCFE)) { - GBACheatSetGameSharkVersion(set, 1); - return GBACheatAddGameSharkRaw(set, o1, o2); - } + gsaP = GBACheatGameSharkProbability(o1, o2); o1 = op1; o2 = op2; GBACheatDecryptGameShark(&o1, &o2, GBACheatProActionReplaySeeds); - if ((o1 & 0xFE000000) == 0xC4000000 && !(o2 & 0xFFFF0000)) { + parP = GBACheatProActionReplayProbability(o1, o2); + o1 = op1; + o2 = op2; + if (gsaP > parP) { + GBACheatSetGameSharkVersion(set, 1); + GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds); + return GBACheatAddGameSharkRaw(set, o1, o2); + } else { + // If probabilities are equal, assume PARv3 GBACheatSetGameSharkVersion(set, 3); + GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds); return GBACheatAddProActionReplayRaw(set, o1, o2); } break;

@@ -314,3 +321,56 @@ *directive = strdup("PARv3");

break; } } + +int GBACheatAddressIsReal(uint32_t address) { + switch (address >> BASE_OFFSET) { + case REGION_BIOS: + return -0x80; + break; + case REGION_WORKING_RAM: + if ((address & OFFSET_MASK) > SIZE_WORKING_RAM) { + return -0x40; + } + return 0x20; + case REGION_WORKING_IRAM: + if ((address & OFFSET_MASK) > SIZE_WORKING_IRAM) { + return -0x40; + } + return 0x20; + case REGION_IO: + if ((address & OFFSET_MASK) > SIZE_IO) { + return -0x80; + } + return 0x10; + case REGION_OAM: + if ((address & OFFSET_MASK) > SIZE_OAM) { + return -0x80; + } + return -0x8; + case REGION_VRAM: + if ((address & OFFSET_MASK) > SIZE_VRAM) { + return -0x80; + } + return -0x8; + case REGION_PALETTE_RAM: + if ((address & OFFSET_MASK) > SIZE_PALETTE_RAM) { + return -0x80; + } + return -0x8; + case REGION_CART0: + case REGION_CART0_EX: + case REGION_CART1: + case REGION_CART1_EX: + case REGION_CART2: + case REGION_CART2_EX: + return -0x8; + case REGION_CART_SRAM: + case REGION_CART_SRAM_MIRROR: + if ((address & OFFSET_MASK) > SIZE_CART_SRAM) { + return -0x80; + } + return -0x8; + default: + return -0xC0; + } +}
M src/gba/cheats.hsrc/gba/cheats.h

@@ -172,4 +172,6 @@ bool GBACheatAddProActionReplayLine(struct GBACheatSet*, const char* line);

bool GBACheatAddVBALine(struct GBACheatSet*, const char* line); +int GBACheatAddressIsReal(uint32_t address); + #endif
M src/gba/cheats/gameshark.csrc/gba/cheats/gameshark.c

@@ -226,3 +226,63 @@ return false;

} return GBACheatAddGameShark(cheats, op1, op2); } + +int GBACheatGameSharkProbability(uint32_t op1, uint32_t op2) { + int probability = 0; + if (op2 == 0x001DC0DE) { + return 0x100; + } + uint32_t address = op1 & 0x0FFFFFFF; + switch (op1 >> 28) { + case GSA_ASSIGN_1: + probability += 0x20; + if (op2 & 0xFFFFFF00) { + probability -= 0x10; + } + probability += GBACheatAddressIsReal(address); + break; + case GSA_ASSIGN_2: + probability += 0x20; + if (op2 & 0xFFFF0000) { + probability -= 0x10; + } + probability += GBACheatAddressIsReal(address); + break; + case GSA_ASSIGN_4: + probability += 0x20; + probability += GBACheatAddressIsReal(address); + break; + case GSA_PATCH: + probability += 0x20; + if (op2 & 0xCFFF0000) { + probability -= 0x10; + } + break; + case GSA_BUTTON: + probability += 0x10; + break; + case GSA_IF_EQ: + probability += 0x20; + if (op2 & 0xFFFF0000) { + probability -= 0x10; + } + probability += GBACheatAddressIsReal(address); + break; + case GSA_IF_EQ_RANGE: + probability += 0x20; + probability += GBACheatAddressIsReal(op2); + if (op1 & 0x0F000000) { + probability -= 0x10; + } + break; + case GSA_HOOK: + probability += 0x20; + if (op2 & 0xFFFF0000) { + probability -= 0x10; + } + break; + default: + probability -= 0x40; + } + return probability; +}
M src/gba/cheats/gameshark.hsrc/gba/cheats/gameshark.h

@@ -14,5 +14,6 @@ void GBACheatDecryptGameShark(uint32_t* op1, uint32_t* op2, const uint32_t* seeds);

void GBACheatReseedGameShark(uint32_t* seeds, uint16_t params, const uint8_t* t1, const uint8_t* t2); void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, int version); bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2); +int GBACheatGameSharkProbability(uint32_t op1, uint32_t op2); #endif
M src/gba/cheats/parv3.csrc/gba/cheats/parv3.c

@@ -326,3 +326,72 @@ return false;

} return GBACheatAddProActionReplay(cheats, op1, op2); } + +int GBACheatProActionReplayProbability(uint32_t op1, uint32_t op2) { + int probability = 0; + if (op2 == 0x001DC0DE) { + return 0x100; + } + if (op1 == 0xDEADFACE && !(op2 & 0xFFFF0000)) { + return 0x100; + } + if (!op1) { + probability += 0x20; + uint32_t address = _parAddr(op2); + switch (op2 & 0xFE000000) { + case PAR3_OTHER_FILL_1: + case PAR3_OTHER_FILL_2: + case PAR3_OTHER_FILL_4: + probability += GBACheatAddressIsReal(address); + break; + case PAR3_OTHER_PATCH_1: + case PAR3_OTHER_PATCH_2: + case PAR3_OTHER_PATCH_3: + case PAR3_OTHER_PATCH_4: + // TODO: Detect ROM address + break; + case PAR3_OTHER_END: + case PAR3_OTHER_SLOWDOWN: + case PAR3_OTHER_BUTTON_1: + case PAR3_OTHER_BUTTON_2: + case PAR3_OTHER_BUTTON_4: + case PAR3_OTHER_ENDIF: + case PAR3_OTHER_ELSE: + if (op2 & 0x01FFFFFF) { + probability -= 0x20; + } + break; + default: + probability -= 0x40; + break; + } + return probability; + } + int width = ((op1 & PAR3_WIDTH) >> (PAR3_WIDTH_BASE - 3)); + if (op1 & PAR3_COND) { + probability += 0x20; + if (width == 32) { + return 0; + } + if (op2 & ~((1 << width) - 1)) { + probability -= 0x10; + } + } else { + uint32_t address = _parAddr(op1); + probability += 0x20; + switch (op1 & PAR3_BASE) { + case PAR3_BASE_ADD: + if (op2 & ~((1 << width) - 1)) { + probability -= 0x10; + } + case PAR3_BASE_ASSIGN: + case PAR3_BASE_INDIRECT: + probability += GBACheatAddressIsReal(address); + // Fall through + break; + case PAR3_BASE_OTHER: + break; + } + } + return probability; +}
M src/gba/cheats/parv3.hsrc/gba/cheats/parv3.h

@@ -11,5 +11,6 @@

extern const uint32_t GBACheatProActionReplaySeeds[4]; bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2); +int GBACheatProActionReplayProbability(uint32_t op1, uint32_t op2); #endif