1 /* Cheat Support for PCSX-Reloaded
2 * Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA
19 #include "psxcommon.h"
23 #include "../frontend/plugin_lib.h" // in_keystate for D4
29 int NumCheatsAllocated = 0;
31 CheatCode *CheatCodes = NULL;
33 int NumCodesAllocated = 0;
36 u32 *SearchResults = NULL;
37 int NumSearchResults = 0;
38 static int NumSearchResultsAllocated = 0;
40 #define ALLOC_INCREMENT 100
42 void ClearAllCheats() {
46 for (i = 0; i < NumCheats; i++) {
47 free(Cheats[i].Descr);
54 NumCheatsAllocated = 0;
56 if (CheatCodes != NULL) {
62 NumCodesAllocated = 0;
65 // load cheats from the specific filename
66 void LoadCheats(const char *filename) {
72 fp = fopen(filename, "r");
79 while (fgets(buf, 255, fp) != NULL) {
83 // Skip comment or blank lines
84 if (buf[0] == '#' || buf[0] == ';' || buf[0] == '/' || buf[0] == '\"' || buf[0] == '\0')
87 if (buf[0] == '[' && buf[strlen(buf) - 1] == ']') {
89 Cheats[NumCheats - 1].n = count;
91 if (NumCheats >= NumCheatsAllocated) {
92 NumCheatsAllocated += ALLOC_INCREMENT;
95 assert(NumCheats == 0);
96 assert(NumCheatsAllocated == ALLOC_INCREMENT);
97 Cheats = (Cheat *)malloc(sizeof(Cheat) * NumCheatsAllocated);
99 Cheats = (Cheat *)realloc(Cheats, sizeof(Cheat) * NumCheatsAllocated);
103 buf[strlen(buf) - 1] = '\0';
107 Cheats[NumCheats].Descr = strdup(buf + 2);
108 Cheats[NumCheats].Enabled = 1;
110 Cheats[NumCheats].Descr = strdup(buf + 1);
111 Cheats[NumCheats].Enabled = 0;
113 Cheats[NumCheats].WasEnabled = 0;
115 Cheats[NumCheats].First = NumCodes;
124 if (NumCodes >= NumCodesAllocated) {
125 NumCodesAllocated += ALLOC_INCREMENT;
127 if (CheatCodes == NULL) {
128 assert(NumCodes == 0);
129 assert(NumCodesAllocated == ALLOC_INCREMENT);
130 CheatCodes = (CheatCode *)malloc(sizeof(CheatCode) * NumCodesAllocated);
132 CheatCodes = (CheatCode *)realloc(CheatCodes, sizeof(CheatCode) * NumCodesAllocated);
136 sscanf(buf, "%x %x", &t1, &t2);
138 CheatCodes[NumCodes].Addr = t1;
139 CheatCodes[NumCodes].Val = t2;
146 Cheats[NumCheats - 1].n = count;
150 SysPrintf(_("Cheats loaded from: %s\n"), filename);
153 // save all cheats to the specified filename
154 void SaveCheats(const char *filename) {
158 fp = fopen(filename, "w");
163 for (i = 0; i < NumCheats; i++) {
164 // write the description
165 if (Cheats[i].Enabled)
166 fprintf(fp, "[*%s]\n", Cheats[i].Descr);
168 fprintf(fp, "[%s]\n", Cheats[i].Descr);
170 // write all cheat codes
171 for (j = 0; j < Cheats[i].n; j++) {
172 fprintf(fp, "%.8X %.4X\n",
173 CheatCodes[Cheats[i].First + j].Addr,
174 CheatCodes[Cheats[i].First + j].Val);
182 SysPrintf(_("Cheats saved to: %s\n"), filename);
185 // apply all enabled cheats
187 int i, j, k, endindex;
190 for (i = 0; i < NumCheats; i++) {
191 was_enabled = Cheats[i].WasEnabled;
192 if (!Cheats[i].Enabled) {
193 if (!Cheats[i].WasEnabled)
196 Cheats[i].WasEnabled = Cheats[i].Enabled;
198 // process all cheat codes
199 endindex = Cheats[i].First + Cheats[i].n;
201 for (j = Cheats[i].First; j < endindex; j++) {
202 u8 type = (uint8_t)(CheatCodes[j].Addr >> 24);
203 u32 addr = (CheatCodes[j].Addr & 0x001FFFFF);
204 u16 val = CheatCodes[j].Val;
210 CheatCodes[j].OldVal = psxMu16(addr);
213 CheatCodes[j].OldVal = psxMu8(addr);
217 else if (!Cheats[i].Enabled) {
218 val = CheatCodes[j].OldVal;
219 if (type != CHEAT_CONST16 && type != CHEAT_CONST8)
225 psxMu8ref(addr) = (u8)val;
229 psxMu16ref(addr) = SWAPu16(val);
232 case CHEAT_SCRATCHPAD16: // 1F
233 psxHs16ref(addr) = SWAPu16(val);
237 psxMu16ref(addr) = SWAPu16(psxMu16(addr) + val);
241 psxMu16ref(addr) = SWAPu16(psxMu16(addr) - val);
245 psxMu8ref(addr) += (u8)val;
249 psxMu8ref(addr) -= (u8)val;
257 type = (uint8_t)(CheatCodes[j].Addr >> 24);
258 taddr = (CheatCodes[j].Addr & 0x001FFFFF);
259 val = CheatCodes[j].Val;
261 if (type == CHEAT_CONST8) {
262 for (k = 0; k < ((addr >> 8) & 0xFF); k++) {
263 psxMu8ref(taddr) = (u8)val;
264 taddr += (s8)(addr & 0xFF);
265 val += (s8)(CheatCodes[j - 1].Val & 0xFF);
268 else if (type == CHEAT_CONST16) {
269 for (k = 0; k < ((addr >> 8) & 0xFF); k++) {
270 psxMu16ref(taddr) = SWAPu16(val);
271 taddr += (s8)(addr & 0xFF);
272 val += (s8)(CheatCodes[j - 1].Val & 0xFF);
282 taddr = (CheatCodes[j].Addr & 0x001FFFFF);
283 for (k = 0; k < val; k++) {
284 psxMu8ref(taddr + k) = PSXMu8(addr + k);
289 if (PSXMu8(addr) != (u8)val)
290 j++; // skip the next code
294 if (PSXMu8(addr) == (u8)val)
295 j++; // skip the next code
298 case CHEAT_LESSTHAN8:
299 if (PSXMu8(addr) >= (u8)val)
300 j++; // skip the next code
303 case CHEAT_GREATERTHAN8:
304 if (PSXMu8(addr) <= (u8)val)
305 j++; // skip the next code
309 if (PSXMu16(addr) != val)
310 j++; // skip the next code
314 if (PSXMu16(addr) == val)
315 j++; // skip the next code
318 case CHEAT_LESSTHAN16:
319 if (PSXMu16(addr) >= val)
320 j++; // skip the next code
323 case CHEAT_GREATERTHAN16:
324 if (PSXMu16(addr) <= val)
325 j++; // skip the next code
328 case CHEAT_BUTTONS1_16: { // D4
329 u16 keys = in_keystate[0];
330 keys = (keys << 8) | (keys >> 8);
332 j++; // skip the next code
337 SysPrintf("unhandled cheat %d,%d code %08X\n",
338 i, j, CheatCodes[j].Addr);
339 Cheats[i].WasEnabled = Cheats[i].Enabled = 0;
346 int AddCheat(const char *descr, char *code) {
350 if (NumCheats >= NumCheatsAllocated) {
351 NumCheatsAllocated += ALLOC_INCREMENT;
353 if (Cheats == NULL) {
354 assert(NumCheats == 0);
355 assert(NumCheatsAllocated == ALLOC_INCREMENT);
356 Cheats = (Cheat *)malloc(sizeof(Cheat) * NumCheatsAllocated);
359 Cheats = (Cheat *)realloc(Cheats, sizeof(Cheat) * NumCheatsAllocated);
363 Cheats[NumCheats].Enabled = 0;
364 Cheats[NumCheats].WasEnabled = 0;
365 Cheats[NumCheats].First = NumCodes;
366 Cheats[NumCheats].n = 0;
372 unsigned int t1, t2, r;
374 while (*p2 != '\n' && *p2 != '\0')
385 r = sscanf(p1, "%x %x", &t1, &t2);
388 SysPrintf("cheat %d: couldn't parse '%s'\n", NumCodes, p1);
389 else if (t1 >= 0x10000000) {
390 if (NumCodes >= NumCodesAllocated) {
391 NumCodesAllocated += ALLOC_INCREMENT;
393 if (CheatCodes == NULL) {
394 assert(NumCodes == 0);
395 assert(NumCodesAllocated == ALLOC_INCREMENT);
396 CheatCodes = (CheatCode *)malloc(sizeof(CheatCode) * NumCodesAllocated);
399 CheatCodes = (CheatCode *)realloc(CheatCodes, sizeof(CheatCode) * NumCodesAllocated);
403 CheatCodes[NumCodes].Addr = t1;
404 CheatCodes[NumCodes].Val = t2;
406 Cheats[NumCheats].n++;
412 if (Cheats[NumCheats].n == 0) {
416 Cheats[NumCheats].Descr = strdup(descr[0] ? descr : _("(Untitled)"));
421 void RemoveCheat(int index) {
422 assert(index >= 0 && index < NumCheats);
424 free(Cheats[index].Descr);
425 Cheats[index].Descr = NULL;
427 while (index < NumCheats - 1) {
428 Cheats[index] = Cheats[index + 1];
435 int EditCheat(int index, const char *descr, char *code) {
440 assert(index >= 0 && index < NumCheats);
448 while (*p2 != '\n' && *p2 != '\0')
459 sscanf(p1, "%x %x", &t1, &t2);
461 if (t1 > 0x10000000) {
462 if (NumCodes >= NumCodesAllocated) {
463 NumCodesAllocated += ALLOC_INCREMENT;
465 if (CheatCodes == NULL) {
466 assert(NumCodes == 0);
467 assert(NumCodesAllocated == ALLOC_INCREMENT);
468 CheatCodes = (CheatCode *)malloc(sizeof(CheatCode) * NumCodesAllocated);
471 CheatCodes = (CheatCode *)realloc(CheatCodes, sizeof(CheatCode) * NumCodesAllocated);
475 CheatCodes[NumCodes].Addr = t1;
476 CheatCodes[NumCodes].Val = t2;
483 if (NumCodes == prev) {
487 free(Cheats[index].Descr);
488 Cheats[index].Descr = strdup(descr[0] ? descr : _("(Untitled)"));
489 Cheats[index].First = prev;
490 Cheats[index].n = NumCodes - prev;
495 void FreeCheatSearchResults() {
496 if (SearchResults != NULL) {
499 SearchResults = NULL;
501 NumSearchResults = 0;
502 NumSearchResultsAllocated = 0;
505 void FreeCheatSearchMem() {
512 void CheatSearchBackupMemory() {
514 memcpy(prevM, psxM, 0x200000);
518 static void CheatSearchInitBackupMemory() {
520 prevM = (s8 *)malloc(0x200000);
521 CheatSearchBackupMemory();
525 static void CheatSearchAddResult(u32 addr) {
526 if (NumSearchResults >= NumSearchResultsAllocated) {
527 NumSearchResultsAllocated += ALLOC_INCREMENT;
529 if (SearchResults == NULL) {
530 SearchResults = (u32 *)malloc(sizeof(u32) * NumSearchResultsAllocated);
533 SearchResults = (u32 *)realloc(SearchResults, sizeof(u32) * NumSearchResultsAllocated);
537 SearchResults[NumSearchResults++] = addr;
540 void CheatSearchEqual8(u8 val) {
543 CheatSearchInitBackupMemory();
545 if (SearchResults == NULL) {
546 // search the whole memory
547 for (i = 0; i < 0x200000; i++) {
548 if (PSXMu8(i) == val) {
549 CheatSearchAddResult(i);
554 // only search within the previous results
557 for (i = 0; i < NumSearchResults; i++) {
558 if (PSXMu8(SearchResults[i]) == val) {
559 SearchResults[j++] = SearchResults[i];
563 NumSearchResults = j;
567 void CheatSearchEqual16(u16 val) {
570 CheatSearchInitBackupMemory();
572 if (SearchResults == NULL) {
573 // search the whole memory
574 for (i = 0; i < 0x200000; i += 2) {
575 if (PSXMu16(i) == val) {
576 CheatSearchAddResult(i);
581 // only search within the previous results
584 for (i = 0; i < NumSearchResults; i++) {
585 if (PSXMu16(SearchResults[i]) == val) {
586 SearchResults[j++] = SearchResults[i];
590 NumSearchResults = j;
594 void CheatSearchEqual32(u32 val) {
597 CheatSearchInitBackupMemory();
599 if (SearchResults == NULL) {
600 // search the whole memory
601 for (i = 0; i < 0x200000; i += 4) {
602 if (PSXMu32(i) == val) {
603 CheatSearchAddResult(i);
608 // only search within the previous results
611 for (i = 0; i < NumSearchResults; i++) {
612 if (PSXMu32(SearchResults[i]) == val) {
613 SearchResults[j++] = SearchResults[i];
617 NumSearchResults = j;
621 void CheatSearchNotEqual8(u8 val) {
624 CheatSearchInitBackupMemory();
626 if (SearchResults == NULL) {
627 // search the whole memory
628 for (i = 0; i < 0x200000; i++) {
629 if (PSXMu8(i) != val) {
630 CheatSearchAddResult(i);
635 // only search within the previous results
638 for (i = 0; i < NumSearchResults; i++) {
639 if (PSXMu8(SearchResults[i]) != val) {
640 SearchResults[j++] = SearchResults[i];
644 NumSearchResults = j;
648 void CheatSearchNotEqual16(u16 val) {
651 CheatSearchInitBackupMemory();
653 if (SearchResults == NULL) {
654 // search the whole memory
655 for (i = 0; i < 0x200000; i += 2) {
656 if (PSXMu16(i) != val) {
657 CheatSearchAddResult(i);
662 // only search within the previous results
665 for (i = 0; i < NumSearchResults; i++) {
666 if (PSXMu16(SearchResults[i]) != val) {
667 SearchResults[j++] = SearchResults[i];
671 NumSearchResults = j;
675 void CheatSearchNotEqual32(u32 val) {
678 CheatSearchInitBackupMemory();
680 if (SearchResults == NULL) {
681 // search the whole memory
682 for (i = 0; i < 0x200000; i += 4) {
683 if (PSXMu32(i) != val) {
684 CheatSearchAddResult(i);
689 // only search within the previous results
692 for (i = 0; i < NumSearchResults; i++) {
693 if (PSXMu32(SearchResults[i]) != val) {
694 SearchResults[j++] = SearchResults[i];
698 NumSearchResults = j;
702 void CheatSearchRange8(u8 min, u8 max) {
705 CheatSearchInitBackupMemory();
707 if (SearchResults == NULL) {
708 // search the whole memory
709 for (i = 0; i < 0x200000; i++) {
710 if (PSXMu8(i) >= min && PSXMu8(i) <= max) {
711 CheatSearchAddResult(i);
716 // only search within the previous results
719 for (i = 0; i < NumSearchResults; i++) {
720 if (PSXMu8(SearchResults[i]) >= min && PSXMu8(SearchResults[i]) <= max) {
721 SearchResults[j++] = SearchResults[i];
725 NumSearchResults = j;
729 void CheatSearchRange16(u16 min, u16 max) {
732 CheatSearchInitBackupMemory();
734 if (SearchResults == NULL) {
735 // search the whole memory
736 for (i = 0; i < 0x200000; i += 2) {
737 if (PSXMu16(i) >= min && PSXMu16(i) <= max) {
738 CheatSearchAddResult(i);
743 // only search within the previous results
746 for (i = 0; i < NumSearchResults; i++) {
747 if (PSXMu16(SearchResults[i]) >= min && PSXMu16(SearchResults[i]) <= max) {
748 SearchResults[j++] = SearchResults[i];
752 NumSearchResults = j;
756 void CheatSearchRange32(u32 min, u32 max) {
759 CheatSearchInitBackupMemory();
761 if (SearchResults == NULL) {
762 // search the whole memory
763 for (i = 0; i < 0x200000; i += 4) {
764 if (PSXMu32(i) >= min && PSXMu32(i) <= max) {
765 CheatSearchAddResult(i);
770 // only search within the previous results
773 for (i = 0; i < NumSearchResults; i++) {
774 if (PSXMu32(SearchResults[i]) >= min && PSXMu32(SearchResults[i]) <= max) {
775 SearchResults[j++] = SearchResults[i];
779 NumSearchResults = j;
783 void CheatSearchIncreasedBy8(u8 val) {
786 assert(prevM != NULL); // not possible for the first search
790 for (i = 0; i < NumSearchResults; i++) {
791 if (PSXMu8(SearchResults[i]) - PrevMu8(SearchResults[i]) == val) {
792 SearchResults[j++] = SearchResults[i];
796 NumSearchResults = j;
799 void CheatSearchIncreasedBy16(u16 val) {
802 assert(prevM != NULL); // not possible for the first search
806 for (i = 0; i < NumSearchResults; i++) {
807 if (PSXMu16(SearchResults[i]) - PrevMu16(SearchResults[i]) == val) {
808 SearchResults[j++] = SearchResults[i];
812 NumSearchResults = j;
815 void CheatSearchIncreasedBy32(u32 val) {
818 assert(prevM != NULL); // not possible for the first search
822 for (i = 0; i < NumSearchResults; i++) {
823 if (PSXMu32(SearchResults[i]) - PrevMu32(SearchResults[i]) == val) {
824 SearchResults[j++] = SearchResults[i];
828 NumSearchResults = j;
831 void CheatSearchDecreasedBy8(u8 val) {
834 assert(prevM != NULL); // not possible for the first search
838 for (i = 0; i < NumSearchResults; i++) {
839 if (PrevMu8(SearchResults[i]) - PSXMu8(SearchResults[i]) == val) {
840 SearchResults[j++] = SearchResults[i];
844 NumSearchResults = j;
847 void CheatSearchDecreasedBy16(u16 val) {
850 assert(prevM != NULL); // not possible for the first search
854 for (i = 0; i < NumSearchResults; i++) {
855 if (PrevMu16(SearchResults[i]) - PSXMu16(SearchResults[i]) == val) {
856 SearchResults[j++] = SearchResults[i];
860 NumSearchResults = j;
863 void CheatSearchDecreasedBy32(u32 val) {
866 assert(prevM != NULL); // not possible for the first search
870 for (i = 0; i < NumSearchResults; i++) {
871 if (PrevMu32(SearchResults[i]) - PSXMu32(SearchResults[i]) == val) {
872 SearchResults[j++] = SearchResults[i];
876 NumSearchResults = j;
879 void CheatSearchIncreased8() {
882 assert(prevM != NULL); // not possible for the first search
886 for (i = 0; i < NumSearchResults; i++) {
887 if (PrevMu8(SearchResults[i]) < PSXMu8(SearchResults[i])) {
888 SearchResults[j++] = SearchResults[i];
892 NumSearchResults = j;
895 void CheatSearchIncreased16() {
898 assert(prevM != NULL); // not possible for the first search
902 for (i = 0; i < NumSearchResults; i++) {
903 if (PrevMu16(SearchResults[i]) < PSXMu16(SearchResults[i])) {
904 SearchResults[j++] = SearchResults[i];
908 NumSearchResults = j;
911 void CheatSearchIncreased32() {
914 assert(prevM != NULL); // not possible for the first search
918 for (i = 0; i < NumSearchResults; i++) {
919 if (PrevMu32(SearchResults[i]) < PSXMu32(SearchResults[i])) {
920 SearchResults[j++] = SearchResults[i];
924 NumSearchResults = j;
927 void CheatSearchDecreased8() {
930 assert(prevM != NULL); // not possible for the first search
934 for (i = 0; i < NumSearchResults; i++) {
935 if (PrevMu8(SearchResults[i]) > PSXMu8(SearchResults[i])) {
936 SearchResults[j++] = SearchResults[i];
940 NumSearchResults = j;
943 void CheatSearchDecreased16() {
946 assert(prevM != NULL); // not possible for the first search
950 for (i = 0; i < NumSearchResults; i++) {
951 if (PrevMu16(SearchResults[i]) > PSXMu16(SearchResults[i])) {
952 SearchResults[j++] = SearchResults[i];
956 NumSearchResults = j;
959 void CheatSearchDecreased32() {
962 assert(prevM != NULL); // not possible for the first search
966 for (i = 0; i < NumSearchResults; i++) {
967 if (PrevMu32(SearchResults[i]) > PSXMu32(SearchResults[i])) {
968 SearchResults[j++] = SearchResults[i];
972 NumSearchResults = j;
975 void CheatSearchDifferent8() {
978 assert(prevM != NULL); // not possible for the first search
982 for (i = 0; i < NumSearchResults; i++) {
983 if (PrevMu8(SearchResults[i]) != PSXMu8(SearchResults[i])) {
984 SearchResults[j++] = SearchResults[i];
988 NumSearchResults = j;
991 void CheatSearchDifferent16() {
994 assert(prevM != NULL); // not possible for the first search
998 for (i = 0; i < NumSearchResults; i++) {
999 if (PrevMu16(SearchResults[i]) != PSXMu16(SearchResults[i])) {
1000 SearchResults[j++] = SearchResults[i];
1004 NumSearchResults = j;
1007 void CheatSearchDifferent32() {
1010 assert(prevM != NULL); // not possible for the first search
1014 for (i = 0; i < NumSearchResults; i++) {
1015 if (PrevMu32(SearchResults[i]) != PSXMu32(SearchResults[i])) {
1016 SearchResults[j++] = SearchResults[i];
1020 NumSearchResults = j;
1023 void CheatSearchNoChange8() {
1026 assert(prevM != NULL); // not possible for the first search
1030 for (i = 0; i < NumSearchResults; i++) {
1031 if (PrevMu8(SearchResults[i]) == PSXMu8(SearchResults[i])) {
1032 SearchResults[j++] = SearchResults[i];
1036 NumSearchResults = j;
1039 void CheatSearchNoChange16() {
1042 assert(prevM != NULL); // not possible for the first search
1046 for (i = 0; i < NumSearchResults; i++) {
1047 if (PrevMu16(SearchResults[i]) == PSXMu16(SearchResults[i])) {
1048 SearchResults[j++] = SearchResults[i];
1052 NumSearchResults = j;
1055 void CheatSearchNoChange32() {
1058 assert(prevM != NULL); // not possible for the first search
1062 for (i = 0; i < NumSearchResults; i++) {
1063 if (PrevMu32(SearchResults[i]) == PSXMu32(SearchResults[i])) {
1064 SearchResults[j++] = SearchResults[i];
1068 NumSearchResults = j;