1 #include <string.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <ctype.h>
5
6 #include "../System.h"
7 #include "../NLS.h"
8 #include "../Util.h"
9
10 #include "gbCheats.h"
11 #include "gbGlobals.h"
12 #include "gb.h"
13 #include "../common/ConfigManager.h"
14
15 gbCheat gbCheatList[MAX_CHEATS];
16 int gbCheatNumber = 0;
17 int gbNextCheat = 0;
18 bool gbCheatMap[0x10000];
19
20 #define GBCHEAT_IS_HEX(a) ( ((a)>='A' && (a) <='F') || ((a) >='0' && (a) <= '9'))
21 #define GBCHEAT_HEX_VALUE(a) ( (a) >= 'A' ? (a) - 'A' + 10 : (a) - '0')
22
gbCheatUpdateMap()23 void gbCheatUpdateMap()
24 {
25 memset(gbCheatMap, 0, 0x10000);
26
27 for(int i = 0; i < gbCheatNumber; i++) {
28 if(gbCheatList[i].enabled)
29 gbCheatMap[gbCheatList[i].address] = true;
30 }
31 }
32
gbCheatsSaveGame(gzFile gzFile)33 void gbCheatsSaveGame(gzFile gzFile)
34 {
35 utilWriteInt(gzFile, gbCheatNumber);
36 if(gbCheatNumber>0)
37 utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
38 }
39
gbCheatsReadGame(gzFile gzFile,int version)40 void gbCheatsReadGame(gzFile gzFile, int version)
41 {
42 if(version <= 8) {
43 int gbGgOn = utilReadInt(gzFile);
44
45 if(gbGgOn) {
46 int n = utilReadInt(gzFile);
47 gbXxCheat tmpCheat;
48 for(int i = 0; i < n; i++) {
49 utilGzRead(gzFile,&tmpCheat, sizeof(gbXxCheat));
50 gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
51 }
52 }
53
54 int gbGsOn = utilReadInt(gzFile);
55
56 if(gbGsOn) {
57 int n = utilReadInt(gzFile);
58 gbXxCheat tmpCheat;
59 for(int i = 0; i < n; i++) {
60 utilGzRead(gzFile,&tmpCheat, sizeof(gbXxCheat));
61 gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
62 }
63 }
64 } else {
65 gbCheatNumber = utilReadInt(gzFile);
66
67 if(gbCheatNumber>0) {
68 utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
69 }
70 }
71
72 gbCheatUpdateMap();
73 }
74
75
gbCheatsReadGameSkip(gzFile gzFile,int version)76 void gbCheatsReadGameSkip(gzFile gzFile, int version)
77 {
78 if( version <= 8 ) {
79 int gbGgOn = utilReadInt( gzFile );
80 if( gbGgOn ) {
81 int n = utilReadInt( gzFile );
82 if( n > 0 ) {
83 utilGzSeek( gzFile, n * sizeof(gbXxCheat), SEEK_CUR );
84 }
85 }
86
87 int gbGsOn = utilReadInt( gzFile );
88 if( gbGsOn ) {
89 int n = utilReadInt(gzFile);
90 if( n > 0 ) {
91 utilGzSeek( gzFile, n * sizeof(gbXxCheat), SEEK_CUR );
92 }
93 }
94 } else {
95 int n = utilReadInt( gzFile );
96
97 if( n > 0 ) {
98 utilGzSeek( gzFile, n * sizeof(gbCheat), SEEK_CUR );
99 }
100 }
101 }
102
103
gbCheatsSaveCheatList(const char * file)104 void gbCheatsSaveCheatList(const char *file)
105 {
106 if(gbCheatNumber == 0)
107 return;
108 FILE *f = fopen(file, "wb");
109 if(f == NULL)
110 return;
111 int version = 1;
112 fwrite(&version, 1, sizeof(version), f);
113 int type = 1;
114 fwrite(&type, 1, sizeof(type), f);
115 fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f);
116 fwrite(gbCheatList, 1, sizeof(gbCheat) * gbCheatNumber, f);
117 fclose(f);
118 }
119
gbCheatsLoadCheatList(const char * file)120 bool gbCheatsLoadCheatList(const char *file)
121 {
122 gbCheatNumber = 0;
123
124 gbCheatUpdateMap();
125
126 int count = 0;
127
128 FILE *f = fopen(file, "rb");
129
130 if(f == NULL)
131 return false;
132
133 int version = 0;
134
135 if(fread(&version, 1, sizeof(version), f) != sizeof(version)) {
136 fclose(f);
137 return false;
138 }
139
140 if(version != 1) {
141 systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,
142 N_("Unsupported cheat list version %d"), version);
143 fclose(f);
144 return false;
145 }
146
147 int type = 0;
148 if(fread(&type, 1, sizeof(type), f) != sizeof(type)) {
149 fclose(f);
150 return false;
151 }
152
153 if(type != 1) {
154 systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,
155 N_("Unsupported cheat list type %d"), type);
156 fclose(f);
157 return false;
158 }
159
160 if(fread(&count, 1, sizeof(count), f) != sizeof(count)) {
161 fclose(f);
162 return false;
163 }
164
165 if(fread(gbCheatList, 1, sizeof(gbCheatList), f) > sizeof(gbCheatList)) {
166 fclose(f);
167 return false;
168 }
169
170 gbCheatNumber = count;
171 gbCheatUpdateMap();
172
173 return true;
174 }
175
gbVerifyGsCode(const char * code)176 bool gbVerifyGsCode(const char *code)
177 {
178 size_t len = strlen(code);
179
180 if(len == 0)
181 return true;
182
183 if(len != 8)
184 return false;
185
186 for(int i = 0; i < 8; i++)
187 if(!GBCHEAT_IS_HEX(code[i]))
188 return false;
189
190 /* int address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
191 GBCHEAT_HEX_VALUE(code[7]) << 8 |
192 GBCHEAT_HEX_VALUE(code[4]) << 4 |
193 GBCHEAT_HEX_VALUE(code[5]);*/
194
195 return true;
196 }
197
gbAddGsCheat(const char * code,const char * desc)198 bool gbAddGsCheat(const char *code, const char *desc)
199 {
200 if(gbCheatNumber > (MAX_CHEATS - 1)) {
201 systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
202 N_("Maximum number of cheats reached."));
203 return false;
204 }
205
206 if(!gbVerifyGsCode(code)) {
207 systemMessage(MSG_INVALID_GAMESHARK_CODE,
208 N_("Invalid GameShark code: %s"), code);
209 return false;
210 }
211
212 int i = gbCheatNumber;
213
214 strcpy(gbCheatList[i].cheatCode, code);
215 strcpy(gbCheatList[i].cheatDesc, desc);
216
217 gbCheatList[i].code = GBCHEAT_HEX_VALUE(code[0]) << 4 |
218 GBCHEAT_HEX_VALUE(code[1]);
219
220 gbCheatList[i].value = GBCHEAT_HEX_VALUE(code[2]) << 4 |
221 GBCHEAT_HEX_VALUE(code[3]);
222
223 gbCheatList[i].address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
224 GBCHEAT_HEX_VALUE(code[7]) << 8 |
225 GBCHEAT_HEX_VALUE(code[4]) << 4 |
226 GBCHEAT_HEX_VALUE(code[5]);
227
228 gbCheatList[i].compare = 0;
229
230 gbCheatList[i].enabled = true;
231
232 int gsCode = gbCheatList[i].code;
233
234 if ((gsCode !=1) && ((gsCode & 0xF0) !=0x80) && ((gsCode & 0xF0) !=0x90) &&
235 ((gsCode & 0xF0) !=0xA0) && ((gsCode) !=0xF0) && ((gsCode) !=0xF1))
236 systemMessage(MSG_WRONG_GAMESHARK_CODE,
237 N_("Wrong GameShark code type : %s"), code);
238 else if (((gsCode & 0xF0) ==0xA0) || ((gsCode) ==0xF0) || ((gsCode) ==0xF1))
239 systemMessage(MSG_UNSUPPORTED_GAMESHARK_CODE,
240 N_("Unsupported GameShark code type : %s"), code);
241
242 gbCheatNumber++;
243
244 return true;
245 }
246
gbVerifyGgCode(const char * code)247 bool gbVerifyGgCode(const char *code)
248 {
249 size_t len = strlen(code);
250
251 if(len != 11 &&
252 len != 7 &&
253 len != 6 &&
254 len != 0)
255 return false;
256
257 if(len == 0)
258 return true;
259
260 if(!GBCHEAT_IS_HEX(code[0]))
261 return false;
262 if(!GBCHEAT_IS_HEX(code[1]))
263 return false;
264 if(!GBCHEAT_IS_HEX(code[2]))
265 return false;
266 if(code[3] != '-')
267 return false;
268 if(!GBCHEAT_IS_HEX(code[4]))
269 return false;
270 if(!GBCHEAT_IS_HEX(code[5]))
271 return false;
272 if(!GBCHEAT_IS_HEX(code[6]))
273 return false;
274 if(code[7] != 0) {
275 if(code[7] != '-')
276 return false;
277 if(code[8] != 0) {
278 if(!GBCHEAT_IS_HEX(code[8]))
279 return false;
280 if(!GBCHEAT_IS_HEX(code[9]))
281 return false;
282 if(!GBCHEAT_IS_HEX(code[10]))
283 return false;
284 }
285 }
286
287 // int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
288 // GBCHEAT_HEX_VALUE(code[1]);
289
290 int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
291 (GBCHEAT_HEX_VALUE(code[4]) << 4) +
292 (GBCHEAT_HEX_VALUE(code[5])) +
293 ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
294
295 if(address >= 0x8000 && address <= 0x9fff)
296 return false;
297
298 if(address >= 0xc000)
299 return false;
300
301 if(code[7] == 0 || code[8] == '0')
302 return true;
303
304 int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
305 (GBCHEAT_HEX_VALUE(code[10]));
306 compare = compare ^ 0xff;
307 compare = (compare >> 2) | ( (compare << 6) & 0xc0);
308 compare ^= 0x45;
309
310 int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9]));
311
312 if(cloak >=1 && cloak <= 7)
313 return false;
314
315 return true;
316 }
317
gbAddGgCheat(const char * code,const char * desc)318 bool gbAddGgCheat(const char *code, const char *desc)
319 {
320 if(gbCheatNumber > (MAX_CHEATS - 1)) {
321 systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
322 N_("Maximum number of cheats reached."));
323 return false;
324 }
325
326 if(!gbVerifyGgCode(code)) {
327 systemMessage(MSG_INVALID_GAMEGENIE_CODE,
328 N_("Invalid GameGenie code: %s"), code);
329 return false;
330 }
331
332 int i = gbCheatNumber;
333
334 size_t len = strlen(code);
335
336 strcpy(gbCheatList[i].cheatCode, code);
337 strcpy(gbCheatList[i].cheatDesc, desc);
338
339 gbCheatList[i].code = 0x101;
340 gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
341 GBCHEAT_HEX_VALUE(code[1]);
342
343 gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
344 (GBCHEAT_HEX_VALUE(code[4]) << 4) +
345 (GBCHEAT_HEX_VALUE(code[5])) +
346 ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
347
348 gbCheatList[i].compare = 0;
349
350 if(len != 7 && len != 8) {
351
352 int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
353 (GBCHEAT_HEX_VALUE(code[10]));
354 compare = compare ^ 0xff;
355 compare = (compare >> 2) | ( (compare << 6) & 0xc0);
356 compare ^= 0x45;
357
358 gbCheatList[i].compare = compare;
359 //gbCheatList[i].code = 0;
360 gbCheatList[i].code = 0x100; // fix for compare value
361
362 }
363
364
365 gbCheatList[i].enabled = true;
366
367 gbCheatMap[gbCheatList[i].address] = true;
368
369 gbCheatNumber++;
370
371 return true;
372 }
373
gbCheatRemove(int i)374 void gbCheatRemove(int i)
375 {
376 if(i < 0 || i >= gbCheatNumber) {
377 systemMessage(MSG_INVALID_CHEAT_TO_REMOVE,
378 N_("Invalid cheat to remove %d"), i);
379 return;
380 }
381
382 if((i+1) < gbCheatNumber) {
383 memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)*
384 (gbCheatNumber-i-1));
385 }
386
387 gbCheatNumber--;
388
389 gbCheatUpdateMap();
390 }
391
gbCheatRemoveAll()392 void gbCheatRemoveAll()
393 {
394 gbCheatNumber = 0;
395 gbCheatUpdateMap();
396 }
397
gbCheatEnable(int i)398 void gbCheatEnable(int i)
399 {
400 if(i >=0 && i < gbCheatNumber) {
401 if(!gbCheatList[i].enabled) {
402 gbCheatList[i].enabled = true;
403 gbCheatUpdateMap();
404 }
405 }
406 }
407
gbCheatDisable(int i)408 void gbCheatDisable(int i)
409 {
410 if(i >=0 && i < gbCheatNumber) {
411 if(gbCheatList[i].enabled) {
412 gbCheatList[i].enabled = false;
413 gbCheatUpdateMap();
414 }
415 }
416 }
417
gbCheatReadGSCodeFile(const char * fileName)418 bool gbCheatReadGSCodeFile(const char *fileName)
419 {
420 FILE *file = fopen(fileName, "rb");
421
422 if(!file) {
423 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
424 return false;
425 }
426
427 fseek(file, 0x18, SEEK_SET);
428 int count = 0;
429 fread(&count, 1, 2, file);
430 int dummy = 0;
431 gbCheatRemoveAll();
432 char desc[13];
433 char code[9];
434 int i;
435 for(i = 0; i < count; i++) {
436 fread(&dummy, 1, 2, file);
437 fread(desc, 1, 12, file);
438 desc[12] = 0;
439 fread(code, 1, 8, file);
440 code[8] = 0;
441 gbAddGsCheat(code, desc);
442 }
443
444 for(i = 0; i < gbCheatNumber; i++)
445 gbCheatDisable(i);
446
447 fclose(file);
448 return true;
449 }
450
451 // Used to emulated GG codes
gbCheatRead(u16 address)452 u8 gbCheatRead(u16 address)
453 {
454 if(!cheatsEnabled)
455 return gbMemoryMap[address>>12][address & 0xFFF];
456
457 for(int i = 0; i < gbCheatNumber; i++) {
458 if(gbCheatList[i].enabled && gbCheatList[i].address == address) {
459 switch(gbCheatList[i].code) {
460 case 0x100: // GameGenie support
461 if(gbMemoryMap[address>>12][address&0xFFF] == gbCheatList[i].compare)
462 return gbCheatList[i].value;
463 break;
464 case 0x101: // GameGenie 6 digits code support
465 return gbCheatList[i].value;
466 break;
467 }
468 }
469 }
470 return gbMemoryMap[address>>12][address&0xFFF];
471 }
472
473
474 // Used to emulate GS codes.
gbCheatWrite(bool reboot)475 void gbCheatWrite(bool reboot)
476 {
477 if(cheatsEnabled)
478 {
479 u16 address = 0;
480
481 if (gbNextCheat >= gbCheatNumber)
482 gbNextCheat = 0;
483
484 for(int i = gbNextCheat; i < gbCheatNumber; i++) {
485 if(gbCheatList[i].enabled) {
486 address = gbCheatList[i].address;
487 if ((!reboot) && (address >= 0x8000) && !((address>=0xA000) && (address<0xC000)))
488 { // These codes are executed one per one, at each Vblank
489 switch(gbCheatList[i].code) {
490 case 0x01:
491 gbWriteMemory(address, gbCheatList[i].value);
492 gbNextCheat = i+1;
493 return;
494 case 0x90:
495 case 0x91:
496 case 0x92:
497 case 0x93:
498 case 0x94:
499 case 0x95:
500 case 0x96:
501 case 0x97:
502 case 0x98:
503 case 0x99:
504 case 0x9A:
505 case 0x9B:
506 case 0x9C:
507 case 0x9D:
508 case 0x9E:
509 case 0x9F:
510 int oldbank = gbMemory[0xff70];
511 gbWriteMemory(0xff70, gbCheatList[i].code & 0xf);
512 gbWriteMemory(address, gbCheatList[i].value);
513 gbWriteMemory(0xff70, oldbank);
514 gbNextCheat = i+1;
515 return;
516 }
517 }
518 else // These codes are only executed when the game is booted
519 {
520 switch(gbCheatList[i].code & 0xF0) {
521 case 0x80:
522 gbWriteMemory(0x0000, 0x0A);
523 gbWriteMemory(0x4000, gbCheatList[i].value & 0xF);
524 gbWriteMemory(address, gbCheatList[i].value);
525 gbNextCheat = i+1;
526 return;
527 }
528 }
529 }
530 }
531 }
532 }
533