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
21 #include "psxcommon.h"
25 #include "../frontend/plugin_lib.h" // in_keystate for D4
31 int NumCheatsAllocated = 0;
33 CheatCode *CheatCodes = NULL;
35 int NumCodesAllocated = 0;
38 u32 *SearchResults = NULL;
39 int NumSearchResults = 0;
40 static int NumSearchResultsAllocated = 0;
42 #define ALLOC_INCREMENT 100
44 void ClearAllCheats() {
48 for (i = 0; i < NumCheats; i++) {
49 free(Cheats[i].Descr);
56 NumCheatsAllocated = 0;
58 if (CheatCodes != NULL) {
64 NumCodesAllocated = 0;
67 // load cheats from the specific filename
68 void LoadCheats(const char *filename) {
74 fp = fopen(filename, "r");
81 while (fgets(buf, 255, fp) != NULL) {
85 // Skip comment or blank lines
86 if (buf[0] == '#' || buf[0] == ';' || buf[0] == '/' || buf[0] == '\"' || buf[0] == '\0')
89 if (buf[0] == '[' && buf[strlen(buf) - 1] == ']') {
91 Cheats[NumCheats - 1].n = count;
93 if (NumCheats >= NumCheatsAllocated) {
94 NumCheatsAllocated += ALLOC_INCREMENT;
97 assert(NumCheats == 0);
98 assert(NumCheatsAllocated == ALLOC_INCREMENT);
99 Cheats = (Cheat *)malloc(sizeof(Cheat) * NumCheatsAllocated);
101 Cheats = (Cheat *)realloc(Cheats, sizeof(Cheat) * NumCheatsAllocated);
105 buf[strlen(buf) - 1] = '\0';
109 Cheats[NumCheats].Descr = strdup(buf + 2);
110 Cheats[NumCheats].Enabled = 1;
112 Cheats[NumCheats].Descr = strdup(buf + 1);
113 Cheats[NumCheats].Enabled = 0;
115 Cheats[NumCheats].WasEnabled = 0;
117 Cheats[NumCheats].First = NumCodes;
126 if (NumCodes >= NumCodesAllocated) {
127 NumCodesAllocated += ALLOC_INCREMENT;
129 if (CheatCodes == NULL) {
130 assert(NumCodes == 0);
131 assert(NumCodesAllocated == ALLOC_INCREMENT);
132 CheatCodes = (CheatCode *)malloc(sizeof(CheatCode) * NumCodesAllocated);
134 CheatCodes = (CheatCode *)realloc(CheatCodes, sizeof(CheatCode) * NumCodesAllocated);
138 sscanf(buf, "%x %x", &t1, &t2);
140 CheatCodes[NumCodes].Addr = t1;
141 CheatCodes[NumCodes].Val = t2;
148 Cheats[NumCheats - 1].n = count;
152 SysPrintf(_("Cheats loaded from: %s\n"), filename);
155 // save all cheats to the specified filename
156 void SaveCheats(const char *filename) {
160 fp = fopen(filename, "w");
165 for (i = 0; i < NumCheats; i++) {
166 // write the description
167 if (Cheats[i].Enabled)
168 fprintf(fp, "[*%s]\n", Cheats[i].Descr);
170 fprintf(fp, "[%s]\n", Cheats[i].Descr);
172 // write all cheat codes
173 for (j = 0; j < Cheats[i].n; j++) {
174 fprintf(fp, "%.8X %.4X\n",
175 CheatCodes[Cheats[i].First + j].Addr,
176 CheatCodes[Cheats[i].First + j].Val);
184 SysPrintf(_("Cheats saved to: %s\n"), filename);
187 // apply all enabled cheats
189 int i, j, k, endindex;
192 for (i = 0; i < NumCheats; i++) {
193 was_enabled = Cheats[i].WasEnabled;
194 if (!Cheats[i].Enabled) {
195 if (!Cheats[i].WasEnabled)
198 Cheats[i].WasEnabled = Cheats[i].Enabled;
200 // process all cheat codes
201 endindex = Cheats[i].First + Cheats[i].n;
203 for (j = Cheats[i].First; j < endindex; j++) {
204 u8 type = (uint8_t)(CheatCodes[j].Addr >> 24);
205 u32 addr = (CheatCodes[j].Addr & 0x001FFFFF);
206 u16 val = CheatCodes[j].Val;
212 CheatCodes[j].OldVal = psxMu16(addr);
215 CheatCodes[j].OldVal = psxMu8(addr);
219 else if (!Cheats[i].Enabled) {
220 val = CheatCodes[j].OldVal;
221 if (type != CHEAT_CONST16 && type != CHEAT_CONST8)
227 psxMu8ref(addr) = (u8)val;
231 psxMu16ref(addr) = SWAPu16(val);
234 case CHEAT_SCRATCHPAD16: // 1F
235 psxHs16ref(addr) = SWAPu16(val);
239 psxMu16ref(addr) = SWAPu16(psxMu16(addr) + val);
243 psxMu16ref(addr) = SWAPu16(psxMu16(addr) - val);
247 psxMu8ref(addr) += (u8)val;
251 psxMu8ref(addr) -= (u8)val;
259 type = (uint8_t)(CheatCodes[j].Addr >> 24);
260 taddr = (CheatCodes[j].Addr & 0x001FFFFF);
261 val = CheatCodes[j].Val;
263 if (type == CHEAT_CONST8) {
264 for (k = 0; k < ((addr >> 8) & 0xFF); k++) {
265 psxMu8ref(taddr) = (u8)val;
266 taddr += (s8)(addr & 0xFF);
267 val += (s8)(CheatCodes[j - 1].Val & 0xFF);
270 else if (type == CHEAT_CONST16) {
271 for (k = 0; k < ((addr >> 8) & 0xFF); k++) {
272 psxMu16ref(taddr) = SWAPu16(val);
273 taddr += (s8)(addr & 0xFF);
274 val += (s8)(CheatCodes[j - 1].Val & 0xFF);
284 taddr = (CheatCodes[j].Addr & 0x001FFFFF);
285 for (k = 0; k < val; k++) {
286 psxMu8ref(taddr + k) = PSXMu8(addr + k);
291 if (PSXMu8(addr) != (u8)val)
292 j++; // skip the next code
296 if (PSXMu8(addr) == (u8)val)
297 j++; // skip the next code
300 case CHEAT_LESSTHAN8:
301 if (PSXMu8(addr) >= (u8)val)
302 j++; // skip the next code
305 case CHEAT_GREATERTHAN8:
306 if (PSXMu8(addr) <= (u8)val)
307 j++; // skip the next code
311 if (PSXMu16(addr) != val)
312 j++; // skip the next code
316 if (PSXMu16(addr) == val)
317 j++; // skip the next code
320 case CHEAT_LESSTHAN16:
321 if (PSXMu16(addr) >= val)
322 j++; // skip the next code
325 case CHEAT_GREATERTHAN16:
326 if (PSXMu16(addr) <= val)
327 j++; // skip the next code
330 case CHEAT_BUTTONS1_16: { // D4
331 u16 keys = in_keystate[0];
332 keys = (keys << 8) | (keys >> 8);
334 j++; // skip the next code
339 SysPrintf("unhandled cheat %d,%d code %08X\n",
340 i, j, CheatCodes[j].Addr);
341 Cheats[i].WasEnabled = Cheats[i].Enabled = 0;
348 int AddCheat(const char *descr, char *code) {
352 if (NumCheats >= NumCheatsAllocated) {
353 NumCheatsAllocated += ALLOC_INCREMENT;
355 if (Cheats == NULL) {
356 assert(NumCheats == 0);
357 assert(NumCheatsAllocated == ALLOC_INCREMENT);
358 Cheats = (Cheat *)malloc(sizeof(Cheat) * NumCheatsAllocated);
361 Cheats = (Cheat *)realloc(Cheats, sizeof(Cheat) * NumCheatsAllocated);
365 Cheats[NumCheats].Enabled = 0;
366 Cheats[NumCheats].WasEnabled = 0;
367 Cheats[NumCheats].First = NumCodes;
368 Cheats[NumCheats].n = 0;
374 unsigned int t1, t2, r;
376 while (*p2 != '\n' && *p2 != '\0')
387 r = sscanf(p1, "%x %x", &t1, &t2);
390 SysPrintf("cheat %d: couldn't parse '%s'\n", NumCodes, p1);
391 else if (t1 >= 0x10000000) {
392 if (NumCodes >= NumCodesAllocated) {
393 NumCodesAllocated += ALLOC_INCREMENT;
395 if (CheatCodes == NULL) {
396 assert(NumCodes == 0);
397 assert(NumCodesAllocated == ALLOC_INCREMENT);
398 CheatCodes = (CheatCode *)malloc(sizeof(CheatCode) * NumCodesAllocated);
401 CheatCodes = (CheatCode *)realloc(CheatCodes, sizeof(CheatCode) * NumCodesAllocated);
405 CheatCodes[NumCodes].Addr = t1;
406 CheatCodes[NumCodes].Val = t2;
408 Cheats[NumCheats].n++;
414 if (Cheats[NumCheats].n == 0) {
418 Cheats[NumCheats].Descr = strdup(descr[0] ? descr : _("(Untitled)"));
423 void RemoveCheat(int index) {
424 assert(index >= 0 && index < NumCheats);
426 free(Cheats[index].Descr);
427 Cheats[index].Descr = NULL;
429 while (index < NumCheats - 1) {
430 Cheats[index] = Cheats[index + 1];
437 int EditCheat(int index, const char *descr, char *code) {
442 assert(index >= 0 && index < NumCheats);
450 while (*p2 != '\n' && *p2 != '\0')
461 sscanf(p1, "%x %x", &t1, &t2);
463 if (t1 > 0x10000000) {
464 if (NumCodes >= NumCodesAllocated) {
465 NumCodesAllocated += ALLOC_INCREMENT;
467 if (CheatCodes == NULL) {
468 assert(NumCodes == 0);
469 assert(NumCodesAllocated == ALLOC_INCREMENT);
470 CheatCodes = (CheatCode *)malloc(sizeof(CheatCode) * NumCodesAllocated);
473 CheatCodes = (CheatCode *)realloc(CheatCodes, sizeof(CheatCode) * NumCodesAllocated);
477 CheatCodes[NumCodes].Addr = t1;
478 CheatCodes[NumCodes].Val = t2;
485 if (NumCodes == prev) {
489 free(Cheats[index].Descr);
490 Cheats[index].Descr = strdup(descr[0] ? descr : _("(Untitled)"));
491 Cheats[index].First = prev;
492 Cheats[index].n = NumCodes - prev;
497 void FreeCheatSearchResults() {
498 if (SearchResults != NULL) {
501 SearchResults = NULL;
503 NumSearchResults = 0;
504 NumSearchResultsAllocated = 0;
507 void FreeCheatSearchMem() {
514 void CheatSearchBackupMemory() {
516 memcpy(prevM, psxM, 0x200000);
520 static void CheatSearchInitBackupMemory() {
522 prevM = (s8 *)malloc(0x200000);
523 CheatSearchBackupMemory();
527 static void CheatSearchAddResult(u32 addr) {
528 if (NumSearchResults >= NumSearchResultsAllocated) {
529 NumSearchResultsAllocated += ALLOC_INCREMENT;
531 if (SearchResults == NULL) {
532 SearchResults = (u32 *)malloc(sizeof(u32) * NumSearchResultsAllocated);
535 SearchResults = (u32 *)realloc(SearchResults, sizeof(u32) * NumSearchResultsAllocated);
539 SearchResults[NumSearchResults++] = addr;
542 void CheatSearchEqual8(u8 val) {
545 CheatSearchInitBackupMemory();
547 if (SearchResults == NULL) {
548 // search the whole memory
549 for (i = 0; i < 0x200000; i++) {
550 if (PSXMu8(i) == val) {
551 CheatSearchAddResult(i);
556 // only search within the previous results
559 for (i = 0; i < NumSearchResults; i++) {
560 if (PSXMu8(SearchResults[i]) == val) {
561 SearchResults[j++] = SearchResults[i];
565 NumSearchResults = j;
569 void CheatSearchEqual16(u16 val) {
572 CheatSearchInitBackupMemory();
574 if (SearchResults == NULL) {
575 // search the whole memory
576 for (i = 0; i < 0x200000; i += 2) {
577 if (PSXMu16(i) == val) {
578 CheatSearchAddResult(i);
583 // only search within the previous results
586 for (i = 0; i < NumSearchResults; i++) {
587 if (PSXMu16(SearchResults[i]) == val) {
588 SearchResults[j++] = SearchResults[i];
592 NumSearchResults = j;
596 void CheatSearchEqual32(u32 val) {
599 CheatSearchInitBackupMemory();
601 if (SearchResults == NULL) {
602 // search the whole memory
603 for (i = 0; i < 0x200000; i += 4) {
604 if (PSXMu32(i) == val) {
605 CheatSearchAddResult(i);
610 // only search within the previous results
613 for (i = 0; i < NumSearchResults; i++) {
614 if (PSXMu32(SearchResults[i]) == val) {
615 SearchResults[j++] = SearchResults[i];
619 NumSearchResults = j;
623 void CheatSearchNotEqual8(u8 val) {
626 CheatSearchInitBackupMemory();
628 if (SearchResults == NULL) {
629 // search the whole memory
630 for (i = 0; i < 0x200000; i++) {
631 if (PSXMu8(i) != val) {
632 CheatSearchAddResult(i);
637 // only search within the previous results
640 for (i = 0; i < NumSearchResults; i++) {
641 if (PSXMu8(SearchResults[i]) != val) {
642 SearchResults[j++] = SearchResults[i];
646 NumSearchResults = j;
650 void CheatSearchNotEqual16(u16 val) {
653 CheatSearchInitBackupMemory();
655 if (SearchResults == NULL) {
656 // search the whole memory
657 for (i = 0; i < 0x200000; i += 2) {
658 if (PSXMu16(i) != val) {
659 CheatSearchAddResult(i);
664 // only search within the previous results
667 for (i = 0; i < NumSearchResults; i++) {
668 if (PSXMu16(SearchResults[i]) != val) {
669 SearchResults[j++] = SearchResults[i];
673 NumSearchResults = j;
677 void CheatSearchNotEqual32(u32 val) {
680 CheatSearchInitBackupMemory();
682 if (SearchResults == NULL) {
683 // search the whole memory
684 for (i = 0; i < 0x200000; i += 4) {
685 if (PSXMu32(i) != val) {
686 CheatSearchAddResult(i);
691 // only search within the previous results
694 for (i = 0; i < NumSearchResults; i++) {
695 if (PSXMu32(SearchResults[i]) != val) {
696 SearchResults[j++] = SearchResults[i];
700 NumSearchResults = j;
704 void CheatSearchRange8(u8 min, u8 max) {
707 CheatSearchInitBackupMemory();
709 if (SearchResults == NULL) {
710 // search the whole memory
711 for (i = 0; i < 0x200000; i++) {
712 if (PSXMu8(i) >= min && PSXMu8(i) <= max) {
713 CheatSearchAddResult(i);
718 // only search within the previous results
721 for (i = 0; i < NumSearchResults; i++) {
722 if (PSXMu8(SearchResults[i]) >= min && PSXMu8(SearchResults[i]) <= max) {
723 SearchResults[j++] = SearchResults[i];
727 NumSearchResults = j;
731 void CheatSearchRange16(u16 min, u16 max) {
734 CheatSearchInitBackupMemory();
736 if (SearchResults == NULL) {
737 // search the whole memory
738 for (i = 0; i < 0x200000; i += 2) {
739 if (PSXMu16(i) >= min && PSXMu16(i) <= max) {
740 CheatSearchAddResult(i);
745 // only search within the previous results
748 for (i = 0; i < NumSearchResults; i++) {
749 if (PSXMu16(SearchResults[i]) >= min && PSXMu16(SearchResults[i]) <= max) {
750 SearchResults[j++] = SearchResults[i];
754 NumSearchResults = j;
758 void CheatSearchRange32(u32 min, u32 max) {
761 CheatSearchInitBackupMemory();
763 if (SearchResults == NULL) {
764 // search the whole memory
765 for (i = 0; i < 0x200000; i += 4) {
766 if (PSXMu32(i) >= min && PSXMu32(i) <= max) {
767 CheatSearchAddResult(i);
772 // only search within the previous results
775 for (i = 0; i < NumSearchResults; i++) {
776 if (PSXMu32(SearchResults[i]) >= min && PSXMu32(SearchResults[i]) <= max) {
777 SearchResults[j++] = SearchResults[i];
781 NumSearchResults = j;
785 void CheatSearchIncreasedBy8(u8 val) {
788 assert(prevM != NULL); // not possible for the first search
792 for (i = 0; i < NumSearchResults; i++) {
793 if (PSXMu8(SearchResults[i]) - PrevMu8(SearchResults[i]) == val) {
794 SearchResults[j++] = SearchResults[i];
798 NumSearchResults = j;
801 void CheatSearchIncreasedBy16(u16 val) {
804 assert(prevM != NULL); // not possible for the first search
808 for (i = 0; i < NumSearchResults; i++) {
809 if (PSXMu16(SearchResults[i]) - PrevMu16(SearchResults[i]) == val) {
810 SearchResults[j++] = SearchResults[i];
814 NumSearchResults = j;
817 void CheatSearchIncreasedBy32(u32 val) {
820 assert(prevM != NULL); // not possible for the first search
824 for (i = 0; i < NumSearchResults; i++) {
825 if (PSXMu32(SearchResults[i]) - PrevMu32(SearchResults[i]) == val) {
826 SearchResults[j++] = SearchResults[i];
830 NumSearchResults = j;
833 void CheatSearchDecreasedBy8(u8 val) {
836 assert(prevM != NULL); // not possible for the first search
840 for (i = 0; i < NumSearchResults; i++) {
841 if (PrevMu8(SearchResults[i]) - PSXMu8(SearchResults[i]) == val) {
842 SearchResults[j++] = SearchResults[i];
846 NumSearchResults = j;
849 void CheatSearchDecreasedBy16(u16 val) {
852 assert(prevM != NULL); // not possible for the first search
856 for (i = 0; i < NumSearchResults; i++) {
857 if (PrevMu16(SearchResults[i]) - PSXMu16(SearchResults[i]) == val) {
858 SearchResults[j++] = SearchResults[i];
862 NumSearchResults = j;
865 void CheatSearchDecreasedBy32(u32 val) {
868 assert(prevM != NULL); // not possible for the first search
872 for (i = 0; i < NumSearchResults; i++) {
873 if (PrevMu32(SearchResults[i]) - PSXMu32(SearchResults[i]) == val) {
874 SearchResults[j++] = SearchResults[i];
878 NumSearchResults = j;
881 void CheatSearchIncreased8() {
884 assert(prevM != NULL); // not possible for the first search
888 for (i = 0; i < NumSearchResults; i++) {
889 if (PrevMu8(SearchResults[i]) < PSXMu8(SearchResults[i])) {
890 SearchResults[j++] = SearchResults[i];
894 NumSearchResults = j;
897 void CheatSearchIncreased16() {
900 assert(prevM != NULL); // not possible for the first search
904 for (i = 0; i < NumSearchResults; i++) {
905 if (PrevMu16(SearchResults[i]) < PSXMu16(SearchResults[i])) {
906 SearchResults[j++] = SearchResults[i];
910 NumSearchResults = j;
913 void CheatSearchIncreased32() {
916 assert(prevM != NULL); // not possible for the first search
920 for (i = 0; i < NumSearchResults; i++) {
921 if (PrevMu32(SearchResults[i]) < PSXMu32(SearchResults[i])) {
922 SearchResults[j++] = SearchResults[i];
926 NumSearchResults = j;
929 void CheatSearchDecreased8() {
932 assert(prevM != NULL); // not possible for the first search
936 for (i = 0; i < NumSearchResults; i++) {
937 if (PrevMu8(SearchResults[i]) > PSXMu8(SearchResults[i])) {
938 SearchResults[j++] = SearchResults[i];
942 NumSearchResults = j;
945 void CheatSearchDecreased16() {
948 assert(prevM != NULL); // not possible for the first search
952 for (i = 0; i < NumSearchResults; i++) {
953 if (PrevMu16(SearchResults[i]) > PSXMu16(SearchResults[i])) {
954 SearchResults[j++] = SearchResults[i];
958 NumSearchResults = j;
961 void CheatSearchDecreased32() {
964 assert(prevM != NULL); // not possible for the first search
968 for (i = 0; i < NumSearchResults; i++) {
969 if (PrevMu32(SearchResults[i]) > PSXMu32(SearchResults[i])) {
970 SearchResults[j++] = SearchResults[i];
974 NumSearchResults = j;
977 void CheatSearchDifferent8() {
980 assert(prevM != NULL); // not possible for the first search
984 for (i = 0; i < NumSearchResults; i++) {
985 if (PrevMu8(SearchResults[i]) != PSXMu8(SearchResults[i])) {
986 SearchResults[j++] = SearchResults[i];
990 NumSearchResults = j;
993 void CheatSearchDifferent16() {
996 assert(prevM != NULL); // not possible for the first search
1000 for (i = 0; i < NumSearchResults; i++) {
1001 if (PrevMu16(SearchResults[i]) != PSXMu16(SearchResults[i])) {
1002 SearchResults[j++] = SearchResults[i];
1006 NumSearchResults = j;
1009 void CheatSearchDifferent32() {
1012 assert(prevM != NULL); // not possible for the first search
1016 for (i = 0; i < NumSearchResults; i++) {
1017 if (PrevMu32(SearchResults[i]) != PSXMu32(SearchResults[i])) {
1018 SearchResults[j++] = SearchResults[i];
1022 NumSearchResults = j;
1025 void CheatSearchNoChange8() {
1028 assert(prevM != NULL); // not possible for the first search
1032 for (i = 0; i < NumSearchResults; i++) {
1033 if (PrevMu8(SearchResults[i]) == PSXMu8(SearchResults[i])) {
1034 SearchResults[j++] = SearchResults[i];
1038 NumSearchResults = j;
1041 void CheatSearchNoChange16() {
1044 assert(prevM != NULL); // not possible for the first search
1048 for (i = 0; i < NumSearchResults; i++) {
1049 if (PrevMu16(SearchResults[i]) == PSXMu16(SearchResults[i])) {
1050 SearchResults[j++] = SearchResults[i];
1054 NumSearchResults = j;
1057 void CheatSearchNoChange32() {
1060 assert(prevM != NULL); // not possible for the first search
1064 for (i = 0; i < NumSearchResults; i++) {
1065 if (PrevMu32(SearchResults[i]) == PSXMu32(SearchResults[i])) {
1066 SearchResults[j++] = SearchResults[i];
1070 NumSearchResults = j;