Skip to content

Commit

Permalink
Merge pull request #36 from ilag11111/cheatSupport
Browse files Browse the repository at this point in the history
Add cheats to SNES games
  • Loading branch information
inactive123 committed Mar 26, 2017
2 parents 5b802d8 + da026a5 commit a9204c5
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 8 deletions.
19 changes: 19 additions & 0 deletions gb/cheat/cheat.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <gb/gb.hpp>
#include <iostream>

namespace GameBoy {

Expand All @@ -25,4 +26,22 @@ optional<unsigned> Cheat::find(unsigned addr, unsigned comp) {
return false;
}

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;
}

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

}
3 changes: 3 additions & 0 deletions gb/cheat/cheat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ struct Cheat {
void append(unsigned addr, unsigned data);
void append(unsigned addr, unsigned comp, unsigned data);
optional<unsigned> find(unsigned addr, unsigned comp);

bool decode(const char *part, unsigned &addr, unsigned &comp, unsigned &data);
void synchronize();
};

extern Cheat cheat;
144 changes: 144 additions & 0 deletions sfc/cheat/cheat.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <sfc/sfc.hpp>
#include <iostream>
#include <cstdlib>

#define CHEAT_CPP
namespace SuperFamicom {
Expand Down Expand Up @@ -29,4 +31,146 @@ 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) {
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() {
return;
}

}
3 changes: 3 additions & 0 deletions sfc/cheat/cheat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ struct Cheat {
void append(unsigned addr, unsigned data);
void append(unsigned addr, unsigned comp, unsigned data);
optional<unsigned> find(unsigned addr, unsigned comp);

bool decode(const char *part, unsigned &addr, unsigned &data);
void synchronize();
};

extern Cheat cheat;
14 changes: 6 additions & 8 deletions target-libretro/libretro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,17 +401,16 @@ Interface::Interface() {
core_bind.iface = &core_interface;
}

void Interface::setCheats(const lstring &) {
#if 0
void Interface::setCheats(const lstring & list) {
if(core_interface.mode == SuperFamicomCartridge::ModeSuperGameBoy) {
GameBoy::cheat.reset();
for(auto &code : list) {
lstring codelist;
codelist.split("+", code);
for(auto &part : codelist) {
unsigned addr, data, comp;
if(GameBoy::Cheat::decode(part, addr, data, comp)) {
GameBoy::cheat.append({addr, data, comp});
if(GameBoy::cheat.decode(part, addr, comp, data)) {
GameBoy::cheat.append(addr, comp, data);
}
}
}
Expand All @@ -425,14 +424,13 @@ void Interface::setCheats(const lstring &) {
codelist.split("+", code);
for(auto &part : codelist) {
unsigned addr, data;
if(SuperFamicom::Cheat::decode(part, addr, data)) {
SuperFamicom::cheat.append({addr, data});
if(SuperFamicom::cheat.decode(part, addr, data)) {
SuperFamicom::cheat.append(addr, data);
}
}
}

SuperFamicom::cheat.synchronize();
#endif
}

unsigned retro_api_version(void) {
Expand Down Expand Up @@ -584,7 +582,7 @@ void retro_cheat_reset(void) {
}

void retro_cheat_set(unsigned index, bool enable, const char *code) {
cheatList.reserve(index+1);
cheatList.resize(index+1);
cheatList[index].enable = enable;
cheatList[index].code = code;

Expand Down

0 comments on commit a9204c5

Please sign in to comment.