1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
4 
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19 #include <string.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 
24 #include "../System.h"
25 #include "../NLS.h"
26 #include "../Util.h"
27 
28 #include "gbCheats.h"
29 #include "gbGlobals.h"
30 
31 gbCheat gbCheatList[100];
32 int gbCheatNumber = 0;
33 bool gbCheatMap[0x10000];
34 
35 extern bool cheatsEnabled;
36 
37 #define GBCHEAT_IS_HEX(a) ( ((a)>='A' && (a) <='F') || ((a) >='0' && (a) <= '9'))
38 #define GBCHEAT_HEX_VALUE(a) ( (a) >= 'A' ? (a) - 'A' + 10 : (a) - '0')
39 
gbCheatUpdateMap()40 void gbCheatUpdateMap()
41 {
42   memset(gbCheatMap, 0, 0x10000);
43 
44   for(int i = 0; i < gbCheatNumber; i++) {
45     if(gbCheatList[i].enabled)
46       gbCheatMap[gbCheatList[i].address] = true;
47   }
48 }
49 
gbCheatsSaveGame(gzFile gzFile)50 void gbCheatsSaveGame(gzFile gzFile)
51 {
52   utilWriteInt(gzFile, gbCheatNumber);
53   if(gbCheatNumber)
54     utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
55 }
56 
gbCheatsReadGame(gzFile gzFile,int version)57 void gbCheatsReadGame(gzFile gzFile, int version)
58 {
59   if(version <= 8) {
60     int gbGgOn = utilReadInt(gzFile);
61 
62     if(gbGgOn) {
63       int n = utilReadInt(gzFile);
64       gbXxCheat tmpCheat;
65       for(int i = 0; i < n; i++) {
66         utilGzRead(gzFile,&tmpCheat, sizeof(gbXxCheat));
67         gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
68       }
69     }
70 
71     int gbGsOn = utilReadInt(gzFile);
72 
73     if(gbGsOn) {
74       int n = utilReadInt(gzFile);
75       gbXxCheat tmpCheat;
76       for(int i = 0; i < n; i++) {
77         utilGzRead(gzFile,&tmpCheat, sizeof(gbXxCheat));
78         gbAddGsCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc);
79       }
80     }
81   } else {
82     gbCheatNumber = utilReadInt(gzFile);
83 
84     if(gbCheatNumber) {
85       utilGzRead(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber);
86     }
87   }
88 
89   gbCheatUpdateMap();
90 }
91 
gbCheatsSaveCheatList(const char * file)92 void gbCheatsSaveCheatList(const char *file)
93 {
94   if(gbCheatNumber == 0)
95     return;
96   FILE *f = fopen(file, "wb");
97   if(f == NULL)
98     return;
99   int version = 1;
100   fwrite(&version, 1, sizeof(version), f);
101   int type = 1;
102   fwrite(&type, 1, sizeof(type), f);
103   fwrite(&gbCheatNumber, 1, sizeof(gbCheatNumber), f);
104   fwrite(gbCheatList, 1, sizeof(gbCheatList), f);
105   fclose(f);
106 }
107 
gbCheatsLoadCheatList(const char * file)108 bool gbCheatsLoadCheatList(const char *file)
109 {
110   gbCheatNumber = 0;
111 
112   gbCheatUpdateMap();
113 
114   int count = 0;
115 
116   FILE *f = fopen(file, "rb");
117 
118   if(f == NULL)
119     return false;
120 
121   int version = 0;
122 
123   if(fread(&version, 1, sizeof(version), f) != sizeof(version)) {
124     fclose(f);
125     return false;
126   }
127 
128   if(version != 1) {
129     systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,
130                   N_("Unsupported cheat list version %d"), version);
131     fclose(f);
132     return false;
133   }
134 
135   int type = 0;
136   if(fread(&type, 1, sizeof(type), f) != sizeof(type)) {
137     fclose(f);
138     return false;
139   }
140 
141   if(type != 1) {
142     systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,
143                   N_("Unsupported cheat list type %d"), type);
144     fclose(f);
145     return false;
146   }
147 
148   if(fread(&count, 1, sizeof(count), f) != sizeof(count)) {
149     fclose(f);
150     return false;
151   }
152 
153   if(fread(gbCheatList, 1, sizeof(gbCheatList), f) != sizeof(gbCheatList)) {
154     fclose(f);
155     return false;
156   }
157 
158   gbCheatNumber = count;
159   gbCheatUpdateMap();
160 
161   return true;
162 }
163 
gbVerifyGsCode(const char * code)164 bool gbVerifyGsCode(const char *code)
165 {
166   int len = strlen(code);
167 
168   if(len == 0)
169     return true;
170 
171   if(len != 8)
172     return false;
173 
174   for(int i = 0; i < 8; i++)
175     if(!GBCHEAT_IS_HEX(code[i]))
176       return false;
177 
178   int address = GBCHEAT_HEX_VALUE(code[6]) << 12 |
179     GBCHEAT_HEX_VALUE(code[7]) << 8 |
180     GBCHEAT_HEX_VALUE(code[4]) << 4 |
181     GBCHEAT_HEX_VALUE(code[5]);
182 
183   if(address < 0xa000 ||
184      address > 0xdfff)
185     return false;
186 
187   return true;
188 }
189 
gbAddGsCheat(const char * code,const char * desc)190 void gbAddGsCheat(const char *code, const char *desc)
191 {
192   if(gbCheatNumber > 99) {
193     systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
194                   N_("Maximum number of cheats reached."));
195     return;
196   }
197 
198   if(!gbVerifyGsCode(code)) {
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 
gbVerifyGgCode(const char * code)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     if(code[7] != '-')
258       return false;
259     if(code[8] != 0) {
260       if(!GBCHEAT_IS_HEX(code[8]))
261         return false;
262       if(!GBCHEAT_IS_HEX(code[9]))
263         return false;
264       if(!GBCHEAT_IS_HEX(code[10]))
265         return false;
266     }
267   }
268 
269   //  int replace = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
270   //    GBCHEAT_HEX_VALUE(code[1]);
271 
272   int address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
273     (GBCHEAT_HEX_VALUE(code[4]) << 4) +
274     (GBCHEAT_HEX_VALUE(code[5])) +
275     ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
276 
277   if(address >= 0x8000 && address <= 0x9fff)
278     return false;
279 
280   if(address >= 0xc000)
281     return false;
282 
283   if(code[7] == 0 || code[8] == '0')
284     return true;
285 
286   int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
287     (GBCHEAT_HEX_VALUE(code[10]));
288   compare = compare ^ 0xff;
289   compare = (compare >> 2) | ( (compare << 6) & 0xc0);
290   compare ^= 0x45;
291 
292   int cloak = (GBCHEAT_HEX_VALUE(code[8])) ^ (GBCHEAT_HEX_VALUE(code[9]));
293 
294   if(cloak >=1 && cloak <= 7)
295     return false;
296 
297   return true;
298 }
299 
gbAddGgCheat(const char * code,const char * desc)300 void gbAddGgCheat(const char *code, const char *desc)
301 {
302   if(gbCheatNumber > 99) {
303     systemMessage(MSG_MAXIMUM_NUMBER_OF_CHEATS,
304                   N_("Maximum number of cheats reached."));
305     return;
306   }
307 
308   if(!gbVerifyGgCode(code)) {
309     systemMessage(MSG_INVALID_GAMEGENIE_CODE,
310                   N_("Invalid GameGenie code: %s"), code);
311     return;
312   }
313 
314   int i = gbCheatNumber;
315 
316   int len = strlen(code);
317 
318   strcpy(gbCheatList[i].cheatCode, code);
319   strcpy(gbCheatList[i].cheatDesc, desc);
320 
321   gbCheatList[i].code = 1;
322   gbCheatList[i].value = (GBCHEAT_HEX_VALUE(code[0]) << 4) +
323     GBCHEAT_HEX_VALUE(code[1]);
324 
325   gbCheatList[i].address = (GBCHEAT_HEX_VALUE(code[2]) << 8) +
326     (GBCHEAT_HEX_VALUE(code[4]) << 4) +
327     (GBCHEAT_HEX_VALUE(code[5])) +
328     ((GBCHEAT_HEX_VALUE(code[6]) ^ 0x0f) << 12);
329 
330   gbCheatList[i].compare = 0;
331 
332   if(len != 7 && len != 8) {
333 
334     int compare = (GBCHEAT_HEX_VALUE(code[8]) << 4) +
335       (GBCHEAT_HEX_VALUE(code[10]));
336     compare = compare ^ 0xff;
337     compare = (compare >> 2) | ( (compare << 6) & 0xc0);
338     compare ^= 0x45;
339 
340     gbCheatList[i].compare = compare;
341     gbCheatList[i].code = 0;
342   }
343 
344   gbCheatList[i].enabled = true;
345 
346   gbCheatMap[gbCheatList[i].address] = true;
347 
348   gbCheatNumber++;
349 }
350 
gbCheatRemove(int i)351 void gbCheatRemove(int i)
352 {
353   if(i < 0 || i >= gbCheatNumber) {
354     systemMessage(MSG_INVALID_CHEAT_TO_REMOVE,
355                   N_("Invalid cheat to remove %d"), i);
356     return;
357   }
358 
359   if((i+1) <  gbCheatNumber) {
360     memcpy(&gbCheatList[i], &gbCheatList[i+1], sizeof(gbCheat)*
361            (gbCheatNumber-i-1));
362   }
363 
364   gbCheatNumber--;
365 
366   gbCheatUpdateMap();
367 }
368 
gbCheatRemoveAll()369 void gbCheatRemoveAll()
370 {
371   gbCheatNumber = 0;
372   gbCheatUpdateMap();
373 }
374 
gbCheatEnable(int i)375 void gbCheatEnable(int i)
376 {
377   if(i >=0 && i < gbCheatNumber) {
378     if(!gbCheatList[i].enabled) {
379       gbCheatList[i].enabled = true;
380       gbCheatUpdateMap();
381     }
382   }
383 }
384 
gbCheatDisable(int i)385 void gbCheatDisable(int i)
386 {
387   if(i >=0 && i < gbCheatNumber) {
388     if(gbCheatList[i].enabled) {
389       gbCheatList[i].enabled = false;
390       gbCheatUpdateMap();
391     }
392   }
393 }
394 
gbCheatReadGSCodeFile(const char * fileName)395 bool gbCheatReadGSCodeFile(const char *fileName)
396 {
397   FILE *file = fopen(fileName, "rb");
398 
399   if(!file) {
400     systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
401     return false;
402   }
403 
404   fseek(file, 0x18, SEEK_SET);
405   int count = 0;
406   fread(&count, 1, 2, file);
407   int dummy = 0;
408   gbCheatRemoveAll();
409   char desc[13];
410   char code[9];
411   int i;
412   for(i = 0; i < count; i++) {
413     fread(&dummy, 1, 2, file);
414     fread(desc, 1, 12, file);
415     desc[12] = 0;
416     fread(code, 1, 8, file);
417     code[8] = 0;
418     gbAddGsCheat(code, desc);
419   }
420 
421   for(i = 0; i < gbCheatNumber; i++)
422     gbCheatDisable(i);
423 
424   fclose(file);
425   return true;
426 }
427 
gbCheatRead(u16 address)428 u8 gbCheatRead(u16 address)
429 {
430   if(!cheatsEnabled)
431     return gbMemoryMap[address>>12][address & 0xFFF];
432 
433   for(int i = 0; i < gbCheatNumber; i++) {
434     if(gbCheatList[i].enabled && gbCheatList[i].address == address) {
435       switch(gbCheatList[i].code) {
436       case 0x100: // GameGenie support
437         if(gbMemoryMap[address>>12][address&0xFFF] == gbCheatList[i].compare)
438           return gbCheatList[i].value;
439         break;
440       case 0x00:
441       case 0x01:
442       case 0x80:
443         return gbCheatList[i].value;
444       case 0x90:
445       case 0x91:
446       case 0x92:
447       case 0x93:
448       case 0x94:
449       case 0x95:
450       case 0x96:
451       case 0x97:
452         if(address >= 0xd000 && address < 0xe000) {
453           if(((gbMemoryMap[0x0d] - gbWram)/0x1000) ==
454              (gbCheatList[i].code - 0x90))
455             return gbCheatList[i].value;
456         } else
457           return gbCheatList[i].value;
458       }
459     }
460   }
461   return gbMemoryMap[address>>12][address&0xFFF];
462 }
463