mirror of https://github.com/snes9xgit/snes9x.git
Update cheat system. It becomes bsnes-compatible.
Notes: - New Snes9x can read old CHT format. Aside from that, I wrote a tool that converts the old CHT to the new one. It helps you if you want to convert a lot of files at a time. http://www.mediafire.com/?v8yb0yy1czsdyxh - New CHT format (CSV) doesn't have a field of "saved value". Development Notes: - I'm afraid I worked on only Windows version. Other ports might need a little modification. (especially when you uses SCheat structure on your port-specific code.) To use the new cheat code on your port, you need to call S9xAddCheat (enable, save_current_value, code, name), instead of S9xAddCheat(enable, save_current_value, address, byte, name)
This commit is contained in:
parent
6cd98accd9
commit
7dec44e1e3
38
cheats.cpp
38
cheats.cpp
|
@ -223,21 +223,38 @@ static bool8 S9xAllHex (const char *code, int len)
|
|||
|
||||
const char * S9xProActionReplayToRaw (const char *code, uint32 &address, uint8 &byte)
|
||||
{
|
||||
uint32 data = 0;
|
||||
bool valid = false;
|
||||
int len = strlen(code);
|
||||
if (len == 9 && S9xAllHex(code, 6) && *(code + 6) == ':' && S9xAllHex(code + 7, 2)) {
|
||||
uint32 address_, byte_;
|
||||
*(char*)(code + 6) = '\0';
|
||||
if (sscanf(code, "%x", &address_) == 1 && sscanf(code + 7, "%x", &byte_) == 1) {
|
||||
address = address_;
|
||||
byte = (uint8) byte_;
|
||||
valid = true;
|
||||
}
|
||||
*(char*)(code + 6) = ':';
|
||||
}
|
||||
else if (len == 8 && S9xAllHex(code, 8)) {
|
||||
uint32 data;
|
||||
if (sscanf(code, "%x", &data) == 1) {
|
||||
address = data >> 8;
|
||||
byte = (uint8) data;
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(code) != 8 || !S9xAllHex(code, 8) || sscanf(code, "%x", &data) != 1)
|
||||
if (valid)
|
||||
return (NULL);
|
||||
else
|
||||
return ("Invalid Pro Action Replay code - should be 8 hex digits in length.");
|
||||
|
||||
address = data >> 8;
|
||||
byte = (uint8) data;
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
const char * S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram, uint8 &num_bytes, uint8 bytes[3])
|
||||
const char * S9xGoldFingerToRaw (const char *code, uint32 &address, uint8 &num_bytes, uint8 bytes[3])
|
||||
{
|
||||
char tmp[15];
|
||||
int i;
|
||||
bool8 sram;
|
||||
|
||||
if (strlen(code) != 14)
|
||||
return ("Invalid Gold Finger code - should be 14 hex digits in length.");
|
||||
|
@ -247,6 +264,10 @@ const char * S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram,
|
|||
if (sscanf(tmp, "%x", &address) != 1)
|
||||
return ("Invalid Gold Finger code.");
|
||||
|
||||
sram = code[13] == '1';
|
||||
if (sram)
|
||||
return ("Unsupported Gold Finger code - writing to SRAM is not supported.");
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
@ -259,7 +280,6 @@ const char * S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram,
|
|||
}
|
||||
|
||||
num_bytes = i;
|
||||
sram = code[13] == '1';
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
|
28
cheats.h
28
cheats.h
|
@ -179,22 +179,28 @@
|
|||
#ifndef _CHEATS_H_
|
||||
#define _CHEATS_H_
|
||||
|
||||
#define MAX_CHEATS 150
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
struct SCheat
|
||||
{
|
||||
uint32 address;
|
||||
uint8 byte;
|
||||
uint8 saved_byte;
|
||||
bool8 enabled;
|
||||
bool8 saved;
|
||||
char name[22];
|
||||
};
|
||||
|
||||
struct SCheatItem
|
||||
{
|
||||
std::vector<SCheat> c;
|
||||
std::string code;
|
||||
std::string name;
|
||||
bool8 enabled;
|
||||
};
|
||||
|
||||
struct SCheatData
|
||||
{
|
||||
struct SCheat c[MAX_CHEATS];
|
||||
uint32 num_cheats;
|
||||
std::vector<SCheatItem> c;
|
||||
uint8 CWRAM[0x20000];
|
||||
uint8 CSRAM[0x10000];
|
||||
uint8 CIRAM[0x2000];
|
||||
|
@ -236,18 +242,22 @@ typedef enum
|
|||
extern SCheatData Cheat;
|
||||
extern Watch watches[16];
|
||||
|
||||
void S9xApplyCheat (uint32);
|
||||
void S9xApplyCheats (void);
|
||||
void S9xApplyCheat (uint32, bool8 = TRUE);
|
||||
void S9xApplyCheats (bool8 = TRUE);
|
||||
void S9xRemoveCheat (uint32);
|
||||
void S9xRemoveCheats (void);
|
||||
void S9xDeleteCheat (uint32);
|
||||
void S9xDeleteCheats (void);
|
||||
void S9xEnableCheat (uint32);
|
||||
void S9xDisableCheat (uint32);
|
||||
void S9xAddCheat (bool8, bool8, uint32, uint8);
|
||||
bool S9xIsValidCheatCode(const char *);
|
||||
void S9xAddCheat (bool8, bool8, const char *, const char *);
|
||||
void S9xAddCheat (bool8, bool8, uint32, uint8, const char * = "");
|
||||
void S9xInitCheatData (void);
|
||||
void S9xInitWatchedAddress (void);
|
||||
bool8 IsOldCheatFile (const char *);
|
||||
bool8 S9xLoadCheatFile (const char *);
|
||||
bool8 S9xLoadCheatFileOld (const char *);
|
||||
bool8 S9xSaveCheatFile (const char *);
|
||||
|
||||
void S9xStartCheatSearch (SCheatData *);
|
||||
|
@ -258,6 +268,6 @@ void S9xOutputCheatSearchResults (SCheatData *);
|
|||
|
||||
const char * S9xGameGenieToRaw (const char *, uint32 &, uint8 &);
|
||||
const char * S9xProActionReplayToRaw (const char *, uint32 &, uint8 &);
|
||||
const char * S9xGoldFingerToRaw (const char *, uint32 &, bool8 &, uint8 &, uint8 bytes[3]);
|
||||
const char * S9xGoldFingerToRaw (const char *, uint32 &, uint8 &, uint8 bytes[3]);
|
||||
|
||||
#endif
|
||||
|
|
451
cheats2.cpp
451
cheats2.cpp
|
@ -180,6 +180,10 @@
|
|||
#include "memmap.h"
|
||||
#include "cheats.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
uint8 S9xGetByteFree (uint32);
|
||||
void S9xSetByteFree (uint8, uint32);
|
||||
|
||||
|
@ -223,69 +227,151 @@ void S9xInitCheatData (void)
|
|||
Cheat.FillRAM = Memory.FillRAM;
|
||||
}
|
||||
|
||||
void S9xAddCheat (bool8 enable, bool8 save_current_value, uint32 address, uint8 byte)
|
||||
bool S9xIsValidCheatCode(const char *codestring)
|
||||
{
|
||||
if (Cheat.num_cheats < sizeof(Cheat.c) / sizeof(Cheat.c[0]))
|
||||
std::string codes(codestring);
|
||||
|
||||
if (codes.empty() || codes[codes.length() - 1] == '+')
|
||||
return false; // std::getline cannot handle this case
|
||||
|
||||
std::istringstream iss(codes);
|
||||
std::string code;
|
||||
while(std::getline(iss, code, '+'))
|
||||
{
|
||||
Cheat.c[Cheat.num_cheats].address = address;
|
||||
Cheat.c[Cheat.num_cheats].byte = byte;
|
||||
Cheat.c[Cheat.num_cheats].enabled = enable;
|
||||
|
||||
if (save_current_value)
|
||||
uint32 address;
|
||||
uint8 byte;
|
||||
if (S9xProActionReplayToRaw(code.c_str(), address, byte) != NULL &&
|
||||
S9xGameGenieToRaw(code.c_str(), address, byte) != NULL)
|
||||
{
|
||||
Cheat.c[Cheat.num_cheats].saved_byte = S9xGetByteFree(address);
|
||||
Cheat.c[Cheat.num_cheats].saved = TRUE;
|
||||
}
|
||||
uint8 bytes[3];
|
||||
uint8 num_bytes;
|
||||
|
||||
Cheat.num_cheats++;
|
||||
if (S9xGoldFingerToRaw(code.c_str(), address, num_bytes, bytes) != NULL)
|
||||
return false; // invalid format
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool S9xCompileCheat(struct SCheatItem& cheat, bool8 save_current_value)
|
||||
{
|
||||
std::string codes(cheat.code);
|
||||
std::vector<SCheat> cheatVector;
|
||||
|
||||
if (codes.empty() || codes[codes.length() - 1] == '+')
|
||||
return false; // std::getline cannot handle this case
|
||||
|
||||
std::istringstream iss(codes);
|
||||
std::string code;
|
||||
while(std::getline(iss, code, '+'))
|
||||
{
|
||||
SCheat c;
|
||||
if (S9xProActionReplayToRaw(code.c_str(), c.address, c.byte) == NULL ||
|
||||
S9xGameGenieToRaw(code.c_str(), c.address, c.byte) == NULL)
|
||||
{
|
||||
c.saved = save_current_value;
|
||||
if (c.saved) {
|
||||
c.saved_byte = S9xGetByteFree(c.address);
|
||||
}
|
||||
cheatVector.push_back(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 address;
|
||||
uint8 bytes[3];
|
||||
uint8 num_bytes;
|
||||
|
||||
if (S9xGoldFingerToRaw(code.c_str(), address, num_bytes, bytes) == NULL)
|
||||
{
|
||||
for (int i = 0; i < num_bytes; i++)
|
||||
{
|
||||
c.address = address + i;
|
||||
c.byte = bytes[i];
|
||||
c.saved = save_current_value;
|
||||
if (c.saved) {
|
||||
c.saved_byte = S9xGetByteFree(c.address);
|
||||
}
|
||||
cheatVector.push_back(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false; // invalid format
|
||||
}
|
||||
}
|
||||
cheat.c.clear();
|
||||
copy(cheatVector.begin(), cheatVector.end(), std::back_inserter(cheat.c));
|
||||
return true;
|
||||
}
|
||||
|
||||
void S9xAddCheat (bool8 enable, bool8 save_current_value, const char *code, const char *name)
|
||||
{
|
||||
struct SCheatItem cheat;
|
||||
cheat.code = code;
|
||||
cheat.name = name;
|
||||
cheat.enabled = enable;
|
||||
if (S9xCompileCheat(cheat, save_current_value))
|
||||
Cheat.c.push_back(cheat);
|
||||
}
|
||||
|
||||
void S9xAddCheat (bool8 enable, bool8 save_current_value, uint32 address, uint8 byte, const char *name)
|
||||
{
|
||||
if (address >= 0x000000 && address <= 0xFFFFFF) {
|
||||
char code[10];
|
||||
sprintf(code, "%06X:%02X", address, byte);
|
||||
S9xAddCheat(enable, save_current_value, code, name);
|
||||
}
|
||||
}
|
||||
|
||||
void S9xDeleteCheat (uint32 which1)
|
||||
{
|
||||
if (which1 < Cheat.num_cheats)
|
||||
std::vector<SCheatItem>::iterator iter = Cheat.c.begin();
|
||||
std::advance(iter, which1);
|
||||
if (which1 < Cheat.c.size())
|
||||
{
|
||||
if (Cheat.c[which1].enabled)
|
||||
S9xRemoveCheat(which1);
|
||||
|
||||
memmove(&Cheat.c[which1], &Cheat.c[which1 + 1], sizeof(Cheat.c[0]) * (Cheat.num_cheats - which1 - 1));
|
||||
|
||||
Cheat.num_cheats--;
|
||||
Cheat.c.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void S9xDeleteCheats (void)
|
||||
{
|
||||
S9xRemoveCheats();
|
||||
Cheat.num_cheats = 0;
|
||||
Cheat.c.clear();
|
||||
}
|
||||
|
||||
void S9xRemoveCheat (uint32 which1)
|
||||
{
|
||||
if (Cheat.c[which1].saved)
|
||||
std::vector<SCheat>::iterator iter = Cheat.c[which1].c.begin();
|
||||
while (iter != Cheat.c[which1].c.end())
|
||||
{
|
||||
uint32 address = Cheat.c[which1].address;
|
||||
SCheat& c = *iter;
|
||||
if (c.saved)
|
||||
{
|
||||
uint32 address = c.address;
|
||||
|
||||
int block = (address & 0xffffff) >> MEMMAP_SHIFT;
|
||||
uint8 *ptr = Memory.Map[block];
|
||||
int block = (address & 0xffffff) >> MEMMAP_SHIFT;
|
||||
uint8 *ptr = Memory.Map[block];
|
||||
|
||||
if (ptr >= (uint8 *) CMemory::MAP_LAST)
|
||||
*(ptr + (address & 0xffff)) = Cheat.c[which1].saved_byte;
|
||||
else
|
||||
S9xSetByteFree(Cheat.c[which1].saved_byte, address);
|
||||
if (ptr >= (uint8 *) CMemory::MAP_LAST)
|
||||
*(ptr + (address & 0xffff)) = c.saved_byte;
|
||||
else
|
||||
S9xSetByteFree(c.saved_byte, address);
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
void S9xRemoveCheats (void)
|
||||
{
|
||||
for (uint32 i = 0; i < Cheat.num_cheats; i++)
|
||||
for (uint32 i = 0; i < Cheat.c.size(); i++)
|
||||
if (Cheat.c[i].enabled)
|
||||
S9xRemoveCheat(i);
|
||||
}
|
||||
|
||||
void S9xEnableCheat (uint32 which1)
|
||||
{
|
||||
if (which1 < Cheat.num_cheats && !Cheat.c[which1].enabled)
|
||||
if (which1 < Cheat.c.size() && !Cheat.c[which1].enabled)
|
||||
{
|
||||
Cheat.c[which1].enabled = TRUE;
|
||||
S9xApplyCheat(which1);
|
||||
|
@ -294,62 +380,222 @@ void S9xEnableCheat (uint32 which1)
|
|||
|
||||
void S9xDisableCheat (uint32 which1)
|
||||
{
|
||||
if (which1 < Cheat.num_cheats && Cheat.c[which1].enabled)
|
||||
if (which1 < Cheat.c.size() && Cheat.c[which1].enabled)
|
||||
{
|
||||
S9xRemoveCheat(which1);
|
||||
Cheat.c[which1].enabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void S9xApplyCheat (uint32 which1)
|
||||
void S9xApplyCheat (uint32 which1, bool8 force_save_current_value)
|
||||
{
|
||||
uint32 address = Cheat.c[which1].address;
|
||||
|
||||
if (!Cheat.c[which1].saved)
|
||||
std::vector<SCheat>::iterator iter = Cheat.c[which1].c.begin();
|
||||
while (iter != Cheat.c[which1].c.end())
|
||||
{
|
||||
Cheat.c[which1].saved_byte = S9xGetByteFree(address);
|
||||
Cheat.c[which1].saved = TRUE;
|
||||
SCheat& c = *iter;
|
||||
uint32 address = c.address;
|
||||
|
||||
if (force_save_current_value)
|
||||
{
|
||||
c.saved_byte = S9xGetByteFree(address);
|
||||
c.saved = TRUE;
|
||||
}
|
||||
|
||||
int block = (address & 0xffffff) >> MEMMAP_SHIFT;
|
||||
uint8 *ptr = Memory.Map[block];
|
||||
|
||||
if (ptr >= (uint8 *) CMemory::MAP_LAST)
|
||||
*(ptr + (address & 0xffff)) = c.byte;
|
||||
else
|
||||
S9xSetByteFree(c.byte, address);
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
int block = (address & 0xffffff) >> MEMMAP_SHIFT;
|
||||
uint8 *ptr = Memory.Map[block];
|
||||
|
||||
if (ptr >= (uint8 *) CMemory::MAP_LAST)
|
||||
*(ptr + (address & 0xffff)) = Cheat.c[which1].byte;
|
||||
else
|
||||
S9xSetByteFree(Cheat.c[which1].byte, address);
|
||||
}
|
||||
|
||||
void S9xApplyCheats (void)
|
||||
void S9xApplyCheats (bool8 force_save_current_value)
|
||||
{
|
||||
if (Settings.ApplyCheats)
|
||||
{
|
||||
for (uint32 i = 0; i < Cheat.num_cheats; i++)
|
||||
for (uint32 i = 0; i < Cheat.c.size(); i++)
|
||||
if (Cheat.c[i].enabled)
|
||||
S9xApplyCheat(i);
|
||||
S9xApplyCheat(i, force_save_current_value);
|
||||
}
|
||||
}
|
||||
|
||||
bool8 S9xLoadCheatFile (const char *filename)
|
||||
std::string& string_replace (std::string& str, const std::string& from, const std::string& to)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
while (pos = str.find(from, pos), pos != std::string::npos) {
|
||||
str.replace(pos, from.length(), to);
|
||||
pos += to.length();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string csv_escape(const std::string &token, bool quoteAlways = false)
|
||||
{
|
||||
std::string res(token);
|
||||
bool needsQuote = false;
|
||||
if (res.find("\"", 0) != std::string::npos) {
|
||||
needsQuote = true;
|
||||
string_replace(res, "\"", "\"\"");
|
||||
}
|
||||
if (res.find(",", 0) != std::string::npos ||
|
||||
res.find("\n", 0) != std::string::npos) {
|
||||
needsQuote = true;
|
||||
}
|
||||
if (needsQuote || quoteAlways) {
|
||||
res.insert(0, "\"");
|
||||
res.append("\"");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
std::string csv_unescape(const std::string &token)
|
||||
{
|
||||
std::string res(token);
|
||||
if (res.length() >= 2 && res[0] == '\"' && res[res.length() - 1] == '\"') {
|
||||
res.erase(res.length() - 1, 1);
|
||||
res.erase(0, 1);
|
||||
}
|
||||
string_replace(res, "\"\"", "\"");
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::string> csv_split(const std::string &str, bool *valid = NULL)
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
||||
if (valid != NULL) {
|
||||
*valid = true;
|
||||
}
|
||||
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type current = 0;
|
||||
std::string::size_type found;
|
||||
bool insideQuote = false;
|
||||
while ((found = str.find_first_of(",\"", current)) != std::string::npos) {
|
||||
char c = str[found];
|
||||
if (c == '\"') {
|
||||
if (insideQuote) {
|
||||
if (str[found + 1] == '\"') {
|
||||
found++; // skip the next quote
|
||||
}
|
||||
else {
|
||||
if (valid != NULL && str[found + 1] != ',' && str[found + 1] != '\0' && str[found + 1] != '\r' && str[found + 1] != '\n') {
|
||||
*valid = false;
|
||||
}
|
||||
insideQuote = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (valid != NULL && found > 0 && str[found - 1] != ',' && str[found - 1] != '\r' && str[found - 1] != '\n') {
|
||||
*valid = false;
|
||||
}
|
||||
insideQuote = true;
|
||||
}
|
||||
}
|
||||
else if (c == ',') {
|
||||
if (!insideQuote) {
|
||||
res.push_back(std::string(str, start, found - start));
|
||||
start = found + 1;
|
||||
}
|
||||
}
|
||||
current = found + 1;
|
||||
}
|
||||
res.push_back(std::string(str, start, str.size() - start));
|
||||
|
||||
if (valid != NULL && insideQuote) {
|
||||
*valid = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < res.size(); i++) {
|
||||
res[i] = csv_unescape(res[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string csv_join(std::vector<std::string> &v, bool quoteAlways = false)
|
||||
{
|
||||
std::string res;
|
||||
|
||||
std::vector<std::string>::iterator iter = v.begin();
|
||||
bool first = true;
|
||||
while(iter != v.end())
|
||||
{
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
res.append(",");
|
||||
}
|
||||
|
||||
res.append(csv_escape(*iter, quoteAlways));
|
||||
iter++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool8 IsOldCheatFile (const char *filename)
|
||||
{
|
||||
FILE *fs;
|
||||
uint8 data[28];
|
||||
|
||||
Cheat.num_cheats = 0;
|
||||
|
||||
fs = fopen(filename, "rb");
|
||||
if (!fs)
|
||||
return (FALSE);
|
||||
|
||||
while (fread((void *) data, 1, 28, fs) == 28)
|
||||
int c = fgetc(fs);
|
||||
fclose(fs);
|
||||
|
||||
return ((c & ~(4 | 8)) == 0);
|
||||
}
|
||||
|
||||
bool8 S9xLoadCheatFile (const char *filename)
|
||||
{
|
||||
FILE *fs;
|
||||
char data[1024];
|
||||
|
||||
if (IsOldCheatFile(filename))
|
||||
return S9xLoadCheatFileOld(filename);
|
||||
|
||||
Cheat.c.clear();
|
||||
|
||||
fs = fopen(filename, "r");
|
||||
if (!fs)
|
||||
return (FALSE);
|
||||
|
||||
while (fgets(data, 1024, fs) != NULL)
|
||||
{
|
||||
Cheat.c[Cheat.num_cheats].enabled = (data[0] & 4) == 0;
|
||||
Cheat.c[Cheat.num_cheats].byte = data[1];
|
||||
Cheat.c[Cheat.num_cheats].address = data[2] | (data[3] << 8) | (data[4] << 16);
|
||||
Cheat.c[Cheat.num_cheats].saved_byte = data[5];
|
||||
Cheat.c[Cheat.num_cheats].saved = (data[0] & 8) != 0;
|
||||
memmove(Cheat.c[Cheat.num_cheats].name, &data[8], 20);
|
||||
Cheat.c[Cheat.num_cheats++].name[20] = 0;
|
||||
data[strlen(data) - 1] = '\0'; // erase newline
|
||||
|
||||
std::vector<std::string> v = csv_split(std::string(data));
|
||||
if (v.size() != 3) {
|
||||
fclose(fs);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
struct SCheatItem c;
|
||||
if (v[0] == "enabled") {
|
||||
c.enabled = TRUE;
|
||||
}
|
||||
else if (v[0] == "disabled") {
|
||||
c.enabled = FALSE;
|
||||
}
|
||||
else {
|
||||
fclose(fs);
|
||||
return (FALSE);
|
||||
}
|
||||
c.code = v[1];
|
||||
c.name = v[2];
|
||||
|
||||
if (!S9xCompileCheat(c, FALSE))
|
||||
{
|
||||
fclose(fs);
|
||||
return (FALSE);
|
||||
}
|
||||
Cheat.c.push_back(c);
|
||||
}
|
||||
|
||||
fclose(fs);
|
||||
|
@ -357,46 +603,83 @@ bool8 S9xLoadCheatFile (const char *filename)
|
|||
return (TRUE);
|
||||
}
|
||||
|
||||
bool8 S9xLoadCheatFileOld (const char *filename)
|
||||
{
|
||||
FILE *fs;
|
||||
uint8 data[28];
|
||||
|
||||
Cheat.c.clear();
|
||||
|
||||
fs = fopen(filename, "rb");
|
||||
if (!fs)
|
||||
return (FALSE);
|
||||
|
||||
while (fread((void *) data, 1, 28, fs) == 28)
|
||||
{
|
||||
struct SCheatItem c;
|
||||
uint32 address;
|
||||
uint8 byte;
|
||||
uint8 saved_byte;
|
||||
bool8 saved;
|
||||
c.enabled = (data[0] & 4) == 0;
|
||||
byte = data[1];
|
||||
address = data[2] | (data[3] << 8) | (data[4] << 16);
|
||||
saved_byte = data[5];
|
||||
saved = (data[0] & 8) != 0;
|
||||
|
||||
char code[10];
|
||||
char name[22];
|
||||
sprintf(code, "%06X%02X", address, byte);
|
||||
memmove(name, &data[8], 20);
|
||||
name[20] = '\0';
|
||||
c.code = code;
|
||||
c.name = name;
|
||||
|
||||
if (!S9xCompileCheat(c, FALSE))
|
||||
{
|
||||
fclose(fs);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
std::vector<SCheat>::iterator iter = c.c.begin();
|
||||
while (iter != c.c.end())
|
||||
{
|
||||
iter->saved_byte = saved_byte;
|
||||
iter->saved = saved;
|
||||
iter++;
|
||||
}
|
||||
|
||||
Cheat.c.push_back(c);
|
||||
}
|
||||
|
||||
fclose(fs);
|
||||
|
||||
S9xSaveCheatFile(filename);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
bool8 S9xSaveCheatFile (const char *filename)
|
||||
{
|
||||
if (Cheat.num_cheats == 0)
|
||||
if (Cheat.c.size() == 0)
|
||||
{
|
||||
remove(filename);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
FILE *fs;
|
||||
uint8 data[28];
|
||||
|
||||
fs = fopen(filename, "wb");
|
||||
fs = fopen(filename, "w");
|
||||
if (!fs)
|
||||
return (FALSE);
|
||||
|
||||
for (uint32 i = 0; i < Cheat.num_cheats; i++)
|
||||
for (uint32 i = 0; i < Cheat.c.size(); i++)
|
||||
{
|
||||
memset(data, 0, 28);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
data[6] = 254;
|
||||
data[7] = 252;
|
||||
}
|
||||
|
||||
if (!Cheat.c[i].enabled)
|
||||
data[0] |= 4;
|
||||
|
||||
if (Cheat.c[i].saved)
|
||||
data[0] |= 8;
|
||||
|
||||
data[1] = Cheat.c[i].byte;
|
||||
data[2] = (uint8) (Cheat.c[i].address >> 0);
|
||||
data[3] = (uint8) (Cheat.c[i].address >> 8);
|
||||
data[4] = (uint8) (Cheat.c[i].address >> 16);
|
||||
data[5] = Cheat.c[i].saved_byte;
|
||||
|
||||
memmove(&data[8], Cheat.c[i].name, 19);
|
||||
|
||||
if (fwrite(data, 28, 1, fs) != 1)
|
||||
struct SCheatItem& c = Cheat.c[i];
|
||||
std::vector<std::string> v;
|
||||
v.push_back(c.enabled ? "enabled" : "disabled");
|
||||
v.push_back(c.code);
|
||||
v.push_back(c.name);
|
||||
if (fprintf(fs, "%s\n", csv_join(v, true).c_str()) < 0)
|
||||
{
|
||||
fclose(fs);
|
||||
return (FALSE);
|
||||
|
|
2
gfx.cpp
2
gfx.cpp
|
@ -448,7 +448,7 @@ void S9xEndScreenRefresh (void)
|
|||
else
|
||||
S9xControlEOF();
|
||||
|
||||
S9xApplyCheats();
|
||||
S9xApplyCheats(FALSE);
|
||||
|
||||
#ifdef DEBUGGER
|
||||
if (CPU.Flags & FRAME_ADVANCE_FLAG)
|
||||
|
|
|
@ -1759,7 +1759,7 @@ bool8 CMemory::LoadROMInt (int32 ROMfillSize)
|
|||
InitROM();
|
||||
|
||||
S9xInitCheatData();
|
||||
S9xApplyCheats();
|
||||
S9xApplyCheats(FALSE);
|
||||
|
||||
S9xReset();
|
||||
|
||||
|
@ -1930,7 +1930,7 @@ bool8 CMemory::LoadMultiCartInt ()
|
|||
InitROM();
|
||||
|
||||
S9xInitCheatData();
|
||||
S9xApplyCheats();
|
||||
S9xApplyCheats(FALSE);
|
||||
|
||||
S9xReset();
|
||||
|
||||
|
|
|
@ -788,11 +788,10 @@ char * S9xParseArgs (char **argv, int argc)
|
|||
{
|
||||
uint32 address;
|
||||
uint8 bytes[3];
|
||||
bool8 sram;
|
||||
uint8 num_bytes;
|
||||
const char *error;
|
||||
|
||||
if ((error = S9xGoldFingerToRaw(argv[++i], address, sram, num_bytes, bytes)) == NULL)
|
||||
if ((error = S9xGoldFingerToRaw(argv[++i], address, num_bytes, bytes)) == NULL)
|
||||
{
|
||||
for (int c = 0; c < num_bytes; c++)
|
||||
S9xAddCheat(TRUE, FALSE, address + c, bytes[c]);
|
||||
|
|
|
@ -1203,16 +1203,7 @@ LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
cht.new_val = rswatches[watchIndex].CurValue;
|
||||
cht.saved_val = rswatches[watchIndex].CurValue;
|
||||
extern INT_PTR CALLBACK DlgCheatSearchAdd(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
if(DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CHEAT_FROM_SEARCH), hDlg, DlgCheatSearchAdd, (LPARAM)&cht))
|
||||
{
|
||||
int p;
|
||||
for(p=0; p<cht.size; p++)
|
||||
{
|
||||
S9xAddCheat(TRUE, cht.saved, cht.address +p, ((cht.new_val>>(8*p))&0xFF));
|
||||
//add cheat
|
||||
strcpy(Cheat.c[Cheat.num_cheats-1].name, cht.name);
|
||||
}
|
||||
}
|
||||
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CHEAT_FROM_SEARCH), hDlg, DlgCheatSearchAdd, (LPARAM)&cht);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -160,11 +160,11 @@
|
|||
#define IDC_JPTOGGLE 1126
|
||||
#define IDC_LOCALVIDMEM 1126
|
||||
#define IDC_VSYNC 1126
|
||||
#define IDC_CHEAT_DESCRIPTION 1127
|
||||
#define IDC_CHEAT_NAME 1127
|
||||
#define IDC_KEYBOARD 1127
|
||||
#define IDC_ALLOWLEFTRIGHT 1127
|
||||
#define IDC_CHEAT_ADDRESS 1128
|
||||
#define IDC_CHEAT_BYTE 1129
|
||||
#define IDC_CHEAT_DEC 1128
|
||||
#define IDC_CHEAT_HEX 1129
|
||||
#define IDC_ADD_CHEAT 1130
|
||||
#define IDC_CHEAT_LIST 1131
|
||||
#define IDC_PICTURE 1132
|
||||
|
@ -253,13 +253,9 @@
|
|||
#define IDC_LABEL_UP10 1189
|
||||
#define IDC_LABEL_MAXSKIP 1190
|
||||
#define IDC_LABEL_UP11 1190
|
||||
#define IDC_LABEL_CHEAT_CODE 1191
|
||||
#define IDC_LABEL_UP12 1191
|
||||
#define IDC_LABEL_CHEAT_DESCRIPTION 1192
|
||||
#define IDC_LABEL_UP13 1192
|
||||
#define IDC_LABEL_CHEAT_ADDRESS 1193
|
||||
#define IDC_LABEL_UP14 1193
|
||||
#define IDC_LABEL_CHEAT_BYTE 1194
|
||||
#define IDC_LABEL_UP15 1194
|
||||
#define IDC_LABEL_SERVERADDY 1195
|
||||
#define IDC_LABEL_UP16 1195
|
||||
|
@ -368,6 +364,7 @@
|
|||
#define IDC_SHADER_HLSL_BROWSE 3016
|
||||
#define IDC_SHADER_GROUP 3017
|
||||
#define IDC_SHADER_GLSL_BROWSE 3018
|
||||
#define IDC_CHEAT_SYNTAX 3018
|
||||
#define IDC_RAMLIST 5000
|
||||
//#define IDC_C_SEARCH 5001
|
||||
#define IDC_C_ADDCHEAT 5002
|
||||
|
@ -578,7 +575,7 @@
|
|||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 151
|
||||
#define _APS_NEXT_COMMAND_VALUE 40175
|
||||
#define _APS_NEXT_CONTROL_VALUE 3018
|
||||
#define _APS_NEXT_CONTROL_VALUE 3019
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -50,7 +50,7 @@ BEGIN
|
|||
VK_BACK, ID_WINDOW_STRETCH, VIRTKEY, ALT, NOINVERT
|
||||
END
|
||||
|
||||
IDR_RWACCELERATOR ACCELERATORS
|
||||
IDR_RWACCELERATOR ACCELERATORS
|
||||
BEGIN
|
||||
"N", RAMMENU_FILE_NEW, VIRTKEY, CONTROL
|
||||
"O", RAMMENU_FILE_OPEN, VIRTKEY, CONTROL
|
||||
|
@ -248,26 +248,28 @@ BEGIN
|
|||
CONTROL "VSync",IDC_VSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,102,37,10
|
||||
END
|
||||
|
||||
IDD_CHEATER DIALOGEX 0, 0, 262, 218
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
|
||||
IDD_CHEATER DIALOGEX 0, 0, 320, 240
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Cheat Entry and Editor"
|
||||
FONT 8, "MS Sans Serif", 0, 0, 0x1
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "List1",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,200,125,WS_EX_CLIENTEDGE
|
||||
PUSHBUTTON "&Add",IDC_ADD_CHEAT,215,5,40,15,WS_DISABLED
|
||||
PUSHBUTTON "&Delete",IDC_DELETE_CHEAT,215,25,40,15,WS_DISABLED
|
||||
PUSHBUTTON "&Update",IDC_UPDATE_CHEAT,215,45,40,15,WS_DISABLED
|
||||
PUSHBUTTON "C&lear",IDC_CLEAR_CHEATS,215,65,40,15
|
||||
EDITTEXT IDC_CHEAT_CODE,86,134,118,15,ES_UPPERCASE | ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_CHEAT_DESCRIPTION,85,154,119,15,ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_CHEAT_ADDRESS,85,175,44,15,ES_UPPERCASE | ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_CHEAT_BYTE,215,175,26,15,ES_UPPERCASE | ES_AUTOHSCROLL
|
||||
PUSHBUTTON "&OK",IDOK,93,196,50,15
|
||||
PUSHBUTTON "&Cancel",IDCANCEL,151,196,50,15
|
||||
RTEXT "Enter Cheat Code:",IDC_LABEL_CHEAT_CODE,23,134,59,15,SS_CENTERIMAGE
|
||||
RTEXT "Cheat Description",IDC_LABEL_CHEAT_DESCRIPTION,19,154,61,15,SS_CENTERIMAGE
|
||||
RTEXT "Cheat Address (hex)",IDC_LABEL_CHEAT_ADDRESS,18,175,64,15,SS_CENTERIMAGE
|
||||
RTEXT "New Value (dec or hex)",IDC_LABEL_CHEAT_BYTE,134,175,74,15,SS_CENTERIMAGE
|
||||
CONTROL "List1",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,260,125,WS_EX_CLIENTEDGE
|
||||
PUSHBUTTON "&Add",IDC_ADD_CHEAT,273,5,40,15,WS_DISABLED
|
||||
PUSHBUTTON "&Delete",IDC_DELETE_CHEAT,273,25,40,15,WS_DISABLED
|
||||
PUSHBUTTON "&Update",IDC_UPDATE_CHEAT,273,45,40,15,WS_DISABLED
|
||||
EDITTEXT IDC_CHEAT_CODE,85,134,179,15,ES_UPPERCASE | ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_CHEAT_NAME,85,154,179,15,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "C&lear",IDC_CLEAR_CHEATS,268,154,40,15
|
||||
PUSHBUTTON "Syntax",IDC_CHEAT_SYNTAX,268,133,40,15
|
||||
EDITTEXT IDC_CHEAT_DEC,85,189,53,15,ES_UPPERCASE | ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_CHEAT_HEX,195,189,45,15,ES_UPPERCASE | ES_AUTOHSCROLL
|
||||
PUSHBUTTON "&OK",IDOK,106,218,50,15
|
||||
PUSHBUTTON "&Cancel",IDCANCEL,164,218,50,15
|
||||
RTEXT "Cheat Code:",IDC_STATIC,22,134,59,15,SS_CENTERIMAGE
|
||||
RTEXT "Cheat Description:",IDC_STATIC,20,154,61,15,SS_CENTERIMAGE
|
||||
RTEXT "decimal",IDC_STATIC,52,189,30,15,SS_CENTERIMAGE
|
||||
RTEXT "hexadecimal",IDC_STATIC,143,189,45,15,SS_CENTERIMAGE
|
||||
GROUPBOX "Radix Converter",IDC_STATIC,29,177,235,36,0,WS_EX_TRANSPARENT
|
||||
END
|
||||
|
||||
IDD_NETPLAYPROGRESS DIALOG 0, 0, 186, 61
|
||||
|
@ -375,8 +377,8 @@ BEGIN
|
|||
PUSHBUTTON "&OK",IDOK,85,123,45,13
|
||||
PUSHBUTTON "&Cancel",IDCANCEL,135,123,45,13
|
||||
EDITTEXT IDC_NC_ADDRESS,79,7,101,12,ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_NC_CURRVAL,79,31,101,12,ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_NC_PREVVAL,79,55,101,12,ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_NC_CURRVAL,79,31,101,12,ES_AUTOHSCROLL | ES_READONLY
|
||||
EDITTEXT IDC_NC_PREVVAL,79,55,101,12,ES_AUTOHSCROLL | ES_READONLY
|
||||
EDITTEXT IDC_NC_NEWVAL,79,79,101,12,ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_NC_DESC,79,103,101,12,ES_AUTOHSCROLL
|
||||
RTEXT "Address",IDC_STATIC,7,7,70,12,SS_CENTERIMAGE
|
||||
|
@ -687,7 +689,7 @@ BEGIN
|
|||
PUSHBUTTON "&Cancel",IDCANCEL,120,80,50,14
|
||||
END
|
||||
|
||||
IDD_PROMPT DIALOG 0, 0, 186, 68
|
||||
IDD_PROMPT DIALOG 0, 0, 186, 68
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Input Prompt"
|
||||
FONT 8, "Ms Shell Dlg 2"
|
||||
|
@ -790,9 +792,9 @@ BEGIN
|
|||
IDD_CHEATER, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 255
|
||||
RIGHTMARGIN, 313
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 211
|
||||
BOTTOMMARGIN, 233
|
||||
END
|
||||
|
||||
IDD_NETPLAYPROGRESS, DIALOG
|
||||
|
@ -1139,7 +1141,7 @@ BEGIN
|
|||
END
|
||||
END
|
||||
|
||||
RAMWATCH_MENU MENU
|
||||
RAMWATCH_MENU MENU
|
||||
BEGIN
|
||||
POPUP "File"
|
||||
BEGIN
|
||||
|
|
|
@ -534,6 +534,8 @@ Nintendo is a trade mark.")
|
|||
#define SEARCH_COLUMN_ADDRESS TEXT("Address")
|
||||
#define SEARCH_COLUMN_VALUE TEXT("Value")
|
||||
#define SEARCH_COLUMN_DESCRIPTION TEXT("Description")
|
||||
#define CHEAT_COLUMN_CODE TEXT("Code")
|
||||
#define CHEAT_COLUMN_DESCRIPTION TEXT("Description")
|
||||
|
||||
// ROM dialog
|
||||
|
||||
|
|
1195
win32/wsnes9x.cpp
1195
win32/wsnes9x.cpp
File diff suppressed because it is too large
Load Diff
|
@ -224,6 +224,22 @@
|
|||
#define _tFromAnsi
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
namespace std {
|
||||
#ifndef tstring
|
||||
#ifdef UNICODE
|
||||
typedef wstring tstring;
|
||||
typedef wstringbuf tstringbuf;
|
||||
typedef wstringstream tstringstream;
|
||||
#else
|
||||
typedef string tstring;
|
||||
typedef stringbuf tstringbuf;
|
||||
typedef stringstream tstringstream;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
inline static void Log (const char *str)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue