mirror of https://github.com/mgba-emu/mgba.git
Core: Refactor out cheats
This commit is contained in:
parent
4b5885624b
commit
44bbb9d1bb
|
@ -0,0 +1,360 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "cheats.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "util/string.h"
|
||||
#include "util/vfs.h"
|
||||
|
||||
#define MAX_LINE_LENGTH 128
|
||||
|
||||
const uint32_t M_CHEAT_DEVICE_ID = 0xABADC0DE;
|
||||
|
||||
mLOG_DEFINE_CATEGORY(CHEATS, "Cheats");
|
||||
|
||||
DEFINE_VECTOR(mCheatList, struct mCheat);
|
||||
DEFINE_VECTOR(mCheatSets, struct mCheatSet*);
|
||||
DEFINE_VECTOR(StringList, char*);
|
||||
|
||||
static int32_t _readMem(struct mCore* core, uint32_t address, int width) {
|
||||
switch (width) {
|
||||
case 1:
|
||||
return core->busRead8(core, address);
|
||||
case 2:
|
||||
return core->busRead16(core, address);
|
||||
case 4:
|
||||
return core->busRead32(core, address);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _writeMem(struct mCore* core, uint32_t address, int width, int32_t value) {
|
||||
switch (width) {
|
||||
case 1:
|
||||
core->busWrite8(core, address, value);
|
||||
break;
|
||||
case 2:
|
||||
core->busWrite16(core, address, value);
|
||||
break;
|
||||
case 4:
|
||||
core->busWrite32(core, address, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mCheatDeviceInit(void*, struct mCPUComponent*);
|
||||
static void mCheatDeviceDeinit(struct mCPUComponent*);
|
||||
|
||||
void mCheatDeviceCreate(struct mCheatDevice* device) {
|
||||
device->d.id = M_CHEAT_DEVICE_ID;
|
||||
device->d.init = mCheatDeviceInit;
|
||||
device->d.deinit = mCheatDeviceDeinit;
|
||||
mCheatSetsInit(&device->cheats, 4);
|
||||
}
|
||||
|
||||
void mCheatDeviceDestroy(struct mCheatDevice* device) {
|
||||
mCheatDeviceClear(device);
|
||||
mCheatSetsDeinit(&device->cheats);
|
||||
}
|
||||
|
||||
void mCheatDeviceClear(struct mCheatDevice* device) {
|
||||
size_t i;
|
||||
for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
|
||||
struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i);
|
||||
mCheatSetDeinit(set);
|
||||
}
|
||||
mCheatSetsClear(&device->cheats);
|
||||
}
|
||||
|
||||
void mCheatSetInit(struct mCheatSet* set, const char* name) {
|
||||
mCheatListInit(&set->list, 4);
|
||||
StringListInit(&set->lines, 4);
|
||||
if (name) {
|
||||
set->name = strdup(name);
|
||||
} else {
|
||||
set->name = 0;
|
||||
}
|
||||
set->enabled = true;
|
||||
}
|
||||
|
||||
void mCheatSetDeinit(struct mCheatSet* set) {
|
||||
mCheatListDeinit(&set->list);
|
||||
size_t i;
|
||||
for (i = 0; i < StringListSize(&set->lines); ++i) {
|
||||
free(*StringListGetPointer(&set->lines, i));
|
||||
}
|
||||
if (set->name) {
|
||||
free(set->name);
|
||||
}
|
||||
set->deinit(set);
|
||||
free(set);
|
||||
}
|
||||
|
||||
void mCheatSetRename(struct mCheatSet* set, const char* name) {
|
||||
if (set->name) {
|
||||
free(set->name);
|
||||
set->name = NULL;
|
||||
}
|
||||
if (name) {
|
||||
set->name = strdup(name);
|
||||
}
|
||||
}
|
||||
|
||||
bool mCheatAddLine(struct mCheatSet* set, const char* line, int type) {
|
||||
if (!set->addLine(set, line, type)) {
|
||||
return false;
|
||||
}
|
||||
*StringListAppend(&set->lines) = strdup(line);
|
||||
return true;
|
||||
}
|
||||
|
||||
void mCheatAddSet(struct mCheatDevice* device, struct mCheatSet* cheats) {
|
||||
*mCheatSetsAppend(&device->cheats) = cheats;
|
||||
cheats->add(cheats, device);
|
||||
}
|
||||
|
||||
void mCheatRemoveSet(struct mCheatDevice* device, struct mCheatSet* cheats) {
|
||||
size_t i;
|
||||
for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
|
||||
if (*mCheatSetsGetPointer(&device->cheats, i) == cheats) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == mCheatSetsSize(&device->cheats)) {
|
||||
return;
|
||||
}
|
||||
mCheatSetsShift(&device->cheats, i, 1);
|
||||
cheats->remove(cheats, device);
|
||||
}
|
||||
|
||||
bool mCheatParseFile(struct mCheatDevice* device, struct VFile* vf) {
|
||||
#warning Cheat loading is currently broken
|
||||
return false;
|
||||
#if 0
|
||||
char cheat[MAX_LINE_LENGTH];
|
||||
struct mCheatSet* set = NULL;
|
||||
struct mCheatSet* newSet;
|
||||
bool nextDisabled = false;
|
||||
void* directives = NULL;
|
||||
while (true) {
|
||||
size_t i = 0;
|
||||
ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat));
|
||||
if (bytesRead == 0) {
|
||||
break;
|
||||
}
|
||||
if (bytesRead < 0) {
|
||||
return false;
|
||||
}
|
||||
while (isspace((int) cheat[i])) {
|
||||
++i;
|
||||
}
|
||||
switch (cheat[i]) {
|
||||
case '#':
|
||||
do {
|
||||
++i;
|
||||
} while (isspace((int) cheat[i]));
|
||||
cheat[strlen(cheat) - 1] = '\0'; // Remove trailing newline
|
||||
newSet = device->createSet(device, &cheat[i]);
|
||||
newSet->enabled = !nextDisabled;
|
||||
nextDisabled = false;
|
||||
if (set) {
|
||||
mCheatAddSet(device, set);
|
||||
}
|
||||
if (set) {
|
||||
newSet->copyProperties(newSet, set);
|
||||
}
|
||||
set = newSet;
|
||||
break;
|
||||
case '!':
|
||||
do {
|
||||
++i;
|
||||
} while (isspace((int) cheat[i]));
|
||||
if (strcasecmp(&cheat[i], "disabled") == 0) {
|
||||
nextDisabled = true;
|
||||
break;
|
||||
}
|
||||
if (strcasecmp(&cheat[i], "reset") == 0) {
|
||||
directives = NULL;
|
||||
break;
|
||||
}
|
||||
directives = set->parseDirective(set, &cheat[i], directives);
|
||||
break;
|
||||
default:
|
||||
if (!set) {
|
||||
set = device->createSet(device, NULL);
|
||||
set->enabled = !nextDisabled;
|
||||
nextDisabled = false;
|
||||
}
|
||||
mCheatAddLine(set, cheat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (set) {
|
||||
mCheatAddSet(device, set);
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mCheatSaveFile(struct mCheatDevice* device, struct VFile* vf) {
|
||||
#warning Cheat saving is currently broken
|
||||
return false;
|
||||
#if 0
|
||||
static const char lineStart[3] = "# ";
|
||||
static const char lineEnd = '\n';
|
||||
void* directives = NULL;
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
|
||||
struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i);
|
||||
void* directives = set->dumpDirectives(set, vf, directives);
|
||||
if (!set->enabled) {
|
||||
static const char* disabledDirective = "!disabled\n";
|
||||
vf->write(vf, disabledDirective, strlen(disabledDirective));
|
||||
}
|
||||
|
||||
vf->write(vf, lineStart, 2);
|
||||
if (set->name) {
|
||||
vf->write(vf, set->name, strlen(set->name));
|
||||
}
|
||||
vf->write(vf, &lineEnd, 1);
|
||||
size_t c;
|
||||
for (c = 0; c < StringListSize(&set->lines); ++c) {
|
||||
const char* line = *StringListGetPointer(&set->lines, c);
|
||||
vf->write(vf, line, strlen(line));
|
||||
vf->write(vf, &lineEnd, 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
|
||||
if (!cheats->enabled) {
|
||||
return;
|
||||
}
|
||||
bool condition = true;
|
||||
int conditionRemaining = 0;
|
||||
int negativeConditionRemaining = 0;
|
||||
cheats->refresh(cheats, device);
|
||||
|
||||
size_t nCodes = mCheatListSize(&cheats->list);
|
||||
size_t i;
|
||||
for (i = 0; i < nCodes; ++i) {
|
||||
if (conditionRemaining > 0) {
|
||||
--conditionRemaining;
|
||||
if (!condition) {
|
||||
continue;
|
||||
}
|
||||
} else if (negativeConditionRemaining > 0) {
|
||||
conditionRemaining = negativeConditionRemaining - 1;
|
||||
negativeConditionRemaining = 0;
|
||||
condition = !condition;
|
||||
if (!condition) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
condition = true;
|
||||
}
|
||||
struct mCheat* cheat = mCheatListGetPointer(&cheats->list, i);
|
||||
int32_t value = 0;
|
||||
int32_t operand = cheat->operand;
|
||||
uint32_t operationsRemaining = cheat->repeat;
|
||||
uint32_t address = cheat->address;
|
||||
bool performAssignment = false;
|
||||
for (; operationsRemaining; --operationsRemaining) {
|
||||
switch (cheat->type) {
|
||||
case CHEAT_ASSIGN:
|
||||
value = operand;
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_ASSIGN_INDIRECT:
|
||||
value = operand;
|
||||
address = _readMem(device->p, address + cheat->addressOffset, 4);
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_AND:
|
||||
value = _readMem(device->p, address, cheat->width) & operand;
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_ADD:
|
||||
value = _readMem(device->p, address, cheat->width) + operand;
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_OR:
|
||||
value = _readMem(device->p, address, cheat->width) | operand;
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_IF_EQ:
|
||||
condition = _readMem(device->p, address, cheat->width) == operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_NE:
|
||||
condition = _readMem(device->p, address, cheat->width) != operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_LT:
|
||||
condition = _readMem(device->p, address, cheat->width) < operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_GT:
|
||||
condition = _readMem(device->p, address, cheat->width) > operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_ULT:
|
||||
condition = (uint32_t) _readMem(device->p, address, cheat->width) < (uint32_t) operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_UGT:
|
||||
condition = (uint32_t) _readMem(device->p, address, cheat->width) > (uint32_t) operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_AND:
|
||||
condition = _readMem(device->p, address, cheat->width) & operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_LAND:
|
||||
condition = _readMem(device->p, address, cheat->width) && operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
}
|
||||
|
||||
if (performAssignment) {
|
||||
_writeMem(device->p, address, cheat->width, value);
|
||||
}
|
||||
|
||||
address += cheat->addressOffset;
|
||||
operand += cheat->operandOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mCheatDeviceInit(void* cpu, struct mCPUComponent* component) {
|
||||
UNUSED(cpu);
|
||||
struct mCheatDevice* device = (struct mCheatDevice*) component;
|
||||
size_t i;
|
||||
for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
|
||||
struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
|
||||
cheats->add(cheats, device);
|
||||
}
|
||||
}
|
||||
|
||||
void mCheatDeviceDeinit(struct mCPUComponent* component) {
|
||||
struct mCheatDevice* device = (struct mCheatDevice*) component;
|
||||
size_t i;
|
||||
for (i = mCheatSetsSize(&device->cheats); i--;) {
|
||||
struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
|
||||
cheats->remove(cheats, device);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef CHEATS_H
|
||||
#define CHEATS_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "core/cpu.h"
|
||||
#include "core/log.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
#define MAX_ROM_PATCHES 4
|
||||
|
||||
enum mCheatType {
|
||||
CHEAT_ASSIGN,
|
||||
CHEAT_ASSIGN_INDIRECT,
|
||||
CHEAT_AND,
|
||||
CHEAT_ADD,
|
||||
CHEAT_OR,
|
||||
CHEAT_IF_EQ,
|
||||
CHEAT_IF_NE,
|
||||
CHEAT_IF_LT,
|
||||
CHEAT_IF_GT,
|
||||
CHEAT_IF_ULT,
|
||||
CHEAT_IF_UGT,
|
||||
CHEAT_IF_AND,
|
||||
CHEAT_IF_LAND
|
||||
};
|
||||
|
||||
struct mCheat {
|
||||
enum mCheatType type;
|
||||
int width;
|
||||
uint32_t address;
|
||||
uint32_t operand;
|
||||
uint32_t repeat;
|
||||
uint32_t negativeRepeat;
|
||||
|
||||
int32_t addressOffset;
|
||||
int32_t operandOffset;
|
||||
};
|
||||
|
||||
mLOG_DECLARE_CATEGORY(CHEATS);
|
||||
|
||||
DECLARE_VECTOR(mCheatList, struct mCheat);
|
||||
DECLARE_VECTOR(StringList, char*);
|
||||
|
||||
struct mCheatDevice;
|
||||
struct mCheatSet {
|
||||
struct mCheatList list;
|
||||
|
||||
void (*deinit)(struct mCheatSet* set);
|
||||
void (*add)(struct mCheatSet* set, struct mCheatDevice* device);
|
||||
void (*remove)(struct mCheatSet* set, struct mCheatDevice* device);
|
||||
|
||||
bool (*addLine)(struct mCheatSet* set, const char* cheat, int type);
|
||||
void (*copyProperties)(struct mCheatSet* set, struct mCheatSet* oldSet);
|
||||
|
||||
void (*refresh)(struct mCheatSet* set, struct mCheatDevice* device);
|
||||
|
||||
char* name;
|
||||
bool enabled;
|
||||
struct StringList lines;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(mCheatSets, struct mCheatSet*);
|
||||
|
||||
struct mCheatDevice {
|
||||
struct mCPUComponent d;
|
||||
struct mCore* p;
|
||||
|
||||
struct mCheatSet* (*createSet)(struct mCheatDevice*, const char* name);
|
||||
|
||||
struct mCheatSets cheats;
|
||||
};
|
||||
|
||||
struct VFile;
|
||||
|
||||
void mCheatDeviceCreate(struct mCheatDevice*);
|
||||
void mCheatDeviceDestroy(struct mCheatDevice*);
|
||||
void mCheatDeviceClear(struct mCheatDevice*);
|
||||
|
||||
void mCheatSetInit(struct mCheatSet*, const char* name);
|
||||
void mCheatSetDeinit(struct mCheatSet*);
|
||||
void mCheatSetRename(struct mCheatSet*, const char* name);
|
||||
|
||||
bool mCheatAddLine(struct mCheatSet*, const char* line, int type);
|
||||
|
||||
void mCheatAddSet(struct mCheatDevice*, struct mCheatSet*);
|
||||
void mCheatRemoveSet(struct mCheatDevice*, struct mCheatSet*);
|
||||
|
||||
bool mCheatParseFile(struct mCheatDevice*, struct VFile*);
|
||||
bool mCheatSaveFile(struct mCheatDevice*, struct VFile*);
|
||||
|
||||
void mCheatRefresh(struct mCheatDevice*, struct mCheatSet*);
|
||||
|
||||
#endif
|
|
@ -117,6 +117,8 @@ struct mCore {
|
|||
struct CLIDebuggerSystem* (*cliDebuggerSystem)(struct mCore*);
|
||||
void (*attachDebugger)(struct mCore*, struct mDebugger*);
|
||||
void (*detachDebugger)(struct mCore*);
|
||||
|
||||
struct mCheatDevice* (*cheatDevice)(struct mCore*);
|
||||
};
|
||||
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
|
|
482
src/gba/cheats.c
482
src/gba/cheats.c
|
@ -9,49 +9,10 @@
|
|||
#include "gba/cheats/parv3.h"
|
||||
#include "gba/gba.h"
|
||||
#include "util/string.h"
|
||||
#include "util/vfs.h"
|
||||
|
||||
#define MAX_LINE_LENGTH 128
|
||||
|
||||
const uint32_t GBA_CHEAT_DEVICE_ID = 0xABADC0DE;
|
||||
|
||||
mLOG_DEFINE_CATEGORY(CHEATS, "Cheats");
|
||||
|
||||
DEFINE_VECTOR(GBACheatList, struct GBACheat);
|
||||
DEFINE_VECTOR(GBACheatSets, struct GBACheatSet*);
|
||||
DEFINE_VECTOR(StringList, char*);
|
||||
|
||||
static int32_t _readMem(struct ARMCore* cpu, uint32_t address, int width) {
|
||||
switch (width) {
|
||||
case 1:
|
||||
return cpu->memory.load8(cpu, address, 0);
|
||||
case 2:
|
||||
return cpu->memory.load16(cpu, address, 0);
|
||||
case 4:
|
||||
return cpu->memory.load32(cpu, address, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _writeMem(struct ARMCore* cpu, uint32_t address, int width, int32_t value) {
|
||||
switch (width) {
|
||||
case 1:
|
||||
cpu->memory.store8(cpu, address, value, 0);
|
||||
break;
|
||||
case 2:
|
||||
cpu->memory.store16(cpu, address, value, 0);
|
||||
break;
|
||||
case 4:
|
||||
cpu->memory.store32(cpu, address, value, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GBACheatRegisterLine(struct GBACheatSet* cheats, const char* line) {
|
||||
*StringListAppend(&cheats->lines) = strdup(line);
|
||||
}
|
||||
|
||||
static void _addBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
|
||||
static void _addBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) {
|
||||
if (!device->p || !cheats->hook) {
|
||||
return;
|
||||
}
|
||||
|
@ -59,10 +20,10 @@ static void _addBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* ch
|
|||
if (cheats->hook->reentries > 1) {
|
||||
return;
|
||||
}
|
||||
GBASetBreakpoint(device->p, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode);
|
||||
GBASetBreakpoint(device->p->board, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode);
|
||||
}
|
||||
|
||||
static void _removeBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
|
||||
static void _removeBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) {
|
||||
if (!device->p || !cheats->hook) {
|
||||
return;
|
||||
}
|
||||
|
@ -70,10 +31,10 @@ static void _removeBreakpoint(struct GBACheatDevice* device, struct GBACheatSet*
|
|||
if (cheats->hook->reentries > 0) {
|
||||
return;
|
||||
}
|
||||
GBAClearBreakpoint(device->p, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode);
|
||||
GBAClearBreakpoint(device->p->board, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode);
|
||||
}
|
||||
|
||||
static void _patchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
|
||||
static void _patchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) {
|
||||
if (!device->p) {
|
||||
return;
|
||||
}
|
||||
|
@ -87,7 +48,7 @@ static void _patchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats)
|
|||
}
|
||||
}
|
||||
|
||||
static void _unpatchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
|
||||
static void _unpatchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) {
|
||||
if (!device->p) {
|
||||
return;
|
||||
}
|
||||
|
@ -101,34 +62,17 @@ static void _unpatchROM(struct GBACheatDevice* device, struct GBACheatSet* cheat
|
|||
}
|
||||
}
|
||||
|
||||
static void GBACheatDeviceInit(void*, struct mCPUComponent*);
|
||||
static void GBACheatDeviceDeinit(struct mCPUComponent*);
|
||||
static void GBACheatSetDeinit(struct mCheatSet* set);
|
||||
static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device);
|
||||
static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device);
|
||||
static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device);
|
||||
static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet);
|
||||
static bool GBACheatAddLine(struct mCheatSet*, const char* line, int type);
|
||||
|
||||
void GBACheatDeviceCreate(struct GBACheatDevice* device) {
|
||||
device->d.id = GBA_CHEAT_DEVICE_ID;
|
||||
device->d.init = GBACheatDeviceInit;
|
||||
device->d.deinit = GBACheatDeviceDeinit;
|
||||
GBACheatSetsInit(&device->cheats, 4);
|
||||
}
|
||||
|
||||
void GBACheatDeviceDestroy(struct GBACheatDevice* device) {
|
||||
GBACheatDeviceClear(device);
|
||||
GBACheatSetsDeinit(&device->cheats);
|
||||
}
|
||||
|
||||
void GBACheatDeviceClear(struct GBACheatDevice* device) {
|
||||
size_t i;
|
||||
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
|
||||
GBACheatSetDeinit(set);
|
||||
free(set);
|
||||
}
|
||||
GBACheatSetsClear(&device->cheats);
|
||||
}
|
||||
|
||||
void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
|
||||
GBACheatListInit(&set->list, 4);
|
||||
StringListInit(&set->lines, 4);
|
||||
static struct mCheatSet* GBACheatSetCreate(struct mCheatDevice* device, const char* name) {
|
||||
UNUSED(device);
|
||||
struct GBACheatSet* set = malloc(sizeof(*set));
|
||||
mCheatSetInit(&set->d, name);
|
||||
set->incompleteCheat = 0;
|
||||
set->incompletePatch = 0;
|
||||
set->currentBlock = 0;
|
||||
|
@ -136,72 +80,58 @@ void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
|
|||
set->cbRngState = 0;
|
||||
set->cbMaster = 0;
|
||||
set->remainingAddresses = 0;
|
||||
set->hook = 0;
|
||||
set->hook = NULL;
|
||||
|
||||
set->d.deinit = GBACheatSetDeinit;
|
||||
set->d.add = GBACheatAddSet;
|
||||
set->d.remove = GBACheatRemoveSet;
|
||||
|
||||
set->d.addLine = GBACheatAddLine;
|
||||
set->d.copyProperties = GBACheatSetCopyProperties;
|
||||
|
||||
set->d.refresh = GBACheatRefresh;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_ROM_PATCHES; ++i) {
|
||||
set->romPatches[i].exists = false;
|
||||
}
|
||||
if (name) {
|
||||
set->name = strdup(name);
|
||||
} else {
|
||||
set->name = 0;
|
||||
}
|
||||
set->enabled = true;
|
||||
return &set->d;
|
||||
}
|
||||
|
||||
void GBACheatSetDeinit(struct GBACheatSet* set) {
|
||||
GBACheatListDeinit(&set->list);
|
||||
size_t i;
|
||||
for (i = 0; i < StringListSize(&set->lines); ++i) {
|
||||
free(*StringListGetPointer(&set->lines, i));
|
||||
}
|
||||
if (set->name) {
|
||||
free(set->name);
|
||||
}
|
||||
if (set->hook) {
|
||||
--set->hook->refs;
|
||||
if (set->hook->refs == 0) {
|
||||
free(set->hook);
|
||||
struct mCheatDevice* GBACheatDeviceCreate(void) {
|
||||
struct mCheatDevice* device = malloc(sizeof(*device));
|
||||
mCheatDeviceCreate(device);
|
||||
device->createSet = GBACheatSetCreate;
|
||||
return device;
|
||||
}
|
||||
|
||||
static void GBACheatSetDeinit(struct mCheatSet* set) {
|
||||
struct GBACheatSet* gbaset = (struct GBACheatSet*) set;
|
||||
if (gbaset->hook) {
|
||||
--gbaset->hook->refs;
|
||||
if (gbaset->hook->refs == 0) {
|
||||
free(gbaset->hook);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) {
|
||||
// TODO: Remove this function
|
||||
if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
|
||||
ARMHotplugDetach(gba->cpu, CPU_COMPONENT_CHEAT_DEVICE);
|
||||
}
|
||||
gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = &device->d;
|
||||
ARMHotplugAttach(gba->cpu, CPU_COMPONENT_CHEAT_DEVICE);
|
||||
static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
|
||||
_addBreakpoint(device, gbaset);
|
||||
_patchROM(device, gbaset);
|
||||
}
|
||||
|
||||
void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
|
||||
*GBACheatSetsAppend(&device->cheats) = cheats;
|
||||
_addBreakpoint(device, cheats);
|
||||
_patchROM(device, cheats);
|
||||
static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
|
||||
_unpatchROM(device, gbaset);
|
||||
_removeBreakpoint(device, gbaset);
|
||||
}
|
||||
|
||||
void GBACheatRemoveSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
|
||||
size_t i;
|
||||
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
|
||||
if (*GBACheatSetsGetPointer(&device->cheats, i) == cheats) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == GBACheatSetsSize(&device->cheats)) {
|
||||
return;
|
||||
}
|
||||
GBACheatSetsShift(&device->cheats, i, 1);
|
||||
_unpatchROM(device, cheats);
|
||||
_removeBreakpoint(device, cheats);
|
||||
}
|
||||
|
||||
bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
|
||||
static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
|
||||
uint32_t o1 = op1;
|
||||
uint32_t o2 = op2;
|
||||
char line[18] = "XXXXXXXX XXXXXXXX";
|
||||
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
|
||||
GBACheatRegisterLine(set, line);
|
||||
|
||||
switch (set->gsaVersion) {
|
||||
case 0:
|
||||
|
@ -229,147 +159,6 @@ bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GBACheatAutodetectLine(struct GBACheatSet* cheats, const char* line) {
|
||||
uint32_t op1;
|
||||
uint32_t op2;
|
||||
line = hex32(line, &op1);
|
||||
if (!line) {
|
||||
return false;
|
||||
}
|
||||
while (*line == ' ') {
|
||||
++line;
|
||||
}
|
||||
line = hex32(line, &op2);
|
||||
if (!line) {
|
||||
return false;
|
||||
}
|
||||
return GBACheatAddAutodetect(cheats, op1, op2);
|
||||
}
|
||||
|
||||
bool GBACheatParseFile(struct GBACheatDevice* device, struct VFile* vf) {
|
||||
char cheat[MAX_LINE_LENGTH];
|
||||
struct GBACheatSet* set = 0;
|
||||
struct GBACheatSet* newSet;
|
||||
int gsaVersion = 0;
|
||||
bool nextDisabled = false;
|
||||
bool reset = false;
|
||||
while (true) {
|
||||
size_t i = 0;
|
||||
ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat));
|
||||
if (bytesRead == 0) {
|
||||
break;
|
||||
}
|
||||
if (bytesRead < 0) {
|
||||
return false;
|
||||
}
|
||||
while (isspace((int) cheat[i])) {
|
||||
++i;
|
||||
}
|
||||
switch (cheat[i]) {
|
||||
case '#':
|
||||
do {
|
||||
++i;
|
||||
} while (isspace((int) cheat[i]));
|
||||
cheat[strlen(cheat) - 1] = '\0'; // Remove trailing newline
|
||||
newSet = malloc(sizeof(*set));
|
||||
GBACheatSetInit(newSet, &cheat[i]);
|
||||
newSet->enabled = !nextDisabled;
|
||||
nextDisabled = false;
|
||||
if (set) {
|
||||
GBACheatAddSet(device, set);
|
||||
}
|
||||
if (set && !reset) {
|
||||
GBACheatSetCopyProperties(newSet, set);
|
||||
} else {
|
||||
GBACheatSetGameSharkVersion(newSet, gsaVersion);
|
||||
}
|
||||
reset = false;
|
||||
set = newSet;
|
||||
break;
|
||||
case '!':
|
||||
do {
|
||||
++i;
|
||||
} while (isspace((int) cheat[i]));
|
||||
if (strncasecmp(&cheat[i], "GSAv", 4) == 0 || strncasecmp(&cheat[i], "PARv", 4) == 0) {
|
||||
i += 4;
|
||||
gsaVersion = atoi(&cheat[i]);
|
||||
break;
|
||||
}
|
||||
if (strcasecmp(&cheat[i], "disabled") == 0) {
|
||||
nextDisabled = true;
|
||||
break;
|
||||
}
|
||||
if (strcasecmp(&cheat[i], "reset") == 0) {
|
||||
reset = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!set) {
|
||||
set = malloc(sizeof(*set));
|
||||
GBACheatSetInit(set, 0);
|
||||
set->enabled = !nextDisabled;
|
||||
nextDisabled = false;
|
||||
GBACheatSetGameSharkVersion(set, gsaVersion);
|
||||
}
|
||||
GBACheatAddLine(set, cheat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (set) {
|
||||
GBACheatAddSet(device, set);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GBACheatSaveFile(struct GBACheatDevice* device, struct VFile* vf) {
|
||||
static const char lineStart[3] = "# ";
|
||||
static const char lineEnd = '\n';
|
||||
|
||||
struct GBACheatHook* lastHook = 0;
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
|
||||
if (lastHook && set->hook != lastHook) {
|
||||
static const char* resetDirective = "!reset\n";
|
||||
vf->write(vf, resetDirective, strlen(resetDirective));
|
||||
}
|
||||
switch (set->gsaVersion) {
|
||||
case 1: {
|
||||
static const char* versionDirective = "!GSAv1\n";
|
||||
vf->write(vf, versionDirective, strlen(versionDirective));
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
static const char* versionDirective = "!PARv3\n";
|
||||
vf->write(vf, versionDirective, strlen(versionDirective));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
lastHook = set->hook;
|
||||
if (!set->enabled) {
|
||||
static const char* disabledDirective = "!disabled\n";
|
||||
vf->write(vf, disabledDirective, strlen(disabledDirective));
|
||||
}
|
||||
|
||||
vf->write(vf, lineStart, 2);
|
||||
if (set->name) {
|
||||
vf->write(vf, set->name, strlen(set->name));
|
||||
}
|
||||
vf->write(vf, &lineEnd, 1);
|
||||
size_t c;
|
||||
for (c = 0; c < StringListSize(&set->lines); ++c) {
|
||||
const char* line = *StringListGetPointer(&set->lines, c);
|
||||
vf->write(vf, line, strlen(line));
|
||||
vf->write(vf, &lineEnd, 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GBACheatAddVBALine(struct GBACheatSet* cheats, const char* line) {
|
||||
uint32_t address;
|
||||
uint8_t op;
|
||||
|
@ -396,7 +185,7 @@ bool GBACheatAddVBALine(struct GBACheatSet* cheats, const char* line) {
|
|||
return false;
|
||||
}
|
||||
|
||||
struct GBACheat* cheat = GBACheatListAppend(&cheats->list);
|
||||
struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->address = address;
|
||||
cheat->operandOffset = 0;
|
||||
cheat->addressOffset = 0;
|
||||
|
@ -404,11 +193,26 @@ bool GBACheatAddVBALine(struct GBACheatSet* cheats, const char* line) {
|
|||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = width;
|
||||
cheat->operand = value;
|
||||
GBACheatRegisterLine(cheats, line);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GBACheatAddLine(struct GBACheatSet* cheats, const char* line) {
|
||||
bool GBACheatAddLine(struct mCheatSet* set, const char* line, int type) {
|
||||
struct GBACheatSet* cheats = (struct GBACheatSet*) set;
|
||||
switch (type) {
|
||||
case GBA_CHEAT_AUTODETECT:
|
||||
break;
|
||||
case GBA_CHEAT_CODEBREAKER:
|
||||
return GBACheatAddCodeBreakerLine(cheats, line);
|
||||
case GBA_CHEAT_GAMESHARK:
|
||||
return GBACheatAddGameSharkLine(cheats, line);
|
||||
case GBA_CHEAT_PRO_ACTION_REPLAY:
|
||||
return GBACheatAddProActionReplayLine(cheats, line);
|
||||
case GBA_CHEAT_VBA:
|
||||
return GBACheatAddVBALine(cheats, line);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t op1;
|
||||
uint16_t op2;
|
||||
uint16_t op3;
|
||||
|
@ -439,150 +243,28 @@ bool GBACheatAddLine(struct GBACheatSet* cheats, const char* line) {
|
|||
return GBACheatAddAutodetect(cheats, op1, realOp2);
|
||||
}
|
||||
|
||||
void GBACheatRefresh(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
|
||||
if (!cheats->enabled) {
|
||||
return;
|
||||
}
|
||||
bool condition = true;
|
||||
int conditionRemaining = 0;
|
||||
int negativeConditionRemaining = 0;
|
||||
_patchROM(device, cheats);
|
||||
|
||||
size_t nCodes = GBACheatListSize(&cheats->list);
|
||||
size_t i;
|
||||
for (i = 0; i < nCodes; ++i) {
|
||||
if (conditionRemaining > 0) {
|
||||
--conditionRemaining;
|
||||
if (!condition) {
|
||||
continue;
|
||||
}
|
||||
} else if (negativeConditionRemaining > 0) {
|
||||
conditionRemaining = negativeConditionRemaining - 1;
|
||||
negativeConditionRemaining = 0;
|
||||
condition = !condition;
|
||||
if (!condition) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
condition = true;
|
||||
}
|
||||
struct GBACheat* cheat = GBACheatListGetPointer(&cheats->list, i);
|
||||
int32_t value = 0;
|
||||
int32_t operand = cheat->operand;
|
||||
uint32_t operationsRemaining = cheat->repeat;
|
||||
uint32_t address = cheat->address;
|
||||
bool performAssignment = false;
|
||||
for (; operationsRemaining; --operationsRemaining) {
|
||||
switch (cheat->type) {
|
||||
case CHEAT_ASSIGN:
|
||||
value = operand;
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_ASSIGN_INDIRECT:
|
||||
value = operand;
|
||||
address = _readMem(device->p->cpu, address + cheat->addressOffset, 4);
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_AND:
|
||||
value = _readMem(device->p->cpu, address, cheat->width) & operand;
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_ADD:
|
||||
value = _readMem(device->p->cpu, address, cheat->width) + operand;
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_OR:
|
||||
value = _readMem(device->p->cpu, address, cheat->width) | operand;
|
||||
performAssignment = true;
|
||||
break;
|
||||
case CHEAT_IF_EQ:
|
||||
condition = _readMem(device->p->cpu, address, cheat->width) == operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_NE:
|
||||
condition = _readMem(device->p->cpu, address, cheat->width) != operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_LT:
|
||||
condition = _readMem(device->p->cpu, address, cheat->width) < operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_GT:
|
||||
condition = _readMem(device->p->cpu, address, cheat->width) > operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_ULT:
|
||||
condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) < (uint32_t) operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_UGT:
|
||||
condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) > (uint32_t) operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_AND:
|
||||
condition = _readMem(device->p->cpu, address, cheat->width) & operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
case CHEAT_IF_LAND:
|
||||
condition = _readMem(device->p->cpu, address, cheat->width) && operand;
|
||||
conditionRemaining = cheat->repeat;
|
||||
negativeConditionRemaining = cheat->negativeRepeat;
|
||||
break;
|
||||
}
|
||||
|
||||
if (performAssignment) {
|
||||
_writeMem(device->p->cpu, address, cheat->width, value);
|
||||
}
|
||||
|
||||
address += cheat->addressOffset;
|
||||
operand += cheat->operandOffset;
|
||||
}
|
||||
}
|
||||
static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
|
||||
_patchROM(device, gbaset);
|
||||
}
|
||||
|
||||
void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set) {
|
||||
newSet->gsaVersion = set->gsaVersion;
|
||||
memcpy(newSet->gsaSeeds, set->gsaSeeds, sizeof(newSet->gsaSeeds));
|
||||
newSet->cbRngState = set->cbRngState;
|
||||
newSet->cbMaster = set->cbMaster;
|
||||
memcpy(newSet->cbSeeds, set->cbSeeds, sizeof(newSet->cbSeeds));
|
||||
memcpy(newSet->cbTable, set->cbTable, sizeof(newSet->cbTable));
|
||||
if (set->hook) {
|
||||
static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
|
||||
struct GBACheatSet* newSet = (struct GBACheatSet*) set;
|
||||
struct GBACheatSet* gbaset = (struct GBACheatSet*) oldSet;
|
||||
newSet->gsaVersion = gbaset->gsaVersion;
|
||||
memcpy(newSet->gsaSeeds, gbaset->gsaSeeds, sizeof(newSet->gsaSeeds));
|
||||
newSet->cbRngState = gbaset->cbRngState;
|
||||
newSet->cbMaster = gbaset->cbMaster;
|
||||
memcpy(newSet->cbSeeds, gbaset->cbSeeds, sizeof(newSet->cbSeeds));
|
||||
memcpy(newSet->cbTable, gbaset->cbTable, sizeof(newSet->cbTable));
|
||||
if (gbaset->hook) {
|
||||
if (newSet->hook) {
|
||||
--newSet->hook->refs;
|
||||
if (newSet->hook->refs == 0) {
|
||||
free(newSet->hook);
|
||||
}
|
||||
}
|
||||
newSet->hook = set->hook;
|
||||
newSet->hook = gbaset->hook;
|
||||
++newSet->hook->refs;
|
||||
}
|
||||
}
|
||||
|
||||
void GBACheatDeviceInit(void* cpu, struct mCPUComponent* component) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) component;
|
||||
device->p = (struct GBA*) ((struct ARMCore*) cpu)->master;
|
||||
size_t i;
|
||||
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
|
||||
_addBreakpoint(device, cheats);
|
||||
_patchROM(device, cheats);
|
||||
}
|
||||
}
|
||||
|
||||
void GBACheatDeviceDeinit(struct mCPUComponent* component) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) component;
|
||||
size_t i;
|
||||
for (i = GBACheatSetsSize(&device->cheats); i--;) {
|
||||
struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
|
||||
_unpatchROM(device, cheats);
|
||||
_removeBreakpoint(device, cheats);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,25 +9,17 @@
|
|||
#include "util/common.h"
|
||||
|
||||
#include "arm/arm.h"
|
||||
#include "core/log.h"
|
||||
#include "core/cheats.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
#define MAX_ROM_PATCHES 4
|
||||
|
||||
enum GBACheatType {
|
||||
CHEAT_ASSIGN,
|
||||
CHEAT_ASSIGN_INDIRECT,
|
||||
CHEAT_AND,
|
||||
CHEAT_ADD,
|
||||
CHEAT_OR,
|
||||
CHEAT_IF_EQ,
|
||||
CHEAT_IF_NE,
|
||||
CHEAT_IF_LT,
|
||||
CHEAT_IF_GT,
|
||||
CHEAT_IF_ULT,
|
||||
CHEAT_IF_UGT,
|
||||
CHEAT_IF_AND,
|
||||
CHEAT_IF_LAND
|
||||
GBA_CHEAT_AUTODETECT,
|
||||
GBA_CHEAT_CODEBREAKER,
|
||||
GBA_CHEAT_GAMESHARK,
|
||||
GBA_CHEAT_PRO_ACTION_REPLAY,
|
||||
GBA_CHEAT_VBA
|
||||
};
|
||||
|
||||
enum GBACodeBreakerType {
|
||||
|
@ -132,18 +124,6 @@ enum {
|
|||
PAR3_WIDTH_BASE = 25
|
||||
};
|
||||
|
||||
struct GBACheat {
|
||||
enum GBACheatType type;
|
||||
int width;
|
||||
uint32_t address;
|
||||
uint32_t operand;
|
||||
uint32_t repeat;
|
||||
uint32_t negativeRepeat;
|
||||
|
||||
int32_t addressOffset;
|
||||
int32_t operandOffset;
|
||||
};
|
||||
|
||||
struct GBACheatHook {
|
||||
uint32_t address;
|
||||
enum ExecutionMode mode;
|
||||
|
@ -152,14 +132,9 @@ struct GBACheatHook {
|
|||
size_t reentries;
|
||||
};
|
||||
|
||||
mLOG_DECLARE_CATEGORY(CHEATS);
|
||||
|
||||
DECLARE_VECTOR(GBACheatList, struct GBACheat);
|
||||
DECLARE_VECTOR(StringList, char*);
|
||||
|
||||
struct GBACheatSet {
|
||||
struct mCheatSet d;
|
||||
struct GBACheatHook* hook;
|
||||
struct GBACheatList list;
|
||||
|
||||
struct GBACheatPatch {
|
||||
uint32_t address;
|
||||
|
@ -169,9 +144,9 @@ struct GBACheatSet {
|
|||
bool exists;
|
||||
} romPatches[MAX_ROM_PATCHES];
|
||||
|
||||
struct GBACheat* incompleteCheat;
|
||||
struct mCheat* incompleteCheat;
|
||||
struct GBACheatPatch* incompletePatch;
|
||||
struct GBACheat* currentBlock;
|
||||
struct mCheat* currentBlock;
|
||||
|
||||
int gsaVersion;
|
||||
uint32_t gsaSeeds[4];
|
||||
|
@ -180,35 +155,11 @@ struct GBACheatSet {
|
|||
uint8_t cbTable[0x30];
|
||||
uint32_t cbSeeds[4];
|
||||
int remainingAddresses;
|
||||
|
||||
char* name;
|
||||
bool enabled;
|
||||
struct StringList lines;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(GBACheatSets, struct GBACheatSet*);
|
||||
|
||||
struct GBACheatDevice {
|
||||
struct mCPUComponent d;
|
||||
struct GBA* p;
|
||||
|
||||
struct GBACheatSets cheats;
|
||||
};
|
||||
|
||||
struct VFile;
|
||||
|
||||
void GBACheatDeviceCreate(struct GBACheatDevice*);
|
||||
void GBACheatDeviceDestroy(struct GBACheatDevice*);
|
||||
void GBACheatDeviceClear(struct GBACheatDevice*);
|
||||
|
||||
void GBACheatSetInit(struct GBACheatSet*, const char* name);
|
||||
void GBACheatSetDeinit(struct GBACheatSet*);
|
||||
|
||||
void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice*);
|
||||
|
||||
void GBACheatAddSet(struct GBACheatDevice*, struct GBACheatSet*);
|
||||
void GBACheatRemoveSet(struct GBACheatDevice*, struct GBACheatSet*);
|
||||
void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set);
|
||||
struct mCheatDevice* GBACheatDeviceCreate(void);
|
||||
|
||||
bool GBACheatAddCodeBreaker(struct GBACheatSet*, uint32_t op1, uint16_t op2);
|
||||
bool GBACheatAddCodeBreakerLine(struct GBACheatSet*, const char* line);
|
||||
|
@ -221,13 +172,4 @@ bool GBACheatAddProActionReplayLine(struct GBACheatSet*, const char* line);
|
|||
|
||||
bool GBACheatAddVBALine(struct GBACheatSet*, const char* line);
|
||||
|
||||
bool GBACheatAddAutodetect(struct GBACheatSet*, uint32_t op1, uint32_t op2);
|
||||
|
||||
bool GBACheatParseFile(struct GBACheatDevice*, struct VFile*);
|
||||
bool GBACheatSaveFile(struct GBACheatDevice*, struct VFile*);
|
||||
|
||||
bool GBACheatAddLine(struct GBACheatSet*, const char* line);
|
||||
|
||||
void GBACheatRefresh(struct GBACheatDevice*, struct GBACheatSet*);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef GBA_CHEATS_PRIVATE_H
|
||||
#define GBA_CHEATS_PRIVATE_H
|
||||
|
||||
#include "gba/cheats.h"
|
||||
|
||||
void GBACheatRegisterLine(struct GBACheatSet* set, const char* line);
|
||||
|
||||
#endif
|
|
@ -5,7 +5,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "gba/cheats.h"
|
||||
|
||||
#include "gba/cheats/cheats-private.h"
|
||||
#include "gba/gba.h"
|
||||
#include "gba/io.h"
|
||||
#include "util/string.h"
|
||||
|
@ -190,14 +189,13 @@ static void _cbReseed(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
|
|||
bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
|
||||
char line[14] = "XXXXXXXX XXXX";
|
||||
snprintf(line, sizeof(line), "%08X %04X", op1, op2);
|
||||
GBACheatRegisterLine(cheats, line);
|
||||
|
||||
if (cheats->cbMaster) {
|
||||
_cbDecrypt(cheats, &op1, &op2);
|
||||
}
|
||||
|
||||
enum GBACodeBreakerType type = op1 >> 28;
|
||||
struct GBACheat* cheat = 0;
|
||||
struct mCheat* cheat = NULL;
|
||||
|
||||
if (cheats->incompleteCheat) {
|
||||
cheats->incompleteCheat->repeat = op1 & 0xFFFF;
|
||||
|
@ -222,17 +220,17 @@ bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t o
|
|||
cheats->hook->reentries = 0;
|
||||
return true;
|
||||
case CB_OR_2:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_OR;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
case CB_ASSIGN_1:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 1;
|
||||
break;
|
||||
case CB_FILL:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 2;
|
||||
cheats->incompleteCheat = cheat;
|
||||
|
@ -241,17 +239,17 @@ bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t o
|
|||
mLOG(CHEATS, STUB, "CodeBreaker code %08X %04X not supported", op1, op2);
|
||||
return false;
|
||||
case CB_AND_2:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_AND;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
case CB_IF_EQ:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_IF_EQ;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
case CB_ASSIGN_2:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
|
@ -259,24 +257,24 @@ bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t o
|
|||
_cbReseed(cheats, op1, op2);
|
||||
return true;
|
||||
case CB_IF_NE:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_IF_NE;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
case CB_IF_GT:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_IF_GT;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
case CB_IF_LT:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_IF_LT;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
case CB_IF_SPECIAL:
|
||||
switch (op1 & 0x0FFFFFFF) {
|
||||
case 0x20:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_IF_AND;
|
||||
cheat->width = 2;
|
||||
cheat->address = BASE_IO | REG_JOYSTAT;
|
||||
|
@ -288,12 +286,12 @@ bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t o
|
|||
return false;
|
||||
}
|
||||
case CB_ADD_2:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ADD;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
case CB_IF_AND:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_IF_AND;
|
||||
cheat->width = 2;
|
||||
break;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "gameshark.h"
|
||||
|
||||
#include "gba/cheats/cheats-private.h"
|
||||
#include "gba/cheats/parv3.h"
|
||||
#include "gba/gba.h"
|
||||
#include "util/string.h"
|
||||
|
@ -90,11 +89,11 @@ void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, int version) {
|
|||
|
||||
bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
|
||||
enum GBAGameSharkType type = op1 >> 28;
|
||||
struct GBACheat* cheat = 0;
|
||||
struct mCheat* cheat = 0;
|
||||
|
||||
if (cheats->incompleteCheat) {
|
||||
if (cheats->remainingAddresses > 0) {
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 4;
|
||||
cheat->address = op1;
|
||||
|
@ -103,7 +102,7 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
|
|||
--cheats->remainingAddresses;
|
||||
}
|
||||
if (cheats->remainingAddresses > 0) {
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 4;
|
||||
cheat->address = op2;
|
||||
|
@ -119,26 +118,26 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
|
|||
|
||||
switch (type) {
|
||||
case GSA_ASSIGN_1:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 1;
|
||||
cheat->address = op1 & 0x0FFFFFFF;
|
||||
break;
|
||||
case GSA_ASSIGN_2:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 2;
|
||||
cheat->address = op1 & 0x0FFFFFFF;
|
||||
break;
|
||||
case GSA_ASSIGN_4:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 4;
|
||||
cheat->address = op1 & 0x0FFFFFFF;
|
||||
break;
|
||||
case GSA_ASSIGN_LIST:
|
||||
cheats->remainingAddresses = (op1 & 0xFFFF) - 1;
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 4;
|
||||
cheat->address = op2;
|
||||
|
@ -159,13 +158,13 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
|
|||
GBACheatReseedGameShark(cheats->gsaSeeds, op2, _gsa1T1, _gsa1T2);
|
||||
return true;
|
||||
}
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_IF_EQ;
|
||||
cheat->width = 2;
|
||||
cheat->address = op1 & 0x0FFFFFFF;
|
||||
break;
|
||||
case GSA_IF_EQ_RANGE:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->type = CHEAT_IF_EQ;
|
||||
cheat->width = 2;
|
||||
cheat->address = op2 & 0x0FFFFFFF;
|
||||
|
@ -195,7 +194,6 @@ bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
|
|||
uint32_t o2 = op2;
|
||||
char line[18] = "XXXXXXXX XXXXXXXX";
|
||||
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
|
||||
GBACheatRegisterLine(set, line);
|
||||
|
||||
switch (set->gsaVersion) {
|
||||
case 0:
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "parv3.h"
|
||||
|
||||
#include "gba/cheats/cheats-private.h"
|
||||
#include "gba/cheats/gameshark.h"
|
||||
#include "gba/gba.h"
|
||||
#include "util/string.h"
|
||||
|
@ -54,7 +53,7 @@ static uint32_t _parAddr(uint32_t x) {
|
|||
}
|
||||
|
||||
static void _parEndBlock(struct GBACheatSet* cheats) {
|
||||
size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock);
|
||||
size_t size = mCheatListSize(&cheats->d.list) - mCheatListIndex(&cheats->d.list, cheats->currentBlock);
|
||||
if (cheats->currentBlock->repeat) {
|
||||
cheats->currentBlock->negativeRepeat = size - cheats->currentBlock->repeat;
|
||||
} else {
|
||||
|
@ -64,7 +63,7 @@ static void _parEndBlock(struct GBACheatSet* cheats) {
|
|||
}
|
||||
|
||||
static void _parElseBlock(struct GBACheatSet* cheats) {
|
||||
size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock);
|
||||
size_t size = mCheatListSize(&cheats->d.list) - mCheatListIndex(&cheats->d.list, cheats->currentBlock);
|
||||
cheats->currentBlock->repeat = size;
|
||||
}
|
||||
|
||||
|
@ -80,7 +79,7 @@ static bool _addPAR3Cond(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2)
|
|||
return false;
|
||||
}
|
||||
|
||||
struct GBACheat* cheat = GBACheatListAppend(&cheats->list);
|
||||
struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->address = _parAddr(op1);
|
||||
cheat->width = width;
|
||||
cheat->operand = op2 & (0xFFFFFFFFU >> ((4 - width) * 8));
|
||||
|
@ -139,7 +138,7 @@ static bool _addPAR3Cond(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2)
|
|||
}
|
||||
|
||||
static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
|
||||
struct GBACheat* cheat;
|
||||
struct mCheat* cheat;
|
||||
switch (op2 & 0xFF000000) {
|
||||
case PAR3_OTHER_SLOWDOWN:
|
||||
// TODO: Slowdown
|
||||
|
@ -188,19 +187,19 @@ static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
|
|||
}
|
||||
return false;
|
||||
case PAR3_OTHER_FILL_1:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->address = _parAddr(op2);
|
||||
cheat->width = 1;
|
||||
cheats->incompleteCheat = cheat;
|
||||
break;
|
||||
case PAR3_OTHER_FILL_2:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->address = _parAddr(op2);
|
||||
cheat->width = 2;
|
||||
cheats->incompleteCheat = cheat;
|
||||
break;
|
||||
case PAR3_OTHER_FILL_4:
|
||||
cheat = GBACheatListAppend(&cheats->list);
|
||||
cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->address = _parAddr(op2);
|
||||
cheat->width = 3;
|
||||
cheats->incompleteCheat = cheat;
|
||||
|
@ -253,7 +252,7 @@ bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uin
|
|||
}
|
||||
|
||||
int width = 1 << ((op1 & PAR3_WIDTH) >> PAR3_WIDTH_BASE);
|
||||
struct GBACheat* cheat = GBACheatListAppend(&cheats->list);
|
||||
struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
|
||||
cheat->address = _parAddr(op1);
|
||||
cheat->operandOffset = 0;
|
||||
cheat->addressOffset = 0;
|
||||
|
@ -293,7 +292,6 @@ bool GBACheatAddProActionReplay(struct GBACheatSet* set, uint32_t op1, uint32_t
|
|||
uint32_t o2 = op2;
|
||||
char line[18] = "XXXXXXXX XXXXXXXX";
|
||||
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
|
||||
GBACheatRegisterLine(set, line);
|
||||
|
||||
switch (set->gsaVersion) {
|
||||
case 0:
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "core/core.h"
|
||||
#include "core/log.h"
|
||||
#include "gba/cheats.h"
|
||||
#include "gba/gba.h"
|
||||
#include "gba/extra/cli.h"
|
||||
#include "gba/overrides.h"
|
||||
|
@ -23,6 +24,7 @@ struct GBACore {
|
|||
struct mCPUComponent* components[CPU_COMPONENT_MAX];
|
||||
const struct Configuration* overrides;
|
||||
struct mDebuggerPlatform* debuggerPlatform;
|
||||
struct mCheatDevice* cheatDevice;
|
||||
};
|
||||
|
||||
static bool _GBACoreInit(struct mCore* core) {
|
||||
|
@ -38,8 +40,9 @@ static bool _GBACoreInit(struct mCore* core) {
|
|||
core->cpu = cpu;
|
||||
core->board = gba;
|
||||
core->debugger = NULL;
|
||||
gbacore->overrides = NULL;
|
||||
gbacore->debuggerPlatform = NULL;
|
||||
gbacore->overrides = 0;
|
||||
gbacore->cheatDevice = NULL;
|
||||
|
||||
GBACreate(gba);
|
||||
// TODO: Restore cheats
|
||||
|
@ -68,6 +71,13 @@ static void _GBACoreDeinit(struct mCore* core) {
|
|||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
mDirectorySetDeinit(&core->dirs);
|
||||
#endif
|
||||
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
free(gbacore->debuggerPlatform);
|
||||
if (gbacore->cheatDevice) {
|
||||
mCheatDeviceDestroy(gbacore->cheatDevice);
|
||||
}
|
||||
free(gbacore->cheatDevice);
|
||||
free(core);
|
||||
}
|
||||
|
||||
|
@ -401,6 +411,17 @@ static void _GBACoreDetachDebugger(struct mCore* core) {
|
|||
core->debugger = NULL;
|
||||
}
|
||||
|
||||
static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) {
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
if (!gbacore->cheatDevice) {
|
||||
gbacore->cheatDevice = GBACheatDeviceCreate();
|
||||
((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d;
|
||||
ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
|
||||
gbacore->cheatDevice->p = core;
|
||||
}
|
||||
return gbacore->cheatDevice;
|
||||
}
|
||||
|
||||
struct mCore* GBACoreCreate(void) {
|
||||
struct GBACore* gbacore = malloc(sizeof(*gbacore));
|
||||
struct mCore* core = &gbacore->d;
|
||||
|
@ -460,5 +481,6 @@ struct mCore* GBACoreCreate(void) {
|
|||
core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
|
||||
core->attachDebugger = _GBACoreAttachDebugger;
|
||||
core->detachDebugger = _GBACoreDetachDebugger;
|
||||
core->cheatDevice = _GBACoreCheatDevice;
|
||||
return core;
|
||||
}
|
||||
|
|
|
@ -774,13 +774,13 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) {
|
|||
break;
|
||||
case CPU_COMPONENT_CHEAT_DEVICE:
|
||||
if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
struct GBACheatHook* hook = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
|
||||
for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i);
|
||||
if (cheats->hook && cheats->hook->address == _ARMPCAddress(cpu)) {
|
||||
GBACheatRefresh(device, cheats);
|
||||
mCheatRefresh(device, &cheats->d);
|
||||
hook = cheats->hook;
|
||||
}
|
||||
}
|
||||
|
@ -808,12 +808,12 @@ void GBAFrameEnded(struct GBA* gba) {
|
|||
}
|
||||
|
||||
if (gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
size_t i;
|
||||
for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
|
||||
for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i);
|
||||
if (!cheats->hook) {
|
||||
GBACheatRefresh(device, cheats);
|
||||
mCheatRefresh(device, &cheats->d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -383,10 +383,10 @@ bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, int flags) {
|
|||
}
|
||||
struct VFile* cheatVf = 0;
|
||||
if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
cheatVf = VFileMemChunk(0, 0);
|
||||
if (cheatVf) {
|
||||
GBACheatSaveFile(device, cheatVf);
|
||||
mCheatSaveFile(device, cheatVf);
|
||||
struct GBAExtdataItem item = {
|
||||
.size = cheatVf->size(cheatVf),
|
||||
.data = cheatVf->map(cheatVf, cheatVf->size(cheatVf), MAP_READ),
|
||||
|
@ -479,11 +479,11 @@ bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf, int flags) {
|
|||
}
|
||||
if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE] && GBAExtdataGet(&extdata, EXTDATA_CHEATS, &item)) {
|
||||
if (item.size) {
|
||||
struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
|
||||
struct VFile* svf = VFileFromMemory(item.data, item.size);
|
||||
if (svf) {
|
||||
GBACheatDeviceClear(device);
|
||||
GBACheatParseFile(device, svf);
|
||||
mCheatDeviceClear(device);
|
||||
mCheatParseFile(device, svf);
|
||||
svf->close(svf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
#include <QSet>
|
||||
|
||||
extern "C" {
|
||||
#include "gba/cheats.h"
|
||||
#include "core/cheats.h"
|
||||
}
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
CheatsModel::CheatsModel(GBACheatDevice* device, QObject* parent)
|
||||
CheatsModel::CheatsModel(mCheatDevice* device, QObject* parent)
|
||||
: QAbstractItemModel(parent)
|
||||
, m_device(device)
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ QVariant CheatsModel::data(const QModelIndex& index, int role) const {
|
|||
|
||||
if (index.parent().isValid()) {
|
||||
int row = index.row();
|
||||
GBACheatSet* cheats = static_cast<GBACheatSet*>(index.internalPointer());
|
||||
mCheatSet* cheats = static_cast<mCheatSet*>(index.internalPointer());
|
||||
const char* line = *StringListGetPointer(&cheats->lines, row);
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
|
@ -42,12 +42,12 @@ QVariant CheatsModel::data(const QModelIndex& index, int role) const {
|
|||
}
|
||||
}
|
||||
|
||||
if (index.row() >= GBACheatSetsSize(&m_device->cheats)) {
|
||||
if (index.row() >= mCheatSetsSize(&m_device->cheats)) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int row = index.row();
|
||||
const GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
const mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
|
@ -60,20 +60,16 @@ QVariant CheatsModel::data(const QModelIndex& index, int role) const {
|
|||
}
|
||||
|
||||
bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
||||
if (!index.isValid() || index.parent().isValid() || index.row() > GBACheatSetsSize(&m_device->cheats)) {
|
||||
if (!index.isValid() || index.parent().isValid() || index.row() > mCheatSetsSize(&m_device->cheats)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int row = index.row();
|
||||
GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
if (cheats->name) {
|
||||
free(cheats->name);
|
||||
cheats->name = nullptr;
|
||||
}
|
||||
cheats->name = strdup(value.toString().toUtf8().constData());
|
||||
mCheatSetRename(cheats, value.toString().toUtf8().constData());
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
case Qt::CheckStateRole:
|
||||
|
@ -87,7 +83,7 @@ bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int r
|
|||
|
||||
QModelIndex CheatsModel::index(int row, int column, const QModelIndex& parent) const {
|
||||
if (parent.isValid()) {
|
||||
return createIndex(row, column, *GBACheatSetsGetPointer(&m_device->cheats, parent.row()));
|
||||
return createIndex(row, column, *mCheatSetsGetPointer(&m_device->cheats, parent.row()));
|
||||
} else {
|
||||
return createIndex(row, column, nullptr);
|
||||
}
|
||||
|
@ -97,12 +93,12 @@ QModelIndex CheatsModel::parent(const QModelIndex& index) const {
|
|||
if (!index.isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
const GBACheatSet* cheats = static_cast<const GBACheatSet*>(index.internalPointer());
|
||||
const mCheatSet* cheats = static_cast<const mCheatSet*>(index.internalPointer());
|
||||
if (!cheats) {
|
||||
return QModelIndex();
|
||||
}
|
||||
for (size_t i = 0; i < GBACheatSetsSize(&m_device->cheats); ++i) {
|
||||
if (cheats == *GBACheatSetsGetPointer(&m_device->cheats, i)) {
|
||||
for (size_t i = 0; i < mCheatSetsSize(&m_device->cheats); ++i) {
|
||||
if (cheats == *mCheatSetsGetPointer(&m_device->cheats, i)) {
|
||||
return createIndex(i, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -130,45 +126,44 @@ int CheatsModel::rowCount(const QModelIndex& parent) const {
|
|||
if (parent.internalPointer()) {
|
||||
return 0;
|
||||
}
|
||||
const GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, parent.row());
|
||||
const mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, parent.row());
|
||||
return StringListSize(&set->lines);
|
||||
}
|
||||
return GBACheatSetsSize(&m_device->cheats);
|
||||
return mCheatSetsSize(&m_device->cheats);
|
||||
}
|
||||
|
||||
GBACheatSet* CheatsModel::itemAt(const QModelIndex& index) {
|
||||
mCheatSet* CheatsModel::itemAt(const QModelIndex& index) {
|
||||
if (!index.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (index.parent().isValid()) {
|
||||
return static_cast<GBACheatSet*>(index.internalPointer());
|
||||
return static_cast<mCheatSet*>(index.internalPointer());
|
||||
}
|
||||
if (index.row() >= GBACheatSetsSize(&m_device->cheats)) {
|
||||
if (index.row() >= mCheatSetsSize(&m_device->cheats)) {
|
||||
return nullptr;
|
||||
}
|
||||
return *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
return *mCheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
}
|
||||
|
||||
void CheatsModel::removeAt(const QModelIndex& index) {
|
||||
if (!index.isValid() || index.parent().isValid() || index.row() >= GBACheatSetsSize(&m_device->cheats)) {
|
||||
if (!index.isValid() || index.parent().isValid() || index.row() >= mCheatSetsSize(&m_device->cheats)) {
|
||||
return;
|
||||
}
|
||||
int row = index.row();
|
||||
GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
GBACheatRemoveSet(m_device, set);
|
||||
GBACheatSetDeinit(set);
|
||||
delete set;
|
||||
mCheatRemoveSet(m_device, set);
|
||||
mCheatSetDeinit(set);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
QString CheatsModel::toString(const QModelIndexList& indices) const {
|
||||
QMap<int, GBACheatSet*> setOrder;
|
||||
QMap<GBACheatSet*, QSet<size_t>> setIndices;
|
||||
QMap<int, mCheatSet*> setOrder;
|
||||
QMap<mCheatSet*, QSet<size_t>> setIndices;
|
||||
for (const QModelIndex& index : indices) {
|
||||
GBACheatSet* set = static_cast<GBACheatSet*>(index.internalPointer());
|
||||
mCheatSet* set = static_cast<mCheatSet*>(index.internalPointer());
|
||||
if (!set) {
|
||||
set = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
set = *mCheatSetsGetPointer(&m_device->cheats, index.row());
|
||||
setOrder[index.row()] = set;
|
||||
QSet<size_t> range;
|
||||
for (size_t i = 0; i < StringListSize(&set->lines); ++i) {
|
||||
|
@ -185,7 +180,7 @@ QString CheatsModel::toString(const QModelIndexList& indices) const {
|
|||
QList<int> order = setOrder.keys();
|
||||
std::sort(order.begin(), order.end());
|
||||
for (int i : order) {
|
||||
GBACheatSet* set = setOrder[i];
|
||||
mCheatSet* set = setOrder[i];
|
||||
QList<size_t> indexOrdex = setIndices[set].toList();
|
||||
std::sort(indexOrdex.begin(), indexOrdex.end());
|
||||
for (size_t j : indexOrdex) {
|
||||
|
@ -215,7 +210,7 @@ void CheatsModel::loadFile(const QString& path) {
|
|||
return;
|
||||
}
|
||||
beginResetModel();
|
||||
GBACheatParseFile(m_device, vf);
|
||||
mCheatParseFile(m_device, vf);
|
||||
endResetModel();
|
||||
vf->close(vf);
|
||||
}
|
||||
|
@ -225,17 +220,17 @@ void CheatsModel::saveFile(const QString& path) {
|
|||
if (!vf) {
|
||||
return;
|
||||
}
|
||||
GBACheatSaveFile(m_device, vf);
|
||||
mCheatSaveFile(m_device, vf);
|
||||
vf->close(vf);
|
||||
}
|
||||
|
||||
void CheatsModel::addSet(GBACheatSet* set) {
|
||||
beginInsertRows(QModelIndex(), GBACheatSetsSize(&m_device->cheats), GBACheatSetsSize(&m_device->cheats));
|
||||
size_t size = GBACheatSetsSize(&m_device->cheats);
|
||||
void CheatsModel::addSet(mCheatSet* set) {
|
||||
beginInsertRows(QModelIndex(), mCheatSetsSize(&m_device->cheats), mCheatSetsSize(&m_device->cheats));
|
||||
size_t size = mCheatSetsSize(&m_device->cheats);
|
||||
if (size) {
|
||||
GBACheatSetCopyProperties(set, *GBACheatSetsGetPointer(&m_device->cheats, size - 1));
|
||||
set->copyProperties(set, *mCheatSetsGetPointer(&m_device->cheats, size - 1));
|
||||
}
|
||||
GBACheatAddSet(m_device, set);
|
||||
mCheatAddSet(m_device, set);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
struct GBACheatDevice;
|
||||
struct GBACheatSet;
|
||||
struct mCheatDevice;
|
||||
struct mCheatSet;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
|
@ -17,7 +17,7 @@ class CheatsModel : public QAbstractItemModel {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheatsModel(GBACheatDevice* m_device, QObject* parent = nullptr);
|
||||
CheatsModel(mCheatDevice* m_device, QObject* parent = nullptr);
|
||||
|
||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
||||
|
@ -29,7 +29,7 @@ public:
|
|||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
GBACheatSet* itemAt(const QModelIndex& index);
|
||||
mCheatSet* itemAt(const QModelIndex& index);
|
||||
void removeAt(const QModelIndex& index);
|
||||
QString toString(const QModelIndexList& indices) const;
|
||||
|
||||
|
@ -39,15 +39,15 @@ public:
|
|||
void loadFile(const QString& path);
|
||||
void saveFile(const QString& path);
|
||||
|
||||
void addSet(GBACheatSet* set);
|
||||
void addSet(mCheatSet* set);
|
||||
|
||||
public slots:
|
||||
void invalidated();
|
||||
|
||||
private:
|
||||
GBACheatDevice* m_device;
|
||||
mCheatDevice* m_device;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
#include <QClipboard>
|
||||
|
||||
extern "C" {
|
||||
#include "core/cheats.h"
|
||||
#ifdef M_CORE_GBA
|
||||
#include "gba/cheats.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace QGBA;
|
||||
|
@ -34,19 +37,19 @@ CheatsView::CheatsView(GameController* controller, QWidget* parent)
|
|||
connect(controller, SIGNAL(stateLoaded(mCoreThread*)), &m_model, SLOT(invalidated()));
|
||||
|
||||
connect(m_ui.add, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GBACheatAddLine);
|
||||
enterCheat(GBA_CHEAT_AUTODETECT);
|
||||
});
|
||||
|
||||
connect(m_ui.addGSA, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GBACheatAddGameSharkLine);
|
||||
enterCheat(GBA_CHEAT_GAMESHARK);
|
||||
});
|
||||
|
||||
connect(m_ui.addPAR, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GBACheatAddProActionReplayLine);
|
||||
enterCheat(GBA_CHEAT_PRO_ACTION_REPLAY);
|
||||
});
|
||||
|
||||
connect(m_ui.addCB, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GBACheatAddCodeBreakerLine);
|
||||
enterCheat(GBA_CHEAT_CODEBREAKER);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -79,9 +82,8 @@ void CheatsView::save() {
|
|||
}
|
||||
|
||||
void CheatsView::addSet() {
|
||||
GBACheatSet* set = new GBACheatSet;
|
||||
GBACheatSetInit(set, nullptr);
|
||||
m_controller->threadInterrupt();
|
||||
mCheatSet* set = m_controller->cheatDevice()->createSet(m_controller->cheatDevice(), nullptr);
|
||||
m_model.addSet(set);
|
||||
m_controller->threadContinue();
|
||||
}
|
||||
|
@ -99,13 +101,12 @@ void CheatsView::removeSet() {
|
|||
m_controller->threadContinue();
|
||||
}
|
||||
|
||||
void CheatsView::enterCheat(std::function<bool(GBACheatSet*, const char*)> callback) {
|
||||
GBACheatSet* set = nullptr;
|
||||
void CheatsView::enterCheat(int codeType) {
|
||||
mCheatSet* set = nullptr;
|
||||
QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes();
|
||||
QModelIndex index;
|
||||
if (selection.count() == 0) {
|
||||
set = new GBACheatSet;
|
||||
GBACheatSetInit(set, nullptr);
|
||||
set = m_controller->cheatDevice()->createSet(m_controller->cheatDevice(), nullptr);
|
||||
} else if (selection.count() == 1) {
|
||||
index = selection[0];
|
||||
set = m_model.itemAt(index);
|
||||
|
@ -123,7 +124,7 @@ void CheatsView::enterCheat(std::function<bool(GBACheatSet*, const char*)> callb
|
|||
QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', QString::SkipEmptyParts);
|
||||
for (const QString& string : cheats) {
|
||||
m_model.beginAppendRow(index);
|
||||
callback(set, string.toUtf8().constData());
|
||||
mCheatAddLine(set, string.toUtf8().constData(), codeType);
|
||||
m_model.endAppendRow();
|
||||
}
|
||||
m_controller->threadContinue();
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "ui_CheatsView.h"
|
||||
|
||||
struct GBACheatDevice;
|
||||
struct mCheatDevice;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
|
@ -35,7 +35,7 @@ private slots:
|
|||
void removeSet();
|
||||
|
||||
private:
|
||||
void enterCheat(std::function<bool(GBACheatSet*, const char*)> callback);
|
||||
void enterCheat(int codeType);
|
||||
|
||||
Ui::CheatsView m_ui;
|
||||
GameController* m_controller;
|
||||
|
@ -44,4 +44,4 @@ private:
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -69,8 +69,6 @@ GameController::GameController(QObject* parent)
|
|||
, m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS)
|
||||
, m_loadStateFlags(SAVESTATE_SCREENSHOT)
|
||||
{
|
||||
GBACheatDeviceCreate(&m_cheatDevice);
|
||||
|
||||
m_lux.p = this;
|
||||
m_lux.sample = [](GBALuminanceSource* context) {
|
||||
GameControllerLux* lux = static_cast<GameControllerLux*>(context);
|
||||
|
@ -235,7 +233,6 @@ GameController::~GameController() {
|
|||
disconnect();
|
||||
clearMultiplayerController();
|
||||
closeGame();
|
||||
GBACheatDeviceDestroy(&m_cheatDevice);
|
||||
delete m_backupLoadState;
|
||||
}
|
||||
|
||||
|
@ -476,13 +473,6 @@ void GameController::closeGame() {
|
|||
|
||||
m_patch = QString();
|
||||
|
||||
for (size_t i = 0; i < GBACheatSetsSize(&m_cheatDevice.cheats); ++i) {
|
||||
GBACheatSet* set = *GBACheatSetsGetPointer(&m_cheatDevice.cheats, i);
|
||||
GBACheatSetDeinit(set);
|
||||
delete set;
|
||||
}
|
||||
GBACheatSetsClear(&m_cheatDevice.cheats);
|
||||
|
||||
m_threadContext.core->deinit(m_threadContext.core);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
|
||||
const uint32_t* drawContext() const { return m_drawContext; }
|
||||
mCoreThread* thread() { return &m_threadContext; }
|
||||
GBACheatDevice* cheatDevice() { return &m_cheatDevice; }
|
||||
mCheatDevice* cheatDevice() { return m_threadContext.core ? m_threadContext.core->cheatDevice(m_threadContext.core) : nullptr; }
|
||||
|
||||
void threadInterrupt();
|
||||
void threadContinue();
|
||||
|
@ -174,7 +174,7 @@ private:
|
|||
uint32_t* m_frontBuffer;
|
||||
mCoreThread m_threadContext;
|
||||
const mCoreConfig* m_config;
|
||||
GBACheatDevice m_cheatDevice;
|
||||
mCheatDevice* m_cheatDevice;
|
||||
int m_activeKeys;
|
||||
int m_activeButtons;
|
||||
int m_inactiveKeys;
|
||||
|
|
Loading…
Reference in New Issue