Mercurial > vba-clojure
view src/gba/GBACheats.cpp @ 395:6ab872c5a7e7
set H for real
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 13 Apr 2012 04:37:12 -0500 |
parents | f9f4f1b99eed |
children |
line wrap: on
line source
1 #include <cstdio>2 #include <cctype>3 #include <cstring>5 #include "../common/System.h"6 #include "../common/Util.h"7 #include "../NLS.h"8 #include "GBACheats.h"9 #include "GBA.h"10 #include "GBAinline.h"11 #include "GBAGlobals.h"13 /**14 * Gameshark code types:15 *16 * NNNNNNNN 001DC0DE - ID code for the game (game 4 character name) from ROM17 * DEADFACE XXXXXXXX - changes decryption seeds18 * 0AAAAAAA 000000YY - 8-bit constant write19 * 1AAAAAAA 0000YYYY - 16-bit constant write20 * 2AAAAAAA YYYYYYYY - 32-bit constant write21 * 3AAAAAAA YYYYYYYY - ??22 * 6AAAAAAA 0000YYYY - 16-bit ROM Patch (address >> 1)23 * 6AAAAAAA 1000YYYY - 16-bit ROM Patch ? (address >> 1)24 * 6AAAAAAA 2000YYYY - 16-bit ROM Patch ? (address >> 1)25 * 8A1AAAAA 000000YY - 8-bit button write26 * 8A2AAAAA 0000YYYY - 16-bit button write27 * 8A3AAAAA YYYYYYYY - 32-bit button write28 * 80F00000 0000YYYY - button slow motion29 * DAAAAAAA 0000YYYY - if address contains 16-bit value enable next code30 * FAAAAAAA 0000YYYY - Master code function31 *32 * CodeBreaker codes types:33 *34 * 0000AAAA 000Y - Game CRC (Y are flags: 8 - CRC, 2 - DI)35 * 1AAAAAAA YYYY - Master Code function (store address at ((YYYY << 0x16)36 * + 0x08000100))37 * 2AAAAAAA YYYY - 16-bit or38 * 3AAAAAAA YYYY - 8-bit constant write39 * 4AAAAAAA YYYY - Slide code40 * XXXXCCCC IIII (C is count and I is address increment, X is value incr.)41 * 5AAAAAAA CCCC - Super code (Write bytes to address, CCCC is count)42 * BBBBBBBB BBBB43 * 6AAAAAAA YYYY - 16-bit and44 * 7AAAAAAA YYYY - if address contains 16-bit value enable next code45 * 8AAAAAAA YYYY - 16-bit constant write46 * 9AAAAAAA YYYY - change decryption (when first code only?)47 * AAAAAAAA YYYY - if address does not contain 16-bit value enable next code48 * BAAAAAAA YYYY - if 16-bit < YYYY49 * CAAAAAAA YYYY - if 16-bit > YYYY50 * D0000020 YYYY - if button keys equal value enable next code51 * EAAAAAAA YYYY - increase value stored in address52 */53 #define UNKNOWN_CODE -154 #define INT_8_BIT_WRITE 055 #define INT_16_BIT_WRITE 156 #define INT_32_BIT_WRITE 257 #define GSA_16_BIT_ROM_PATCH 358 #define GSA_8_BIT_GS_WRITE 459 #define GSA_16_BIT_GS_WRITE 560 #define GSA_32_BIT_GS_WRITE 661 #define CBA_IF_KEYS_PRESSED 762 #define CBA_IF_TRUE 863 #define CBA_SLIDE_CODE 964 #define CBA_IF_FALSE 1065 #define CBA_AND 1166 #define GSA_8_BIT_GS_WRITE2 1267 #define GSA_16_BIT_GS_WRITE2 1368 #define GSA_32_BIT_GS_WRITE2 1469 #define GSA_16_BIT_ROM_PATCH2 1570 #define GSA_8_BIT_SLIDE 1671 #define GSA_16_BIT_SLIDE 1772 #define GSA_32_BIT_SLIDE 1873 #define GSA_8_BIT_IF_TRUE 1974 #define GSA_32_BIT_IF_TRUE 2075 #define GSA_8_BIT_IF_FALSE 2176 #define GSA_32_BIT_IF_FALSE 2277 #define GSA_8_BIT_FILL 2378 #define GSA_16_BIT_FILL 2479 #define GSA_8_BIT_IF_TRUE2 2580 #define GSA_16_BIT_IF_TRUE2 2681 #define GSA_32_BIT_IF_TRUE2 2782 #define GSA_8_BIT_IF_FALSE2 2883 #define GSA_16_BIT_IF_FALSE2 2984 #define GSA_32_BIT_IF_FALSE2 3085 #define GSA_SLOWDOWN 3186 #define CBA_ADD 3287 #define CBA_OR 3388 #define CBA_LT 3489 #define CBA_GT 3590 #define CBA_SUPER 3692 CheatsData cheatsList[100];93 int cheatsNumber = 0;95 u8 cheatsCBASeedBuffer[0x30];96 u32 cheatsCBASeed[4];97 u32 cheatsCBATemporaryValue = 0;98 u16 cheatsCBATable[256];99 bool cheatsCBATableGenerated = false;101 u8 cheatsCBACurrentSeed[12] = {102 0x00, 0x00, 0x00, 0x00,103 0x00, 0x00, 0x00, 0x00,104 0x00, 0x00, 0x00, 0x00105 };107 #define CHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9'))109 #define CHEAT_PATCH_ROM_16BIT(a, v) \110 WRITE16LE(((u16 *)&rom[(a) & 0x1ffffff]), v);112 static bool isMultilineWithData(int i)113 {114 // we consider it a multiline code if it has more than one line of data115 // otherwise, it can still be considered a single code116 if (i < cheatsNumber && i >= 0)117 switch (cheatsList[i].size)118 {119 case INT_8_BIT_WRITE:120 case INT_16_BIT_WRITE:121 case INT_32_BIT_WRITE:122 case GSA_16_BIT_ROM_PATCH:123 case GSA_8_BIT_GS_WRITE:124 case GSA_16_BIT_GS_WRITE:125 case GSA_32_BIT_GS_WRITE:126 case CBA_AND:127 case CBA_IF_KEYS_PRESSED:128 case CBA_IF_TRUE:129 case CBA_IF_FALSE:130 case GSA_8_BIT_IF_TRUE:131 case GSA_32_BIT_IF_TRUE:132 case GSA_8_BIT_IF_FALSE:133 case GSA_32_BIT_IF_FALSE:134 case GSA_8_BIT_FILL:135 case GSA_16_BIT_FILL:136 case GSA_8_BIT_IF_TRUE2:137 case GSA_16_BIT_IF_TRUE2:138 case GSA_32_BIT_IF_TRUE2:139 case GSA_8_BIT_IF_FALSE2:140 case GSA_16_BIT_IF_FALSE2:141 case GSA_32_BIT_IF_FALSE2:142 case GSA_SLOWDOWN:143 case CBA_ADD:144 case CBA_OR:145 return false;146 // the codes below have two lines of data147 case CBA_SLIDE_CODE:148 case GSA_8_BIT_GS_WRITE2:149 case GSA_16_BIT_GS_WRITE2:150 case GSA_32_BIT_GS_WRITE2:151 case GSA_16_BIT_ROM_PATCH2:152 case GSA_8_BIT_SLIDE:153 case GSA_16_BIT_SLIDE:154 case GSA_32_BIT_SLIDE:155 case CBA_LT:156 case CBA_GT:157 case CBA_SUPER:158 return true;159 }160 return false;161 }163 static int getCodeLength(int num)164 {165 if (num >= cheatsNumber || num < 0)166 return 1;168 // this is for all the codes that are true multiline169 switch (cheatsList[num].size)170 {171 case INT_8_BIT_WRITE:172 case INT_16_BIT_WRITE:173 case INT_32_BIT_WRITE:174 case GSA_16_BIT_ROM_PATCH:175 case GSA_8_BIT_GS_WRITE:176 case GSA_16_BIT_GS_WRITE:177 case GSA_32_BIT_GS_WRITE:178 case CBA_AND:179 case GSA_8_BIT_FILL:180 case GSA_16_BIT_FILL:181 case GSA_SLOWDOWN:182 case CBA_ADD:183 case CBA_OR:184 return 1;185 case CBA_IF_KEYS_PRESSED:186 case CBA_IF_TRUE:187 case CBA_IF_FALSE:188 case CBA_SLIDE_CODE:189 case GSA_8_BIT_GS_WRITE2:190 case GSA_16_BIT_GS_WRITE2:191 case GSA_32_BIT_GS_WRITE2:192 case GSA_16_BIT_ROM_PATCH2:193 case GSA_8_BIT_SLIDE:194 case GSA_16_BIT_SLIDE:195 case GSA_32_BIT_SLIDE:196 case GSA_8_BIT_IF_TRUE:197 case GSA_32_BIT_IF_TRUE:198 case GSA_8_BIT_IF_FALSE:199 case GSA_32_BIT_IF_FALSE:200 case CBA_LT:201 case CBA_GT:202 return 2;203 case GSA_8_BIT_IF_TRUE2:204 case GSA_16_BIT_IF_TRUE2:205 case GSA_32_BIT_IF_TRUE2:206 case GSA_8_BIT_IF_FALSE2:207 case GSA_16_BIT_IF_FALSE2:208 case GSA_32_BIT_IF_FALSE2:209 return 3;210 case CBA_SUPER:211 return (cheatsList[num].value+5)/6;212 }213 return 1;214 }216 int cheatsCheckKeys(u32 keys, u32 extended)217 {218 int ticks = 0;219 for (int i = 0; i < cheatsNumber; i++)220 {221 if (!cheatsList[i].enabled)222 {223 // make sure we skip other lines in this code224 i += getCodeLength(i)-1;225 continue;226 }227 switch (cheatsList[i].size)228 {229 case INT_8_BIT_WRITE:230 CPUWriteByte(cheatsList[i].address, cheatsList[i].value);231 break;232 case INT_16_BIT_WRITE:233 CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value);234 break;235 case INT_32_BIT_WRITE:236 CPUWriteMemory(cheatsList[i].address, cheatsList[i].value);237 break;238 case GSA_16_BIT_ROM_PATCH:239 if ((cheatsList[i].status & 1) == 0)240 {241 if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)242 {243 cheatsList[i].oldValue = CPUReadHalfWord(cheatsList[i].address);244 cheatsList[i].status |= 1;245 CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value);246 }247 }248 break;249 case GSA_8_BIT_GS_WRITE:250 if (extended & 4)251 {252 CPUWriteByte(cheatsList[i].address, cheatsList[i].value);253 }254 break;255 case GSA_16_BIT_GS_WRITE:256 if (extended & 4)257 {258 CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value);259 }260 break;261 case GSA_32_BIT_GS_WRITE:262 if (extended & 4)263 {264 CPUWriteMemory(cheatsList[i].address, cheatsList[i].value);265 }266 break;267 case CBA_IF_KEYS_PRESSED:268 {269 u16 value = cheatsList[i].value;270 u32 addr = cheatsList[i].address;271 if ((addr & 0x30) == 0x20)272 {273 if ((keys & value) != value)274 {275 i++;276 }277 }278 else if ((addr & 0x30) == 0x10)279 {280 if ((keys & value) == value)281 {282 i++;283 }284 }285 break;286 }287 case CBA_IF_TRUE:288 if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)289 {290 i++;291 }292 break;293 case CBA_SLIDE_CODE:294 {295 u32 address = cheatsList[i].address;296 u16 value = cheatsList[i].value;297 i++;298 if (i < cheatsNumber)299 {300 int count = (cheatsList[i].address & 0xFFFF);301 u16 vinc = (cheatsList[i].address >> 16) & 0xFFFF;302 int inc = cheatsList[i].value;304 for (int x = 0; x < count; x++)305 {306 CPUWriteHalfWord(address, value);307 address += inc;308 value += vinc;309 }310 }311 break;312 }313 case CBA_IF_FALSE:314 if (CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value)315 {316 i++;317 }318 break;319 case CBA_AND:320 CPUWriteHalfWord(cheatsList[i].address,321 CPUReadHalfWord(cheatsList[i].address) &322 cheatsList[i].value);323 break;324 case GSA_8_BIT_GS_WRITE2:325 i++;326 if (i < cheatsNumber)327 {328 if (extended & 4)329 {330 CPUWriteByte(cheatsList[i-1].value, cheatsList[i].address);331 }332 }333 break;334 case GSA_16_BIT_GS_WRITE2:335 i++;336 if (i < cheatsNumber)337 {338 if (extended & 4)339 {340 CPUWriteHalfWord(cheatsList[i-1].value, cheatsList[i].address);341 }342 }343 break;344 case GSA_32_BIT_GS_WRITE2:345 i++;346 if (i < cheatsNumber)347 {348 if (extended & 4)349 {350 CPUWriteMemory(cheatsList[i-1].value, cheatsList[i].address);351 }352 }353 break;354 case GSA_16_BIT_ROM_PATCH2:355 i++;356 if (i < cheatsNumber)357 {358 if ((cheatsList[i-1].status & 1) == 0)359 {360 u32 addr = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000;361 if (CPUReadHalfWord(addr) != (cheatsList[i].address & 0xFFFF))362 {363 cheatsList[i-1].oldValue = CPUReadHalfWord(addr);364 cheatsList[i-1].status |= 1;365 CHEAT_PATCH_ROM_16BIT(addr, cheatsList[i].address & 0xFFFF);366 }367 }368 }369 break;370 case GSA_8_BIT_SLIDE:371 i++;372 if (i < cheatsNumber)373 {374 u32 addr = cheatsList[i-1].value;375 u8 value = cheatsList[i].address;376 int vinc = (cheatsList[i].value >> 24) & 255;377 int count = (cheatsList[i].value >> 16) & 255;378 int ainc = (cheatsList[i].value & 0xffff);379 while (count > 0)380 {381 CPUWriteByte(addr, value);382 value += vinc;383 addr += ainc;384 count--;385 }386 }387 break;388 case GSA_16_BIT_SLIDE:389 i++;390 if (i < cheatsNumber)391 {392 u32 addr = cheatsList[i-1].value;393 u16 value = cheatsList[i].address;394 int vinc = (cheatsList[i].value >> 24) & 255;395 int count = (cheatsList[i].value >> 16) & 255;396 int ainc = (cheatsList[i].value & 0xffff)*2;397 while (count > 0)398 {399 CPUWriteHalfWord(addr, value);400 value += vinc;401 addr += ainc;402 count--;403 }404 }405 break;406 case GSA_32_BIT_SLIDE:407 i++;408 if (i < cheatsNumber)409 {410 u32 addr = cheatsList[i-1].value;411 u32 value = cheatsList[i].address;412 int vinc = (cheatsList[i].value >> 24) & 255;413 int count = (cheatsList[i].value >> 16) & 255;414 int ainc = (cheatsList[i].value & 0xffff)*4;415 while (count > 0)416 {417 CPUWriteMemory(addr, value);418 value += vinc;419 addr += ainc;420 count--;421 }422 }423 break;424 case GSA_8_BIT_IF_TRUE:425 if (CPUReadByte(cheatsList[i].address) != cheatsList[i].value)426 {427 i++;428 }429 break;430 case GSA_32_BIT_IF_TRUE:431 if (CPUReadMemory(cheatsList[i].address) != cheatsList[i].value)432 {433 i++;434 }435 break;436 case GSA_8_BIT_IF_FALSE:437 if (CPUReadByte(cheatsList[i].address) == cheatsList[i].value)438 {439 i++;440 }441 break;442 case GSA_32_BIT_IF_FALSE:443 if (CPUReadMemory(cheatsList[i].address) == cheatsList[i].value)444 {445 i++;446 }447 break;448 case GSA_8_BIT_FILL:449 {450 u32 addr = cheatsList[i].address;451 u8 v = cheatsList[i].value & 0xff;452 u32 end = addr + (cheatsList[i].value >> 8);453 do454 {455 CPUWriteByte(addr, v);456 addr++;457 }458 while (addr <= end);459 break;460 }461 case GSA_16_BIT_FILL:462 {463 u32 addr = cheatsList[i].address;464 u16 v = cheatsList[i].value & 0xffff;465 u32 end = addr + ((cheatsList[i].value >> 16) << 1);466 do467 {468 CPUWriteHalfWord(addr, v);469 addr += 2;470 }471 while (addr <= end);472 break;473 }474 case GSA_8_BIT_IF_TRUE2:475 if (CPUReadByte(cheatsList[i].address) != cheatsList[i].value)476 {477 i += 2;478 }479 break;480 case GSA_16_BIT_IF_TRUE2:481 if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value)482 {483 i += 2;484 }485 break;486 case GSA_32_BIT_IF_TRUE2:487 if (CPUReadMemory(cheatsList[i].address) != cheatsList[i].value)488 {489 i += 2;490 }491 break;492 case GSA_8_BIT_IF_FALSE2:493 if (CPUReadByte(cheatsList[i].address) == cheatsList[i].value)494 {495 i += 2;496 }497 break;498 case GSA_16_BIT_IF_FALSE2:499 if (CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value)500 {501 i += 2;502 }503 break;504 case GSA_32_BIT_IF_FALSE2:505 if (CPUReadMemory(cheatsList[i].address) == cheatsList[i].value)506 {507 i += 2;508 }509 break;510 case GSA_SLOWDOWN:511 // check if button was pressed and released, if so toggle our state512 if ((cheatsList[i].status & 4) && !(extended & 4))513 cheatsList[i].status ^= 1;514 if (extended & 4)515 cheatsList[i].status |= 4;516 else517 cheatsList[i].status &= ~4;519 if (cheatsList[i].status & 1)520 ticks += 2*256*((cheatsList[i].value >> 8) & 255);521 break;522 case CBA_ADD:523 CPUWriteHalfWord(cheatsList[i].address,524 CPUReadHalfWord(cheatsList[i].address) +525 (u16)cheatsList[i].value);526 break;527 case CBA_OR:528 CPUWriteHalfWord(cheatsList[i].address,529 CPUReadHalfWord(cheatsList[i].address) |530 cheatsList[i].value);531 break;532 case CBA_LT:533 if (CPUReadHalfWord(cheatsList[i].address) >= cheatsList[i].value)534 i++;535 break;536 case CBA_GT:537 if (CPUReadHalfWord(cheatsList[i].address) <= cheatsList[i].value)538 i++;539 break;540 case CBA_SUPER:541 {542 int count = 2*cheatsList[i].value;543 u32 address = cheatsList[i].address;544 for (int x = 0; x < count; x++)545 {546 u8 b;547 int res = x % 6;548 if (res < 4)549 b = (cheatsList[i].address >> (24-8*res)) & 0xFF;550 else551 b = (cheatsList[i].value >> (8 - 8*(res-4))) & 0x0FF;552 CPUWriteByte(address, b);553 address++;554 if (x && !res)555 i++;556 }557 if (count % 6)558 i++;559 break;560 }561 }562 }563 return ticks;564 }566 void cheatsAdd(const char *codeStr,567 const char *desc,568 u32 address,569 u32 value,570 int code,571 int size)572 {573 if (cheatsNumber < 100)574 {575 int x = cheatsNumber;576 cheatsList[x].code = code;577 cheatsList[x].size = size;578 cheatsList[x].address = address;579 cheatsList[x].value = value;580 strcpy(cheatsList[x].codestring, codeStr);581 strcpy(cheatsList[x].desc, desc);582 cheatsList[x].enabled = true;583 cheatsList[x].status = 0;585 // we only store the old value for this simple codes. ROM patching586 // is taken care when it actually patches the ROM587 switch (cheatsList[x].size)588 {589 case INT_8_BIT_WRITE:590 cheatsList[x].oldValue = CPUReadByte(address);591 break;592 case INT_16_BIT_WRITE:593 cheatsList[x].oldValue = CPUReadHalfWord(address);594 break;595 case INT_32_BIT_WRITE:596 cheatsList[x].oldValue = CPUReadMemory(address);597 break;598 }599 cheatsNumber++;600 }601 }603 void cheatsDelete(int number, bool restore)604 {605 if (number < cheatsNumber && number >= 0)606 {607 int x = number;609 if (restore)610 {611 switch (cheatsList[x].size)612 {613 case INT_8_BIT_WRITE:614 CPUWriteByte(cheatsList[x].address, (u8)cheatsList[x].oldValue);615 break;616 case INT_16_BIT_WRITE:617 CPUWriteHalfWord(cheatsList[x].address, (u16)cheatsList[x].oldValue);618 break;619 case INT_32_BIT_WRITE:620 CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue);621 break;622 case GSA_16_BIT_ROM_PATCH:623 if (cheatsList[x].status & 1)624 {625 cheatsList[x].status &= ~1;626 CHEAT_PATCH_ROM_16BIT(cheatsList[x].address,627 cheatsList[x].oldValue);628 }629 break;630 case GSA_16_BIT_ROM_PATCH2:631 if (cheatsList[x].status & 1)632 {633 cheatsList[x].status &= ~1;634 CHEAT_PATCH_ROM_16BIT(((cheatsList[x].value & 0x00FFFFFF) << 1)+635 0x8000000,636 cheatsList[x].oldValue);637 }638 break;639 }640 }641 if ((x+1) < cheatsNumber)642 {643 memcpy(&cheatsList[x], &cheatsList[x+1], sizeof(CheatsData)*644 (cheatsNumber-x-1));645 }646 cheatsNumber--;647 }648 }650 void cheatsDeleteAll(bool restore)651 {652 for (int i = cheatsNumber-1; i >= 0; i--)653 {654 cheatsDelete(i, restore);655 }656 }658 void cheatsEnable(int i)659 {660 if (i >= 0 && i < cheatsNumber)661 {662 cheatsList[i].enabled = true;663 }664 }666 void cheatsDisable(int i)667 {668 if (i >= 0 && i < cheatsNumber)669 {670 switch (cheatsList[i].size)671 {672 case GSA_16_BIT_ROM_PATCH:673 if (cheatsList[i].status & 1)674 {675 cheatsList[i].status &= ~1;676 CHEAT_PATCH_ROM_16BIT(cheatsList[i].address,677 cheatsList[i].oldValue);678 }679 break;680 case GSA_16_BIT_ROM_PATCH2:681 if (cheatsList[i].status & 1)682 {683 cheatsList[i].status &= ~1;684 CHEAT_PATCH_ROM_16BIT(((cheatsList[i].value & 0x00FFFFFF) << 1)+685 0x8000000,686 cheatsList[i].oldValue);687 }688 break;689 }690 cheatsList[i].enabled = false;691 }692 }694 bool cheatsVerifyCheatCode(const char *code, const char *desc)695 {696 int len = strlen(code);697 if (len != 11 && len != 13 && len != 17)698 {699 systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code);700 return false;701 }703 if (code[8] != ':')704 {705 systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code);706 return false;707 }709 int i;710 for (i = 0; i < 8; i++)711 {712 if (!CHEAT_IS_HEX(code[i]))713 {714 // wrong cheat715 systemMessage(MSG_INVALID_CHEAT_CODE,716 N_("Invalid cheat code '%s'"), code);717 return false;718 }719 }720 for (i = 9; i < len; i++)721 {722 if (!CHEAT_IS_HEX(code[i]))723 {724 // wrong cheat725 systemMessage(MSG_INVALID_CHEAT_CODE,726 N_("Invalid cheat code '%s'"), code);727 return false;728 }729 }731 u32 address = 0;732 u32 value = 0;734 char buffer[10];735 strncpy(buffer, code, 8);736 buffer[8] = 0;737 sscanf(buffer, "%x", &address);739 switch (address >> 24)740 {741 case 2:742 case 3:743 break;744 default:745 systemMessage(MSG_INVALID_CHEAT_CODE_ADDRESS,746 N_("Invalid cheat code address: %08x"),747 address);748 return false;749 }751 strncpy(buffer, &code[9], 8);752 sscanf(buffer, "%x", &value);753 int type = 0;754 if (len == 13)755 type = 1;756 if (len == 17)757 type = 2;758 cheatsAdd(code, desc, address, value, type, type);759 return true;760 }762 void cheatsAddCheatCode(const char *code, const char *desc)763 {764 cheatsVerifyCheatCode(code, desc);765 }767 void cheatsDecryptGSACode(u32& address, u32& value, bool v3)768 {769 u32 rollingseed = 0xC6EF3720;770 u32 seeds_v1[] = { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 };771 u32 seeds_v3[] = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 };772 u32 *seeds = v3 ? seeds_v3 : seeds_v1;774 int bitsleft = 32;775 while (bitsleft > 0)776 {777 value -= ((((address << 4) + seeds[2]) ^ (address + rollingseed)) ^778 ((address >> 5) + seeds[3]));779 address -= ((((value << 4) + seeds[0]) ^ (value + rollingseed)) ^780 ((value >> 5) + seeds[1]));781 rollingseed -= 0x9E3779B9;782 bitsleft--;783 }784 }786 void cheatsAddGSACode(const char *code, const char *desc, bool v3)787 {788 if (strlen(code) != 16)789 {790 // wrong cheat791 systemMessage(MSG_INVALID_GSA_CODE,792 N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY"));793 return;794 }796 int i;797 for (i = 0; i < 16; i++)798 {799 if (!CHEAT_IS_HEX(code[i]))800 {801 // wrong cheat802 systemMessage(MSG_INVALID_GSA_CODE,803 N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY"));804 return;805 }806 }808 char buffer[10];809 strncpy(buffer, code, 8);810 buffer[8] = 0;811 u32 address;812 sscanf(buffer, "%x", &address);813 strncpy(buffer, &code[8], 8);814 buffer[8] = 0;815 u32 value;816 sscanf(buffer, "%x", &value);818 cheatsDecryptGSACode(address, value, v3);820 if (value == 0x1DC0DE)821 {822 u32 gamecode = READ32LE(((u32 *)&rom[0xac]));823 if (gamecode != address)824 {825 char buffer[5];826 *((u32 *)buffer) = address;827 buffer[4] = 0;828 char buffer2[5];829 *((u32 *)buffer2) = READ32LE(((u32 *)&rom[0xac]));830 buffer2[4] = 0;831 systemMessage(MSG_GBA_CODE_WARNING,832 N_("Warning: cheats are for game %s. Current game is %s.\nCodes may not work correctly."),833 buffer, buffer2);834 }835 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, v3 ? 257 : 256,836 UNKNOWN_CODE);837 return;838 }839 if (isMultilineWithData(cheatsNumber-1))840 {841 cheatsAdd(code, desc, address, value, v3 ? 257 : 256, UNKNOWN_CODE);842 return;843 }844 if (v3)845 {846 int type = (address >> 25) & 127;847 u32 addr = (address & 0x00F00000) << 4 | (address & 0x0003FFFF);848 switch (type)849 {850 case 0x00:851 if (address == 0)852 {853 type = (value >> 25) & 127;854 addr = (value & 0x00F00000) << 4 | (value & 0x0003FFFF);855 switch (type)856 {857 case 0x04:858 cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_SLOWDOWN);859 break;860 case 0x08:861 cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_GS_WRITE2);862 break;863 case 0x09:864 cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_GS_WRITE2);865 break;866 case 0x0a:867 cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_GS_WRITE2);868 break;869 case 0x0c:870 case 0x0d:871 case 0x0e:872 case 0x0f:873 cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2);874 break;875 case 0x40:876 cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_SLIDE);877 break;878 case 0x41:879 cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_SLIDE);880 break;881 case 0x42:882 cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_SLIDE);883 break;884 default:885 cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE);886 break;887 }888 }889 else890 cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_FILL);891 break;892 case 0x01:893 cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_FILL);894 break;895 case 0x02:896 cheatsAdd(code, desc, addr, value, 257, INT_32_BIT_WRITE);897 break;898 case 0x04:899 cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE);900 break;901 case 0x05:902 cheatsAdd(code, desc, addr, value, 257, CBA_IF_TRUE);903 break;904 case 0x06:905 cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE);906 break;907 case 0x08:908 cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE);909 break;910 case 0x09:911 cheatsAdd(code, desc, addr, value, 257, CBA_IF_FALSE);912 break;913 case 0x0a:914 cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE);915 break;916 case 0x24:917 cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE2);918 break;919 case 0x25:920 cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_TRUE2);921 break;922 case 0x26:923 cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE2);924 break;925 case 0x28:926 cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE2);927 break;928 case 0x29:929 cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_FALSE2);930 break;931 case 0x2a:932 cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE2);933 break;934 default:935 cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE);936 break;937 }938 }939 else940 {941 int type = (address >> 28) & 15;942 switch (type)943 {944 case 0:945 case 1:946 case 2:947 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, type);948 break;949 case 6:950 address <<= 1;951 type = (address >> 28) & 15;952 if (type == 0x0c)953 {954 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256,955 GSA_16_BIT_ROM_PATCH);956 break;957 }958 // unsupported code959 cheatsAdd(code, desc, address, value, 256,960 UNKNOWN_CODE);961 break;962 case 8:963 switch ((address >> 20) & 15)964 {965 case 1:966 cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,967 GSA_8_BIT_GS_WRITE);968 break;969 case 2:970 cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,971 GSA_16_BIT_GS_WRITE);972 break;973 case 3:974 cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256,975 GSA_32_BIT_GS_WRITE);976 case 15:977 cheatsAdd(code, desc, 0, value & 0xFF00, 256, GSA_SLOWDOWN);978 break;979 default:980 // unsupported code981 cheatsAdd(code, desc, address, value, 256,982 UNKNOWN_CODE);983 break;984 }985 break;986 case 0x0d:987 if (address != 0xDEADFACE)988 {989 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256,990 CBA_IF_TRUE);991 }992 else993 cheatsAdd(code, desc, address, value, 256,994 UNKNOWN_CODE);995 break;996 default:997 // unsupported code998 cheatsAdd(code, desc, address, value, 256,999 UNKNOWN_CODE);1000 break;1001 }1002 }1003 }1005 bool cheatsImportGSACodeFile(const char *name, int game, bool v3)1006 {1007 FILE *f = fopen(name, "rb");1008 if (!f)1009 return false;1011 int games = 0;1012 int len = 0;1013 fseek(f, 0x1e, SEEK_CUR);1014 fread(&games, 1, 4, f);1015 bool found = false;1016 int g = 0;1017 while (games > 0)1018 {1019 if (g == game)1020 {1021 found = true;1022 break;1023 }1024 fread(&len, 1, 4, f);1025 fseek(f, len, SEEK_CUR);1026 int codes = 0;1027 fread(&codes, 1, 4, f);1028 while (codes > 0)1029 {1030 fread(&len, 1, 4, f);1031 fseek(f, len, SEEK_CUR);1032 fseek(f, 8, SEEK_CUR);1033 fread(&len, 1, 4, f);1034 fseek(f, len*12, SEEK_CUR);1035 codes--;1036 }1037 games--;1038 g++;1039 }1040 if (found)1041 {1042 char desc[256];1043 char code[17];1044 fread(&len, 1, 4, f);1045 fseek(f, len, SEEK_CUR);1046 int codes = 0;1047 fread(&codes, 1, 4, f);1048 while (codes > 0)1049 {1050 fread(&len, 1, 4, f);1051 fread(desc, 1, len, f);1052 desc[len] = 0;1053 desc[31] = 0;1054 fread(&len, 1, 4, f);1055 fseek(f, len, SEEK_CUR);1056 fseek(f, 4, SEEK_CUR);1057 fread(&len, 1, 4, f);1058 while (len)1059 {1060 fseek(f, 4, SEEK_CUR);1061 fread(code, 1, 8, f);1062 fseek(f, 4, SEEK_CUR);1063 fread(&code[8], 1, 8, f);1064 code[16] = 0;1065 cheatsAddGSACode(code, desc, v3);1066 len -= 2;1067 }1068 codes--;1069 }1070 }1071 fclose(f);1072 return false;1073 }1075 void cheatsCBAReverseArray(u8 *array, u8 *dest)1076 {1077 dest[0] = array[3];1078 dest[1] = array[2];1079 dest[2] = array[1];1080 dest[3] = array[0];1081 dest[4] = array[5];1082 dest[5] = array[4];1083 }1085 void chatsCBAScramble(u8 *array, int count, u8 b)1086 {1087 u8 *x = array + (count >> 3);1088 u8 *y = array + (b >> 3);1089 u32 z = *x & (1 << (count & 7));1090 u32 x0 = (*x & (~(1 << (count & 7))));1091 if (z != 0)1092 z = 1;1093 if ((*y & (1 << (b & 7))) != 0)1094 x0 |= (1 << (count & 7));1095 *x = x0;1096 u32 temp = *y & (~(1 << (b & 7)));1097 if (z != 0)1098 temp |= (1 << (b & 7));1099 *y = temp;1100 }1102 u32 cheatsCBAGetValue(u8 *array)1103 {1104 return array[0] | array[1]<<8 | array[2] << 16 | array[3]<<24;1105 }1107 u16 cheatsCBAGetData(u8 *array)1108 {1109 return array[4] | array[5]<<8;1110 }1112 void cheatsCBAArrayToValue(u8 *array, u8 *dest)1113 {1114 dest[0] = array[3];1115 dest[1] = array[2];1116 dest[2] = array[1];1117 dest[3] = array[0];1118 dest[4] = array[5];1119 dest[5] = array[4];1120 }1122 void cheatsCBAParseSeedCode(u32 address, u32 value, u32 *array)1123 {1124 array[0] = 1;1125 array[1] = value & 0xFF;1126 array[2] = (address >> 0x10) & 0xFF;1127 array[3] = (value >> 8) & 0xFF;1128 array[4] = (address >> 0x18) & 0x0F;1129 array[5] = address & 0xFFFF;1130 array[6] = address;1131 array[7] = value;1132 }1134 u32 cheatsCBAEncWorker()1135 {1136 u32 x = (cheatsCBATemporaryValue * 0x41c64e6d) + 0x3039;1137 u32 y = (x * 0x41c64e6d) + 0x3039;1138 u32 z = x >> 0x10;1139 x = ((y >> 0x10) & 0x7fff) << 0x0f;1140 z = (z << 0x1e) | x;1141 x = (y * 0x41c64e6d) + 0x3039;1142 cheatsCBATemporaryValue = x;1143 return z | ((x >> 0x10) & 0x7fff);1144 }1146 #define ROR(v, s) \1147 (((v) >> (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))1149 u32 cheatsCBACalcIndex(u32 x, u32 y)1150 {1151 if (y != 0)1152 {1153 if (y == 1)1154 x = 0;1155 else if (x == y)1156 x = 0;1157 if (y < 1)1158 return x;1159 else if (x < y)1160 return x;1161 u32 x0 = 1;1163 while (y < 0x10000000)1164 {1165 if (y < x)1166 {1167 y = y << 4;1168 x0 = x0 << 4;1169 }1170 else1171 break;1172 }1174 while (y < 0x80000000)1175 {1176 if (y < x)1177 {1178 y = y << 1;1179 x0 = x0 << 1;1180 }1181 else1182 break;1183 }1185 loop:1186 u32 z = 0;1187 if (x >= y)1188 x -= y;1189 if (x >= (y >> 1))1190 {1191 x -= (y >> 1);1192 z |= ROR(x0, 1);1193 }1194 if (x >= (y >> 2))1195 {1196 x -= (y >> 2);1197 z |= ROR(x0, 2);1198 }1199 if (x >= (y >> 3))1200 {1201 x -= (y >> 3);1202 z |= ROR(x0, 3);1203 }1205 u32 temp = x0;1207 if (x != 0)1208 {1209 x0 = x0 >> 4;1210 if (x0 != 0)1211 {1212 y = y >> 4;1213 goto loop;1214 }1215 }1217 z = z & 0xe0000000;1219 if (z != 0)1220 {1221 if ((temp & 7) == 0)1222 return x;1223 }1224 else1225 return x;1227 if ((z & ROR(temp, 3)) != 0)1228 x += y >> 3;1229 if ((z & ROR(temp, 2)) != 0)1230 x += y >> 2;1231 if ((z & ROR(temp, 1)) != 0)1232 x += y >> 1;1233 return x;1234 }1235 else1236 {}1237 // should not happen in the current code1238 return 0;1239 }1241 void cheatsCBAUpdateSeedBuffer(u32 a, u8 *buffer, int count)1242 {1243 int i;1244 for (i = 0; i < count; i++)1245 buffer[i] = i;1246 for (i = 0; (u32)i < a; i++)1247 {1248 u32 a = cheatsCBACalcIndex(cheatsCBAEncWorker(), count);1249 u32 b = cheatsCBACalcIndex(cheatsCBAEncWorker(), count);1250 u32 t = buffer[a];1251 buffer[a] = buffer[b];1252 buffer[b] = t;1253 }1254 }1256 void cheatsCBAChangeEncryption(u32 *seed)1257 {1258 int i;1260 cheatsCBATemporaryValue = (seed[1] ^ 0x1111);1261 cheatsCBAUpdateSeedBuffer(0x50, cheatsCBASeedBuffer, 0x30);1262 cheatsCBATemporaryValue = 0x4efad1c3;1264 for (i = 0; (u32)i < seed[4]; i++)1265 {1266 cheatsCBATemporaryValue = cheatsCBAEncWorker();1267 }1268 cheatsCBASeed[2] = cheatsCBAEncWorker();1269 cheatsCBASeed[3] = cheatsCBAEncWorker();1271 cheatsCBATemporaryValue = seed[3] ^ 0xf254;1273 for (i = 0; (u32)i < seed[3]; i++)1274 {1275 cheatsCBATemporaryValue = cheatsCBAEncWorker();1276 }1278 cheatsCBASeed[0] = cheatsCBAEncWorker();1279 cheatsCBASeed[1] = cheatsCBAEncWorker();1281 *((u32 *)&cheatsCBACurrentSeed[0]) = seed[6];1282 *((u32 *)&cheatsCBACurrentSeed[4]) = seed[7];1283 *((u32 *)&cheatsCBACurrentSeed[8]) = 0;1284 }1286 u16 cheatsCBAGenValue(u32 x, u32 y, u32 z)1287 {1288 y <<= 0x10;1289 z <<= 0x10;1290 x <<= 0x18;1291 u32 x0 = (int)y >> 0x10;1292 z = (int)z >> 0x10;1293 x = (int)x >> 0x10;1294 for (int i = 0; i < 8; i++)1295 {1296 u32 temp = z ^ x;1297 if ((int)temp >= 0)1298 {1299 temp = z << 0x11;1300 }1301 else1302 {1303 temp = z << 0x01;1304 temp ^= x0;1305 temp = temp << 0x10;1306 }1307 z = (int)temp >> 0x10;1308 temp = x << 0x11;1309 x = (int)temp >> 0x10;1310 }1311 return z & 0xffff;1312 }1314 void cheatsCBAGenTable()1315 {1316 for (int i = 0; i < 0x100; i++)1317 {1318 cheatsCBATable[i] = cheatsCBAGenValue(i, 0x1021, 0);1319 }1320 cheatsCBATableGenerated = true;1321 }1323 u16 cheatsCBACalcCRC(u8 *rom, int count)1324 {1325 u32 crc = 0xffffffff;1327 if (count & 3)1328 {1329 // 0x08000EAE1330 }1331 else1332 {1333 count = (count >> 2) - 1;1334 if (count != -1)1335 {1336 while (count != -1)1337 {1338 crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)1339 ^ *rom++]) << 0x10) >> 0x10;1340 crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)1341 ^ *rom++]) << 0x10) >> 0x10;1342 crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)1343 ^ *rom++]) << 0x10) >> 0x10;1344 crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18)1345 ^ *rom++]) << 0x10) >> 0x10;1346 count--;1347 }1348 }1349 }1350 return crc & 0xffff;1351 }1353 void cheatsCBADecrypt(u8 *decrypt)1354 {1355 u8 buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };1356 u8 *array = &buffer[1];1358 cheatsCBAReverseArray(decrypt, array);1360 for (int count = 0x2f; count >= 0; count--)1361 {1362 chatsCBAScramble(array, count, cheatsCBASeedBuffer[count]);1363 }1364 cheatsCBAArrayToValue(array, decrypt);1365 *((u32 *)decrypt) = cheatsCBAGetValue(decrypt) ^1366 cheatsCBASeed[0];1367 *((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) ^1368 cheatsCBASeed[1]) & 0xffff;1370 cheatsCBAReverseArray(decrypt, array);1372 u32 cs = cheatsCBAGetValue(cheatsCBACurrentSeed);1373 for (int i = 0; i <= 4; i++)1374 {1375 array[i] = ((cs >> 8) ^ array[i+1]) ^ array[i] ;1376 }1378 array[5] = (cs >> 8) ^ array[5];1380 for (int j = 5; j >= 0; j--)1381 {1382 array[j] = (cs ^ array[j-1]) ^ array[j];1383 }1385 cheatsCBAArrayToValue(array, decrypt);1387 *((u32 *)decrypt) = cheatsCBAGetValue(decrypt)1388 ^ cheatsCBASeed[2];1389 *((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt)1390 ^ cheatsCBASeed[3]) & 0xffff;1391 }1393 int cheatsCBAGetCount()1394 {1395 int count = 0;1396 for (int i = 0; i < cheatsNumber; i++)1397 {1398 if (cheatsList[i].code == 512)1399 count++;1400 }1401 return count;1402 }1404 bool cheatsCBAShouldDecrypt()1405 {1406 for (int i = 0; i < cheatsNumber; i++)1407 {1408 if (cheatsList[i].code == 512)1409 {1410 return (cheatsList[i].codestring[0] == '9');1411 }1412 }1413 return false;1414 }1416 void cheatsAddCBACode(const char *code, const char *desc)1417 {1418 if (strlen(code) != 13)1419 {1420 // wrong cheat1421 systemMessage(MSG_INVALID_CBA_CODE,1422 N_("Invalid CBA code. Format is XXXXXXXX YYYY."));1423 return;1424 }1426 int i;1427 for (i = 0; i < 8; i++)1428 {1429 if (!CHEAT_IS_HEX(code[i]))1430 {1431 // wrong cheat1432 systemMessage(MSG_INVALID_CBA_CODE,1433 N_("Invalid CBA code. Format is XXXXXXXX YYYY."));1434 return;1435 }1436 }1438 if (code[8] != ' ')1439 {1440 systemMessage(MSG_INVALID_CBA_CODE,1441 N_("Invalid CBA code. Format is XXXXXXXX YYYY."));1442 return;1443 }1445 for (i = 9; i < 13; i++)1446 {1447 if (!CHEAT_IS_HEX(code[i]))1448 {1449 // wrong cheat1450 systemMessage(MSG_INVALID_CBA_CODE,1451 N_("Invalid CBA code. Format is XXXXXXXX YYYY."));1452 return;1453 }1454 }1456 char buffer[10];1457 strncpy(buffer, code, 8);1458 buffer[8] = 0;1459 u32 address;1460 sscanf(buffer, "%x", &address);1461 strncpy(buffer, &code[9], 4);1462 buffer[4] = 0;1463 u32 value;1464 sscanf(buffer, "%x", &value);1466 u8 array[8] = {1467 address &255,1468 (address >> 8) & 255,1469 (address >> 16) & 255,1470 (address >> 24) & 255,1471 (value & 255),1472 (value >> 8) & 255,1473 0,1474 01475 };1477 if (cheatsCBAGetCount() == 0 &&1478 (address >> 28) == 9)1479 {1480 u32 seed[8];1481 cheatsCBAParseSeedCode(address, value, seed);1482 cheatsCBAChangeEncryption(seed);1483 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, UNKNOWN_CODE);1484 }1485 else1486 {1487 if (cheatsCBAShouldDecrypt())1488 cheatsCBADecrypt(array);1490 address = READ32LE(((u32 *)array));1491 value = READ16LE(((u16 *)&array[4]));1493 int type = (address >> 28) & 15;1495 if (isMultilineWithData(cheatsNumber-1))1496 {1497 cheatsAdd(code, desc, address, value, 512, UNKNOWN_CODE);1498 return;1499 }1501 switch (type)1502 {1503 case 0x00:1504 {1505 if (!cheatsCBATableGenerated)1506 cheatsCBAGenTable();1507 u32 crc = cheatsCBACalcCRC(rom, 0x10000);1508 if (crc != address)1509 {1510 systemMessage(MSG_CBA_CODE_WARNING,1511 N_("Warning: Codes seem to be for a different game.\nCodes may not work correctly."));1512 }1513 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1514 UNKNOWN_CODE);1515 break;1516 }1517 case 0x02:1518 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1519 CBA_OR);1520 break;1521 case 0x03:1522 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1523 INT_8_BIT_WRITE);1524 break;1525 case 0x04:1526 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1527 CBA_SLIDE_CODE);1528 break;1529 case 0x05:1530 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1531 CBA_SUPER);1532 break;1533 case 0x06:1534 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1535 CBA_AND);1536 break;1537 case 0x07:1538 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1539 CBA_IF_TRUE);1540 break;1541 case 0x08:1542 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1543 INT_16_BIT_WRITE);1544 break;1545 case 0x0a:1546 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1547 CBA_IF_FALSE);1548 break;1549 case 0x0b:1550 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1551 CBA_LT);1552 break;1553 case 0x0c:1554 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1555 CBA_GT);1556 break;1557 case 0x0d:1558 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1559 CBA_IF_KEYS_PRESSED);1560 break;1561 case 0x0e:1562 cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512,1563 CBA_ADD);1564 break;1565 default:1566 // unsupported code1567 cheatsAdd(code, desc, address & 0xFFFFFFFF, value, 512,1568 UNKNOWN_CODE);1569 break;1570 }1571 }1572 }1574 void cheatsSaveGame(gzFile file)1575 {1576 utilWriteInt(file, cheatsNumber);1578 utilGzWrite(file, cheatsList, sizeof(cheatsList));1579 }1581 void cheatsReadGame(gzFile file)1582 {1583 cheatsNumber = 0;1585 cheatsNumber = utilReadInt(file);1587 utilGzRead(file, cheatsList, sizeof(cheatsList));1589 bool firstCodeBreaker = true;1591 for (int i = 0; i < cheatsNumber; i++)1592 {1593 cheatsList[i].status = 0;1594 if (!cheatsList[i].codestring[0])1595 {1596 switch (cheatsList[i].size)1597 {1598 case 0:1599 sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address,1600 cheatsList[i].value);1601 break;1602 case 1:1603 sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address,1604 cheatsList[i].value);1605 break;1606 case 2:1607 sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address,1608 cheatsList[i].value);1609 break;1610 }1611 }1613 if (cheatsList[i].enabled)1614 {1615 cheatsEnable(i);1616 }1618 if (cheatsList[i].code == 512 && firstCodeBreaker)1619 {1620 firstCodeBreaker = false;1621 char buffer[10];1622 strncpy(buffer, cheatsList[i].codestring, 8);1623 buffer[8] = 0;1624 u32 address;1625 sscanf(buffer, "%x", &address);1626 if ((address >> 28) == 9)1627 {1628 strncpy(buffer, &cheatsList[i].codestring[9], 4);1629 buffer[4] = 0;1630 u32 value;1631 sscanf(buffer, "%x", &value);1633 u32 seed[8];1634 cheatsCBAParseSeedCode(address, value, seed);1635 cheatsCBAChangeEncryption(seed);1636 }1637 }1638 }1639 }1641 void cheatsSaveCheatList(const char *file)1642 {1643 if (cheatsNumber == 0)1644 return;1645 FILE *f = fopen(file, "wb");1646 if (f == NULL)1647 return;1648 int version = 1;1649 fwrite(&version, 1, sizeof(version), f);1650 int type = 0;1651 fwrite(&type, 1, sizeof(type), f);1652 fwrite(&cheatsNumber, 1, sizeof(cheatsNumber), f);1653 fwrite(cheatsList, 1, sizeof(cheatsList), f);1654 fclose(f);1655 }1657 bool cheatsLoadCheatList(const char *file)1658 {1659 cheatsNumber = 0;1661 int count = 0;1663 FILE *f = fopen(file, "rb");1665 if (f == NULL)1666 return false;1668 int version = 0;1670 if (fread(&version, 1, sizeof(version), f) != sizeof(version))1671 {1672 fclose(f);1673 return false;1674 }1676 if (version != 1)1677 {1678 systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION,1679 N_("Unsupported cheat list version %d"), version);1680 fclose(f);1681 return false;1682 }1684 int type = 0;1685 if (fread(&type, 1, sizeof(type), f) != sizeof(type))1686 {1687 fclose(f);1688 return false;1689 }1691 if (type != 0)1692 {1693 systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE,1694 N_("Unsupported cheat list type %d"), type);1695 fclose(f);1696 return false;1697 }1699 if (fread(&count, 1, sizeof(count), f) != sizeof(count))1700 {1701 fclose(f);1702 return false;1703 }1705 if (fread(cheatsList, 1, sizeof(cheatsList), f) != sizeof(cheatsList))1706 {1707 fclose(f);1708 return false;1709 }1711 bool firstCodeBreaker = true;1713 for (int i = 0; i < count; i++)1714 {1715 cheatsList[i].status = 0; // remove old status as it is not used1716 if (!cheatsList[i].codestring[0])1717 {1718 switch (cheatsList[i].size)1719 {1720 case 0:1721 sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address,1722 cheatsList[i].value);1723 break;1724 case 1:1725 sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address,1726 cheatsList[i].value);1727 break;1728 case 2:1729 sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address,1730 cheatsList[i].value);1731 break;1732 }1733 }1735 if (cheatsList[i].code == 512 && firstCodeBreaker)1736 {1737 firstCodeBreaker = false;1738 char buffer[10];1739 strncpy(buffer, cheatsList[i].codestring, 8);1740 buffer[8] = 0;1741 u32 address;1742 sscanf(buffer, "%x", &address);1743 if ((address >> 28) == 9)1744 {1745 strncpy(buffer, &cheatsList[i].codestring[9], 4);1746 buffer[4] = 0;1747 u32 value;1748 sscanf(buffer, "%x", &value);1750 u32 seed[8];1751 cheatsCBAParseSeedCode(address, value, seed);1752 cheatsCBAChangeEncryption(seed);1753 }1754 }1755 }1756 cheatsNumber = count;1757 fclose(f);1758 return true;1759 }1761 extern int *extCpuLoopTicks;1762 extern int *extClockTicks;1763 extern int *extTicks;1764 extern int cpuSavedTicks;1766 extern void debuggerBreakOnWrite(u32 *, u32, u32, int);1768 #define CPU_BREAK_LOOP2 \1769 cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \1770 *extCpuLoopTicks = *extClockTicks; \1771 *extTicks = *extClockTicks;1773 void cheatsWriteMemory(u32 *address, u32 value, u32 mask)1774 {1775 #ifdef BKPT_SUPPORT1776 #ifdef SDL1777 if (cheatsNumber == 0)1778 {1779 debuggerBreakOnWrite(address, *address, value, 2);1780 CPU_BREAK_LOOP2;1781 *address = value;1782 return;1783 }1784 #endif1785 #endif1786 }1788 void cheatsWriteHalfWord(u16 *address, u16 value, u16 mask)1789 {1790 #ifdef BKPT_SUPPORT1791 #ifdef SDL1792 if (cheatsNumber == 0)1793 {1794 debuggerBreakOnWrite((u32 *)address, *address, value, 1);1795 CPU_BREAK_LOOP2;1796 *address = value;1797 return;1798 }1799 #endif1800 #endif1801 }1803 #if defined BKPT_SUPPORT && defined SDL1804 void cheatsWriteByte(u8 *address, u8 value)1805 #else1806 void cheatsWriteByte(u8 *, u8)1807 #endif1808 {1809 #ifdef BKPT_SUPPORT1810 #ifdef SDL1811 if (cheatsNumber == 0)1812 {1813 debuggerBreakOnWrite((u32 *)address, *address, value, 0);1814 CPU_BREAK_LOOP2;1815 *address = value;1816 return;1817 }1818 #endif1819 #endif1820 }1822 #undef CPU_BREAK_LOOP2