diff --git a/CHANGES b/CHANGES index ab7ff318b..498c34bd4 100644 --- a/CHANGES +++ b/CHANGES @@ -96,6 +96,7 @@ Misc: - GB I/O: Implement preliminary support for PCM12/PCM34 (closes mgba.io/i/1468) - GBA: Allow pausing event loop while CPU is blocked - GBA BIOS: Division by zero should emit a FATAL error + - GBA Cheats: Allow unlimited ROM patch-type codes per set - GBA Video: Convert OpenGL VRAM texture to integer - GBA Video: Skip attempting to render offscreen sprites in OpenGL - GBA Video: New GL palette approach, no more batch splitting on palette edits diff --git a/include/mgba/internal/gba/cheats.h b/include/mgba/internal/gba/cheats.h index fe17af1a6..575d103ca 100644 --- a/include/mgba/internal/gba/cheats.h +++ b/include/mgba/internal/gba/cheats.h @@ -12,8 +12,8 @@ CXX_GUARD_START #include #include +#include -#define MAX_ROM_PATCHES 10 #define COMPLETE ((size_t) -1) enum GBACheatType { @@ -134,17 +134,20 @@ struct GBACheatHook { size_t reentries; }; +struct GBACheatPatch { + uint32_t address; + int16_t newValue; + int16_t oldValue; + bool applied; +}; + +DECLARE_VECTOR(GBACheatPatchList, struct GBACheatPatch); + struct GBACheatSet { struct mCheatSet d; struct GBACheatHook* hook; - struct GBACheatPatch { - uint32_t address; - int16_t newValue; - int16_t oldValue; - bool applied; - bool exists; - } romPatches[MAX_ROM_PATCHES]; + struct GBACheatPatchList romPatches; size_t incompleteCheat; struct GBACheatPatch* incompletePatch; diff --git a/src/gba/cheats.c b/src/gba/cheats.c index 8999abc23..fc396bacf 100644 --- a/src/gba/cheats.c +++ b/src/gba/cheats.c @@ -13,6 +13,8 @@ #define MAX_LINE_LENGTH 128 +DEFINE_VECTOR(GBACheatPatchList, struct GBACheatPatch); + static void _addBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p || !cheats->hook) { return; @@ -39,13 +41,14 @@ static void _patchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p) { return; } - int i; - for (i = 0; i < MAX_ROM_PATCHES; ++i) { - if (!cheats->romPatches[i].exists || cheats->romPatches[i].applied) { + size_t i; + for (i = 0; i < GBACheatPatchListSize(&cheats->romPatches); ++i) { + struct GBACheatPatch* patch = GBACheatPatchListGetPointer(&cheats->romPatches, i); + if (patch->applied) { continue; } - GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].newValue, &cheats->romPatches[i].oldValue); - cheats->romPatches[i].applied = true; + GBAPatch16(device->p->cpu, patch->address, patch->newValue, &patch->oldValue); + patch->applied = true; } } @@ -53,13 +56,14 @@ static void _unpatchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) if (!device->p) { return; } - int i; - for (i = 0; i < MAX_ROM_PATCHES; ++i) { - if (!cheats->romPatches[i].exists || !cheats->romPatches[i].applied) { + size_t i; + for (i = 0; i < GBACheatPatchListSize(&cheats->romPatches); ++i) { + struct GBACheatPatch* patch = GBACheatPatchListGetPointer(&cheats->romPatches, i); + if (!patch->applied) { continue; } - GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].oldValue, 0); - cheats->romPatches[i].applied = false; + GBAPatch16(device->p->cpu, patch->address, patch->oldValue, NULL); + patch->applied = false; } } @@ -97,10 +101,7 @@ static struct mCheatSet* GBACheatSetCreate(struct mCheatDevice* device, const ch set->d.refresh = GBACheatRefresh; - int i; - for (i = 0; i < MAX_ROM_PATCHES; ++i) { - set->romPatches[i].exists = false; - } + GBACheatPatchListInit(&set->romPatches, 4); return &set->d; } @@ -119,6 +120,7 @@ static void GBACheatSetDeinit(struct mCheatSet* set) { free(gbaset->hook); } } + GBACheatPatchListDeinit(&gbaset->romPatches); } static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) { diff --git a/src/gba/cheats/gameshark.c b/src/gba/cheats/gameshark.c index b7981699e..ba49cec3d 100644 --- a/src/gba/cheats/gameshark.c +++ b/src/gba/cheats/gameshark.c @@ -93,7 +93,7 @@ void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, enum GBACheatGameSh bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) { enum GBAGameSharkType type = op1 >> 28; struct mCheat* cheat = 0; - int romPatch = 0; + struct GBACheatPatch* romPatch; if (cheats->incompleteCheat != COMPLETE) { struct mCheat* incompleteCheat = mCheatListGetPointer(&cheats->d.list, cheats->incompleteCheat); @@ -149,16 +149,10 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat); break; case GSA_PATCH: - while (cheats->romPatches[romPatch].exists) { - ++romPatch; - if (romPatch >= MAX_ROM_PATCHES) { - break; - } - } - cheats->romPatches[romPatch].address = BASE_CART0 | ((op1 & 0xFFFFFF) << 1); - cheats->romPatches[romPatch].newValue = op2; - cheats->romPatches[romPatch].applied = false; - cheats->romPatches[romPatch].exists = true; + romPatch = GBACheatPatchListAppend(&cheats->romPatches); + romPatch->address = BASE_CART0 | ((op1 & 0xFFFFFF) << 1); + romPatch->newValue = op2; + romPatch->applied = false; return true; case GSA_BUTTON: switch (op1 & 0x00F00000) { diff --git a/src/gba/cheats/parv3.c b/src/gba/cheats/parv3.c index 4f3a89310..4f042f1ed 100644 --- a/src/gba/cheats/parv3.c +++ b/src/gba/cheats/parv3.c @@ -230,16 +230,10 @@ static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) { break; } if (romPatch >= 0) { - while (cheats->romPatches[romPatch].exists) { - ++romPatch; - if (romPatch >= MAX_ROM_PATCHES) { - break; - } - } - cheats->romPatches[romPatch].address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1); - cheats->romPatches[romPatch].applied = false; - cheats->romPatches[romPatch].exists = true; - cheats->incompletePatch = &cheats->romPatches[romPatch]; + struct GBACheatPatch* patch = GBACheatPatchListAppend(&cheats->romPatches); + patch->address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1); + patch->applied = false; + cheats->incompletePatch = patch; } return true; }