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