Get initial cheat support down.

This commit is contained in:
Themaister 2011-04-17 13:30:59 +02:00
parent 1005d7fa9b
commit 092fa9d531
11 changed files with 262 additions and 3 deletions

View File

@ -92,7 +92,7 @@ ifeq ($(HAVE_CG), 1)
endif
ifeq ($(HAVE_XML), 1)
OBJ += gfx/shader_glsl.o sha256.o
OBJ += gfx/shader_glsl.o sha256.o cheats.o
LIBS += $(XML_LIBS)
DEFINES += $(XML_CFLAGS)
endif

View File

@ -50,7 +50,7 @@ ifeq ($(HAVE_RSOUND), 1)
endif
ifeq ($(HAVE_XML), 1)
OBJ += gfx/shader_glsl.o sha256.o
OBJ += gfx/shader_glsl.o sha256.o cheats.o
DEFINES += $(XML_CFLAGS) -DHAVE_XML
LIBS += -lxml2
endif

163
cheats.c Normal file
View File

@ -0,0 +1,163 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "cheats.h"
#include "sha256.h"
#include "dynamic.h"
#include "general.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
struct cheat
{
char *desc;
bool state;
char *code;
};
struct cheat_manager
{
struct cheat *cheats;
unsigned ptr;
unsigned size;
};
static void xml_grab_cheats(cheat_manager_t *handle, xmlNodePtr ptr)
{
xmlNodePtr node = NULL;
for (node = ptr; node; node = node->next)
{
if (strcmp((const char*)node->name, "name") == 0)
{
xmlChar *name = xmlNodeGetContent(node);
if (name)
{
SSNES_LOG("Found cheat for game: \"%s\"\n", name);
xmlFree(name);
}
}
}
}
cheat_manager_t* cheat_manager_new(const char *path)
{
psnes_cheat_reset();
cheat_manager_t *handle = calloc(1, sizeof(handle));
if (!handle)
return NULL;
xmlParserCtxtPtr ctx = NULL;
xmlDocPtr doc = NULL;
ctx = xmlNewParserCtxt();
if (!ctx)
goto error;
doc = xmlCtxtReadFile(ctx, path, NULL, 0);
if (!doc)
{
SSNES_ERR("Failed to parse XML file: %s\n", path);
goto error;
}
if (ctx->valid == 0)
{
SSNES_ERR("Cannot validate XML file: %s\n", path);
goto error;
}
xmlNodePtr head = xmlDocGetRootElement(doc);
xmlNodePtr cur = NULL;
for (cur = head; cur; cur = cur->next)
{
if (cur->type == XML_ELEMENT_NODE && strcmp((const char*)cur->name, "database") == 0)
break;
}
if (!cur)
goto error;
for (cur = cur->children; cur; cur = cur->next)
{
if (cur->type != XML_ELEMENT_NODE)
continue;
if (strcmp((const char*)cur->name, "cartridge") == 0)
{
xmlChar *sha256 = xmlGetProp(cur, (const xmlChar*)"sha256");
if (!sha256)
continue;
if (memcmp(sha256, g_extern.sha256, 64) == 0)
{
xmlFree(sha256);
break;
}
xmlFree(sha256);
}
}
if (!cur)
goto error;
xml_grab_cheats(handle, cur->children);
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctx);
return handle;
error:
cheat_manager_free(handle);
if (doc)
xmlFreeDoc(doc);
if (ctx)
xmlFreeParserCtxt(ctx);
return NULL;
}
void cheat_manager_free(cheat_manager_t *handle)
{
if (!handle)
return;
if (handle->cheats)
{
for (unsigned i = 0; i < handle->size; i++)
{
xmlFree(handle->cheats[i].desc);
xmlFree(handle->cheats[i].code);
}
free(handle->cheats);
}
free(handle);
}
void cheat_manager_toggle(cheat_manager_t *handle)
{
handle->cheats[handle->ptr].state ^= true;
psnes_cheat_set(handle->ptr, handle->cheats[handle->ptr].state, handle->cheats[handle->ptr].code);
}

29
cheats.h Normal file
View File

@ -0,0 +1,29 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_CHEATS_H
#define __SSNES_CHEATS_H
typedef struct cheat_manager cheat_manager_t;
cheat_manager_t* cheat_manager_new(const char *path);
void cheat_manager_free(cheat_manager_t *handle);
void cheat_manager_index_offset(cheat_manager_t *handle, int offset);
void cheat_manager_toggle(cheat_manager_t *handle);
#endif

View File

@ -42,6 +42,9 @@ enum
SSNES_RESET,
SSNES_SHADER_NEXT,
SSNES_SHADER_PREV,
SSNES_CHEAT_INDEX_PLUS,
SSNES_CHEAT_INDEX_MINUS,
SSNES_CHEAT_TOGGLE
};

View File

