comparison src/gb/gbCheats.cpp @ 17:75e5bb1e0aa1

going to now integrate the gb src tree since it has no dependencies
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 11:44:47 -0600
parents f9f4f1b99eed
children 5e8e5083da94
comparison
equal deleted inserted replaced
16:9e598342e182 17:75e5bb1e0aa1
1 #include <cstdio>
2 #include <cstdlib>
3 #include <cctype>
4 #include <cstring>
5
6 #include "../NLS.h"
7 #include "../common/System.h"
8 #include "../common/Util.h"
9
10 #include "gbCheats.h"
11 #include "gbGlobals.h"
12
13 gbCheat gbCheatList[100];
14 int gbCheatNumber = 0;
15 bool gbCheatMap[0x10000];
16
17 extern bool8 cheatsEnabled;
18
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')
21
22 void gbCheatUpdateMap()
23 {
24 memset(gbCheatMap, 0, 0x10000);
25
26 for (int i = 0; i < gbCheatNumber; i++)
27 {
28 if (gbCheatList[i].enabled)
29 gbCheatMap[gbCheatList[i].address] = true;
30 }
31 }
32
33 void gbCheatsSaveGame(gzFile gzFile)
34 {
35 utilWriteInt(gzFile, gbCheatNumber);
36 if (gbCheatNumber)
37 utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
38 }
39
40 void gbCheatsReadGame(gzFile gzFile, int version)
41 {
42 if (version <= 8)
43 {
44 int gbGgOn = utilReadInt(gzFile);
45
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 }
56
57 int gbGsOn = utilReadInt(gzFile);
58
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);
73
74 if (gbCheatNumber)
75 {
76 utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
77 }
78 }
79
80 gbCheatUpdateMap();
81 }
82
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 }
98
99 bool gbCheatsLoadCheatList(const char *file)
100 {
101 gbCheatNumber = 0;
102
103 gbCheatUpdateMap();
104
105 int count = 0;
106
107 FILE *f = fopen(file, "rb");
108
109 if (f == NULL)
110 return false;
111
112 int version = 0;
113
114 if (fread(&version, 1, sizeof(version), f) != sizeof(version))
115 {
116 fclose(f);
117 return false;
118 }
119
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 }
127
128 int type = 0;
129 if (fread(&type, 1, sizeof(type), f) != sizeof(type))
130 {
131 fclose(f);
132 return false;
133 }
134
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 }
142
143 if (fread(&count, 1, sizeof(count), f) != sizeof(count))
144 {
145 fclose(f);
146 return false;
147 }
148
149 if (fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList))
150 {
151 fclose(f);
152 return false;
153 }
154
155 fclose(f);
156 gbCheatNumber = count;
157 gbCheatUpdateMap();
158
159 return true;
160 }
161
162 bool gbVerifyGsCode(const char *code)
163 {
164 int len = strlen(code);
165
166 if (len == 0)
167 return true;
168
169 if (len != 8)
170 return false;
171
172 for (int i = 0; i < 8; i++)
173 if (!GBCHEAT_IS_HEX(code[i]))
174 return false;
175
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]);
180
181 if (address < 0xa000 ||
182 address > 0xdfff)
183 return false;
184
185 return true;
186 }
187
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 }
196
197 if (!gbVerifyGsCode(code))
198 {
199 systemMessage(MSG_INVALID_GAMESHARK_CODE,
200 N_("Invalid GameShark code: %s"), code);
201 return;
202 }
203
204 int i = gbCheatNumber;
205
206 strcpy(gbCheatList[i].cheatCode, code);
207 strcpy(gbCheatList[i].cheatDesc, desc);
208
209 gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 |
210 GBCHEAT_HEX_VALUE(code[1]);
211
212 gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 |
213 GBCHEAT_HEX_VALUE(code[3]);
214
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]);
219
220 gbCheatList[i].compare = 0;
221
222 gbCheatList[i].enabled = true;
223
224 gbCheatMap[gbCheatList[i].address] = true;
225
226 gbCheatNumber++;
227 }
228
229 bool gbVerifyGgCode(const char *code)
230 {
231 int len = strlen(code);
232
233 if (len != 11 &&
234 len != 7 &&
235 len != 6 &&
236 len != 0)
237 return false;
238
239 if (len == 0)
240 return true;
241
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 }
270
271 // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
272 // GBCHEAT_HEX_VALUE(code[1]);
273
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);
278
279 if (address >= 0x8000 && address <= 0x9fff)
280 return false;
281
282 if (address >= 0xc000)
283 return false;
284
285 if (code[7] == 0 || code[8] == '0')
286 return true;
287
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;
293
294 int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9]));
295
296 if (cloak >= 1 && cloak <= 7)
297 return false;
298
299 return true;
300 }
301
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 }
310
311 if (!gbVerifyGgCode(code))
312 {
313 systemMessage(MSG_INVALID_GAMEGENIE_CODE,
314 N_("Invalid GameGenie code: %s"), code);
315 return;
316 }
317
318 int i = gbCheatNumber;
319
320 int len = strlen(code);
321
322 strcpy(gbCheatList[i].cheatCode, code);
323 strcpy(gbCheatList[i].cheatDesc, desc);
324
325 gbCheatList[i].code = 1;
326 gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
327 GBCHEAT_HEX_VALUE(code[1]);
328
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);
333
334 gbCheatList[i].compare = 0;
335
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;
343
344 gbCheatList[i].compare = compare;
345 gbCheatList[i].code = 0;
346 }
347
348 gbCheatList[i].enabled = true;
349
350 gbCheatMap[gbCheatList[i].address] = true;
351
352 gbCheatNumber++;
353 }
354
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 }
363
364 if ((i+1) < gbCheatNumber)
365 {
366 memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)*
367 (gbCheatNumber-i-1));
368 }
369
370 gbCheatNumber--;
371
372 gbCheatUpdateMap();
373 }
374
375 void gbCheatRemoveAll()
376 {
377 gbCheatNumber = 0;
378 gbCheatUpdateMap();
379 }
380
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 }
392
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 }
404
405 bool gbCheatReadGSCodeFile(const char *fileName)
406 {
407 FILE *file = fopen(fileName, "rb");
408
409 if (!file)
410 return false;
411
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 }
429
430 for (i = 0; i < gbCheatNumber; i++)
431 gbCheatDisable(i);
432
433 fclose(file);
434 return true;
435 }
436
437 u8 gbCheatRead(u16 address)
438 {
439 if (!cheatsEnabled)
440 return gbReadMemoryQuick(address);
441
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 }
477