all repos — mgba @ 54e4d914575be4ad901fa451a91305777c23fdf6

mGBA Game Boy Advance Emulator

src/gb/cheats.c (view raw)

  1/* Copyright (c) 2013-2016 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "cheats.h"
  7
  8#include "core/core.h"
  9#include "gb/memory.h"
 10#include "util/string.h"
 11
 12DEFINE_VECTOR(GBCheatPatchList, struct GBCheatPatch);
 13
 14static void _patchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) {
 15	if (!device->p) {
 16		return;
 17	}
 18	size_t i;
 19	for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) {
 20		struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i);
 21		if (patch->applied) {
 22			continue;
 23		}
 24		// TODO: Byte check
 25		GBPatch8(device->p->cpu, patch->address, patch->newValue, &patch->oldValue);
 26		patch->applied = true;
 27	}
 28}
 29
 30static void _unpatchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) {
 31	if (!device->p) {
 32		return;
 33	}
 34	size_t i;
 35	for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) {
 36		struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i);
 37		if (!patch->applied) {
 38			continue;
 39		}
 40		GBPatch8(device->p->cpu, patch->address, patch->oldValue, NULL);
 41		patch->applied = false;
 42	}
 43}
 44
 45static void GBCheatSetDeinit(struct mCheatSet* set);
 46static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device);
 47static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device);
 48static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device);
 49static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet);
 50static bool GBCheatAddLine(struct mCheatSet*, const char* line, int type);
 51
 52static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) {
 53	UNUSED(device);
 54	struct GBCheatSet* set = malloc(sizeof(*set));
 55	mCheatSetInit(&set->d, name);
 56
 57	GBCheatPatchListInit(&set->romPatches, 0);
 58
 59	set->d.deinit = GBCheatSetDeinit;
 60	set->d.add = GBCheatAddSet;
 61	set->d.remove = GBCheatRemoveSet;
 62
 63	set->d.addLine = GBCheatAddLine;
 64	set->d.copyProperties = GBCheatSetCopyProperties;
 65
 66	set->d.refresh = GBCheatRefresh;
 67	return &set->d;
 68}
 69
 70struct mCheatDevice* GBCheatDeviceCreate(void) {
 71	struct mCheatDevice* device = malloc(sizeof(*device));
 72	mCheatDeviceCreate(device);
 73	device->createSet = GBCheatSetCreate;
 74	return device;
 75}
 76
 77static void GBCheatSetDeinit(struct mCheatSet* set) {
 78	struct GBCheatSet* gbset = (struct GBCheatSet*) set;
 79	GBCheatPatchListDeinit(&gbset->romPatches);
 80}
 81
 82static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
 83	struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
 84	_patchROM(device, gbset);
 85}
 86
 87static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
 88	struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
 89	_unpatchROM(device, gbset);
 90}
 91
 92static bool GBCheatAddCodebreaker(struct GBCheatSet* cheats, uint16_t address, uint8_t data) {
 93	struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
 94	cheat->type = CHEAT_ASSIGN;
 95	cheat->width = 1;
 96	cheat->address = address;
 97	cheat->operand = data;
 98	cheat->repeat = 1;
 99	cheat->negativeRepeat = 0;
100	return true;
101}
102
103static bool GBCheatAddGameShark(struct GBCheatSet* cheats, uint32_t op) {
104	return GBCheatAddCodebreaker(cheats, ((op & 0xFF) << 8) | ((op >> 8) & 0xFF), (op >> 16) & 0xFF);
105}
106
107static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line) {
108	uint32_t op;
109	if (!hex32(line, &op)) {
110		return false;
111	}
112	return GBCheatAddGameShark(cheats, op);
113}
114
115static bool GBCheatAddGameGenieLine(struct GBCheatSet* cheats, const char* line) {
116	uint16_t op1;
117	uint16_t op2;
118	const char* lineNext = hex12(line, &op1);
119	if (!lineNext || lineNext[0] != '-') {
120		return false;
121	}
122	++lineNext;
123	lineNext = hex12(lineNext, &op2);
124	if (!lineNext) {
125		return false;
126	}
127	uint16_t address = (op1 & 0xF) << 8;
128	address |= (op2 >> 4) & 0xFF;
129	address |= ((op2 & 0xF) ^ 0xF) << 12;
130	struct GBCheatPatch* patch = GBCheatPatchListAppend(&cheats->romPatches);
131	patch->address = address;
132	patch->newValue = op1 >> 4;
133	patch->applied = false;
134	return true;
135}
136
137static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) {
138	uint16_t address;
139	uint8_t value;
140	const char* lineNext = hex16(line, &address);
141	if (!lineNext && lineNext[0] != ':') {
142		return false;
143	}
144	if (!hex8(line, &value)) {
145		return false;
146	}
147	struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
148	cheat->type = CHEAT_ASSIGN;
149	cheat->width = 1;
150	cheat->address = address;
151	cheat->operand = value;
152	cheat->repeat = 1;
153	cheat->negativeRepeat = 0;
154	return true;
155}
156
157bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
158	struct GBCheatSet* cheats = (struct GBCheatSet*) set;
159	switch (type) {
160	case GB_CHEAT_AUTODETECT:
161		break;
162	case GB_CHEAT_GAME_GENIE:
163		return GBCheatAddGameGenieLine(cheats, line);
164	case GB_CHEAT_GAMESHARK:
165		return GBCheatAddGameSharkLine(cheats, line);
166	case GB_CHEAT_VBA:
167		return GBCheatAddVBALine(cheats, line);
168	default:
169		return false;
170	}
171
172	uint16_t op1;
173	uint8_t op2;
174	uint8_t op3;
175	bool codebreaker = false;
176	const char* lineNext = hex16(line, &op1);
177	if (!lineNext) {
178		return GBCheatAddGameGenieLine(cheats, line);
179	}
180	if (lineNext[0] == ':') {
181		return GBCheatAddVBALine(cheats, line);
182	}
183	lineNext = hex8(lineNext, &op2);
184	if (!lineNext) {
185		return false;
186	}
187	if (lineNext[0] == '-') {
188		codebreaker = true;
189		++lineNext;
190	}
191	lineNext = hex8(lineNext, &op3);
192	if (!lineNext) {
193		return false;
194	}
195	if (codebreaker) {
196		uint16_t address = (op1 << 8) | op2;
197		return GBCheatAddCodebreaker(cheats, address, op3);
198	} else {
199		uint32_t realOp = op1 << 16;
200		realOp |= op2 << 8;
201		realOp |= op3;
202		return GBCheatAddGameShark(cheats, realOp);
203	}
204}
205
206static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
207	struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
208	_patchROM(device, gbset);
209}
210
211static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
212	UNUSED(set);
213	UNUSED(oldSet);
214}