Mercurial > vba-clojure
comparison src/gb/gbCheats.cpp @ 19:5e8e5083da94
brought in common and gba, fixed problems with outdated Makefile.am files in both of these packages
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 04 Mar 2012 14:33:52 -0600 |
parents | f9f4f1b99eed |
children |
comparison
equal
deleted
inserted
replaced
18:ac56489c2ca6 | 19:5e8e5083da94 |
---|---|
19 #define GBCHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9')) | 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') | 20 #define GBCHEAT_HEX_VALUE(a) ((a) >= 'A' ? (a) - 'A' + 10 : (a) - '0') |
21 | 21 |
22 void gbCheatUpdateMap() | 22 void gbCheatUpdateMap() |
23 { | 23 { |
24 memset(gbCheatMap, 0, 0x10000); | 24 memset(gbCheatMap, 0, 0x10000); |
25 | 25 |
26 for (int i = 0; i < gbCheatNumber; i++) | 26 for (int i = 0; i < gbCheatNumber; i++) |
27 { | 27 { |
28 if (gbCheatList[i].enabled) | 28 if (gbCheatList[i].enabled) |
29 gbCheatMap[gbCheatList[i].address] = true; | 29 gbCheatMap[gbCheatList[i].address] = true; |
30 } | 30 } |
31 } | 31 } |
32 | 32 |
33 void gbCheatsSaveGame(gzFile gzFile) | 33 void gbCheatsSaveGame(gzFile gzFile) |
34 { | 34 { |
35 utilWriteInt(gzFile, gbCheatNumber); | 35 utilWriteInt(gzFile, gbCheatNumber); |
36 if (gbCheatNumber) | 36 if (gbCheatNumber) |
37 utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); | 37 utilGzWrite(gzFile, &gbCheatList[0], sizeof(gbCheat)*gbCheatNumber); |
38 } | 38 } |
39 | 39 |
40 void gbCheatsReadGame(gzFile gzFile, int version) | 40 void gbCheatsReadGame(gzFile gzFile, int version) |
41 { | 41 { |
42 if (version <= 8) | 42 if (version <= 8) |
43 { | 43 { |
44 int gbGgOn = utilReadInt(gzFile); | 44 int gbGgOn = utilReadInt(gzFile); |
45 | 45 |
46 if (gbGgOn) | 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) | |
47 { | 465 { |
48 int n = utilReadInt(gzFile); | 466 if (((gbMemoryMap[0x0d] - gbWram)/0x1000) == |
49 gbXxCheat tmpCheat; | 467 (gbCheatList[i].code - 0x90)) |
50 for (int i = 0; i < n; i++) | 468 return gbCheatList[i].value; |
51 { | |
52 utilGzRead(gzFile, &tmpCheat, sizeof(gbXxCheat)); | |
53 gbAddGgCheat(tmpCheat.cheatCode, tmpCheat.cheatDesc); | |
54 } | |
55 } | 469 } |
56 | 470 else |
57 int gbGsOn = utilReadInt(gzFile); | 471 return gbCheatList[i].value; |
58 | 472 } |
59 if (gbGsOn) | 473 } |
60 { | 474 } |
61 int n = utilReadInt(gzFile); | 475 return gbReadMemoryQuick(address); |
62 gbXxCheat tmpCheat; | 476 } |
63 for (int i = 0; i < n; i++) | 477 |
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 |