Skip to content

Commit

Permalink
Add cheat decoding code for multiple formats.
Browse files Browse the repository at this point in the history
  • Loading branch information
ilag11111 committed Mar 26, 2017
1 parent e808994 commit da026a5
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 3 deletions.
8 changes: 8 additions & 0 deletions gb/cheat/cheat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ optional<unsigned> Cheat::find(unsigned addr, unsigned comp) {
}

bool Cheat::decode(const char *part, unsigned &addr, unsigned &comp, unsigned &data) {
/* Code Types
* RAW:
* AAAA:DD
* Game Genie: http://gamehacking.org/library/114
* GameShark: 0BDDAAAA - Byteswapped Address, bank+1
* Codebreaker: 0BAAAA-DD
* Xploder: Unknown
*/
std::cerr << "[bsnes]: Decoding cheats not implemented." << std::endl;
return false;
}
Expand Down
139 changes: 136 additions & 3 deletions sfc/cheat/cheat.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <sfc/sfc.hpp>
#include <iostream>
#include <cstdlib>

#define CHEAT_CPP
namespace SuperFamicom {
Expand Down Expand Up @@ -30,13 +31,145 @@ optional<unsigned> Cheat::find(unsigned addr, unsigned comp) {
return false;
}

static char genie_replace(char input){
switch (input){
case '0':
return '4';
case '1':
return '6';
case '2':
return 'D';
case '3':
return 'E';
case '4':
return '2';
case '5':
return '7';
case '6':
return '8';
case '7':
return '3';
case '8':
return 'B';
case '9':
return '5';
case 'A':
case 'a':
return 'C';
case 'B':
case 'b':
return '9';
case 'C':
case 'c':
return 'A';
case 'D':
case 'd':
return '0';
case 'E':
case 'e':
return 'F';
case 'F':
case 'f':
return '1';
}
}

bool Cheat::decode(const char *part, unsigned &addr, unsigned &data) {
std::cerr << "[bsnes]: Decoding cheats not implemented." << std::endl;
return false;
char addr_str[7], data_str[3];
addr_str[6]=0;
data_str[2]=0;
addr=data=0;

//RAW
if (strlen(part)>=9 && part[6]==':') {
strncpy(addr_str,part,6);
strncpy(data_str,part+7,2);
addr=strtoul(addr_str,'\0',16);
data=strtoul(data_str,'\0',16);
}

//Game Genie
else if (strlen(part)>=9 && part[4]=='-') {
strncpy(data_str,part,2);
strncpy(addr_str,part+2,2);
strncpy(addr_str+2,part+5,4);
for (int i=0;i<2;i++)
data_str[i]=genie_replace(data_str[i]);
for (int i=0;i<6;i++)
addr_str[i]=genie_replace(addr_str[i]);
data=strtoul(data_str,'\0',16);
int addr_scrambled=strtoul(addr_str,'\0',16);
addr=(addr_scrambled&0x003C00)<<10;
addr|=(addr_scrambled&0x00003C)<<14;
addr|=(addr_scrambled&0xF00000)>>8;
addr|=(addr_scrambled&0x000003)<<10;
addr|=(addr_scrambled&0x00C000)>>6;
addr|=(addr_scrambled&0x0F0000)>>12;
addr|=(addr_scrambled&0x0003C0)>>6;
return true;
}

//PAR & X-Terminator
else if (strlen(part)==8) {
strncpy(addr_str,part,6);
strncpy(data_str,part+6,2);
addr=strtoul(addr_str,'\0',16);
data=strtoul(data_str,'\0',16);
}

//Gold Finger
else if (strlen(part)==14) {
if (part[13]=='1'){
std::cout << "[bsnes]: CHEAT: Goldfinger SRAM cheats not supported: " << part << std::endl;
return false;
}
addr_str[0]='0';
strncpy(addr_str+1,part,5);
strncpy(data_str,part+5,2);
if (part[7]!='X' && part[7]!='x')
std::cout << "[bsnes]: CHEAT: Goldfinger multibyte cheats not supported: " << part << std::endl;

char pair_str[3];
pair_str[2]=0;
int csum_calc=0,csum_code;
for (int i=0;i<6;i++){
if (i<3){
strncpy(pair_str,addr_str+2*i,2);
} else {
strncpy(pair_str,part+2*i-1,2);
}
csum_calc+=strtoul(pair_str,'\0',16);
}
csum_calc-=0x160;
csum_calc&=0xFF;
strncpy(pair_str,part+11,2);
csum_code=strtoul(pair_str,'\0',16);
if (csum_calc!=csum_code){
std::cout << "[bsnes]: CHEAT: Goldfinger calculated checksum '" << std::hex << csum_calc << "' doesn't match code: " << part << std::endl;
return false;
}

int addr_scrambled=strtoul(addr_str,'\0',16);
addr=(addr_scrambled&0x7FFF)|((addr_scrambled&0x7F8000)<<1)|0x8000;
data=strtoul(data_str,'\0',16);
std::cout << "CHEAT: " << part << " decoded as " << std::hex << addr << ":" << data << std::endl;
}

//Unknown
else {
std::cout << "[bsnes]: CHEAT: Unrecognized code type: " << part << std::endl;
return false;
}

if (addr == 0 || data == 0){
std::cout << "[bsnes]: CHEAT: Decoding failed: " << part << std::endl;
return false;
}

return true;
}

void Cheat::synchronize() {
std::cerr << "[bsnes]: Synchronizing cheats not implemented." << std::endl;
return;
}

Expand Down

0 comments on commit da026a5

Please sign in to comment.