mirror of https://github.com/snes9xgit/snes9x.git
Revamping cheats support.
This commit is contained in:
parent
c727189d3e
commit
0d102b72ff
59
bml.cpp
59
bml.cpp
|
@ -12,6 +12,8 @@ static inline bml_node *bml_node_new(void)
|
|||
node->data = NULL;
|
||||
node->name = NULL;
|
||||
node->depth = -1;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static char *strndup_trim (char *str, int len)
|
||||
|
@ -45,14 +47,14 @@ static inline unsigned int bml_read_depth (char *data)
|
|||
return depth;
|
||||
}
|
||||
|
||||
static unsigned int bml_parse_depth (bml_node *node, char **data)
|
||||
static void bml_parse_depth (bml_node *node, char **data)
|
||||
{
|
||||
unsigned int depth = bml_read_depth (*data);
|
||||
*data += depth;
|
||||
node->depth = depth;
|
||||
}
|
||||
|
||||
static char *bml_parse_name (bml_node *node, char **data)
|
||||
static void bml_parse_name (bml_node *node, char **data)
|
||||
{
|
||||
int len;
|
||||
|
||||
|
@ -70,7 +72,7 @@ static void bml_parse_data (bml_node *node, char **data)
|
|||
if (p[0] == '=' && p[1] == '\"')
|
||||
{
|
||||
len = 2;
|
||||
while (p[len] && !islf (p[len]))
|
||||
while (p[len] && p[len] != '\"' && !islf (p[len]))
|
||||
len++;
|
||||
if (p[len] != '\"')
|
||||
return;
|
||||
|
@ -177,7 +179,8 @@ static void bml_parse_attr (bml_node *node, char **data)
|
|||
n->name = strndup_trim (p, len);
|
||||
p += len;
|
||||
bml_parse_data (n, &p);
|
||||
node->attr.push_back (n);
|
||||
n->depth = bml_attr_type;
|
||||
node->child.push_back (n);
|
||||
}
|
||||
|
||||
*data = p;
|
||||
|
@ -196,10 +199,12 @@ static int contains_space (char *str)
|
|||
|
||||
static void bml_print_node (bml_node *node, int depth)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < depth * 2; i++)
|
||||
for (i = 0; i < depth * 2; i++)
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
|
@ -210,22 +215,21 @@ static void bml_print_node (bml_node *node, int depth)
|
|||
if (node->data)
|
||||
{
|
||||
if (contains_space (node->data))
|
||||
printf (": \"%s\"", node->data);
|
||||
printf ("=\"%s\"", node->data);
|
||||
else
|
||||
printf (": %s", node->data);
|
||||
}
|
||||
|
||||
for (int i = 0; i < node->attr.size(); i++)
|
||||
for (i = 0; i < (int) node->child.size () && node->child[i]->depth == bml_attr_type; i++)
|
||||
{
|
||||
if (node->attr[i]->name)
|
||||
if (node->child[i]->name)
|
||||
{
|
||||
printf (" %s", node->attr[i]->name);
|
||||
if (node->attr[i]->data)
|
||||
printf (" %s", node->child[i]->name);
|
||||
if (node->child[i]->data)
|
||||
{
|
||||
if (contains_space (node->attr[i]->data))
|
||||
printf ("=\"%s\"", node->attr[i]->data);
|
||||
if (contains_space (node->child[i]->data))
|
||||
printf ("=\"%s\"", node->child[i]->data);
|
||||
else
|
||||
printf ("=%s", node->attr[i]->data);
|
||||
printf ("=%s", node->child[i]->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +237,7 @@ static void bml_print_node (bml_node *node, int depth)
|
|||
if (depth >= 0)
|
||||
printf ("\n");
|
||||
|
||||
for (int i = 0; i < node->child.size(); i++)
|
||||
for (; i < (int) node->child.size(); i++)
|
||||
{
|
||||
bml_print_node (node->child[i], depth + 1);
|
||||
}
|
||||
|
@ -265,7 +269,7 @@ static bml_node *bml_parse_node (char **doc)
|
|||
return NULL;
|
||||
|
||||
bml_skip_empty (doc);
|
||||
while (*doc && bml_read_depth (*doc) > node->depth)
|
||||
while (*doc && (int) bml_read_depth (*doc) > node->depth)
|
||||
{
|
||||
bml_node *child = bml_parse_node (doc);
|
||||
|
||||
|
@ -283,18 +287,12 @@ void bml_free_node (bml_node *node)
|
|||
delete[] (node->name);
|
||||
delete[] (node->data);
|
||||
|
||||
for (int i = 0; i < node->child.size(); i++)
|
||||
for (unsigned int i = 0; i < node->child.size(); i++)
|
||||
{
|
||||
bml_free_node (node->child[i]);
|
||||
delete node->child[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < node->attr.size(); i++)
|
||||
{
|
||||
bml_free_node (node->attr[i]);
|
||||
delete node->attr[i];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -320,7 +318,20 @@ bml_node *bml_parse (char **doc)
|
|||
return root;
|
||||
}
|
||||
|
||||
bml_node *bml_parse_file (char *filename)
|
||||
bml_node *bml_find_sub (bml_node *n, const char *name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < n->child.size (); i++)
|
||||
{
|
||||
if (!strcasecmp (n->child[i]->name, name))
|
||||
return n->child[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bml_node *bml_parse_file (const char *filename)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
char *buffer = NULL;
|
||||
|
|
7
bml.h
7
bml.h
|
@ -2,6 +2,8 @@
|
|||
#define __BML_H
|
||||
#include <vector>
|
||||
|
||||
const int bml_attr_type = -2;
|
||||
|
||||
typedef struct bml_node
|
||||
{
|
||||
char *name;
|
||||
|
@ -9,12 +11,13 @@ typedef struct bml_node
|
|||
|
||||
int depth;
|
||||
|
||||
std::vector<bml_node *> attr;
|
||||
std::vector<bml_node *> child;
|
||||
|
||||
} bml_node;
|
||||
|
||||
bml_node *bml_parse_file (char *filename);
|
||||
bml_node *bml_find_sub (bml_node *node, const char *name);
|
||||
|
||||
bml_node *bml_parse_file (const char *filename);
|
||||
|
||||
/* Parse character array into BML tree. Destructive to input. */
|
||||
bml_node *bml_parse (char **buffer);
|
||||
|
|
40
cheats.h
40
cheats.h
|
@ -193,22 +193,30 @@
|
|||
#ifndef _CHEATS_H_
|
||||
#define _CHEATS_H_
|
||||
|
||||
#define MAX_CHEATS 150
|
||||
#include "port.h"
|
||||
#include <vector>
|
||||
|
||||
struct SCheat
|
||||
{
|
||||
uint32 address;
|
||||
uint8 byte;
|
||||
uint8 saved_byte;
|
||||
bool8 conditional;
|
||||
bool8 cond_true;
|
||||
uint8 cond_byte;
|
||||
bool8 enabled;
|
||||
bool8 saved;
|
||||
char name[22];
|
||||
};
|
||||
|
||||
struct SCheatGroup
|
||||
{
|
||||
char *name;
|
||||
bool8 enabled;
|
||||
std::vector<struct SCheat> c;
|
||||
};
|
||||
|
||||
struct SCheatData
|
||||
{
|
||||
struct SCheat c[MAX_CHEATS];
|
||||
uint32 num_cheats;
|
||||
std::vector<struct SCheatGroup> g;
|
||||
uint8 CWRAM[0x20000];
|
||||
uint8 CSRAM[0x10000];
|
||||
uint8 CIRAM[0x2000];
|
||||
|
@ -250,20 +258,20 @@ typedef enum
|
|||
extern SCheatData Cheat;
|
||||
extern Watch watches[16];
|
||||
|
||||
void S9xApplyCheat (uint32);
|
||||
void S9xApplyCheats (void);
|
||||
void S9xRemoveCheat (uint32);
|
||||
void S9xRemoveCheats (void);
|
||||
void S9xDeleteCheat (uint32);
|
||||
int S9xAddCheatGroup (const char *name, const char *cheat);
|
||||
int S9xModifyCheatGroup (uint32 index, const char *name, const char *cheat);
|
||||
void S9xEnableCheatGroup (uint32 index);
|
||||
void S9xDisableCheatGroup (uint32 index);
|
||||
void S9xDeleteCheats (void);
|
||||
void S9xEnableCheat (uint32);
|
||||
void S9xDisableCheat (uint32);
|
||||
void S9xAddCheat (bool8, bool8, uint32, uint8);
|
||||
char *S9xCheatGroupToText (uint32 index);
|
||||
void S9xDeleteCheatGroup (uint32 index);
|
||||
bool8 S9xLoadCheatFile (const char *filename);
|
||||
bool8 S9xSaveCheatFile (const char *filename);
|
||||
void S9xUpdateCheatsInMemory (void);
|
||||
bool8 S9xImportCheatsFromDatabase (const char *filename);
|
||||
|
||||
void S9xInitCheatData (void);
|
||||
void S9xInitWatchedAddress (void);
|
||||
bool8 S9xLoadCheatFile (const char *);
|
||||
bool8 S9xSaveCheatFile (const char *);
|
||||
|
||||
void S9xStartCheatSearch (SCheatData *);
|
||||
void S9xSearchForChange (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, bool8, bool8);
|
||||
void S9xSearchForValue (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, uint32, bool8, bool8);
|
||||
|
|
457
cheats2.cpp
457
cheats2.cpp
|
@ -189,10 +189,10 @@
|
|||
Nintendo Co., Limited and its subsidiary companies.
|
||||
***********************************************************************************/
|
||||
|
||||
|
||||
#include "snes9x.h"
|
||||
#include "memmap.h"
|
||||
#include "cheats.h"
|
||||
#include "bml.h"
|
||||
|
||||
static inline uint8 S9xGetByteFree (uint32 Address)
|
||||
{
|
||||
|
@ -283,7 +283,7 @@ static inline uint8 S9xGetByteFree (uint32 Address)
|
|||
static inline void S9xSetByteFree (uint8 Byte, uint32 Address)
|
||||
{
|
||||
int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
|
||||
uint8 *SetAddress = Memory.WriteMap[block];
|
||||
uint8 *SetAddress = Memory.Map[block];
|
||||
|
||||
if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
|
||||
{
|
||||
|
@ -328,7 +328,6 @@ static inline void S9xSetByteFree (uint8 Byte, uint32 Address)
|
|||
*(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) = Byte;
|
||||
CPU.SRAMModified = TRUE;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case CMemory::MAP_BWRAM:
|
||||
|
@ -374,7 +373,6 @@ void S9xInitWatchedAddress (void)
|
|||
{
|
||||
for (unsigned int i = 0; i < sizeof(watches) / sizeof(watches[0]); i++)
|
||||
watches[i].on = false;
|
||||
|
||||
}
|
||||
|
||||
void S9xInitCheatData (void)
|
||||
|
@ -384,185 +382,414 @@ void S9xInitCheatData (void)
|
|||
Cheat.FillRAM = Memory.FillRAM;
|
||||
}
|
||||
|
||||
void S9xAddCheat (bool8 enable, bool8 save_current_value, uint32 address, uint8 byte)
|
||||
{
|
||||
if (Cheat.num_cheats < sizeof(Cheat.c) / sizeof(Cheat.c[0]))
|
||||
{
|
||||
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)
|
||||
void S9xUpdateCheatInMemory (SCheat *c)
|
||||
{
|
||||
Cheat.c[Cheat.num_cheats].saved_byte = S9xGetByteFree(address);
|
||||
Cheat.c[Cheat.num_cheats].saved = TRUE;
|
||||
uint8 byte;
|
||||
|
||||
if (!c->enabled)
|
||||
return;
|
||||
|
||||
byte = S9xGetByteFree (c->address);
|
||||
|
||||
if (byte != c->byte)
|
||||
{
|
||||
/* The game wrote a different byte to the address, update saved_byte */
|
||||
c->saved_byte = byte;
|
||||
|
||||
if (c->conditional)
|
||||
{
|
||||
if (c->saved_byte != c->cond_byte && c->cond_true)
|
||||
{
|
||||
/* Condition is now false, let the byte stand */
|
||||
c->cond_true = false;
|
||||
}
|
||||
else if (c->saved_byte == c->cond_byte && !c->cond_true)
|
||||
{
|
||||
c->cond_true = true;
|
||||
S9xSetByteFree (c->byte, c->address);
|
||||
}
|
||||
}
|
||||
else
|
||||
S9xSetByteFree (c->byte, c->address);
|
||||
}
|
||||
else if (c->conditional)
|
||||
{
|
||||
if (byte == c->cond_byte)
|
||||
{
|
||||
c->cond_true = true;
|
||||
c->saved_byte = byte;
|
||||
S9xSetByteFree (c->byte, c->address);
|
||||
}
|
||||
|
||||
Cheat.num_cheats++;
|
||||
}
|
||||
}
|
||||
|
||||
void S9xDeleteCheat (uint32 which1)
|
||||
void S9xDisableCheat (SCheat *c)
|
||||
{
|
||||
if (which1 < Cheat.num_cheats)
|
||||
{
|
||||
if (Cheat.c[which1].enabled)
|
||||
S9xRemoveCheat(which1);
|
||||
if (!c->enabled)
|
||||
return;
|
||||
|
||||
memmove(&Cheat.c[which1], &Cheat.c[which1 + 1], sizeof(Cheat.c[0]) * (Cheat.num_cheats - which1 - 1));
|
||||
S9xUpdateCheatInMemory (c);
|
||||
c->enabled = false;
|
||||
|
||||
Cheat.num_cheats--;
|
||||
if (c->conditional && !c->cond_true)
|
||||
return;
|
||||
|
||||
S9xSetByteFree (c->saved_byte, c->address);
|
||||
c->cond_true = false;
|
||||
}
|
||||
|
||||
void S9xDeleteCheatGroup (uint32 g)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (g >= Cheat.g.size ())
|
||||
return;
|
||||
|
||||
for (i = 0; i < Cheat.g[g].c.size (); i++)
|
||||
{
|
||||
S9xDisableCheat (&Cheat.g[g].c[i]);
|
||||
}
|
||||
|
||||
delete[] Cheat.g[g].name;
|
||||
|
||||
Cheat.g.erase (Cheat.g.begin () + g);
|
||||
}
|
||||
|
||||
void S9xDeleteCheats (void)
|
||||
{
|
||||
S9xRemoveCheats();
|
||||
Cheat.num_cheats = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < Cheat.g.size (); i++)
|
||||
{
|
||||
S9xDisableCheatGroup (i);
|
||||
|
||||
delete[] Cheat.g[i].name;
|
||||
}
|
||||
|
||||
void S9xRemoveCheat (uint32 which1)
|
||||
{
|
||||
if (Cheat.c[which1].saved)
|
||||
{
|
||||
uint32 address = Cheat.c[which1].address;
|
||||
Cheat.g.clear ();
|
||||
}
|
||||
|
||||
int block = (address & 0xffffff) >> MEMMAP_SHIFT;
|
||||
uint8 *ptr = Memory.Map[block];
|
||||
void S9xEnableCheat (SCheat *c)
|
||||
{
|
||||
uint8 byte;
|
||||
|
||||
if (c->enabled)
|
||||
return;
|
||||
|
||||
c->enabled = true;
|
||||
byte = S9xGetByteFree(c->address);
|
||||
|
||||
if (c->conditional)
|
||||
{
|
||||
if (byte != c->cond_byte)
|
||||
return;
|
||||
|
||||
c->cond_true = true;
|
||||
}
|
||||
|
||||
c->saved_byte = byte;
|
||||
S9xSetByteFree (c->byte, c->address);
|
||||
}
|
||||
|
||||
void S9xEnableCheatGroup (uint32 num)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < Cheat.g[num].c.size (); i++)
|
||||
{
|
||||
S9xEnableCheat (&Cheat.g[num].c[i]);
|
||||
}
|
||||
|
||||
Cheat.g[num].enabled = true;
|
||||
}
|
||||
|
||||
void S9xDisableCheatGroup (uint32 num)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < Cheat.g[num].c.size (); i++)
|
||||
{
|
||||
S9xDisableCheat (&Cheat.g[num].c[i]);
|
||||
|
||||
}
|
||||
Cheat.g[num].enabled = false;
|
||||
}
|
||||
|
||||
SCheat S9xTextToCheat (char *text)
|
||||
{
|
||||
SCheat c;
|
||||
unsigned int byte = 0;
|
||||
unsigned int cond_byte = 0;
|
||||
|
||||
c.enabled = false;
|
||||
c.conditional = false;
|
||||
|
||||
if (!S9xGameGenieToRaw (text, c.address, c.byte))
|
||||
{
|
||||
byte = c.byte;
|
||||
}
|
||||
|
||||
else if (!S9xProActionReplayToRaw (text, c.address, c.byte))
|
||||
{
|
||||
byte = c.byte;
|
||||
}
|
||||
|
||||
else if (sscanf (text, "%x=%x?%x", &c.address, &cond_byte, &byte) == 3)
|
||||
{
|
||||
c.conditional = true;
|
||||
}
|
||||
|
||||
else if (sscanf (text, "%x=%x", &c.address, &byte) == 2)
|
||||
{
|
||||
}
|
||||
|
||||
else if (sscanf (text, "%x/%x/%x", &c.address, &cond_byte, &byte) == 3)
|
||||
{
|
||||
c.conditional = true;
|
||||
}
|
||||
|
||||
else if (sscanf (text, "%x/%x", &c.address, &byte) == 2)
|
||||
{
|
||||
}
|
||||
|
||||
if (ptr >= (uint8 *) CMemory::MAP_LAST)
|
||||
*(ptr + (address & 0xffff)) = Cheat.c[which1].saved_byte;
|
||||
else
|
||||
S9xSetByteFree(Cheat.c[which1].saved_byte, address);
|
||||
{
|
||||
c.address = 0;
|
||||
byte = 0;
|
||||
}
|
||||
|
||||
c.byte = byte;
|
||||
c.cond_byte = cond_byte;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
SCheatGroup S9xCreateCheatGroup (const char *name, const char *cheat)
|
||||
{
|
||||
SCheatGroup g;
|
||||
char *code;
|
||||
char *code_string = strdup (cheat);
|
||||
|
||||
g.name = strdup (name);
|
||||
g.enabled = false;
|
||||
|
||||
for (code = strtok (code_string, "+"); code; code = strtok (NULL, "+"))
|
||||
{
|
||||
if (code)
|
||||
{
|
||||
SCheat c = S9xTextToCheat (code);
|
||||
if (c.address)
|
||||
g.c.push_back (c);
|
||||
}
|
||||
}
|
||||
|
||||
void S9xRemoveCheats (void)
|
||||
{
|
||||
for (uint32 i = 0; i < Cheat.num_cheats; i++)
|
||||
if (Cheat.c[i].enabled)
|
||||
S9xRemoveCheat(i);
|
||||
delete[] code_string;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
void S9xEnableCheat (uint32 which1)
|
||||
int S9xAddCheatGroup (const char *name, const char *cheat)
|
||||
{
|
||||
if (which1 < Cheat.num_cheats && !Cheat.c[which1].enabled)
|
||||
{
|
||||
Cheat.c[which1].enabled = TRUE;
|
||||
S9xApplyCheat(which1);
|
||||
}
|
||||
SCheatGroup g = S9xCreateCheatGroup (name, cheat);
|
||||
if (g.c.size () == 0)
|
||||
return -1;
|
||||
|
||||
Cheat.g.push_back (S9xCreateCheatGroup (name, cheat));
|
||||
|
||||
return Cheat.g.size () - 1;
|
||||
}
|
||||
|
||||
void S9xDisableCheat (uint32 which1)
|
||||
int S9xModifyCheatGroup (uint32 num, const char *name, const char *cheat)
|
||||
{
|
||||
if (which1 < Cheat.num_cheats && Cheat.c[which1].enabled)
|
||||
{
|
||||
S9xRemoveCheat(which1);
|
||||
Cheat.c[which1].enabled = FALSE;
|
||||
}
|
||||
S9xDisableCheatGroup (num);
|
||||
delete[] Cheat.g[num].name;
|
||||
|
||||
Cheat.g[num] = S9xCreateCheatGroup (name, cheat);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
void S9xApplyCheat (uint32 which1)
|
||||
char *S9xCheatToText (SCheat *c)
|
||||
{
|
||||
uint32 address = Cheat.c[which1].address;
|
||||
int size = 10; /* 6 address, 1 =, 2 byte, 1 NUL */
|
||||
char *text;
|
||||
|
||||
if (!Cheat.c[which1].saved)
|
||||
{
|
||||
Cheat.c[which1].saved_byte = S9xGetByteFree(address);
|
||||
Cheat.c[which1].saved = TRUE;
|
||||
}
|
||||
if (c->conditional)
|
||||
size += 3; /* additional 2 byte, 1 ? */
|
||||
|
||||
int block = (address & 0xffffff) >> MEMMAP_SHIFT;
|
||||
uint8 *ptr = Memory.Map[block];
|
||||
text = new char[size];
|
||||
|
||||
if (ptr >= (uint8 *) CMemory::MAP_LAST)
|
||||
*(ptr + (address & 0xffff)) = Cheat.c[which1].byte;
|
||||
if (c->conditional)
|
||||
snprintf (text, size, "%x=%x?%x", c->address, c->cond_byte, c->byte);
|
||||
else
|
||||
S9xSetByteFree(Cheat.c[which1].byte, address);
|
||||
snprintf (text, size, "%x=%x", c->address, c->byte);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void S9xApplyCheats (void)
|
||||
char *S9xCheatGroupToText (uint32 num)
|
||||
{
|
||||
if (Settings.ApplyCheats)
|
||||
std::string text = "";
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < Cheat.g[num].c.size (); i++)
|
||||
{
|
||||
for (uint32 i = 0; i < Cheat.num_cheats; i++)
|
||||
if (Cheat.c[i].enabled)
|
||||
S9xApplyCheat(i);
|
||||
char *tmp = S9xCheatToText (&Cheat.g[num].c[i]);
|
||||
if (i != 0)
|
||||
text += '+';
|
||||
text += tmp;
|
||||
delete[] tmp;
|
||||
}
|
||||
|
||||
return strdup (text.c_str ());
|
||||
}
|
||||
|
||||
void S9xUpdateCheatsInMemory (void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
|
||||
for (i = 0; i < Cheat.g.size (); i++)
|
||||
{
|
||||
for (j = 0; j < Cheat.g[i].c.size (); j++)
|
||||
{
|
||||
S9xUpdateCheatInMemory (&Cheat.g[i].c[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void S9xLoadCheatsFromBMLNode (bml_node *n)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < n->child.size (); i++)
|
||||
{
|
||||
if (!strcasecmp (n->child[i]->name, "cheat"))
|
||||
{
|
||||
char *desc = NULL;
|
||||
char *code = NULL;
|
||||
bool8 enabled = false;
|
||||
|
||||
bml_node *c = n->child[i];
|
||||
bml_node *tmp = NULL;
|
||||
|
||||
tmp = bml_find_sub(c, "description");
|
||||
desc = tmp->data;
|
||||
|
||||
tmp = bml_find_sub(c, "code");
|
||||
code = tmp->data;
|
||||
|
||||
if (bml_find_sub(c, "enabled"))
|
||||
enabled = true;
|
||||
|
||||
if (desc && code)
|
||||
{
|
||||
int index = S9xAddCheatGroup (desc, code);
|
||||
|
||||
if (enabled)
|
||||
S9xEnableCheatGroup (index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool8 S9xLoadCheatFile (const char *filename)
|
||||
{
|
||||
FILE *fs;
|
||||
uint8 data[28];
|
||||
bml_node *bml = NULL;
|
||||
bml_node *n = NULL;
|
||||
|
||||
Cheat.num_cheats = 0;
|
||||
bml = bml_parse_file (filename);
|
||||
if (!bml)
|
||||
return FALSE;
|
||||
|
||||
fs = fopen(filename, "rb");
|
||||
if (!fs)
|
||||
return (FALSE);
|
||||
S9xDeleteCheats ();
|
||||
|
||||
while (fread((void *) data, 1, 28, fs) == 28)
|
||||
n = bml_find_sub (bml, "cartridge");
|
||||
if (n)
|
||||
{
|
||||
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;
|
||||
S9xLoadCheatsFromBMLNode (n);
|
||||
}
|
||||
|
||||
fclose(fs);
|
||||
bml_free_node (bml);
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
bool8 S9xSaveCheatFile (const char *filename)
|
||||
{
|
||||
if (Cheat.num_cheats == 0)
|
||||
unsigned int i;
|
||||
FILE *file = NULL;
|
||||
|
||||
if (Cheat.g.size () == 0)
|
||||
return TRUE;
|
||||
|
||||
file = fopen (filename, "w");
|
||||
|
||||
if (!file)
|
||||
return FALSE;
|
||||
|
||||
fprintf (file, "cartridge sha256=");
|
||||
for (i = 0; i < 32; i++)
|
||||
fprintf (file, "%02x", Memory.ROMSHA256[i]);
|
||||
fprintf (file, "\n");
|
||||
|
||||
for (i = 0; i < Cheat.g.size (); i++)
|
||||
{
|
||||
remove(filename);
|
||||
return (TRUE);
|
||||
fprintf (file,
|
||||
" cheat%s\n"
|
||||
" description: %s\n"
|
||||
" code: %s\n\n",
|
||||
(Cheat.g[i].enabled ? " enabled" : ""),
|
||||
Cheat.g[i].name,
|
||||
S9xCheatGroupToText (i));
|
||||
}
|
||||
|
||||
FILE *fs;
|
||||
uint8 data[28];
|
||||
fclose (file);
|
||||
|
||||
fs = fopen(filename, "wb");
|
||||
if (!fs)
|
||||
return (FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < Cheat.num_cheats; i++)
|
||||
bool8 S9xImportCheatsFromDatabase (const char *filename)
|
||||
{
|
||||
memset(data, 0, 28);
|
||||
bml_node *bml;
|
||||
char sha256_txt[65];
|
||||
char hextable[] = "0123456789abcdef";
|
||||
unsigned int i;
|
||||
|
||||
if (i == 0)
|
||||
bml = bml_parse_file (filename);
|
||||
|
||||
if (!bml)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
data[6] = 254;
|
||||
data[7] = 252;
|
||||
sha256_txt[i * 2] = hextable[Memory.ROMSHA256[i] >> 4];
|
||||
sha256_txt[i * 2 + 1] = hextable[Memory.ROMSHA256[i] & 0xf];
|
||||
}
|
||||
sha256_txt[64] = '\0';
|
||||
|
||||
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)
|
||||
for (i = 0; i < bml->child.size (); i++)
|
||||
{
|
||||
fclose(fs);
|
||||
return (FALSE);
|
||||
if (!strcasecmp (bml->child[i]->name, "cartridge"))
|
||||
{
|
||||
bml_node *n;
|
||||
|
||||
if ((n = bml_find_sub (bml->child[i], "sha256")))
|
||||
{
|
||||
if (!strcasecmp (n->data, sha256_txt))
|
||||
{
|
||||
S9xLoadCheatsFromBMLNode (bml->child[i]);
|
||||
bml_free_node (bml);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (fclose(fs) == 0);
|
||||
bml_free_node (bml);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
|
2
gfx.cpp
2
gfx.cpp
|
@ -452,7 +452,7 @@ void S9xEndScreenRefresh (void)
|
|||
else
|
||||
S9xControlEOF();
|
||||
|
||||
S9xApplyCheats();
|
||||
S9xUpdateCheatsInMemory ();
|
||||
|
||||
#ifdef DEBUGGER
|
||||
if (CPU.Flags & FRAME_ADVANCE_FLAG)
|
||||
|
|
|
@ -180,7 +180,8 @@ snes9x_gtk_SOURCES += \
|
|||
../screenshot.cpp \
|
||||
../movie.cpp \
|
||||
../statemanager.cpp \
|
||||
../sha256.cpp
|
||||
../sha256.cpp \
|
||||
../bml.cpp
|
||||
|
||||
# ASMCPU Doesn't exist anymore.
|
||||
snes9x_gtk_SOURCES += \
|
||||
|
|
|
@ -13,14 +13,6 @@ enum
|
|||
|
||||
extern SCheatData Cheat;
|
||||
|
||||
static void
|
||||
add_cheat (uint32 address, uint8 byte, const char *description)
|
||||
{
|
||||
S9xAddCheat (FALSE, TRUE, address, byte);
|
||||
S9xEnableCheat (Cheat.num_cheats - 1);
|
||||
strncpy (Cheat.c[Cheat.num_cheats - 1].name, description, 22);
|
||||
}
|
||||
|
||||
static void
|
||||
display_errorbox (const char *error)
|
||||
{
|
||||
|
@ -190,27 +182,22 @@ void
|
|||
Snes9xCheats::refresh_tree_view (void)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
char str [1024];
|
||||
|
||||
gtk_list_store_clear (store);
|
||||
|
||||
for (unsigned int i = 0; i < Cheat.num_cheats; i++)
|
||||
for (unsigned int i = 0; i < Cheat.g.size (); i++)
|
||||
{
|
||||
snprintf (str,
|
||||
1024,
|
||||
"%06x:%02x/%02x",
|
||||
Cheat.c [i].address,
|
||||
Cheat.c [i].byte,
|
||||
Cheat.c [i].saved_byte);
|
||||
char *str = S9xCheatGroupToText (i);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
COLUMN_DESCRIPTION,
|
||||
!strcmp (Cheat.c [i].name, "") ? _("No description")
|
||||
: Cheat.c [i].name,
|
||||
!strcmp (Cheat.g [i].name, "") ? _("No description")
|
||||
: Cheat.g [i].name,
|
||||
COLUMN_CHEAT, str,
|
||||
COLUMN_ENABLED, Cheat.c [i].enabled,
|
||||
COLUMN_ENABLED, Cheat.g [i].enabled,
|
||||
-1);
|
||||
delete[] str;
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,32 +207,15 @@ Snes9xCheats::refresh_tree_view (void)
|
|||
void
|
||||
Snes9xCheats::add_code (void)
|
||||
{
|
||||
uint32 address;
|
||||
uint8 byte;
|
||||
uint8 bytes [3];
|
||||
bool8 sram;
|
||||
uint8 num_bytes;
|
||||
const char *description;
|
||||
|
||||
const gchar *code = get_entry_text ("code_entry");
|
||||
|
||||
description = get_entry_text ("description_entry");
|
||||
if (description[0] == '\0')
|
||||
description = _("No description");
|
||||
|
||||
if (!S9xGameGenieToRaw (code, address, byte))
|
||||
add_cheat (address, byte, description);
|
||||
else if (!S9xProActionReplayToRaw (code, address, byte))
|
||||
add_cheat (address, byte, description);
|
||||
else if (!S9xGoldFingerToRaw (code, address, sram, num_bytes, bytes))
|
||||
{
|
||||
for (int c = 0; c < num_bytes; c++)
|
||||
add_cheat (address + c, bytes[c], description);
|
||||
}
|
||||
else
|
||||
{
|
||||
display_errorbox (_("Code does not match Game Genie, ProAction Replay, or GoldFinger format."));
|
||||
}
|
||||
if (S9xAddCheatGroup (description, code) < 0)
|
||||
display_errorbox (_("Couldn't find any cheat codes in input."));
|
||||
|
||||
gtk_widget_grab_focus (get_widget ("code_entry"));
|
||||
|
||||
|
@ -262,7 +232,7 @@ Snes9xCheats::remove_code (void)
|
|||
if (index < 0)
|
||||
return;
|
||||
|
||||
S9xDeleteCheat (index);
|
||||
S9xDeleteCheatGroup (index);
|
||||
|
||||
refresh_tree_view ();
|
||||
|
||||
|
@ -277,10 +247,10 @@ Snes9xCheats::toggle_code (const gchar *path)
|
|||
if (index < 0)
|
||||
return;
|
||||
|
||||
if (Cheat.c[index].enabled)
|
||||
S9xDisableCheat (index);
|
||||
if (Cheat.g[index].enabled)
|
||||
S9xDisableCheatGroup (index);
|
||||
else
|
||||
S9xEnableCheat (index);
|
||||
S9xEnableCheatGroup (index);
|
||||
|
||||
refresh_tree_view ();
|
||||
|
||||
|
|
|
@ -256,7 +256,6 @@ Snes9xConfig::load_defaults (void)
|
|||
Settings.DynamicRateControl = 1;
|
||||
Settings.DynamicRateLimit = 5;
|
||||
Settings.HDMATimingHack = 100;
|
||||
Settings.ApplyCheats = 1;
|
||||
|
||||
#ifdef NETPLAY_SUPPORT
|
||||
Settings.NetPlay = FALSE;
|
||||
|
|
|
@ -196,16 +196,6 @@ S9xOpenROM (const char *rom_filename)
|
|||
{
|
||||
Memory.LoadSRAM (S9xGetFilename (".srm", SRAM_DIR));
|
||||
S9xLoadCheatFile (S9xGetFilename (".cht", CHEAT_DIR));
|
||||
|
||||
for (unsigned int i = 0; i < Cheat.num_cheats; i++)
|
||||
{
|
||||
if (Cheat.c[i].enabled)
|
||||
{
|
||||
/* RAM is fresh, so we need to clean out old saved values */
|
||||
Cheat.c[i].saved = FALSE;
|
||||
S9xApplyCheat (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -316,7 +316,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="hscrollbar_policy">automatic</property>
|
||||
<property name="vscrollbar_policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="cheat_treeview">
|
||||
|
@ -391,7 +391,7 @@
|
|||
<object class="GtkEntry" id="description_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="max_length">21</property>
|
||||
<property name="max_length">1024</property>
|
||||
<property name="activates_default">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
|
|
15
memmap.cpp
15
memmap.cpp
|
@ -1783,15 +1783,12 @@ bool8 CMemory::LoadROMInt (int32 ROMfillSize)
|
|||
memset(&SNESGameFixes, 0, sizeof(SNESGameFixes));
|
||||
SNESGameFixes.SRAMInitialValue = 0x60;
|
||||
|
||||
S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
|
||||
|
||||
InitROM();
|
||||
|
||||
S9xInitCheatData();
|
||||
S9xApplyCheats();
|
||||
|
||||
S9xReset();
|
||||
|
||||
S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
@ -1951,15 +1948,13 @@ bool8 CMemory::LoadMultiCartInt ()
|
|||
memset(&SNESGameFixes, 0, sizeof(SNESGameFixes));
|
||||
SNESGameFixes.SRAMInitialValue = 0x60;
|
||||
|
||||
S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
|
||||
|
||||
InitROM();
|
||||
|
||||
S9xInitCheatData();
|
||||
S9xApplyCheats();
|
||||
|
||||
S9xReset();
|
||||
|
||||
S9xInitCheatData();
|
||||
S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
|
49
snes9x.cpp
49
snes9x.cpp
|
@ -777,57 +777,14 @@ char * S9xParseArgs (char **argv, int argc)
|
|||
if (!strcasecmp(argv[i], "-cheat"))
|
||||
Settings.ApplyCheats = TRUE;
|
||||
else
|
||||
if (!strcasecmp(argv[i], "-gamegenie"))
|
||||
if (!strcasecmp(argv[i], "-gamegenie") || !strcasecmp(argv[i], "-actionreplay"))
|
||||
{
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
uint32 address;
|
||||
uint8 byte;
|
||||
const char *error;
|
||||
|
||||
if ((error = S9xGameGenieToRaw(argv[++i], address, byte)) == NULL)
|
||||
S9xAddCheat(TRUE, FALSE, address, byte);
|
||||
else
|
||||
S9xMessage(S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, error);
|
||||
}
|
||||
else
|
||||
S9xUsage();
|
||||
}
|
||||
else
|
||||
if (!strcasecmp(argv[i], "-actionreplay"))
|
||||
if (S9xAddCheatGroup ("Unknown", argv[++i]) < 0)
|
||||
{
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
uint32 address;
|
||||
uint8 byte;
|
||||
const char *error;
|
||||
|
||||
if ((error = S9xProActionReplayToRaw(argv[++i], address, byte)) == NULL)
|
||||
S9xAddCheat(TRUE, FALSE, address, byte);
|
||||
else
|
||||
S9xMessage(S9X_ERROR, S9X_ACTION_REPLY_CODE_ERROR, error);
|
||||
S9xMessage(S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, "Code format invalid");
|
||||
}
|
||||
else
|
||||
S9xUsage();
|
||||
}
|
||||
else
|
||||
if (!strcasecmp(argv[i], "-goldfinger"))
|
||||
{
|
||||
if (i + 1 < 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)
|
||||
{
|
||||
for (int c = 0; c < num_bytes; c++)
|
||||
S9xAddCheat(TRUE, FALSE, address + c, bytes[c]);
|
||||
}
|
||||
else
|
||||
S9xMessage(S9X_ERROR, S9X_GOLD_FINGER_CODE_ERROR, error);
|
||||
}
|
||||
else
|
||||
S9xUsage();
|
||||
|
|
Loading…
Reference in New Issue