view src/gb/gbCheats.cpp @ 396:c7a43f4ffd9d

fixed bug where A was always 0 when the self-modigying code was executed.
author Robert McIntyre <rlm@mit.edu>
date Fri, 13 Apr 2012 04:50:58 -0500
parents 5e8e5083da94
children
line wrap: on
line source
1 #include <cstdio>
2 #include <cstdlib>
3 #include <cctype>
4 #include <cstring>
6 #include "../NLS.h"
7 #include "../common/System.h"
8 #include "../common/Util.h"
10 #include "gbCheats.h"
11 #include "gbGlobals.h"
13 gbCheat gbCheatList[100];
14 int gbCheatNumber = 0;
15 bool gbCheatMap[0x10000];
17 extern bool8 cheatsEnabled;
19 #define GBCHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9'))
20 #define GBCHEAT_HEX_VALUE(a) ((a) >= 'A' ? (a) - 'A' + 10 : (a) - '0')
22 void gbCheatUpdateMap()
23 {
24 memset(gbCheatMap, 0, 0x10000);
26 for (int i = 0; i < gbCheatNumber; i++)
27 {
28 if (gbCheatList[i].enabled)
29 gbCheatMap[gbCheatList[i].address] = true;
30 }
31 }
33 void gbCheatsSaveGame(gzFile gzFile)
34 {
35 utilWriteInt(gzFile, gbCheatNumber);
36 if (gbCheatNumber)
37 utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
38 }
40 void gbCheatsReadGame(gzFile gzFile, int version)
41 {
42 if (version <= 8)
43 {
44 int gbGgOn = utilReadInt(gzFile);
46 if (gbGgOn)
47 {
48 int n = utilReadInt(gzFile);
49 gbXxCheat tmpCheat;
50 for (int i = 0; i < n; i++)
51 {
52 utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));
53 gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
54 }
55 }
57 int gbGsOn = utilReadInt(gzFile);
59 if (gbGsOn)
60 {
61 int n = utilReadInt(gzFile);
62 gbXxCheat tmpCheat;
63 for (int i = 0; i < n; i++)
64 {
65 utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat));
66 gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
67 }
68 }
69 }
70 else
71 {
72 gbCheatNumber = utilReadInt(gzFile);
74 if (gbCheatNumber)
75 {
76 utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
77 }
78 }
80 gbCheatUpdateMap();
81 }
83 void gbCheatsSaveCheatList(const char *file)
84 {
85 if (gbCheatNumber == 0)
86 return;
87 FILE *f = fopen(file, "wb");
88 if (f == NULL)
89 return;
90 int version = 1;
91 fwrite(&version, 1, sizeof(version), f);
92 int type = 1;
93 fwrite(&type, 1, sizeof(type), f);
94 fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f);
95 fwrite(gbCheatList, 1, sizeof(gbCheatList), f);
96 fclose(f);
97 }
99 bool gbCheatsLoadCheatList(const char *file)
100 {
101 gbCheatNumber = 0;
103 gbCheatUpdateMap();
105 int count = 0;
107 FILE *f = fopen(file, "rb");
109 if (f == NULL)
110 return false;
112 int version = 0;
114 if (fread(&version, 1, sizeof(version), f) != sizeof(version))
115 {
116 fclose(f);
117 return false;
118 }
120 if (version != 1)
121 {
122 systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,
123 N_("Unsupported cheat list version %d"), version);
124 fclose(f);
125 return false;
126 }
128 int type = 0;
129 if (fread(&type, 1, sizeof(type), f) != sizeof(type))
130 {
131 fclose(f);
132 return false;
133 }
135 if (type != 1)
136 {
137 systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,
138 N_("Unsupported cheat list type %d"), type);
139 fclose(f);
140 return false;
141 }
143 if (fread(&count, 1, sizeof(count), f) != sizeof(count))
144 {
145 fclose(f);
146 return false;
147 }
149 if (fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList))
150 {
151 fclose(f);
152 return false;
153 }
155 fclose(f);
156 gbCheatNumber = count;
157 gbCheatUpdateMap();
159 return true;
160 }
162 bool gbVerifyGsCode(const char *code)
163 {
164 int len = strlen(code);
166 if (len == 0)
167 return true;
169 if (len != 8)
170 return false;
172 for (int i = 0; i < 8; i++)
173 if (!GBCHEAT_IS_HEX(code[i]))
174 return false;
176 int address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
177 GBCHEAT_HEX_VALUE(code[7]) << 8 |
178 GBCHEAT_HEX_VALUE(code[4]) << 4 |
179 GBCHEAT_HEX_VALUE(code[5]);
181 if (address < 0xa000 ||
182 address > 0xdfff)
183 return false;
185 return true;
186 }
188 void gbAddGsCheat(const char *code, const char *desc)
189 {
190 if (gbCheatNumber > 99)
191 {
192 systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
193 N_("Maximum number of cheats reached."));
194 return;
195 }
197 if (!gbVerifyGsCode(code))
198 {
199 systemMessage(MSG_INVALID_GAMESHARK_CODE,
200 N_("Invalid GameShark code: %s"), code);
201 return;
202 }
204 int i = gbCheatNumber;
206 strcpy(gbCheatList[i].cheatCode, code);
207 strcpy(gbCheatList[i].cheatDesc, desc);
209 gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 |
210 GBCHEAT_HEX_VALUE(code[1]);
212 gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 |
213 GBCHEAT_HEX_VALUE(code[3]);
215 gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
216 GBCHEAT_HEX_VALUE(code[7]) << 8 |
217 GBCHEAT_HEX_VALUE(code[4]) << 4 |
218 GBCHEAT_HEX_VALUE(code[5]);
220 gbCheatList[i].compare = 0;
222 gbCheatList[i].enabled = true;
224 gbCheatMap[gbCheatList[i].address] = true;
226 gbCheatNumber++;
227 }
229 bool gbVerifyGgCode(const char *code)
230 {
231 int len = strlen(code);
233 if (len != 11 &&
234 len != 7 &&
235 len != 6 &&
236 len != 0)
237 return false;
239 if (len == 0)
240 return true;
242 if (!GBCHEAT_IS_HEX(code[0]))
243 return false;
244 if (!GBCHEAT_IS_HEX(code[1]))
245 return false;
246 if (!GBCHEAT_IS_HEX(code[2]))
247 return false;
248 if (code[3] != '-')
249 return false;
250 if (!GBCHEAT_IS_HEX(code[4]))
251 return false;
252 if (!GBCHEAT_IS_HEX(code[5]))
253 return false;
254 if (!GBCHEAT_IS_HEX(code[6]))
255 return false;
256 if (code[7] != 0)
257 {
258 if (code[7] != '-')
259 return false;
260 if (code[8] != 0)
261 {
262 if (!GBCHEAT_IS_HEX(code[8]))
263 return false;
264 if (!GBCHEAT_IS_HEX(code[9]))
265 return false;
266 if (!GBCHEAT_IS_HEX(code[10]))
267 return false;
268 }
269 }
271 // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
272 // GBCHEAT_HEX_VALUE(code[1]);
274 int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
275 (GBCHEAT_HEX_VALUE(code[4]) << 4) +
276 (GBCHEAT_HEX_VALUE(code[5])) +
277 ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
279 if (address >= 0x8000 && address <= 0x9fff)
280 return false;
282 if (address >= 0xc000)
283 return false;
285 if (code[7] == 0 || code[8] == '0')
286 return true;
288 int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
289 (GBCHEAT_HEX_VALUE(code[10]));
290 compare = compare ^ 0xff;
291 compare = (compare >> 2) | ((compare << 6) & 0xc0);
292 compare ^= 0x45;
294 int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9]));
296 if (cloak >= 1 && cloak <= 7)
297 return false;
299 return true;
300 }
302 void gbAddGgCheat(const char *code, const char *desc)
303 {
304 if (gbCheatNumber > 99)
305 {
306 systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
307 N_("Maximum number of cheats reached."));
308 return;
309 }
311 if (!gbVerifyGgCode(code))
312 {
313 systemMessage(MSG_INVALID_GAMEGENIE_CODE,
314 N_("Invalid GameGenie code: %s"), code);
315 return;
316 }
318 int i = gbCheatNumber;
320 int len = strlen(code);
322 strcpy(gbCheatList[i].cheatCode, code);
323 strcpy(gbCheatList[i].cheatDesc, desc);
325 gbCheatList[i].code = 1;
326 gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
327 GBCHEAT_HEX_VALUE(code[1]);
329 gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
330 (GBCHEAT_HEX_VALUE(code[4]) << 4) +
331 (GBCHEAT_HEX_VALUE(code[5])) +
332 ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
334 gbCheatList[i].compare = 0;
336 if (len != 7 && len != 8)
337 {
338 int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
339 (GBCHEAT_HEX_VALUE(code[10]));
340 compare = compare ^ 0xff;
341 compare = (compare >> 2) | ((compare << 6) & 0xc0);
342 compare ^= 0x45;
344 gbCheatList[i].compare = compare;
345 gbCheatList[i].code = 0;
346 }
348 gbCheatList[i].enabled = true;
350 gbCheatMap[gbCheatList[i].address] = true;
352 gbCheatNumber++;
353 }
355 void gbCheatRemove(int i)
356 {
357 if (i < 0 || i >= gbCheatNumber)
358 {
359 systemMessage(MSG_INVALID_CHEAT_TO_REMOVE,
360 N_("Invalid cheat to remove %d"), i);
361 return;
362 }
364 if ((i+1) < gbCheatNumber)
365 {
366 memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)*
367 (gbCheatNumber-i-1));
368 }
370 gbCheatNumber--;
372 gbCheatUpdateMap();
373 }
375 void gbCheatRemoveAll()
376 {
377 gbCheatNumber = 0;
378 gbCheatUpdateMap();
379 }
381 void gbCheatEnable(int i)
382 {
383 if (i >= 0 && i < gbCheatNumber)
384 {
385 if (!gbCheatList[i].enabled)
386 {
387 gbCheatList[i].enabled = true;
388 gbCheatUpdateMap();
389 }
390 }
391 }
393 void gbCheatDisable(int i)
394 {
395 if (i >= 0 && i < gbCheatNumber)
396 {
397 if (gbCheatList[i].enabled)
398 {
399 gbCheatList[i].enabled = false;
400 gbCheatUpdateMap();
401 }
402 }
403 }
405 bool gbCheatReadGSCodeFile(const char *fileName)
406 {
407 FILE *file = fopen(fileName, "rb");
409 if (!file)
410 return false;
412 fseek(file, 0x18, SEEK_SET);
413 int count = 0;
414 fread(&count, 1, 2, file);
415 int dummy = 0;
416 gbCheatRemoveAll();
417 char desc[13];
418 char code[9];
419 int i;
420 for (i = 0; i < count; i++)
421 {
422 fread(&dummy, 1, 2, file);
423 fread(desc, 1, 12, file);
424 desc[12] = 0;
425 fread(code, 1, 8, file);
426 code[8] = 0;
427 gbAddGsCheat(code, desc);
428 }
430 for (i = 0; i < gbCheatNumber; i++)
431 gbCheatDisable(i);
433 fclose(file);
434 return true;
435 }
437 u8 gbCheatRead(u16 address)
438 {
439 if (!cheatsEnabled)
440 return gbReadMemoryQuick(address);
442 for (int i = 0; i < gbCheatNumber; i++)
443 {
444 if (gbCheatList[i].enabled && gbCheatList[i].address == address)
445 {
446 switch (gbCheatList[i].code)
447 {
448 case 0x100: // GameGenie support
449 if (gbReadMemoryQuick(address) == gbCheatList[i].compare)
450 return gbCheatList[i].value;
451 break;
452 case 0x00:
453 case 0x01:
454 case 0x80:
455 return gbCheatList[i].value;
456 case 0x90:
457 case 0x91:
458 case 0x92:
459 case 0x93:
460 case 0x94:
461 case 0x95:
462 case 0x96:
463 case 0x97:
464 if (address >= 0xd000 && address < 0xe000)
465 {
466 if (((gbMemoryMap[0x0d] - gbWram)/0x1000) ==
467 (gbCheatList[i].code - 0x90))
468 return gbCheatList[i].value;
469 }
470 else
471 return gbCheatList[i].value;
472 }
473 }
474 }
475 return gbReadMemoryQuick(address);
476 }