diff --git a/libretro/libretro.c b/libretro/libretro.c index 73819fd..8b68c49 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -1190,114 +1190,57 @@ static uint32_t decode_cheat(char *string, int index) uint32_t address = 0; uint16_t data = 0; uint8_t ref = 0; - /* 16-bit Game Genie code (ABCD-EFGH) */ - if ((strlen(string) >= 9) && (string[4] == '-')) - { - /* 16-bit system only */ - if ((system_hw & SYSTEM_PBC) != SYSTEM_MD) + + if ((system_hw & SYSTEM_PBC) == SYSTEM_MD){ + //If system is Genesis-based + + //Game-Genie + if ((strlen(string) >= 9) && (string[4] == '-')) { - return 0; - } - for (i = 0; i < 8; i++) - { - if (i == 4) string++; - p = strchr (ggvalidchars, *string++); - if (p == NULL) return 0; - n = p - ggvalidchars; - switch (i) + for (i = 0; i < 8; i++) { - case 0: - data |= n << 3; - break; - case 1: - data |= n >> 2; - address |= (n & 3) << 14; - break; - case 2: - address |= n << 9; - break; - case 3: - address |= (n & 0xF) << 20 | (n >> 4) << 8; - break; - case 4: - data |= (n & 1) << 12; - address |= (n >> 1) << 16; - break; - case 5: - data |= (n & 1) << 15 | (n >> 1) << 8; - break; - case 6: - data |= (n >> 3) << 13; - address |= (n & 7) << 5; - break; - case 7: - address |= n; - break; + if (i == 4) string++; + p = strchr (ggvalidchars, *string++); + if (p == NULL) return 0; + n = p - ggvalidchars; + switch (i) + { + case 0: + data |= n << 3; + break; + case 1: + data |= n >> 2; + address |= (n & 3) << 14; + break; + case 2: + address |= n << 9; + break; + case 3: + address |= (n & 0xF) << 20 | (n >> 4) << 8; + break; + case 4: + data |= (n & 1) << 12; + address |= (n >> 1) << 16; + break; + case 5: + data |= (n & 1) << 15 | (n >> 1) << 8; + break; + case 6: + data |= (n >> 3) << 13; + address |= (n & 7) << 5; + break; + case 7: + address |= n; + break; + } } + /* code length */ + len = 9; } - /* code length */ - len = 9; - } - /* 8-bit Game Genie code (DDA-AAA-XXX) */ - else if ((strlen(string) >= 11) && (string[3] == '-') && (string[7] == '-')) - { - /* 8-bit system only */ - if ((system_hw & SYSTEM_PBC) == SYSTEM_MD) + + //Patch and PAR + else if ((strlen(string) >=9) && (string[6] == ':')) { - return 0; - } - /* decode 8-bit data */ - for (i=0; i<2; i++) - { - p = strchr (arvalidchars, *string++); - if (p == NULL) return 0; - n = (p - arvalidchars) & 0xF; - data |= (n << ((1 - i) * 4)); - } - /* decode 16-bit address (low 12-bits) */ - for (i=0; i<3; i++) - { - if (i==1) string++; /* skip separator */ - p = strchr (arvalidchars, *string++); - if (p == NULL) return 0; - n = (p - arvalidchars) & 0xF; - address |= (n << ((2 - i) * 4)); - } - /* decode 16-bit address (high 4-bits) */ - p = strchr (arvalidchars, *string++); - if (p == NULL) return 0; - n = (p - arvalidchars) & 0xF; - n ^= 0xF; /* bits inversion */ - address |= (n << 12); - /* RAM address are also supported */ - if (address >= 0xC000) - { - /* convert to 24-bit Work RAM address */ - address = 0xFF0000 | (address & 0x1FFF); - } - /* decode reference 8-bit data */ - for (i=0; i<2; i++) - { - string++; /* skip separator and 2nd digit */ - p = strchr (arvalidchars, *string++); - if (p == NULL) return 0; - n = (p - arvalidchars) & 0xF; - ref |= (n << ((1 - i) * 4)); - } - ref = (ref >> 2) | ((ref & 0x03) << 6); /* 2-bit right rotation */ - ref ^= 0xBA; /* XOR */ - /* update old data value */ - cheatlist[index].old = ref; - /* code length */ - len = 11; - } - /* Action Replay code */ - else if (string[6] == ':') - { - if ((system_hw & SYSTEM_PBC) == SYSTEM_MD) - { - /* 16-bit code (AAAAAA:DDDD) */ - if (strlen(string) < 11) return 0; /* decode 24-bit address */ for (i=0; i<6; i++) { @@ -1311,19 +1254,125 @@ static uint32_t decode_cheat(char *string, int index) for (i=0; i<4; i++) { p = strchr (arvalidchars, *string++); - if (p == NULL) return 0; + if (p == NULL) break; n = (p - arvalidchars) & 0xF; data |= (n << ((3 - i) * 4)); } /* code length */ len = 11; } - else + } else { + //If System is Master-based + + //Game Genie + if ((strlen(string) >=7) && (string[3] == '-')) { - /* 8-bit code (xxAAAA:DD) */ - if (strlen(string) < 9) return 0; - /* decode 16-bit address */ + /* decode 8-bit data */ + for (i=0; i<2; i++) + { + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + data |= (n << ((1 - i) * 4)); + } + /* decode 16-bit address (low 12-bits) */ + for (i=0; i<3; i++) + { + if (i==1) string++; /* skip separator */ + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + address |= (n << ((2 - i) * 4)); + } + /* decode 16-bit address (high 4-bits) */ + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + n ^= 0xF; /* bits inversion */ + address |= (n << 12); + /* Optional: decode reference 8-bit data */ + if (*string=='-') + { + for (i=0; i<2; i++) + { + string++; /* skip separator and 2nd digit */ + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + ref |= (n << ((1 - i) * 4)); + } + ref = (ref >> 2) | ((ref & 0x03) << 6); /* 2-bit right rotation */ + ref ^= 0xBA; /* XOR */ + /* code length */ + len = 11; + } + else + { + /* code length */ + len = 7; + } + } + + //Action Replay + else if ((strlen(string) >=9) && (string[4] == '-')){ string+=2; + /* decode 16-bit address */ + for (i=0; i<4; i++) + { + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + address |= (n << ((3 - i) * 4)); + if (i==1) string++; + } + /* decode 8-bit data */ + for (i=0; i<2; i++) + { + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + data |= (n << ((1 - i) * 4)); + } + /* code length */ + len = 9; + } + + //Fusion RAM + else if ((strlen(string) >=7) && (string[4] == ':')) + { + /* decode 16-bit address */ + for (i=0; i<4; i++) + { + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + address |= (n << ((3 - i) * 4)); + } + /* decode 8-bit data */ + string++; + for (i=0; i<2; i++) + { + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + data |= (n << ((1 - i) * 4)); + } + /* code length */ + len = 7; + } + + //Fusion ROM + else if ((strlen(string) >=9) && (string[6] == ':')) + { + /* decode reference 8-bit data */ + for (i=0; i<2; i++) + { + p = strchr (arvalidchars, *string++); + if (p == NULL) return 0; + n = (p - arvalidchars) & 0xF; + ref |= (n << ((1 - i) * 4)); + } + /* decode 16-bit address */ for (i=0; i<4; i++) { p = strchr (arvalidchars, *string++); @@ -1331,10 +1380,6 @@ static uint32_t decode_cheat(char *string, int index) n = (p - arvalidchars) & 0xF; address |= (n << ((3 - i) * 4)); } - /* ROM addresses are not supported */ - if (address < 0xC000) return 0; - /* convert to 24-bit Work RAM address */ - address = 0xFF0000 | (address & 0x1FFF); /* decode 8-bit data */ string++; for (i=0; i<2; i++) @@ -1347,6 +1392,11 @@ static uint32_t decode_cheat(char *string, int index) /* code length */ len = 9; } + /* convert to 24-bit Work RAM address */ + if (address >= 0xC000) + { + address = 0xFF0000 | (address & 0x1FFF); + } } /* Valid code found ? */ if (len) @@ -1354,6 +1404,7 @@ static uint32_t decode_cheat(char *string, int index) /* update cheat address & data values */ cheatlist[index].address = address; cheatlist[index].data = data; + cheatlist[index].old = ref; } /* return code length (0 = invalid) */ return len; @@ -1497,8 +1548,8 @@ void ROMCheatUpdate(void) /* get current banked ROM address */ ptr = &z80_readmap[(cheatlist[index].address) >> 10][cheatlist[index].address & 0x03FF]; - /* check if reference matches original ROM data */ - if (((uint8_t)cheatlist[index].old) == *ptr) + /* check if reference exists and matches original ROM data */ + if (!cheatlist[index].old || ((uint8_t)cheatlist[index].old) == *ptr) { /* patch data */ *ptr = cheatlist[index].data; @@ -1892,32 +1943,46 @@ void retro_cheat_reset(void) void retro_cheat_set(unsigned index, bool enabled, const char *code) { + char codeCopy[256]; + char *buff; + + /* Avoid crashing when giving empty input */ + if (code=='\0') return; + /* clear existing ROM patches */ clear_cheats(); - /* interpret code and check if this is a valid cheat code */ - if (decode_cheat((char *)code, maxcheats)) - { - int i; + /* Detect and split multiline cheats */ + strcpy(codeCopy,code); + buff = strtok(codeCopy,"+"); - /* check if cheat code already exists */ - for (i=0; i