rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: #include "../common/System.h" rlm@1: #include "../common/Util.h" rlm@1: #include "../NLS.h" rlm@1: #include "GBACheats.h" rlm@1: #include "GBA.h" rlm@1: #include "GBAinline.h" rlm@1: #include "GBAGlobals.h" rlm@1: rlm@1: /** rlm@1: * Gameshark code types: rlm@1: * rlm@1: * NNNNNNNN 001DC0DE - ID code for the game (game 4 character name) from ROM rlm@1: * DEADFACE XXXXXXXX - changes decryption seeds rlm@1: * 0AAAAAAA 000000YY - 8-bit constant write rlm@1: * 1AAAAAAA 0000YYYY - 16-bit constant write rlm@1: * 2AAAAAAA YYYYYYYY - 32-bit constant write rlm@1: * 3AAAAAAA YYYYYYYY - ?? rlm@1: * 6AAAAAAA 0000YYYY - 16-bit ROM Patch (address >> 1) rlm@1: * 6AAAAAAA 1000YYYY - 16-bit ROM Patch ? (address >> 1) rlm@1: * 6AAAAAAA 2000YYYY - 16-bit ROM Patch ? (address >> 1) rlm@1: * 8A1AAAAA 000000YY - 8-bit button write rlm@1: * 8A2AAAAA 0000YYYY - 16-bit button write rlm@1: * 8A3AAAAA YYYYYYYY - 32-bit button write rlm@1: * 80F00000 0000YYYY - button slow motion rlm@1: * DAAAAAAA 0000YYYY - if address contains 16-bit value enable next code rlm@1: * FAAAAAAA 0000YYYY - Master code function rlm@1: * rlm@1: * CodeBreaker codes types: rlm@1: * rlm@1: * 0000AAAA 000Y - Game CRC (Y are flags: 8 - CRC, 2 - DI) rlm@1: * 1AAAAAAA YYYY - Master Code function (store address at ((YYYY << 0x16) rlm@1: * + 0x08000100)) rlm@1: * 2AAAAAAA YYYY - 16-bit or rlm@1: * 3AAAAAAA YYYY - 8-bit constant write rlm@1: * 4AAAAAAA YYYY - Slide code rlm@1: * XXXXCCCC IIII (C is count and I is address increment, X is value incr.) rlm@1: * 5AAAAAAA CCCC - Super code (Write bytes to address, CCCC is count) rlm@1: * BBBBBBBB BBBB rlm@1: * 6AAAAAAA YYYY - 16-bit and rlm@1: * 7AAAAAAA YYYY - if address contains 16-bit value enable next code rlm@1: * 8AAAAAAA YYYY - 16-bit constant write rlm@1: * 9AAAAAAA YYYY - change decryption (when first code only?) rlm@1: * AAAAAAAA YYYY - if address does not contain 16-bit value enable next code rlm@1: * BAAAAAAA YYYY - if 16-bit < YYYY rlm@1: * CAAAAAAA YYYY - if 16-bit > YYYY rlm@1: * D0000020 YYYY - if button keys equal value enable next code rlm@1: * EAAAAAAA YYYY - increase value stored in address rlm@1: */ rlm@1: #define UNKNOWN_CODE -1 rlm@1: #define INT_8_BIT_WRITE 0 rlm@1: #define INT_16_BIT_WRITE 1 rlm@1: #define INT_32_BIT_WRITE 2 rlm@1: #define GSA_16_BIT_ROM_PATCH 3 rlm@1: #define GSA_8_BIT_GS_WRITE 4 rlm@1: #define GSA_16_BIT_GS_WRITE 5 rlm@1: #define GSA_32_BIT_GS_WRITE 6 rlm@1: #define CBA_IF_KEYS_PRESSED 7 rlm@1: #define CBA_IF_TRUE 8 rlm@1: #define CBA_SLIDE_CODE 9 rlm@1: #define CBA_IF_FALSE 10 rlm@1: #define CBA_AND 11 rlm@1: #define GSA_8_BIT_GS_WRITE2 12 rlm@1: #define GSA_16_BIT_GS_WRITE2 13 rlm@1: #define GSA_32_BIT_GS_WRITE2 14 rlm@1: #define GSA_16_BIT_ROM_PATCH2 15 rlm@1: #define GSA_8_BIT_SLIDE 16 rlm@1: #define GSA_16_BIT_SLIDE 17 rlm@1: #define GSA_32_BIT_SLIDE 18 rlm@1: #define GSA_8_BIT_IF_TRUE 19 rlm@1: #define GSA_32_BIT_IF_TRUE 20 rlm@1: #define GSA_8_BIT_IF_FALSE 21 rlm@1: #define GSA_32_BIT_IF_FALSE 22 rlm@1: #define GSA_8_BIT_FILL 23 rlm@1: #define GSA_16_BIT_FILL 24 rlm@1: #define GSA_8_BIT_IF_TRUE2 25 rlm@1: #define GSA_16_BIT_IF_TRUE2 26 rlm@1: #define GSA_32_BIT_IF_TRUE2 27 rlm@1: #define GSA_8_BIT_IF_FALSE2 28 rlm@1: #define GSA_16_BIT_IF_FALSE2 29 rlm@1: #define GSA_32_BIT_IF_FALSE2 30 rlm@1: #define GSA_SLOWDOWN 31 rlm@1: #define CBA_ADD 32 rlm@1: #define CBA_OR 33 rlm@1: #define CBA_LT 34 rlm@1: #define CBA_GT 35 rlm@1: #define CBA_SUPER 36 rlm@1: rlm@1: CheatsData cheatsList[100]; rlm@1: int cheatsNumber = 0; rlm@1: rlm@1: u8 cheatsCBASeedBuffer[0x30]; rlm@1: u32 cheatsCBASeed[4]; rlm@1: u32 cheatsCBATemporaryValue = 0; rlm@1: u16 cheatsCBATable[256]; rlm@1: bool cheatsCBATableGenerated = false; rlm@1: rlm@1: u8 cheatsCBACurrentSeed[12] = { rlm@1: 0x00, 0x00, 0x00, 0x00, rlm@1: 0x00, 0x00, 0x00, 0x00, rlm@1: 0x00, 0x00, 0x00, 0x00 rlm@1: }; rlm@1: rlm@1: #define CHEAT_IS_HEX(a) (((a) >= 'A' && (a) <= 'F') || ((a) >= '0' && (a) <= '9')) rlm@1: rlm@1: #define CHEAT_PATCH_ROM_16BIT(a, v) \ rlm@1: WRITE16LE(((u16 *)&rom[(a) & 0x1ffffff]), v); rlm@1: rlm@1: static bool isMultilineWithData(int i) rlm@1: { rlm@1: // we consider it a multiline code if it has more than one line of data rlm@1: // otherwise, it can still be considered a single code rlm@1: if (i < cheatsNumber && i >= 0) rlm@1: switch (cheatsList[i].size) rlm@1: { rlm@1: case INT_8_BIT_WRITE: rlm@1: case INT_16_BIT_WRITE: rlm@1: case INT_32_BIT_WRITE: rlm@1: case GSA_16_BIT_ROM_PATCH: rlm@1: case GSA_8_BIT_GS_WRITE: rlm@1: case GSA_16_BIT_GS_WRITE: rlm@1: case GSA_32_BIT_GS_WRITE: rlm@1: case CBA_AND: rlm@1: case CBA_IF_KEYS_PRESSED: rlm@1: case CBA_IF_TRUE: rlm@1: case CBA_IF_FALSE: rlm@1: case GSA_8_BIT_IF_TRUE: rlm@1: case GSA_32_BIT_IF_TRUE: rlm@1: case GSA_8_BIT_IF_FALSE: rlm@1: case GSA_32_BIT_IF_FALSE: rlm@1: case GSA_8_BIT_FILL: rlm@1: case GSA_16_BIT_FILL: rlm@1: case GSA_8_BIT_IF_TRUE2: rlm@1: case GSA_16_BIT_IF_TRUE2: rlm@1: case GSA_32_BIT_IF_TRUE2: rlm@1: case GSA_8_BIT_IF_FALSE2: rlm@1: case GSA_16_BIT_IF_FALSE2: rlm@1: case GSA_32_BIT_IF_FALSE2: rlm@1: case GSA_SLOWDOWN: rlm@1: case CBA_ADD: rlm@1: case CBA_OR: rlm@1: return false; rlm@1: // the codes below have two lines of data rlm@1: case CBA_SLIDE_CODE: rlm@1: case GSA_8_BIT_GS_WRITE2: rlm@1: case GSA_16_BIT_GS_WRITE2: rlm@1: case GSA_32_BIT_GS_WRITE2: rlm@1: case GSA_16_BIT_ROM_PATCH2: rlm@1: case GSA_8_BIT_SLIDE: rlm@1: case GSA_16_BIT_SLIDE: rlm@1: case GSA_32_BIT_SLIDE: rlm@1: case CBA_LT: rlm@1: case CBA_GT: rlm@1: case CBA_SUPER: rlm@1: return true; rlm@1: } rlm@1: return false; rlm@1: } rlm@1: rlm@1: static int getCodeLength(int num) rlm@1: { rlm@1: if (num >= cheatsNumber || num < 0) rlm@1: return 1; rlm@1: rlm@1: // this is for all the codes that are true multiline rlm@1: switch (cheatsList[num].size) rlm@1: { rlm@1: case INT_8_BIT_WRITE: rlm@1: case INT_16_BIT_WRITE: rlm@1: case INT_32_BIT_WRITE: rlm@1: case GSA_16_BIT_ROM_PATCH: rlm@1: case GSA_8_BIT_GS_WRITE: rlm@1: case GSA_16_BIT_GS_WRITE: rlm@1: case GSA_32_BIT_GS_WRITE: rlm@1: case CBA_AND: rlm@1: case GSA_8_BIT_FILL: rlm@1: case GSA_16_BIT_FILL: rlm@1: case GSA_SLOWDOWN: rlm@1: case CBA_ADD: rlm@1: case CBA_OR: rlm@1: return 1; rlm@1: case CBA_IF_KEYS_PRESSED: rlm@1: case CBA_IF_TRUE: rlm@1: case CBA_IF_FALSE: rlm@1: case CBA_SLIDE_CODE: rlm@1: case GSA_8_BIT_GS_WRITE2: rlm@1: case GSA_16_BIT_GS_WRITE2: rlm@1: case GSA_32_BIT_GS_WRITE2: rlm@1: case GSA_16_BIT_ROM_PATCH2: rlm@1: case GSA_8_BIT_SLIDE: rlm@1: case GSA_16_BIT_SLIDE: rlm@1: case GSA_32_BIT_SLIDE: rlm@1: case GSA_8_BIT_IF_TRUE: rlm@1: case GSA_32_BIT_IF_TRUE: rlm@1: case GSA_8_BIT_IF_FALSE: rlm@1: case GSA_32_BIT_IF_FALSE: rlm@1: case CBA_LT: rlm@1: case CBA_GT: rlm@1: return 2; rlm@1: case GSA_8_BIT_IF_TRUE2: rlm@1: case GSA_16_BIT_IF_TRUE2: rlm@1: case GSA_32_BIT_IF_TRUE2: rlm@1: case GSA_8_BIT_IF_FALSE2: rlm@1: case GSA_16_BIT_IF_FALSE2: rlm@1: case GSA_32_BIT_IF_FALSE2: rlm@1: return 3; rlm@1: case CBA_SUPER: rlm@1: return (cheatsList[num].value+5)/6; rlm@1: } rlm@1: return 1; rlm@1: } rlm@1: rlm@1: int cheatsCheckKeys(u32 keys, u32 extended) rlm@1: { rlm@1: int ticks = 0; rlm@1: for (int i = 0; i < cheatsNumber; i++) rlm@1: { rlm@1: if (!cheatsList[i].enabled) rlm@1: { rlm@1: // make sure we skip other lines in this code rlm@1: i += getCodeLength(i)-1; rlm@1: continue; rlm@1: } rlm@1: switch (cheatsList[i].size) rlm@1: { rlm@1: case INT_8_BIT_WRITE: rlm@1: CPUWriteByte(cheatsList[i].address, cheatsList[i].value); rlm@1: break; rlm@1: case INT_16_BIT_WRITE: rlm@1: CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value); rlm@1: break; rlm@1: case INT_32_BIT_WRITE: rlm@1: CPUWriteMemory(cheatsList[i].address, cheatsList[i].value); rlm@1: break; rlm@1: case GSA_16_BIT_ROM_PATCH: rlm@1: if ((cheatsList[i].status & 1) == 0) rlm@1: { rlm@1: if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) rlm@1: { rlm@1: cheatsList[i].oldValue = CPUReadHalfWord(cheatsList[i].address); rlm@1: cheatsList[i].status |= 1; rlm@1: CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value); rlm@1: } rlm@1: } rlm@1: break; rlm@1: case GSA_8_BIT_GS_WRITE: rlm@1: if (extended & 4) rlm@1: { rlm@1: CPUWriteByte(cheatsList[i].address, cheatsList[i].value); rlm@1: } rlm@1: break; rlm@1: case GSA_16_BIT_GS_WRITE: rlm@1: if (extended & 4) rlm@1: { rlm@1: CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value); rlm@1: } rlm@1: break; rlm@1: case GSA_32_BIT_GS_WRITE: rlm@1: if (extended & 4) rlm@1: { rlm@1: CPUWriteMemory(cheatsList[i].address, cheatsList[i].value); rlm@1: } rlm@1: break; rlm@1: case CBA_IF_KEYS_PRESSED: rlm@1: { rlm@1: u16 value = cheatsList[i].value; rlm@1: u32 addr = cheatsList[i].address; rlm@1: if ((addr & 0x30) == 0x20) rlm@1: { rlm@1: if ((keys & value) != value) rlm@1: { rlm@1: i++; rlm@1: } rlm@1: } rlm@1: else if ((addr & 0x30) == 0x10) rlm@1: { rlm@1: if ((keys & value) == value) rlm@1: { rlm@1: i++; rlm@1: } rlm@1: } rlm@1: break; rlm@1: } rlm@1: case CBA_IF_TRUE: rlm@1: if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) rlm@1: { rlm@1: i++; rlm@1: } rlm@1: break; rlm@1: case CBA_SLIDE_CODE: rlm@1: { rlm@1: u32 address = cheatsList[i].address; rlm@1: u16 value = cheatsList[i].value; rlm@1: i++; rlm@1: if (i < cheatsNumber) rlm@1: { rlm@1: int count = (cheatsList[i].address & 0xFFFF); rlm@1: u16 vinc = (cheatsList[i].address >> 16) & 0xFFFF; rlm@1: int inc = cheatsList[i].value; rlm@1: rlm@1: for (int x = 0; x < count; x++) rlm@1: { rlm@1: CPUWriteHalfWord(address, value); rlm@1: address += inc; rlm@1: value += vinc; rlm@1: } rlm@1: } rlm@1: break; rlm@1: } rlm@1: case CBA_IF_FALSE: rlm@1: if (CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value) rlm@1: { rlm@1: i++; rlm@1: } rlm@1: break; rlm@1: case CBA_AND: rlm@1: CPUWriteHalfWord(cheatsList[i].address, rlm@1: CPUReadHalfWord(cheatsList[i].address) & rlm@1: cheatsList[i].value); rlm@1: break; rlm@1: case GSA_8_BIT_GS_WRITE2: rlm@1: i++; rlm@1: if (i < cheatsNumber) rlm@1: { rlm@1: if (extended & 4) rlm@1: { rlm@1: CPUWriteByte(cheatsList[i-1].value, cheatsList[i].address); rlm@1: } rlm@1: } rlm@1: break; rlm@1: case GSA_16_BIT_GS_WRITE2: rlm@1: i++; rlm@1: if (i < cheatsNumber) rlm@1: { rlm@1: if (extended & 4) rlm@1: { rlm@1: CPUWriteHalfWord(cheatsList[i-1].value, cheatsList[i].address); rlm@1: } rlm@1: } rlm@1: break; rlm@1: case GSA_32_BIT_GS_WRITE2: rlm@1: i++; rlm@1: if (i < cheatsNumber) rlm@1: { rlm@1: if (extended & 4) rlm@1: { rlm@1: CPUWriteMemory(cheatsList[i-1].value, cheatsList[i].address); rlm@1: } rlm@1: } rlm@1: break; rlm@1: case GSA_16_BIT_ROM_PATCH2: rlm@1: i++; rlm@1: if (i < cheatsNumber) rlm@1: { rlm@1: if ((cheatsList[i-1].status & 1) == 0) rlm@1: { rlm@1: u32 addr = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000; rlm@1: if (CPUReadHalfWord(addr) != (cheatsList[i].address & 0xFFFF)) rlm@1: { rlm@1: cheatsList[i-1].oldValue = CPUReadHalfWord(addr); rlm@1: cheatsList[i-1].status |= 1; rlm@1: CHEAT_PATCH_ROM_16BIT(addr, cheatsList[i].address & 0xFFFF); rlm@1: } rlm@1: } rlm@1: } rlm@1: break; rlm@1: case GSA_8_BIT_SLIDE: rlm@1: i++; rlm@1: if (i < cheatsNumber) rlm@1: { rlm@1: u32 addr = cheatsList[i-1].value; rlm@1: u8 value = cheatsList[i].address; rlm@1: int vinc = (cheatsList[i].value >> 24) & 255; rlm@1: int count = (cheatsList[i].value >> 16) & 255; rlm@1: int ainc = (cheatsList[i].value & 0xffff); rlm@1: while (count > 0) rlm@1: { rlm@1: CPUWriteByte(addr, value); rlm@1: value += vinc; rlm@1: addr += ainc; rlm@1: count--; rlm@1: } rlm@1: } rlm@1: break; rlm@1: case GSA_16_BIT_SLIDE: rlm@1: i++; rlm@1: if (i < cheatsNumber) rlm@1: { rlm@1: u32 addr = cheatsList[i-1].value; rlm@1: u16 value = cheatsList[i].address; rlm@1: int vinc = (cheatsList[i].value >> 24) & 255; rlm@1: int count = (cheatsList[i].value >> 16) & 255; rlm@1: int ainc = (cheatsList[i].value & 0xffff)*2; rlm@1: while (count > 0) rlm@1: { rlm@1: CPUWriteHalfWord(addr, value); rlm@1: value += vinc; rlm@1: addr += ainc; rlm@1: count--; rlm@1: } rlm@1: } rlm@1: break; rlm@1: case GSA_32_BIT_SLIDE: rlm@1: i++; rlm@1: if (i < cheatsNumber) rlm@1: { rlm@1: u32 addr = cheatsList[i-1].value; rlm@1: u32 value = cheatsList[i].address; rlm@1: int vinc = (cheatsList[i].value >> 24) & 255; rlm@1: int count = (cheatsList[i].value >> 16) & 255; rlm@1: int ainc = (cheatsList[i].value & 0xffff)*4; rlm@1: while (count > 0) rlm@1: { rlm@1: CPUWriteMemory(addr, value); rlm@1: value += vinc; rlm@1: addr += ainc; rlm@1: count--; rlm@1: } rlm@1: } rlm@1: break; rlm@1: case GSA_8_BIT_IF_TRUE: rlm@1: if (CPUReadByte(cheatsList[i].address) != cheatsList[i].value) rlm@1: { rlm@1: i++; rlm@1: } rlm@1: break; rlm@1: case GSA_32_BIT_IF_TRUE: rlm@1: if (CPUReadMemory(cheatsList[i].address) != cheatsList[i].value) rlm@1: { rlm@1: i++; rlm@1: } rlm@1: break; rlm@1: case GSA_8_BIT_IF_FALSE: rlm@1: if (CPUReadByte(cheatsList[i].address) == cheatsList[i].value) rlm@1: { rlm@1: i++; rlm@1: } rlm@1: break; rlm@1: case GSA_32_BIT_IF_FALSE: rlm@1: if (CPUReadMemory(cheatsList[i].address) == cheatsList[i].value) rlm@1: { rlm@1: i++; rlm@1: } rlm@1: break; rlm@1: case GSA_8_BIT_FILL: rlm@1: { rlm@1: u32 addr = cheatsList[i].address; rlm@1: u8 v = cheatsList[i].value & 0xff; rlm@1: u32 end = addr + (cheatsList[i].value >> 8); rlm@1: do rlm@1: { rlm@1: CPUWriteByte(addr, v); rlm@1: addr++; rlm@1: } rlm@1: while (addr <= end); rlm@1: break; rlm@1: } rlm@1: case GSA_16_BIT_FILL: rlm@1: { rlm@1: u32 addr = cheatsList[i].address; rlm@1: u16 v = cheatsList[i].value & 0xffff; rlm@1: u32 end = addr + ((cheatsList[i].value >> 16) << 1); rlm@1: do rlm@1: { rlm@1: CPUWriteHalfWord(addr, v); rlm@1: addr += 2; rlm@1: } rlm@1: while (addr <= end); rlm@1: break; rlm@1: } rlm@1: case GSA_8_BIT_IF_TRUE2: rlm@1: if (CPUReadByte(cheatsList[i].address) != cheatsList[i].value) rlm@1: { rlm@1: i += 2; rlm@1: } rlm@1: break; rlm@1: case GSA_16_BIT_IF_TRUE2: rlm@1: if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) rlm@1: { rlm@1: i += 2; rlm@1: } rlm@1: break; rlm@1: case GSA_32_BIT_IF_TRUE2: rlm@1: if (CPUReadMemory(cheatsList[i].address) != cheatsList[i].value) rlm@1: { rlm@1: i += 2; rlm@1: } rlm@1: break; rlm@1: case GSA_8_BIT_IF_FALSE2: rlm@1: if (CPUReadByte(cheatsList[i].address) == cheatsList[i].value) rlm@1: { rlm@1: i += 2; rlm@1: } rlm@1: break; rlm@1: case GSA_16_BIT_IF_FALSE2: rlm@1: if (CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value) rlm@1: { rlm@1: i += 2; rlm@1: } rlm@1: break; rlm@1: case GSA_32_BIT_IF_FALSE2: rlm@1: if (CPUReadMemory(cheatsList[i].address) == cheatsList[i].value) rlm@1: { rlm@1: i += 2; rlm@1: } rlm@1: break; rlm@1: case GSA_SLOWDOWN: rlm@1: // check if button was pressed and released, if so toggle our state rlm@1: if ((cheatsList[i].status & 4) && !(extended & 4)) rlm@1: cheatsList[i].status ^= 1; rlm@1: if (extended & 4) rlm@1: cheatsList[i].status |= 4; rlm@1: else rlm@1: cheatsList[i].status &= ~4; rlm@1: rlm@1: if (cheatsList[i].status & 1) rlm@1: ticks += 2*256*((cheatsList[i].value >> 8) & 255); rlm@1: break; rlm@1: case CBA_ADD: rlm@1: CPUWriteHalfWord(cheatsList[i].address, rlm@1: CPUReadHalfWord(cheatsList[i].address) + rlm@1: (u16)cheatsList[i].value); rlm@1: break; rlm@1: case CBA_OR: rlm@1: CPUWriteHalfWord(cheatsList[i].address, rlm@1: CPUReadHalfWord(cheatsList[i].address) | rlm@1: cheatsList[i].value); rlm@1: break; rlm@1: case CBA_LT: rlm@1: if (CPUReadHalfWord(cheatsList[i].address) >= cheatsList[i].value) rlm@1: i++; rlm@1: break; rlm@1: case CBA_GT: rlm@1: if (CPUReadHalfWord(cheatsList[i].address) <= cheatsList[i].value) rlm@1: i++; rlm@1: break; rlm@1: case CBA_SUPER: rlm@1: { rlm@1: int count = 2*cheatsList[i].value; rlm@1: u32 address = cheatsList[i].address; rlm@1: for (int x = 0; x < count; x++) rlm@1: { rlm@1: u8 b; rlm@1: int res = x % 6; rlm@1: if (res < 4) rlm@1: b = (cheatsList[i].address >> (24-8*res)) & 0xFF; rlm@1: else rlm@1: b = (cheatsList[i].value >> (8 - 8*(res-4))) & 0x0FF; rlm@1: CPUWriteByte(address, b); rlm@1: address++; rlm@1: if (x && !res) rlm@1: i++; rlm@1: } rlm@1: if (count % 6) rlm@1: i++; rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: return ticks; rlm@1: } rlm@1: rlm@1: void cheatsAdd(const char *codeStr, rlm@1: const char *desc, rlm@1: u32 address, rlm@1: u32 value, rlm@1: int code, rlm@1: int size) rlm@1: { rlm@1: if (cheatsNumber < 100) rlm@1: { rlm@1: int x = cheatsNumber; rlm@1: cheatsList[x].code = code; rlm@1: cheatsList[x].size = size; rlm@1: cheatsList[x].address = address; rlm@1: cheatsList[x].value = value; rlm@1: strcpy(cheatsList[x].codestring, codeStr); rlm@1: strcpy(cheatsList[x].desc, desc); rlm@1: cheatsList[x].enabled = true; rlm@1: cheatsList[x].status = 0; rlm@1: rlm@1: // we only store the old value for this simple codes. ROM patching rlm@1: // is taken care when it actually patches the ROM rlm@1: switch (cheatsList[x].size) rlm@1: { rlm@1: case INT_8_BIT_WRITE: rlm@1: cheatsList[x].oldValue = CPUReadByte(address); rlm@1: break; rlm@1: case INT_16_BIT_WRITE: rlm@1: cheatsList[x].oldValue = CPUReadHalfWord(address); rlm@1: break; rlm@1: case INT_32_BIT_WRITE: rlm@1: cheatsList[x].oldValue = CPUReadMemory(address); rlm@1: break; rlm@1: } rlm@1: cheatsNumber++; rlm@1: } rlm@1: } rlm@1: rlm@1: void cheatsDelete(int number, bool restore) rlm@1: { rlm@1: if (number < cheatsNumber && number >= 0) rlm@1: { rlm@1: int x = number; rlm@1: rlm@1: if (restore) rlm@1: { rlm@1: switch (cheatsList[x].size) rlm@1: { rlm@1: case INT_8_BIT_WRITE: rlm@1: CPUWriteByte(cheatsList[x].address, (u8)cheatsList[x].oldValue); rlm@1: break; rlm@1: case INT_16_BIT_WRITE: rlm@1: CPUWriteHalfWord(cheatsList[x].address, (u16)cheatsList[x].oldValue); rlm@1: break; rlm@1: case INT_32_BIT_WRITE: rlm@1: CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue); rlm@1: break; rlm@1: case GSA_16_BIT_ROM_PATCH: rlm@1: if (cheatsList[x].status & 1) rlm@1: { rlm@1: cheatsList[x].status &= ~1; rlm@1: CHEAT_PATCH_ROM_16BIT(cheatsList[x].address, rlm@1: cheatsList[x].oldValue); rlm@1: } rlm@1: break; rlm@1: case GSA_16_BIT_ROM_PATCH2: rlm@1: if (cheatsList[x].status & 1) rlm@1: { rlm@1: cheatsList[x].status &= ~1; rlm@1: CHEAT_PATCH_ROM_16BIT(((cheatsList[x].value & 0x00FFFFFF) << 1)+ rlm@1: 0x8000000, rlm@1: cheatsList[x].oldValue); rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: if ((x+1) < cheatsNumber) rlm@1: { rlm@1: memcpy(&cheatsList[x], &cheatsList[x+1], sizeof(CheatsData)* rlm@1: (cheatsNumber-x-1)); rlm@1: } rlm@1: cheatsNumber--; rlm@1: } rlm@1: } rlm@1: rlm@1: void cheatsDeleteAll(bool restore) rlm@1: { rlm@1: for (int i = cheatsNumber-1; i >= 0; i--) rlm@1: { rlm@1: cheatsDelete(i, restore); rlm@1: } rlm@1: } rlm@1: rlm@1: void cheatsEnable(int i) rlm@1: { rlm@1: if (i >= 0 && i < cheatsNumber) rlm@1: { rlm@1: cheatsList[i].enabled = true; rlm@1: } rlm@1: } rlm@1: rlm@1: void cheatsDisable(int i) rlm@1: { rlm@1: if (i >= 0 && i < cheatsNumber) rlm@1: { rlm@1: switch (cheatsList[i].size) rlm@1: { rlm@1: case GSA_16_BIT_ROM_PATCH: rlm@1: if (cheatsList[i].status & 1) rlm@1: { rlm@1: cheatsList[i].status &= ~1; rlm@1: CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, rlm@1: cheatsList[i].oldValue); rlm@1: } rlm@1: break; rlm@1: case GSA_16_BIT_ROM_PATCH2: rlm@1: if (cheatsList[i].status & 1) rlm@1: { rlm@1: cheatsList[i].status &= ~1; rlm@1: CHEAT_PATCH_ROM_16BIT(((cheatsList[i].value & 0x00FFFFFF) << 1)+ rlm@1: 0x8000000, rlm@1: cheatsList[i].oldValue); rlm@1: } rlm@1: break; rlm@1: } rlm@1: cheatsList[i].enabled = false; rlm@1: } rlm@1: } rlm@1: rlm@1: bool cheatsVerifyCheatCode(const char *code, const char *desc) rlm@1: { rlm@1: int len = strlen(code); rlm@1: if (len != 11 && len != 13 && len != 17) rlm@1: { rlm@1: systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (code[8] != ':') rlm@1: { rlm@1: systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code); rlm@1: return false; rlm@1: } rlm@1: rlm@1: int i; rlm@1: for (i = 0; i < 8; i++) rlm@1: { rlm@1: if (!CHEAT_IS_HEX(code[i])) rlm@1: { rlm@1: // wrong cheat rlm@1: systemMessage(MSG_INVALID_CHEAT_CODE, rlm@1: N_("Invalid cheat code '%s'"), code); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: for (i = 9; i < len; i++) rlm@1: { rlm@1: if (!CHEAT_IS_HEX(code[i])) rlm@1: { rlm@1: // wrong cheat rlm@1: systemMessage(MSG_INVALID_CHEAT_CODE, rlm@1: N_("Invalid cheat code '%s'"), code); rlm@1: return false; rlm@1: } rlm@1: } rlm@1: rlm@1: u32 address = 0; rlm@1: u32 value = 0; rlm@1: rlm@1: char buffer[10]; rlm@1: strncpy(buffer, code, 8); rlm@1: buffer[8] = 0; rlm@1: sscanf(buffer, "%x", &address); rlm@1: rlm@1: switch (address >> 24) rlm@1: { rlm@1: case 2: rlm@1: case 3: rlm@1: break; rlm@1: default: rlm@1: systemMessage(MSG_INVALID_CHEAT_CODE_ADDRESS, rlm@1: N_("Invalid cheat code address: %08x"), rlm@1: address); rlm@1: return false; rlm@1: } rlm@1: rlm@1: strncpy(buffer, &code[9], 8); rlm@1: sscanf(buffer, "%x", &value); rlm@1: int type = 0; rlm@1: if (len == 13) rlm@1: type = 1; rlm@1: if (len == 17) rlm@1: type = 2; rlm@1: cheatsAdd(code, desc, address, value, type, type); rlm@1: return true; rlm@1: } rlm@1: rlm@1: void cheatsAddCheatCode(const char *code, const char *desc) rlm@1: { rlm@1: cheatsVerifyCheatCode(code, desc); rlm@1: } rlm@1: rlm@1: void cheatsDecryptGSACode(u32& address, u32& value, bool v3) rlm@1: { rlm@1: u32 rollingseed = 0xC6EF3720; rlm@1: u32 seeds_v1[] = { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 }; rlm@1: u32 seeds_v3[] = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 }; rlm@1: u32 *seeds = v3 ? seeds_v3 : seeds_v1; rlm@1: rlm@1: int bitsleft = 32; rlm@1: while (bitsleft > 0) rlm@1: { rlm@1: value -= ((((address << 4) + seeds[2]) ^ (address + rollingseed)) ^ rlm@1: ((address >> 5) + seeds[3])); rlm@1: address -= ((((value << 4) + seeds[0]) ^ (value + rollingseed)) ^ rlm@1: ((value >> 5) + seeds[1])); rlm@1: rollingseed -= 0x9E3779B9; rlm@1: bitsleft--; rlm@1: } rlm@1: } rlm@1: rlm@1: void cheatsAddGSACode(const char *code, const char *desc, bool v3) rlm@1: { rlm@1: if (strlen(code) != 16) rlm@1: { rlm@1: // wrong cheat rlm@1: systemMessage(MSG_INVALID_GSA_CODE, rlm@1: N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY")); rlm@1: return; rlm@1: } rlm@1: rlm@1: int i; rlm@1: for (i = 0; i < 16; i++) rlm@1: { rlm@1: if (!CHEAT_IS_HEX(code[i])) rlm@1: { rlm@1: // wrong cheat rlm@1: systemMessage(MSG_INVALID_GSA_CODE, rlm@1: N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY")); rlm@1: return; rlm@1: } rlm@1: } rlm@1: rlm@1: char buffer[10]; rlm@1: strncpy(buffer, code, 8); rlm@1: buffer[8] = 0; rlm@1: u32 address; rlm@1: sscanf(buffer, "%x", &address); rlm@1: strncpy(buffer, &code[8], 8); rlm@1: buffer[8] = 0; rlm@1: u32 value; rlm@1: sscanf(buffer, "%x", &value); rlm@1: rlm@1: cheatsDecryptGSACode(address, value, v3); rlm@1: rlm@1: if (value == 0x1DC0DE) rlm@1: { rlm@1: u32 gamecode = READ32LE(((u32 *)&rom[0xac])); rlm@1: if (gamecode != address) rlm@1: { rlm@1: char buffer[5]; rlm@1: *((u32 *)buffer) = address; rlm@1: buffer[4] = 0; rlm@1: char buffer2[5]; rlm@1: *((u32 *)buffer2) = READ32LE(((u32 *)&rom[0xac])); rlm@1: buffer2[4] = 0; rlm@1: systemMessage(MSG_GBA_CODE_WARNING, rlm@1: N_("Warning: cheats are for game %s. Current game is %s.\nCodes may not work correctly."), rlm@1: buffer, buffer2); rlm@1: } rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, v3 ? 257 : 256, rlm@1: UNKNOWN_CODE); rlm@1: return; rlm@1: } rlm@1: if (isMultilineWithData(cheatsNumber-1)) rlm@1: { rlm@1: cheatsAdd(code, desc, address, value, v3 ? 257 : 256, UNKNOWN_CODE); rlm@1: return; rlm@1: } rlm@1: if (v3) rlm@1: { rlm@1: int type = (address >> 25) & 127; rlm@1: u32 addr = (address & 0x00F00000) << 4 | (address & 0x0003FFFF); rlm@1: switch (type) rlm@1: { rlm@1: case 0x00: rlm@1: if (address == 0) rlm@1: { rlm@1: type = (value >> 25) & 127; rlm@1: addr = (value & 0x00F00000) << 4 | (value & 0x0003FFFF); rlm@1: switch (type) rlm@1: { rlm@1: case 0x04: rlm@1: cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_SLOWDOWN); rlm@1: break; rlm@1: case 0x08: rlm@1: cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_GS_WRITE2); rlm@1: break; rlm@1: case 0x09: rlm@1: cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_GS_WRITE2); rlm@1: break; rlm@1: case 0x0a: rlm@1: cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_GS_WRITE2); rlm@1: break; rlm@1: case 0x0c: rlm@1: case 0x0d: rlm@1: case 0x0e: rlm@1: case 0x0f: rlm@1: cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2); rlm@1: break; rlm@1: case 0x40: rlm@1: cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_SLIDE); rlm@1: break; rlm@1: case 0x41: rlm@1: cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_SLIDE); rlm@1: break; rlm@1: case 0x42: rlm@1: cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_SLIDE); rlm@1: break; rlm@1: default: rlm@1: cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE); rlm@1: break; rlm@1: } rlm@1: } rlm@1: else rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_FILL); rlm@1: break; rlm@1: case 0x01: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_FILL); rlm@1: break; rlm@1: case 0x02: rlm@1: cheatsAdd(code, desc, addr, value, 257, INT_32_BIT_WRITE); rlm@1: break; rlm@1: case 0x04: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE); rlm@1: break; rlm@1: case 0x05: rlm@1: cheatsAdd(code, desc, addr, value, 257, CBA_IF_TRUE); rlm@1: break; rlm@1: case 0x06: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE); rlm@1: break; rlm@1: case 0x08: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE); rlm@1: break; rlm@1: case 0x09: rlm@1: cheatsAdd(code, desc, addr, value, 257, CBA_IF_FALSE); rlm@1: break; rlm@1: case 0x0a: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE); rlm@1: break; rlm@1: case 0x24: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE2); rlm@1: break; rlm@1: case 0x25: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_TRUE2); rlm@1: break; rlm@1: case 0x26: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE2); rlm@1: break; rlm@1: case 0x28: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE2); rlm@1: break; rlm@1: case 0x29: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_FALSE2); rlm@1: break; rlm@1: case 0x2a: rlm@1: cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE2); rlm@1: break; rlm@1: default: rlm@1: cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE); rlm@1: break; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: int type = (address >> 28) & 15; rlm@1: switch (type) rlm@1: { rlm@1: case 0: rlm@1: case 1: rlm@1: case 2: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, type); rlm@1: break; rlm@1: case 6: rlm@1: address <<= 1; rlm@1: type = (address >> 28) & 15; rlm@1: if (type == 0x0c) rlm@1: { rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, rlm@1: GSA_16_BIT_ROM_PATCH); rlm@1: break; rlm@1: } rlm@1: // unsupported code rlm@1: cheatsAdd(code, desc, address, value, 256, rlm@1: UNKNOWN_CODE); rlm@1: break; rlm@1: case 8: rlm@1: switch ((address >> 20) & 15) rlm@1: { rlm@1: case 1: rlm@1: cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256, rlm@1: GSA_8_BIT_GS_WRITE); rlm@1: break; rlm@1: case 2: rlm@1: cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256, rlm@1: GSA_16_BIT_GS_WRITE); rlm@1: break; rlm@1: case 3: rlm@1: cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256, rlm@1: GSA_32_BIT_GS_WRITE); rlm@1: case 15: rlm@1: cheatsAdd(code, desc, 0, value & 0xFF00, 256, GSA_SLOWDOWN); rlm@1: break; rlm@1: default: rlm@1: // unsupported code rlm@1: cheatsAdd(code, desc, address, value, 256, rlm@1: UNKNOWN_CODE); rlm@1: break; rlm@1: } rlm@1: break; rlm@1: case 0x0d: rlm@1: if (address != 0xDEADFACE) rlm@1: { rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, rlm@1: CBA_IF_TRUE); rlm@1: } rlm@1: else rlm@1: cheatsAdd(code, desc, address, value, 256, rlm@1: UNKNOWN_CODE); rlm@1: break; rlm@1: default: rlm@1: // unsupported code rlm@1: cheatsAdd(code, desc, address, value, 256, rlm@1: UNKNOWN_CODE); rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: bool cheatsImportGSACodeFile(const char *name, int game, bool v3) rlm@1: { rlm@1: FILE *f = fopen(name, "rb"); rlm@1: if (!f) rlm@1: return false; rlm@1: rlm@1: int games = 0; rlm@1: int len = 0; rlm@1: fseek(f, 0x1e, SEEK_CUR); rlm@1: fread(&games, 1, 4, f); rlm@1: bool found = false; rlm@1: int g = 0; rlm@1: while (games > 0) rlm@1: { rlm@1: if (g == game) rlm@1: { rlm@1: found = true; rlm@1: break; rlm@1: } rlm@1: fread(&len, 1, 4, f); rlm@1: fseek(f, len, SEEK_CUR); rlm@1: int codes = 0; rlm@1: fread(&codes, 1, 4, f); rlm@1: while (codes > 0) rlm@1: { rlm@1: fread(&len, 1, 4, f); rlm@1: fseek(f, len, SEEK_CUR); rlm@1: fseek(f, 8, SEEK_CUR); rlm@1: fread(&len, 1, 4, f); rlm@1: fseek(f, len*12, SEEK_CUR); rlm@1: codes--; rlm@1: } rlm@1: games--; rlm@1: g++; rlm@1: } rlm@1: if (found) rlm@1: { rlm@1: char desc[256]; rlm@1: char code[17]; rlm@1: fread(&len, 1, 4, f); rlm@1: fseek(f, len, SEEK_CUR); rlm@1: int codes = 0; rlm@1: fread(&codes, 1, 4, f); rlm@1: while (codes > 0) rlm@1: { rlm@1: fread(&len, 1, 4, f); rlm@1: fread(desc, 1, len, f); rlm@1: desc[len] = 0; rlm@1: desc[31] = 0; rlm@1: fread(&len, 1, 4, f); rlm@1: fseek(f, len, SEEK_CUR); rlm@1: fseek(f, 4, SEEK_CUR); rlm@1: fread(&len, 1, 4, f); rlm@1: while (len) rlm@1: { rlm@1: fseek(f, 4, SEEK_CUR); rlm@1: fread(code, 1, 8, f); rlm@1: fseek(f, 4, SEEK_CUR); rlm@1: fread(&code[8], 1, 8, f); rlm@1: code[16] = 0; rlm@1: cheatsAddGSACode(code, desc, v3); rlm@1: len -= 2; rlm@1: } rlm@1: codes--; rlm@1: } rlm@1: } rlm@1: fclose(f); rlm@1: return false; rlm@1: } rlm@1: rlm@1: void cheatsCBAReverseArray(u8 *array, u8 *dest) rlm@1: { rlm@1: dest[0] = array[3]; rlm@1: dest[1] = array[2]; rlm@1: dest[2] = array[1]; rlm@1: dest[3] = array[0]; rlm@1: dest[4] = array[5]; rlm@1: dest[5] = array[4]; rlm@1: } rlm@1: rlm@1: void chatsCBAScramble(u8 *array, int count, u8 b) rlm@1: { rlm@1: u8 *x = array + (count >> 3); rlm@1: u8 *y = array + (b >> 3); rlm@1: u32 z = *x & (1 << (count & 7)); rlm@1: u32 x0 = (*x & (~(1 << (count & 7)))); rlm@1: if (z != 0) rlm@1: z = 1; rlm@1: if ((*y & (1 << (b & 7))) != 0) rlm@1: x0 |= (1 << (count & 7)); rlm@1: *x = x0; rlm@1: u32 temp = *y & (~(1 << (b & 7))); rlm@1: if (z != 0) rlm@1: temp |= (1 << (b & 7)); rlm@1: *y = temp; rlm@1: } rlm@1: rlm@1: u32 cheatsCBAGetValue(u8 *array) rlm@1: { rlm@1: return array[0] | array[1]<<8 | array[2] << 16 | array[3]<<24; rlm@1: } rlm@1: rlm@1: u16 cheatsCBAGetData(u8 *array) rlm@1: { rlm@1: return array[4] | array[5]<<8; rlm@1: } rlm@1: rlm@1: void cheatsCBAArrayToValue(u8 *array, u8 *dest) rlm@1: { rlm@1: dest[0] = array[3]; rlm@1: dest[1] = array[2]; rlm@1: dest[2] = array[1]; rlm@1: dest[3] = array[0]; rlm@1: dest[4] = array[5]; rlm@1: dest[5] = array[4]; rlm@1: } rlm@1: rlm@1: void cheatsCBAParseSeedCode(u32 address, u32 value, u32 *array) rlm@1: { rlm@1: array[0] = 1; rlm@1: array[1] = value & 0xFF; rlm@1: array[2] = (address >> 0x10) & 0xFF; rlm@1: array[3] = (value >> 8) & 0xFF; rlm@1: array[4] = (address >> 0x18) & 0x0F; rlm@1: array[5] = address & 0xFFFF; rlm@1: array[6] = address; rlm@1: array[7] = value; rlm@1: } rlm@1: rlm@1: u32 cheatsCBAEncWorker() rlm@1: { rlm@1: u32 x = (cheatsCBATemporaryValue * 0x41c64e6d) + 0x3039; rlm@1: u32 y = (x * 0x41c64e6d) + 0x3039; rlm@1: u32 z = x >> 0x10; rlm@1: x = ((y >> 0x10) & 0x7fff) << 0x0f; rlm@1: z = (z << 0x1e) | x; rlm@1: x = (y * 0x41c64e6d) + 0x3039; rlm@1: cheatsCBATemporaryValue = x; rlm@1: return z | ((x >> 0x10) & 0x7fff); rlm@1: } rlm@1: rlm@1: #define ROR(v, s) \ rlm@1: (((v) >> (s)) | (((v) & ((1 << (s))-1)) << (32 - (s)))) rlm@1: rlm@1: u32 cheatsCBACalcIndex(u32 x, u32 y) rlm@1: { rlm@1: if (y != 0) rlm@1: { rlm@1: if (y == 1) rlm@1: x = 0; rlm@1: else if (x == y) rlm@1: x = 0; rlm@1: if (y < 1) rlm@1: return x; rlm@1: else if (x < y) rlm@1: return x; rlm@1: u32 x0 = 1; rlm@1: rlm@1: while (y < 0x10000000) rlm@1: { rlm@1: if (y < x) rlm@1: { rlm@1: y = y << 4; rlm@1: x0 = x0 << 4; rlm@1: } rlm@1: else rlm@1: break; rlm@1: } rlm@1: rlm@1: while (y < 0x80000000) rlm@1: { rlm@1: if (y < x) rlm@1: { rlm@1: y = y << 1; rlm@1: x0 = x0 << 1; rlm@1: } rlm@1: else rlm@1: break; rlm@1: } rlm@1: rlm@1: loop: rlm@1: u32 z = 0; rlm@1: if (x >= y) rlm@1: x -= y; rlm@1: if (x >= (y >> 1)) rlm@1: { rlm@1: x -= (y >> 1); rlm@1: z |= ROR(x0, 1); rlm@1: } rlm@1: if (x >= (y >> 2)) rlm@1: { rlm@1: x -= (y >> 2); rlm@1: z |= ROR(x0, 2); rlm@1: } rlm@1: if (x >= (y >> 3)) rlm@1: { rlm@1: x -= (y >> 3); rlm@1: z |= ROR(x0, 3); rlm@1: } rlm@1: rlm@1: u32 temp = x0; rlm@1: rlm@1: if (x != 0) rlm@1: { rlm@1: x0 = x0 >> 4; rlm@1: if (x0 != 0) rlm@1: { rlm@1: y = y >> 4; rlm@1: goto loop; rlm@1: } rlm@1: } rlm@1: rlm@1: z = z & 0xe0000000; rlm@1: rlm@1: if (z != 0) rlm@1: { rlm@1: if ((temp & 7) == 0) rlm@1: return x; rlm@1: } rlm@1: else rlm@1: return x; rlm@1: rlm@1: if ((z & ROR(temp, 3)) != 0) rlm@1: x += y >> 3; rlm@1: if ((z & ROR(temp, 2)) != 0) rlm@1: x += y >> 2; rlm@1: if ((z & ROR(temp, 1)) != 0) rlm@1: x += y >> 1; rlm@1: return x; rlm@1: } rlm@1: else rlm@1: {} rlm@1: // should not happen in the current code rlm@1: return 0; rlm@1: } rlm@1: rlm@1: void cheatsCBAUpdateSeedBuffer(u32 a, u8 *buffer, int count) rlm@1: { rlm@1: int i; rlm@1: for (i = 0; i < count; i++) rlm@1: buffer[i] = i; rlm@1: for (i = 0; (u32)i < a; i++) rlm@1: { rlm@1: u32 a = cheatsCBACalcIndex(cheatsCBAEncWorker(), count); rlm@1: u32 b = cheatsCBACalcIndex(cheatsCBAEncWorker(), count); rlm@1: u32 t = buffer[a]; rlm@1: buffer[a] = buffer[b]; rlm@1: buffer[b] = t; rlm@1: } rlm@1: } rlm@1: rlm@1: void cheatsCBAChangeEncryption(u32 *seed) rlm@1: { rlm@1: int i; rlm@1: rlm@1: cheatsCBATemporaryValue = (seed[1] ^ 0x1111); rlm@1: cheatsCBAUpdateSeedBuffer(0x50, cheatsCBASeedBuffer, 0x30); rlm@1: cheatsCBATemporaryValue = 0x4efad1c3; rlm@1: rlm@1: for (i = 0; (u32)i < seed[4]; i++) rlm@1: { rlm@1: cheatsCBATemporaryValue = cheatsCBAEncWorker(); rlm@1: } rlm@1: cheatsCBASeed[2] = cheatsCBAEncWorker(); rlm@1: cheatsCBASeed[3] = cheatsCBAEncWorker(); rlm@1: rlm@1: cheatsCBATemporaryValue = seed[3] ^ 0xf254; rlm@1: rlm@1: for (i = 0; (u32)i < seed[3]; i++) rlm@1: { rlm@1: cheatsCBATemporaryValue = cheatsCBAEncWorker(); rlm@1: } rlm@1: rlm@1: cheatsCBASeed[0] = cheatsCBAEncWorker(); rlm@1: cheatsCBASeed[1] = cheatsCBAEncWorker(); rlm@1: rlm@1: *((u32 *)&cheatsCBACurrentSeed[0]) = seed[6]; rlm@1: *((u32 *)&cheatsCBACurrentSeed[4]) = seed[7]; rlm@1: *((u32 *)&cheatsCBACurrentSeed[8]) = 0; rlm@1: } rlm@1: rlm@1: u16 cheatsCBAGenValue(u32 x, u32 y, u32 z) rlm@1: { rlm@1: y <<= 0x10; rlm@1: z <<= 0x10; rlm@1: x <<= 0x18; rlm@1: u32 x0 = (int)y >> 0x10; rlm@1: z = (int)z >> 0x10; rlm@1: x = (int)x >> 0x10; rlm@1: for (int i = 0; i < 8; i++) rlm@1: { rlm@1: u32 temp = z ^ x; rlm@1: if ((int)temp >= 0) rlm@1: { rlm@1: temp = z << 0x11; rlm@1: } rlm@1: else rlm@1: { rlm@1: temp = z << 0x01; rlm@1: temp ^= x0; rlm@1: temp = temp << 0x10; rlm@1: } rlm@1: z = (int)temp >> 0x10; rlm@1: temp = x << 0x11; rlm@1: x = (int)temp >> 0x10; rlm@1: } rlm@1: return z & 0xffff; rlm@1: } rlm@1: rlm@1: void cheatsCBAGenTable() rlm@1: { rlm@1: for (int i = 0; i < 0x100; i++) rlm@1: { rlm@1: cheatsCBATable[i] = cheatsCBAGenValue(i, 0x1021, 0); rlm@1: } rlm@1: cheatsCBATableGenerated = true; rlm@1: } rlm@1: rlm@1: u16 cheatsCBACalcCRC(u8 *rom, int count) rlm@1: { rlm@1: u32 crc = 0xffffffff; rlm@1: rlm@1: if (count & 3) rlm@1: { rlm@1: // 0x08000EAE rlm@1: } rlm@1: else rlm@1: { rlm@1: count = (count >> 2) - 1; rlm@1: if (count != -1) rlm@1: { rlm@1: while (count != -1) rlm@1: { rlm@1: crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) rlm@1: ^ *rom++]) << 0x10) >> 0x10; rlm@1: crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) rlm@1: ^ *rom++]) << 0x10) >> 0x10; rlm@1: crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) rlm@1: ^ *rom++]) << 0x10) >> 0x10; rlm@1: crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) rlm@1: ^ *rom++]) << 0x10) >> 0x10; rlm@1: count--; rlm@1: } rlm@1: } rlm@1: } rlm@1: return crc & 0xffff; rlm@1: } rlm@1: rlm@1: void cheatsCBADecrypt(u8 *decrypt) rlm@1: { rlm@1: u8 buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; rlm@1: u8 *array = &buffer[1]; rlm@1: rlm@1: cheatsCBAReverseArray(decrypt, array); rlm@1: rlm@1: for (int count = 0x2f; count >= 0; count--) rlm@1: { rlm@1: chatsCBAScramble(array, count, cheatsCBASeedBuffer[count]); rlm@1: } rlm@1: cheatsCBAArrayToValue(array, decrypt); rlm@1: *((u32 *)decrypt) = cheatsCBAGetValue(decrypt) ^ rlm@1: cheatsCBASeed[0]; rlm@1: *((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) ^ rlm@1: cheatsCBASeed[1]) & 0xffff; rlm@1: rlm@1: cheatsCBAReverseArray(decrypt, array); rlm@1: rlm@1: u32 cs = cheatsCBAGetValue(cheatsCBACurrentSeed); rlm@1: for (int i = 0; i <= 4; i++) rlm@1: { rlm@1: array[i] = ((cs >> 8) ^ array[i+1]) ^ array[i] ; rlm@1: } rlm@1: rlm@1: array[5] = (cs >> 8) ^ array[5]; rlm@1: rlm@1: for (int j = 5; j >= 0; j--) rlm@1: { rlm@1: array[j] = (cs ^ array[j-1]) ^ array[j]; rlm@1: } rlm@1: rlm@1: cheatsCBAArrayToValue(array, decrypt); rlm@1: rlm@1: *((u32 *)decrypt) = cheatsCBAGetValue(decrypt) rlm@1: ^ cheatsCBASeed[2]; rlm@1: *((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) rlm@1: ^ cheatsCBASeed[3]) & 0xffff; rlm@1: } rlm@1: rlm@1: int cheatsCBAGetCount() rlm@1: { rlm@1: int count = 0; rlm@1: for (int i = 0; i < cheatsNumber; i++) rlm@1: { rlm@1: if (cheatsList[i].code == 512) rlm@1: count++; rlm@1: } rlm@1: return count; rlm@1: } rlm@1: rlm@1: bool cheatsCBAShouldDecrypt() rlm@1: { rlm@1: for (int i = 0; i < cheatsNumber; i++) rlm@1: { rlm@1: if (cheatsList[i].code == 512) rlm@1: { rlm@1: return (cheatsList[i].codestring[0] == '9'); rlm@1: } rlm@1: } rlm@1: return false; rlm@1: } rlm@1: rlm@1: void cheatsAddCBACode(const char *code, const char *desc) rlm@1: { rlm@1: if (strlen(code) != 13) rlm@1: { rlm@1: // wrong cheat rlm@1: systemMessage(MSG_INVALID_CBA_CODE, rlm@1: N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); rlm@1: return; rlm@1: } rlm@1: rlm@1: int i; rlm@1: for (i = 0; i < 8; i++) rlm@1: { rlm@1: if (!CHEAT_IS_HEX(code[i])) rlm@1: { rlm@1: // wrong cheat rlm@1: systemMessage(MSG_INVALID_CBA_CODE, rlm@1: N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); rlm@1: return; rlm@1: } rlm@1: } rlm@1: rlm@1: if (code[8] != ' ') rlm@1: { rlm@1: systemMessage(MSG_INVALID_CBA_CODE, rlm@1: N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); rlm@1: return; rlm@1: } rlm@1: rlm@1: for (i = 9; i < 13; i++) rlm@1: { rlm@1: if (!CHEAT_IS_HEX(code[i])) rlm@1: { rlm@1: // wrong cheat rlm@1: systemMessage(MSG_INVALID_CBA_CODE, rlm@1: N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); rlm@1: return; rlm@1: } rlm@1: } rlm@1: rlm@1: char buffer[10]; rlm@1: strncpy(buffer, code, 8); rlm@1: buffer[8] = 0; rlm@1: u32 address; rlm@1: sscanf(buffer, "%x", &address); rlm@1: strncpy(buffer, &code[9], 4); rlm@1: buffer[4] = 0; rlm@1: u32 value; rlm@1: sscanf(buffer, "%x", &value); rlm@1: rlm@1: u8 array[8] = { rlm@1: address &255, rlm@1: (address >> 8) & 255, rlm@1: (address >> 16) & 255, rlm@1: (address >> 24) & 255, rlm@1: (value & 255), rlm@1: (value >> 8) & 255, rlm@1: 0, rlm@1: 0 rlm@1: }; rlm@1: rlm@1: if (cheatsCBAGetCount() == 0 && rlm@1: (address >> 28) == 9) rlm@1: { rlm@1: u32 seed[8]; rlm@1: cheatsCBAParseSeedCode(address, value, seed); rlm@1: cheatsCBAChangeEncryption(seed); rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, UNKNOWN_CODE); rlm@1: } rlm@1: else rlm@1: { rlm@1: if (cheatsCBAShouldDecrypt()) rlm@1: cheatsCBADecrypt(array); rlm@1: rlm@1: address = READ32LE(((u32 *)array)); rlm@1: value = READ16LE(((u16 *)&array[4])); rlm@1: rlm@1: int type = (address >> 28) & 15; rlm@1: rlm@1: if (isMultilineWithData(cheatsNumber-1)) rlm@1: { rlm@1: cheatsAdd(code, desc, address, value, 512, UNKNOWN_CODE); rlm@1: return; rlm@1: } rlm@1: rlm@1: switch (type) rlm@1: { rlm@1: case 0x00: rlm@1: { rlm@1: if (!cheatsCBATableGenerated) rlm@1: cheatsCBAGenTable(); rlm@1: u32 crc = cheatsCBACalcCRC(rom, 0x10000); rlm@1: if (crc != address) rlm@1: { rlm@1: systemMessage(MSG_CBA_CODE_WARNING, rlm@1: N_("Warning: Codes seem to be for a different game.\nCodes may not work correctly.")); rlm@1: } rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: UNKNOWN_CODE); rlm@1: break; rlm@1: } rlm@1: case 0x02: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_OR); rlm@1: break; rlm@1: case 0x03: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: INT_8_BIT_WRITE); rlm@1: break; rlm@1: case 0x04: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_SLIDE_CODE); rlm@1: break; rlm@1: case 0x05: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_SUPER); rlm@1: break; rlm@1: case 0x06: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_AND); rlm@1: break; rlm@1: case 0x07: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_IF_TRUE); rlm@1: break; rlm@1: case 0x08: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: INT_16_BIT_WRITE); rlm@1: break; rlm@1: case 0x0a: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_IF_FALSE); rlm@1: break; rlm@1: case 0x0b: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_LT); rlm@1: break; rlm@1: case 0x0c: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_GT); rlm@1: break; rlm@1: case 0x0d: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_IF_KEYS_PRESSED); rlm@1: break; rlm@1: case 0x0e: rlm@1: cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, rlm@1: CBA_ADD); rlm@1: break; rlm@1: default: rlm@1: // unsupported code rlm@1: cheatsAdd(code, desc, address & 0xFFFFFFFF, value, 512, rlm@1: UNKNOWN_CODE); rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void cheatsSaveGame(gzFile file) rlm@1: { rlm@1: utilWriteInt(file, cheatsNumber); rlm@1: rlm@1: utilGzWrite(file, cheatsList, sizeof(cheatsList)); rlm@1: } rlm@1: rlm@1: void cheatsReadGame(gzFile file) rlm@1: { rlm@1: cheatsNumber = 0; rlm@1: rlm@1: cheatsNumber = utilReadInt(file); rlm@1: rlm@1: utilGzRead(file, cheatsList, sizeof(cheatsList)); rlm@1: rlm@1: bool firstCodeBreaker = true; rlm@1: rlm@1: for (int i = 0; i < cheatsNumber; i++) rlm@1: { rlm@1: cheatsList[i].status = 0; rlm@1: if (!cheatsList[i].codestring[0]) rlm@1: { rlm@1: switch (cheatsList[i].size) rlm@1: { rlm@1: case 0: rlm@1: sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address, rlm@1: cheatsList[i].value); rlm@1: break; rlm@1: case 1: rlm@1: sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address, rlm@1: cheatsList[i].value); rlm@1: break; rlm@1: case 2: rlm@1: sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address, rlm@1: cheatsList[i].value); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: if (cheatsList[i].enabled) rlm@1: { rlm@1: cheatsEnable(i); rlm@1: } rlm@1: rlm@1: if (cheatsList[i].code == 512 && firstCodeBreaker) rlm@1: { rlm@1: firstCodeBreaker = false; rlm@1: char buffer[10]; rlm@1: strncpy(buffer, cheatsList[i].codestring, 8); rlm@1: buffer[8] = 0; rlm@1: u32 address; rlm@1: sscanf(buffer, "%x", &address); rlm@1: if ((address >> 28) == 9) rlm@1: { rlm@1: strncpy(buffer, &cheatsList[i].codestring[9], 4); rlm@1: buffer[4] = 0; rlm@1: u32 value; rlm@1: sscanf(buffer, "%x", &value); rlm@1: rlm@1: u32 seed[8]; rlm@1: cheatsCBAParseSeedCode(address, value, seed); rlm@1: cheatsCBAChangeEncryption(seed); rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void cheatsSaveCheatList(const char *file) rlm@1: { rlm@1: if (cheatsNumber == 0) rlm@1: return; rlm@1: FILE *f = fopen(file, "wb"); rlm@1: if (f == NULL) rlm@1: return; rlm@1: int version = 1; rlm@1: fwrite(&version, 1, sizeof(version), f); rlm@1: int type = 0; rlm@1: fwrite(&type, 1, sizeof(type), f); rlm@1: fwrite(&cheatsNumber, 1, sizeof(cheatsNumber), f); rlm@1: fwrite(cheatsList, 1, sizeof(cheatsList), f); rlm@1: fclose(f); rlm@1: } rlm@1: rlm@1: bool cheatsLoadCheatList(const char *file) rlm@1: { rlm@1: cheatsNumber = 0; rlm@1: rlm@1: int count = 0; rlm@1: rlm@1: FILE *f = fopen(file, "rb"); rlm@1: rlm@1: if (f == NULL) rlm@1: return false; rlm@1: rlm@1: int version = 0; rlm@1: rlm@1: if (fread(&version, 1, sizeof(version), f) != sizeof(version)) rlm@1: { rlm@1: fclose(f); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (version != 1) rlm@1: { rlm@1: systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION, rlm@1: N_("Unsupported cheat list version %d"), version); rlm@1: fclose(f); rlm@1: return false; rlm@1: } rlm@1: rlm@1: int type = 0; rlm@1: if (fread(&type, 1, sizeof(type), f) != sizeof(type)) rlm@1: { rlm@1: fclose(f); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (type != 0) rlm@1: { rlm@1: systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE, rlm@1: N_("Unsupported cheat list type %d"), type); rlm@1: fclose(f); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (fread(&count, 1, sizeof(count), f) != sizeof(count)) rlm@1: { rlm@1: fclose(f); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (fread(cheatsList, 1, sizeof(cheatsList), f) != sizeof(cheatsList)) rlm@1: { rlm@1: fclose(f); rlm@1: return false; rlm@1: } rlm@1: rlm@1: bool firstCodeBreaker = true; rlm@1: rlm@1: for (int i = 0; i < count; i++) rlm@1: { rlm@1: cheatsList[i].status = 0; // remove old status as it is not used rlm@1: if (!cheatsList[i].codestring[0]) rlm@1: { rlm@1: switch (cheatsList[i].size) rlm@1: { rlm@1: case 0: rlm@1: sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address, rlm@1: cheatsList[i].value); rlm@1: break; rlm@1: case 1: rlm@1: sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address, rlm@1: cheatsList[i].value); rlm@1: break; rlm@1: case 2: rlm@1: sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address, rlm@1: cheatsList[i].value); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: if (cheatsList[i].code == 512 && firstCodeBreaker) rlm@1: { rlm@1: firstCodeBreaker = false; rlm@1: char buffer[10]; rlm@1: strncpy(buffer, cheatsList[i].codestring, 8); rlm@1: buffer[8] = 0; rlm@1: u32 address; rlm@1: sscanf(buffer, "%x", &address); rlm@1: if ((address >> 28) == 9) rlm@1: { rlm@1: strncpy(buffer, &cheatsList[i].codestring[9], 4); rlm@1: buffer[4] = 0; rlm@1: u32 value; rlm@1: sscanf(buffer, "%x", &value); rlm@1: rlm@1: u32 seed[8]; rlm@1: cheatsCBAParseSeedCode(address, value, seed); rlm@1: cheatsCBAChangeEncryption(seed); rlm@1: } rlm@1: } rlm@1: } rlm@1: cheatsNumber = count; rlm@1: fclose(f); rlm@1: return true; rlm@1: } rlm@1: rlm@1: extern int *extCpuLoopTicks; rlm@1: extern int *extClockTicks; rlm@1: extern int *extTicks; rlm@1: extern int cpuSavedTicks; rlm@1: rlm@1: extern void debuggerBreakOnWrite(u32 *, u32, u32, int); rlm@1: rlm@1: #define CPU_BREAK_LOOP2 \ rlm@1: cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks; \ rlm@1: *extCpuLoopTicks = *extClockTicks; \ rlm@1: *extTicks = *extClockTicks; rlm@1: rlm@1: void cheatsWriteMemory(u32 *address, u32 value, u32 mask) rlm@1: { rlm@1: #ifdef BKPT_SUPPORT rlm@1: #ifdef SDL rlm@1: if (cheatsNumber == 0) rlm@1: { rlm@1: debuggerBreakOnWrite(address, *address, value, 2); rlm@1: CPU_BREAK_LOOP2; rlm@1: *address = value; rlm@1: return; rlm@1: } rlm@1: #endif rlm@1: #endif rlm@1: } rlm@1: rlm@1: void cheatsWriteHalfWord(u16 *address, u16 value, u16 mask) rlm@1: { rlm@1: #ifdef BKPT_SUPPORT rlm@1: #ifdef SDL rlm@1: if (cheatsNumber == 0) rlm@1: { rlm@1: debuggerBreakOnWrite((u32 *)address, *address, value, 1); rlm@1: CPU_BREAK_LOOP2; rlm@1: *address = value; rlm@1: return; rlm@1: } rlm@1: #endif rlm@1: #endif rlm@1: } rlm@1: rlm@1: #if defined BKPT_SUPPORT && defined SDL rlm@1: void cheatsWriteByte(u8 *address, u8 value) rlm@1: #else rlm@1: void cheatsWriteByte(u8 *, u8) rlm@1: #endif rlm@1: { rlm@1: #ifdef BKPT_SUPPORT rlm@1: #ifdef SDL rlm@1: if (cheatsNumber == 0) rlm@1: { rlm@1: debuggerBreakOnWrite((u32 *)address, *address, value, 0); rlm@1: CPU_BREAK_LOOP2; rlm@1: *address = value; rlm@1: return; rlm@1: } rlm@1: #endif rlm@1: #endif rlm@1: } rlm@1: rlm@1: #undef CPU_BREAK_LOOP2