all repos — mgba @ 1e017ade23e1bac555f84d4283cfc13ab532bed8

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 <mgba/internal/gb/cheats.h>
  7
  8#include <mgba/core/core.h>
  9#include <mgba/internal/gb/gb.h>
 10#include <mgba/internal/gb/memory.h>
 11#include <mgba-util/string.h>
 12
 13static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet);
 14static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives);
 15static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives);
 16static bool GBCheatAddLine(struct mCheatSet*, const char* line, int type);
 17
 18static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) {
 19	UNUSED(device);
 20	struct mCheatSet* set = malloc(sizeof(*set));
 21	mCheatSetInit(set, name);
 22
 23	set->deinit = NULL;
 24	set->add = NULL;
 25	set->remove = NULL;
 26
 27	set->addLine = GBCheatAddLine;
 28	set->copyProperties = GBCheatSetCopyProperties;
 29
 30	set->parseDirectives = GBCheatParseDirectives;
 31	set->dumpDirectives = GBCheatDumpDirectives;
 32
 33	set->refresh = NULL;
 34	return set;
 35}
 36
 37struct mCheatDevice* GBCheatDeviceCreate(void) {
 38	struct mCheatDevice* device = malloc(sizeof(*device));
 39	mCheatDeviceCreate(device);
 40	device->createSet = GBCheatSetCreate;
 41	return device;
 42}
 43
 44static bool GBCheatAddCodebreaker(struct mCheatSet* cheats, uint16_t address, uint8_t data) {
 45	struct mCheat* cheat = mCheatListAppend(&cheats->list);
 46	cheat->type = CHEAT_ASSIGN;
 47	cheat->width = 1;
 48	cheat->address = address;
 49	cheat->operand = data;
 50	cheat->repeat = 1;
 51	cheat->negativeRepeat = 0;
 52	return true;
 53}
 54
 55static bool GBCheatAddGameShark(struct mCheatSet* cheats, uint32_t op) {
 56	return GBCheatAddCodebreaker(cheats, ((op & 0xFF) << 8) | ((op >> 8) & 0xFF), (op >> 16) & 0xFF);
 57}
 58
 59static bool GBCheatAddGameSharkLine(struct mCheatSet* cheats, const char* line) {
 60	uint32_t op;
 61	if (!hex32(line, &op)) {
 62		return false;
 63	}
 64	return GBCheatAddGameShark(cheats, op);
 65}
 66
 67static bool GBCheatAddGameGenieLine(struct mCheatSet* cheats, const char* line) {
 68	uint16_t op1;
 69	uint16_t op2;
 70	uint16_t op3 = 0x1000;
 71	const char* lineNext = hex12(line, &op1);
 72	if (!lineNext || lineNext[0] != '-') {
 73		return false;
 74	}
 75	++lineNext;
 76	lineNext = hex12(lineNext, &op2);
 77	if (!lineNext) {
 78		return false;
 79	}
 80	if (lineNext[0] == '-') {
 81		++lineNext;
 82		lineNext = hex12(lineNext, &op3);
 83	}
 84	if (!lineNext || lineNext[0]) {
 85		return false;
 86	}
 87	uint16_t address = (op1 & 0xF) << 8;
 88	address |= (op2 >> 4) & 0xFF;
 89	address |= ((op2 & 0xF) ^ 0xF) << 12;
 90	struct mCheatPatch* patch = mCheatPatchListAppend(&cheats->romPatches);
 91	patch->address = address;
 92	patch->value = op1 >> 4;
 93	patch->applied = false;
 94	patch->width = 1;
 95	patch->segment = -1;
 96	if (op3 < 0x1000) {
 97		uint32_t value = ((op3 & 0xF00) << 20) | (op3 & 0xF);
 98		value = ROR(value, 2);
 99		value |= value >> 24;
100		value ^= 0xBA;
101		patch->checkValue = value;
102		patch->check = true;
103	} else {
104		patch->check = false;
105	}
106	return true;
107}
108
109static bool GBCheatAddVBALine(struct mCheatSet* cheats, const char* line) {
110	uint16_t address;
111	uint8_t value;
112	const char* lineNext = hex16(line, &address);
113	if (!lineNext || lineNext[0] != ':') {
114		return false;
115	}
116	if (!hex8(line, &value)) {
117		return false;
118	}
119	struct mCheat* cheat = mCheatListAppend(&cheats->list);
120	cheat->type = CHEAT_ASSIGN;
121	cheat->width = 1;
122	cheat->address = address;
123	cheat->operand = value;
124	cheat->repeat = 1;
125	cheat->negativeRepeat = 0;
126	return true;
127}
128
129bool GBCheatAddLine(struct mCheatSet* cheats, const char* line, int type) {
130	switch (type) {
131	case GB_CHEAT_AUTODETECT:
132		break;
133	case GB_CHEAT_GAME_GENIE:
134		return GBCheatAddGameGenieLine(cheats, line);
135	case GB_CHEAT_GAMESHARK:
136		return GBCheatAddGameSharkLine(cheats, line);
137	case GB_CHEAT_VBA:
138		return GBCheatAddVBALine(cheats, line);
139	default:
140		return false;
141	}
142
143	uint16_t op1;
144	uint8_t op2;
145	uint8_t op3;
146	bool codebreaker = false;
147	const char* lineNext = hex16(line, &op1);
148	if (!lineNext) {
149		return GBCheatAddGameGenieLine(cheats, line);
150	}
151	if (lineNext[0] == ':') {
152		return GBCheatAddVBALine(cheats, line);
153	}
154	lineNext = hex8(lineNext, &op2);
155	if (!lineNext) {
156		return false;
157	}
158	if (lineNext[0] == '-') {
159		codebreaker = true;
160		++lineNext;
161	}
162	lineNext = hex8(lineNext, &op3);
163	if (!lineNext) {
164		return false;
165	}
166	if (codebreaker) {
167		uint16_t address = (op1 << 8) | op2;
168		return GBCheatAddCodebreaker(cheats, address, op3);
169	} else {
170		uint32_t realOp = op1 << 16;
171		realOp |= op2 << 8;
172		realOp |= op3;
173		return GBCheatAddGameShark(cheats, realOp);
174	}
175}
176
177static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
178	UNUSED(set);
179	UNUSED(oldSet);
180}
181
182static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives) {
183	UNUSED(set);
184	UNUSED(directives);
185}
186
187static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives) {
188	UNUSED(set);
189	UNUSED(directives);
190}