mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-11-13 06:15:07 +01:00
Merge pull request #127 from libretro/master
[libretro] merge cheat support changes
This commit is contained in:
commit
e0e10c5375
@ -1190,114 +1190,57 @@ static uint32_t decode_cheat(char *string, int index)
|
|||||||
uint32_t address = 0;
|
uint32_t address = 0;
|
||||||
uint16_t data = 0;
|
uint16_t data = 0;
|
||||||
uint8_t ref = 0;
|
uint8_t ref = 0;
|
||||||
/* 16-bit Game Genie code (ABCD-EFGH) */
|
|
||||||
if ((strlen(string) >= 9) && (string[4] == '-'))
|
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD){
|
||||||
{
|
//If system is Genesis-based
|
||||||
/* 16-bit system only */
|
|
||||||
if ((system_hw & SYSTEM_PBC) != SYSTEM_MD)
|
//Game-Genie
|
||||||
|
if ((strlen(string) >= 9) && (string[4] == '-'))
|
||||||
{
|
{
|
||||||
return 0;
|
for (i = 0; i < 8; i++)
|
||||||
}
|
|
||||||
for (i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if (i == 4) string++;
|
|
||||||
p = strchr (ggvalidchars, *string++);
|
|
||||||
if (p == NULL) return 0;
|
|
||||||
n = p - ggvalidchars;
|
|
||||||
switch (i)
|
|
||||||
{
|
{
|
||||||
case 0:
|
if (i == 4) string++;
|
||||||
data |= n << 3;
|
p = strchr (ggvalidchars, *string++);
|
||||||
break;
|
if (p == NULL) return 0;
|
||||||
case 1:
|
n = p - ggvalidchars;
|
||||||
data |= n >> 2;
|
switch (i)
|
||||||
address |= (n & 3) << 14;
|
{
|
||||||
break;
|
case 0:
|
||||||
case 2:
|
data |= n << 3;
|
||||||
address |= n << 9;
|
break;
|
||||||
break;
|
case 1:
|
||||||
case 3:
|
data |= n >> 2;
|
||||||
address |= (n & 0xF) << 20 | (n >> 4) << 8;
|
address |= (n & 3) << 14;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 2:
|
||||||
data |= (n & 1) << 12;
|
address |= n << 9;
|
||||||
address |= (n >> 1) << 16;
|
break;
|
||||||
break;
|
case 3:
|
||||||
case 5:
|
address |= (n & 0xF) << 20 | (n >> 4) << 8;
|
||||||
data |= (n & 1) << 15 | (n >> 1) << 8;
|
break;
|
||||||
break;
|
case 4:
|
||||||
case 6:
|
data |= (n & 1) << 12;
|
||||||
data |= (n >> 3) << 13;
|
address |= (n >> 1) << 16;
|
||||||
address |= (n & 7) << 5;
|
break;
|
||||||
break;
|
case 5:
|
||||||
case 7:
|
data |= (n & 1) << 15 | (n >> 1) << 8;
|
||||||
address |= n;
|
break;
|
||||||
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;
|
//Patch and PAR
|
||||||
}
|
else if ((strlen(string) >=9) && (string[6] == ':'))
|
||||||
/* 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)
|
|
||||||
{
|
{
|
||||||
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 */
|
/* decode 24-bit address */
|
||||||
for (i=0; i<6; i++)
|
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++)
|
for (i=0; i<4; i++)
|
||||||
{
|
{
|
||||||
p = strchr (arvalidchars, *string++);
|
p = strchr (arvalidchars, *string++);
|
||||||
if (p == NULL) return 0;
|
if (p == NULL) break;
|
||||||
n = (p - arvalidchars) & 0xF;
|
n = (p - arvalidchars) & 0xF;
|
||||||
data |= (n << ((3 - i) * 4));
|
data |= (n << ((3 - i) * 4));
|
||||||
}
|
}
|
||||||
/* code length */
|
/* code length */
|
||||||
len = 11;
|
len = 11;
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
|
//If System is Master-based
|
||||||
|
|
||||||
|
//Game Genie
|
||||||
|
if ((strlen(string) >=7) && (string[3] == '-'))
|
||||||
{
|
{
|
||||||
/* 8-bit code (xxAAAA:DD) */
|
/* decode 8-bit data */
|
||||||
if (strlen(string) < 9) return 0;
|
for (i=0; i<2; i++)
|
||||||
/* decode 16-bit address */
|
{
|
||||||
|
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;
|
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++)
|
for (i=0; i<4; i++)
|
||||||
{
|
{
|
||||||
p = strchr (arvalidchars, *string++);
|
p = strchr (arvalidchars, *string++);
|
||||||
@ -1331,10 +1380,6 @@ static uint32_t decode_cheat(char *string, int index)
|
|||||||
n = (p - arvalidchars) & 0xF;
|
n = (p - arvalidchars) & 0xF;
|
||||||
address |= (n << ((3 - i) * 4));
|
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 */
|
/* decode 8-bit data */
|
||||||
string++;
|
string++;
|
||||||
for (i=0; i<2; i++)
|
for (i=0; i<2; i++)
|
||||||
@ -1347,6 +1392,11 @@ static uint32_t decode_cheat(char *string, int index)
|
|||||||
/* code length */
|
/* code length */
|
||||||
len = 9;
|
len = 9;
|
||||||
}
|
}
|
||||||
|
/* convert to 24-bit Work RAM address */
|
||||||
|
if (address >= 0xC000)
|
||||||
|
{
|
||||||
|
address = 0xFF0000 | (address & 0x1FFF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Valid code found ? */
|
/* Valid code found ? */
|
||||||
if (len)
|
if (len)
|
||||||
@ -1354,6 +1404,7 @@ static uint32_t decode_cheat(char *string, int index)
|
|||||||
/* update cheat address & data values */
|
/* update cheat address & data values */
|
||||||
cheatlist[index].address = address;
|
cheatlist[index].address = address;
|
||||||
cheatlist[index].data = data;
|
cheatlist[index].data = data;
|
||||||
|
cheatlist[index].old = ref;
|
||||||
}
|
}
|
||||||
/* return code length (0 = invalid) */
|
/* return code length (0 = invalid) */
|
||||||
return len;
|
return len;
|
||||||
@ -1497,8 +1548,8 @@ void ROMCheatUpdate(void)
|
|||||||
/* get current banked ROM address */
|
/* get current banked ROM address */
|
||||||
ptr = &z80_readmap[(cheatlist[index].address) >> 10][cheatlist[index].address & 0x03FF];
|
ptr = &z80_readmap[(cheatlist[index].address) >> 10][cheatlist[index].address & 0x03FF];
|
||||||
|
|
||||||
/* check if reference matches original ROM data */
|
/* check if reference exists and matches original ROM data */
|
||||||
if (((uint8_t)cheatlist[index].old) == *ptr)
|
if (!cheatlist[index].old || ((uint8_t)cheatlist[index].old) == *ptr)
|
||||||
{
|
{
|
||||||
/* patch data */
|
/* patch data */
|
||||||
*ptr = cheatlist[index].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)
|
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 existing ROM patches */
|
||||||
clear_cheats();
|
clear_cheats();
|
||||||
|
|
||||||
/* interpret code and check if this is a valid cheat code */
|
/* Detect and split multiline cheats */
|
||||||
if (decode_cheat((char *)code, maxcheats))
|
strcpy(codeCopy,code);
|
||||||
{
|
buff = strtok(codeCopy,"+");
|
||||||
int i;
|
|
||||||
|
|
||||||
/* check if cheat code already exists */
|
while (buff != NULL)
|
||||||
for (i=0; i<maxcheats; i++)
|
{
|
||||||
|
/* interpret code and check if this is a valid cheat code */
|
||||||
|
if (decode_cheat((char *)buff, maxcheats))
|
||||||
{
|
{
|
||||||
if ((cheatlist[i].address == cheatlist[maxcheats].address)
|
int i;
|
||||||
&& (cheatlist[i].data == cheatlist[maxcheats].data))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cheat can be enabled or disabled */
|
/* check if cheat code already exists */
|
||||||
cheatlist[i].enable = enabled;
|
for (i=0; i<maxcheats; i++)
|
||||||
|
{
|
||||||
|
if ((cheatlist[i].address == cheatlist[maxcheats].address)
|
||||||
|
&& (cheatlist[i].data == cheatlist[maxcheats].data))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* if new cheat code, check current cheat count */
|
/* cheat can be enabled or disabled */
|
||||||
if ((i == maxcheats) && (i < MAX_CHEATS))
|
cheatlist[i].enable = enabled;
|
||||||
{
|
|
||||||
/* increment cheat count */
|
/* if new cheat code, check current cheat count */
|
||||||
maxcheats++;
|
if ((i == maxcheats) && (i < MAX_CHEATS))
|
||||||
|
{
|
||||||
|
/* increment cheat count */
|
||||||
|
maxcheats++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
buff = strtok(NULL,"+");
|
||||||
|
}
|
||||||
|
|
||||||
/* apply ROM patches */
|
/* apply ROM patches */
|
||||||
apply_cheats();
|
apply_cheats();
|
||||||
|
Loading…
Reference in New Issue
Block a user