GBA Cheats: Better autodetection

This commit is contained in:
Jeffrey Pfau 2016-10-12 22:14:22 -07:00
parent ac0238ef07
commit 18c6e6c330
7 changed files with 199 additions and 5 deletions

View File

@ -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

View File

@ -138,19 +138,26 @@ static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_
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 @@ static void GBACheatDumpDirectives(struct mCheatSet* set, struct StringList* dir
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;
}
}

View File

@ -172,4 +172,6 @@ bool GBACheatAddProActionReplayLine(struct GBACheatSet*, const char* line);
bool GBACheatAddVBALine(struct GBACheatSet*, const char* line);
int GBACheatAddressIsReal(uint32_t address);
#endif

View File

@ -226,3 +226,63 @@ bool GBACheatAddGameSharkLine(struct GBACheatSet* cheats, const char* line) {
}
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;
}

View File

@ -14,5 +14,6 @@ void GBACheatDecryptGameShark(uint32_t* op1, uint32_t* op2, const uint32_t* seed
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

View File

@ -326,3 +326,72 @@ bool GBACheatAddProActionReplayLine(struct GBACheatSet* cheats, const char* line
}
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;
}

View File

@ -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