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