@ -57,6 +57,9 @@ void (*psnes_set_input_state)(snes_input_state_t);
void (*psnes_reset)(void);
void (*psnes_run)(void);
void (*psnes_cheat_reset)(void);
void (*psnes_cheat_set)(unsigned, bool, const char*);
const char *(*psnes_library_id)(void) = NULL;
unsigned (*psnes_library_revision_minor)(void);
unsigned (*psnes_library_revision_major)(void);
@ -111,6 +114,8 @@ static void load_dynamic(void)
OPT_SYM(snes_library_id);
SYM(snes_library_revision_minor);
SYM(snes_library_revision_major);
SYM(snes_cheat_reset);
SYM(snes_cheat_set);
SYM(snes_reset);
SYM(snes_run);
SYM(snes_get_region);
@ -145,6 +150,8 @@ static void set_statics(void)
SSYM(snes_set_input_state);
SSYM(snes_library_revision_minor);
SSYM(snes_library_revision_major);
SSYM(snes_cheat_reset);
SSYM(snes_cheat_set);
SSYM(snes_reset);
SSYM(snes_run);
SSYM(snes_get_region);

View File

@ -37,6 +37,9 @@ extern void (*psnes_set_audio_sample)(snes_audio_sample_t);
extern void (*psnes_set_input_poll)(snes_input_poll_t);
extern void (*psnes_set_input_state)(snes_input_state_t);
extern void (*psnes_cheat_reset)(void);
extern void (*psnes_cheat_set)(unsigned, bool, const char*);
extern const char* (*psnes_library_id)(void);
extern unsigned (*psnes_library_revision_minor)(void);
extern unsigned (*psnes_library_revision_major)(void);

View File

@ -29,6 +29,7 @@
#include "autosave.h"
#include "netplay.h"
#include "dynamic.h"
#include "cheats.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -42,7 +43,7 @@
#define MAX_PLAYERS 5
#define MAX_BINDS 28 // Needs to be increased every time there are new binds added.
#define MAX_BINDS 31 // Needs to be increased every time there are new binds added.
#define SSNES_NO_JOYPAD 0xFFFF
enum ssnes_shader_type
@ -110,6 +111,7 @@ struct settings
} input;
char libsnes[256];
char cheat_database[256];
bool rewind_enable;
unsigned rewind_buffer_size;
@ -245,6 +247,10 @@ struct global
} shader_dir;
char sha256[65];
#ifdef HAVE_XML
cheat_manager_t *cheat;
#endif
};
void parse_config(void);

View File

@ -369,6 +369,8 @@ static void parse_config_file(void)
CONFIG_GET_BOOL(pause_nonactive, "pause_nonactive");
CONFIG_GET_INT(autosave_interval, "autosave_interval");
CONFIG_GET_STRING(cheat_database, "cheat_database_path");
read_keybinds(conf);
config_file_free(conf);
@ -414,6 +416,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
{
DECLARE_BIND(player2_a, SNES_DEVICE_ID_JOYPAD_A)
@ -443,6 +448,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
{
DECLARE_BIND(player3_a, SNES_DEVICE_ID_JOYPAD_A)
@ -472,6 +480,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
{
DECLARE_BIND(player4_a, SNES_DEVICE_ID_JOYPAD_A)
@ -501,6 +512,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
{
DECLARE_BIND(player5_a, SNES_DEVICE_ID_JOYPAD_A)
@ -530,6 +544,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
};

23
ssnes.c
View File

@ -32,6 +32,7 @@
#include "movie.h"
#include "netplay.h"
#include "strl.h"
#include "cheats.h"
#include <assert.h>
#ifdef HAVE_SRC
#include <samplerate.h>
@ -708,6 +709,20 @@ static void deinit_msg_queue(void)
msg_queue_free(g_extern.msg_queue);
}
#ifdef HAVE_XML
static void init_cheats(void)
{
if (*g_settings.cheat_database)
g_extern.cheat = cheat_manager_new(g_settings.cheat_database);
}
static void deinit_cheats(void)
{
if (g_extern.cheat)
cheat_manager_free(g_extern.cheat);
}
#endif
static void init_rewind(void)
{
if (g_settings.rewind_enable)
@ -1279,6 +1294,10 @@ int main(int argc, char *argv[])
if (!init_rom_file(g_extern.game_type))
goto error;
#ifdef HAVE_XML
init_cheats();
#endif
init_msg_queue();
init_movie();
@ -1380,6 +1399,10 @@ int main(int argc, char *argv[])
if (!g_extern.netplay)
deinit_rewind();
#ifdef HAVE_XML
deinit_cheats();
#endif
deinit_movie();
deinit_msg_queue();

View File

@ -252,3 +252,11 @@
# When being client over netplay, use keybinds for player 1.
# netplay_client_swap_input = false
# Path to XML cheat database (as used by bSNES).
# cheat_database_path =
# Cheats.
# input_cheat_index_plus =
# input_cheat_index_minus =
# input_cheat_toggle =