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}