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
13 static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet);
14 static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives);
15 static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives);
16 static bool GBCheatAddLine(struct mCheatSet*, const char* line, int type);
17
GBCheatSetCreate(struct mCheatDevice * device,const char * name)18 static 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
GBCheatDeviceCreate(void)37 struct mCheatDevice* GBCheatDeviceCreate(void) {
38 struct mCheatDevice* device = malloc(sizeof(*device));
39 mCheatDeviceCreate(device);
40 device->createSet = GBCheatSetCreate;
41 return device;
42 }
43
GBCheatAddCodebreaker(struct mCheatSet * cheats,uint16_t address,uint8_t data)44 static 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
GBCheatAddGameShark(struct mCheatSet * cheats,uint32_t op)55 static bool GBCheatAddGameShark(struct mCheatSet* cheats, uint32_t op) {
56 return GBCheatAddCodebreaker(cheats, ((op & 0xFF) << 8) | ((op >> 8) & 0xFF), (op >> 16) & 0xFF);
57 }
58
GBCheatAddGameSharkLine(struct mCheatSet * cheats,const char * line)59 static 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
GBCheatAddGameGenieLine(struct mCheatSet * cheats,const char * line)67 static 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 & 0xFF;
102 patch->check = true;
103 } else {
104 patch->check = false;
105 }
106 return true;
107 }
108
GBCheatAddVBALine(struct mCheatSet * cheats,const char * line)109 static 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
GBCheatAddLine(struct mCheatSet * cheats,const char * line,int type)129 bool 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
GBCheatSetCopyProperties(struct mCheatSet * set,struct mCheatSet * oldSet)177 static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
178 UNUSED(set);
179 UNUSED(oldSet);
180 }
181
GBCheatParseDirectives(struct mCheatSet * set,const struct StringList * directives)182 static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives) {
183 UNUSED(set);
184 UNUSED(directives);
185 }
186
GBCheatDumpDirectives(struct mCheatSet * set,struct StringList * directives)187 static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives) {
188 UNUSED(set);
189 UNUSED(directives);
190 }
191