1 /* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Xodnizel
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <ctype.h>
25
26 #include "fceu-types.h"
27 #include "x6502.h"
28 #include "cheat.h"
29 #include "fceu.h"
30 #include "general.h"
31 #include "cart.h"
32 #include "fceu-memory.h"
33
34 static uint8 *CheatRPtrs[64];
35 uint8 *MMapPtrs[64];
36
FCEU_CheatResetRAM(void)37 void FCEU_CheatResetRAM(void) {
38 int x;
39
40 for (x = 0; x < 64; x++)
41 CheatRPtrs[x] = 0;
42 }
43
FCEU_CheatAddRAM(int s,uint32 A,uint8 * p)44 void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p) {
45 uint32 AB = A >> 10;
46 int x;
47
48 for (x = s - 1; x >= 0; x--) {
49 CheatRPtrs[AB + x] = p - A;
50 MMapPtrs[AB + x] = p + 1024 * x;
51 }
52 }
53
54
55 struct CHEATF {
56 struct CHEATF *next;
57 char *name;
58 uint16 addr;
59 uint8 val;
60 int compare; /* -1 for no compare. */
61 int type; /* 0 for replace, 1 for substitute(GG). */
62 int status;
63 };
64
65 typedef struct {
66 uint16 addr;
67 uint8 val;
68 int compare;
69 readfunc PrevRead;
70 } CHEATF_SUBFAST;
71
72
73 static CHEATF_SUBFAST SubCheats[256];
74 static int numsubcheats = 0;
75 struct CHEATF *cheats = 0, *cheatsl = 0;
76
77
78 #define CHEATC_NONE 0x8000
79 #define CHEATC_EXCLUDED 0x4000
80 #define CHEATC_NOSHOW 0xC000
81
82 static uint16 *CheatComp = 0;
83 static int savecheats;
84
DECLFR(SubCheatsRead)85 static DECLFR(SubCheatsRead) {
86 CHEATF_SUBFAST *s = SubCheats;
87 int x = numsubcheats;
88
89 do {
90 if (s->addr == A) {
91 if (s->compare >= 0) {
92 uint8 pv = s->PrevRead(A);
93
94 if (pv == s->compare)
95 return(s->val);
96 else
97 return(pv);
98 } else return(s->val);
99 }
100 s++;
101 } while (--x);
102 return(0); /* We should never get here. */
103 }
104
RebuildSubCheats(void)105 void RebuildSubCheats(void) {
106 int x;
107 struct CHEATF *c = cheats;
108
109 for (x = 0; x < numsubcheats; x++)
110 SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead);
111
112 numsubcheats = 0;
113 while (c) {
114 if (c->type == 1 && c->status) {
115 if (GetReadHandler(c->addr) == SubCheatsRead) {
116 /* Prevent a catastrophe by this check. */
117 /* FCEU_DispMessage("oops"); */
118 } else {
119 SubCheats[numsubcheats].PrevRead = GetReadHandler(c->addr);
120 SubCheats[numsubcheats].addr = c->addr;
121 SubCheats[numsubcheats].val = c->val;
122 SubCheats[numsubcheats].compare = c->compare;
123 SetReadHandler(c->addr, c->addr, SubCheatsRead);
124 numsubcheats++;
125 }
126 }
127 c = c->next;
128 }
129 }
130
FCEU_PowerCheats()131 void FCEU_PowerCheats() {
132 numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */
133 RebuildSubCheats();
134 }
135
136 static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type);
CheatMemErr(void)137 static void CheatMemErr(void) {
138 FCEUD_PrintError("Error allocating memory for cheat data.");
139 }
140
141 /* This function doesn't allocate any memory for "name" */
AddCheatEntry(char * name,uint32 addr,uint8 val,int compare,int status,int type)142 static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type) {
143 struct CHEATF *temp;
144 if (!(temp = (struct CHEATF*)malloc(sizeof(struct CHEATF)))) {
145 CheatMemErr();
146 return(0);
147 }
148 temp->name = name;
149 temp->addr = addr;
150 temp->val = val;
151 temp->status = status;
152 temp->compare = compare;
153 temp->type = type;
154 temp->next = 0;
155
156 if (cheats) {
157 cheatsl->next = temp;
158 cheatsl = temp;
159 } else
160 cheats = cheatsl = temp;
161
162 return(1);
163 }
164
FCEU_LoadGameCheats(FILE * override)165 void FCEU_LoadGameCheats(FILE *override)
166 {
167 numsubcheats = savecheats = 0;
168 RebuildSubCheats();
169 }
170
FCEU_FlushGameCheats(FILE * override,int nosave)171 void FCEU_FlushGameCheats(FILE *override, int nosave) {
172 if (CheatComp)
173 {
174 free(CheatComp);
175 CheatComp = 0;
176 }
177 RebuildSubCheats(); /* Remove memory handlers. */
178 }
179
FCEU_ResetCheats(void)180 void FCEU_ResetCheats(void)
181 {
182 if (CheatComp) {
183 free(CheatComp);
184 CheatComp = 0;
185 }
186
187 if (cheats)
188 {
189 struct CHEATF *next = cheats;
190 for (;; ) {
191 struct CHEATF *last = next;
192 next = next->next;
193 free(last->name);
194 free(last);
195 if (!next) break;
196 }
197 cheats = cheatsl = 0;
198 }
199
200 RebuildSubCheats(); /* Remove memory handlers. */
201 }
202
203
FCEUI_AddCheat(const char * name,uint32 addr,uint8 val,int compare,int type)204 int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type) {
205 char *t;
206
207 if (!(t = (char*)malloc(strlen(name) + 1))) {
208 CheatMemErr();
209 return(0);
210 }
211 strcpy(t, name);
212 if (!AddCheatEntry(t, addr, val, compare, 1, type)) {
213 free(t);
214 return(0);
215 }
216 savecheats = 1;
217 RebuildSubCheats();
218 return(1);
219 }
220
FCEUI_DelCheat(uint32 which)221 int FCEUI_DelCheat(uint32 which) {
222 struct CHEATF *prev;
223 struct CHEATF *cur;
224 uint32 x = 0;
225
226 for (prev = 0, cur = cheats;; ) {
227 if (x == which) { /* Remove this cheat. */
228 if (prev) { /* Update pointer to this cheat. */
229 if (cur->next) /* More cheats. */
230 prev->next = cur->next;
231 else { /* No more. */
232 prev->next = 0;
233 cheatsl = prev; /* Set the previous cheat as the last cheat. */
234 }
235 } else {/* This is the first cheat. */
236 if (cur->next) /* More cheats */
237 cheats = cur->next;
238 else
239 cheats = cheatsl = 0; /* No (more) cheats. */
240 }
241 free(cur->name);/* Now that all references to this cheat are removed, */
242 free(cur); /* free the memory. */
243 break;
244 } /* *END REMOVE THIS CHEAT* */
245
246
247 if (!cur->next) /* No more cheats to go through(this shouldn't ever happen...) */
248 return(0);
249 prev = cur;
250 cur = prev->next;
251 x++;
252 }
253
254 savecheats = 1;
255 RebuildSubCheats();
256
257 return(1);
258 }
259
FCEU_ApplyPeriodicCheats(void)260 void FCEU_ApplyPeriodicCheats(void) {
261 struct CHEATF *cur = cheats;
262 if (!cur) return;
263
264 for (;; ) {
265 if (cur->status && !(cur->type))
266 if (CheatRPtrs[cur->addr >> 10])
267 CheatRPtrs[cur->addr >> 10][cur->addr] = cur->val;
268 if (cur->next)
269 cur = cur->next;
270 else
271 break;
272 }
273 }
274
275
FCEUI_ListCheats(int (* callb)(char * name,uint32 a,uint8 v,int compare,int s,int type,void * data),void * data)276 void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data) {
277 struct CHEATF *next = cheats;
278
279 while (next) {
280 if (!callb(next->name, next->addr, next->val, next->compare, next->status, next->type, data)) break;
281 next = next->next;
282 }
283 }
284
FCEUI_GetCheat(uint32 which,char ** name,uint32 * a,uint8 * v,int * compare,int * s,int * type)285 int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type) {
286 struct CHEATF *next = cheats;
287 uint32 x = 0;
288
289 while (next) {
290 if (x == which) {
291 if (name)
292 *name = next->name;
293 if (a)
294 *a = next->addr;
295 if (v)
296 *v = next->val;
297 if (s)
298 *s = next->status;
299 if (compare)
300 *compare = next->compare;
301 if (type)
302 *type = next->type;
303 return(1);
304 }
305 next = next->next;
306 x++;
307 }
308 return(0);
309 }
310
GGtobin(char c)311 static int GGtobin(char c) {
312 static char lets[16] = { 'A', 'P', 'Z', 'L', 'G', 'I', 'T', 'Y', 'E', 'O', 'X', 'U', 'K', 'S', 'V', 'N' };
313 int x;
314
315 for (x = 0; x < 16; x++)
316 if (lets[x] == toupper(c)) return(x);
317 return(0);
318 }
319
320 /* Returns 1 on success, 0 on failure. Sets *a,*v,*c. */
FCEUI_DecodeGG(const char * str,uint16 * a,uint8 * v,int * c)321 int FCEUI_DecodeGG(const char *str, uint16 *a, uint8 *v, int *c) {
322 uint16 A;
323 uint8 V, C;
324 uint8 t;
325 int s;
326
327 A = 0x8000;
328 V = 0;
329 C = 0;
330
331 s = strlen(str);
332 if (s != 6 && s != 8) return(0);
333
334 t = GGtobin(*str++);
335 V |= (t & 0x07);
336 V |= (t & 0x08) << 4;
337
338 t = GGtobin(*str++);
339 V |= (t & 0x07) << 4;
340 A |= (t & 0x08) << 4;
341
342 t = GGtobin(*str++);
343 A |= (t & 0x07) << 4;
344 /* if(t&0x08) return(0); */ /* 8-character code?! */
345
346 t = GGtobin(*str++);
347 A |= (t & 0x07) << 12;
348 A |= (t & 0x08);
349
350 t = GGtobin(*str++);
351 A |= (t & 0x07);
352 A |= (t & 0x08) << 8;
353
354 if (s == 6) {
355 t = GGtobin(*str++);
356 A |= (t & 0x07) << 8;
357 V |= (t & 0x08);
358
359 *a = A;
360 *v = V;
361 *c = -1;
362 return(1);
363 } else {
364 t = GGtobin(*str++);
365 A |= (t & 0x07) << 8;
366 C |= (t & 0x08);
367
368 t = GGtobin(*str++);
369 C |= (t & 0x07);
370 C |= (t & 0x08) << 4;
371
372 t = GGtobin(*str++);
373 C |= (t & 0x07) << 4;
374 V |= (t & 0x08);
375 *a = A;
376 *v = V;
377 *c = C;
378 return(1);
379 }
380 return(0);
381 }
382
FCEUI_DecodePAR(const char * str,uint16 * a,uint8 * v,int * c,int * type)383 int FCEUI_DecodePAR(const char *str, uint16 *a, uint8 *v, int *c, int *type) {
384 int boo[4];
385 if (strlen(str) != 8) return(0);
386
387 sscanf(str, "%02x%02x%02x%02x", boo, boo + 1, boo + 2, boo + 3);
388
389 *c = -1;
390
391 /* 2020-08-31 - negativeExponent
392 * Why is the top code set as default on non-debug runtime when
393 * bottom code is what works for PAR?
394 */
395 /* if (1) {
396 *a = (boo[3] << 8) | (boo[2] + 0x7F);
397 *v = 0;
398 } else {
399 *v = boo[3];
400 *a = boo[2] | (boo[1] << 8);
401 } */
402
403 *v = boo[3];
404 *a = boo[2] | (boo[1] << 8);
405
406 /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so
407 we must do the old hacky method of RAM cheats.
408 */
409 if (*a < 0x0100)
410 *type = 0;
411 else
412 *type = 1;
413 return(1);
414 }
415
416 /* name can be NULL if the name isn't going to be changed. */
417 /* same goes for a, v, and s(except the values of each one must be <0) */
418
FCEUI_SetCheat(uint32 which,const char * name,int32 a,int32 v,int compare,int s,int type)419 int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare, int s, int type) {
420 struct CHEATF *next = cheats;
421 uint32 x = 0;
422
423 while (next) {
424 if (x == which) {
425 if (name) {
426 char *t;
427
428 if ((t = (char*)realloc(next->name, strlen(name) + 1))) {
429 next->name = t;
430 strcpy(next->name, name);
431 } else
432 return(0);
433 }
434 if (a >= 0)
435 next->addr = a;
436 if (v >= 0)
437 next->val = v;
438 if (s >= 0)
439 next->status = s;
440 if (compare >= 0)
441 next->compare = compare;
442 next->type = type;
443
444 savecheats = 1;
445 RebuildSubCheats();
446
447 return(1);
448 }
449 next = next->next;
450 x++;
451 }
452 return(0);
453 }
454
455 /* Convenience function. */
FCEUI_ToggleCheat(uint32 which)456 int FCEUI_ToggleCheat(uint32 which) {
457 struct CHEATF *next = cheats;
458 uint32 x = 0;
459
460 while (next) {
461 if (x == which) {
462 next->status = !next->status;
463 savecheats = 1;
464 RebuildSubCheats();
465 return(next->status);
466 }
467 next = next->next;
468 x++;
469 }
470
471 return(-1);
472 }
473
InitCheatComp(void)474 static int InitCheatComp(void) {
475 uint32 x;
476
477 CheatComp = (uint16*)malloc(65536 * sizeof(uint16));
478 if (!CheatComp) {
479 CheatMemErr();
480 return(0);
481 }
482 for (x = 0; x < 65536; x++)
483 CheatComp[x] = CHEATC_NONE;
484
485 return(1);
486 }
487
FCEUI_CheatSearchSetCurrentAsOriginal(void)488 void FCEUI_CheatSearchSetCurrentAsOriginal(void) {
489 uint32 x;
490 for (x = 0x000; x < 0x10000; x++)
491 if (!(CheatComp[x] & CHEATC_NOSHOW)) {
492 if (CheatRPtrs[x >> 10])
493 CheatComp[x] = CheatRPtrs[x >> 10][x];
494 else
495 CheatComp[x] |= CHEATC_NONE;
496 }
497 }
498
FCEUI_CheatSearchShowExcluded(void)499 void FCEUI_CheatSearchShowExcluded(void) {
500 uint32 x;
501
502 for (x = 0x000; x < 0x10000; x++)
503 CheatComp[x] &= ~CHEATC_EXCLUDED;
504 }
505
506
FCEUI_CheatSearchGetCount(void)507 int32 FCEUI_CheatSearchGetCount(void) {
508 uint32 x, c = 0;
509
510 if (CheatComp) {
511 for (x = 0x0000; x < 0x10000; x++)
512 if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10])
513 c++;
514 }
515
516 return c;
517 }
518 /* This function will give the initial value of the search and the current value at a location. */
519
FCEUI_CheatSearchGet(int (* callb)(uint32 a,uint8 last,uint8 current,void * data),void * data)520 void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data), void *data) {
521 uint32 x;
522
523 if (!CheatComp) {
524 if (!InitCheatComp())
525 CheatMemErr();
526 return;
527 }
528
529 for (x = 0; x < 0x10000; x++)
530 if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10])
531 if (!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x], data))
532 break;
533 }
534
FCEUI_CheatSearchGetRange(uint32 first,uint32 last,int (* callb)(uint32 a,uint8 last,uint8 current))535 void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current)) {
536 uint32 x;
537 uint32 in = 0;
538
539 if (!CheatComp) {
540 if (!InitCheatComp())
541 CheatMemErr();
542 return;
543 }
544
545 for (x = 0; x < 0x10000; x++)
546 if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10]) {
547 if (in >= first)
548 if (!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x]))
549 break;
550 in++;
551 if (in > last) return;
552 }
553 }
554
FCEUI_CheatSearchBegin(void)555 void FCEUI_CheatSearchBegin(void) {
556 uint32 x;
557
558 if (!CheatComp) {
559 if (!InitCheatComp()) {
560 CheatMemErr();
561 return;
562 }
563 }
564 for (x = 0; x < 0x10000; x++) {
565 if (CheatRPtrs[x >> 10])
566 CheatComp[x] = CheatRPtrs[x >> 10][x];
567 else
568 CheatComp[x] = CHEATC_NONE;
569 }
570 }
571
572
CAbs(int x)573 static INLINE int CAbs(int x) {
574 if (x < 0)
575 return(0 - x);
576 return x;
577 }
578
FCEUI_CheatSearchEnd(int type,uint8 v1,uint8 v2)579 void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2) {
580 uint32 x;
581
582 if (!CheatComp) {
583 if (!InitCheatComp()) {
584 CheatMemErr();
585 return;
586 }
587 }
588
589
590 if (!type) {/* Change to a specific value. */
591 for (x = 0; x < 0x10000; x++)
592 if (!(CheatComp[x] & CHEATC_NOSHOW)) {
593 if (CheatComp[x] == v1 && CheatRPtrs[x >> 10][x] == v2) {
594 } else
595 CheatComp[x] |= CHEATC_EXCLUDED;
596 }
597 } else if (type == 1) { /* Search for relative change(between values). */
598 for (x = 0; x < 0x10000; x++)
599 if (!(CheatComp[x] & CHEATC_NOSHOW)) {
600 if (CheatComp[x] == v1 && CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) == v2) {
601 } else
602 CheatComp[x] |= CHEATC_EXCLUDED;
603 }
604 } else if (type == 2) { /* Purely relative change. */
605 for (x = 0x000; x < 0x10000; x++)
606 if (!(CheatComp[x] & CHEATC_NOSHOW)) {
607 if (CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) == v2) {
608 } else
609 CheatComp[x] |= CHEATC_EXCLUDED;
610 }
611 } else if (type == 3) { /* Any change. */
612 for (x = 0; x < 0x10000; x++)
613 if (!(CheatComp[x] & CHEATC_NOSHOW)) {
614 if (CheatComp[x] != CheatRPtrs[x >> 10][x]) {
615 } else
616 CheatComp[x] |= CHEATC_EXCLUDED;
617 }
618 } else if (type == 4) { /* Value decreased. */
619 for (x = 0; x < 0x10000; x++)
620 if (!(CheatComp[x] & CHEATC_NOSHOW)) {
621 if (!(CheatRPtrs[x >> 10][x] < CheatComp[x]))
622 CheatComp[x] |= CHEATC_EXCLUDED;
623 }
624 } else if (type == 5) { /* Value increased. */
625 for (x = 0; x < 0x10000; x++)
626 if (!(CheatComp[x] & CHEATC_NOSHOW)) {
627 if (!(CheatRPtrs[x >> 10][x] > CheatComp[x]))
628 CheatComp[x] |= CHEATC_EXCLUDED;
629 }
630 }
631 if (type > 4)
632 FCEUI_CheatSearchSetCurrentAsOriginal();
633 }
634