C++-ified the cheat engine.

This commit is contained in:
Aaron Giles 2010-10-27 05:16:06 +00:00
parent e56b4c9c02
commit 354eec3124
6 changed files with 1668 additions and 1772 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,64 +1,374 @@
/*********************************************************************
/***************************************************************************
cheat.h
Cheat system.
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
****************************************************************************
*********************************************************************/
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
#pragma once
#ifndef __CHEAT_H__
#define __CHEAT_H__
#include "ui.h"
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
//**************************************************************************
// CONSTANTS
//**************************************************************************
/* ----- core system management ----- */
/* initialize the cheat system, loading any cheat files */
void cheat_init(running_machine *machine);
/* re-initialize the cheat system, reloading any cheat files */
void cheat_reload(running_machine *machine);
/* return the global enabled state of the cheat engine */
int cheat_get_global_enable(running_machine *machine);
/* globally enable or disable the cheat engine */
void cheat_set_global_enable(running_machine *machine, int enable);
enum script_state
{
SCRIPT_STATE_OFF = 0,
SCRIPT_STATE_ON,
SCRIPT_STATE_RUN,
SCRIPT_STATE_CHANGE,
SCRIPT_STATE_COUNT
};
DECLARE_ENUM_OPERATORS(script_state)
/* ----- cheat UI helpers ----- */
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
/* render any text overlays */
void cheat_render_text(running_machine *machine, render_container *container);
class cheat_manager;
typedef struct _symbol_table symbol_table;
typedef struct _parsed_expression parsed_expression;
/* return data about the next menu entry, or the first entry if previous == NULL */
void *cheat_get_next_menu_entry(running_machine *machine, void *previous, const char **description, const char **state, UINT32 *flags);
/* activate a oneshot cheat */
int cheat_activate(running_machine *machine, void *entry);
// ======================> number_and_format
/* select the default menu state */
int cheat_select_default_state(running_machine *machine, void *entry);
// helper class to remember a format along with a number
class number_and_format
{
public:
// construction/destruction
number_and_format(UINT64 value = 0, int format = 0)
: m_value(value),
m_format(format) { }
/* select the previous menu state */
int cheat_select_previous_state(running_machine *machine, void *entry);
// pass-through to look like a regular number
operator UINT64 &() { return m_value; }
operator const UINT64 &() const { return m_value; }
// format the number according to its format
const char *format(astring &string) const;
/* select the next menu state */
int cheat_select_next_state(running_machine *machine, void *entry);
private:
// internal state
UINT64 m_value;
int m_format;
};
/* return the displayable comment of the current cheat */
astring &cheat_get_comment(void *entry);
// ======================> cheat_parameter
// a parameter for a cheat, which can be set in the UI
class cheat_parameter
{
public:
// construction/destruction
cheat_parameter(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &paramnode);
// queries
const char *text();
bool has_itemlist() const { return (m_itemlist.count() != 0); }
bool is_minimum() const { return (m_value == ((m_itemlist.count() == 0) ? m_minval : m_itemlist.first()->value())); }
bool is_maximum() const { return (m_value == ((m_itemlist.count() == 0) ? m_maxval : m_itemlist.last()->value())); }
// state setters
bool set_minimum_state();
bool set_prev_state();
bool set_next_state();
// actions
void save(mame_file &cheatfile) const;
private:
// a single item in a parameter item list
class item
{
friend class simple_list<item>;
public:
// construction/destruction
item(const char *text, UINT64 value, int valformat)
: m_next(NULL),
m_text(text),
m_value(value, valformat) { }
// getters
item *next() const { return m_next; }
const number_and_format &value() const { return m_value; }
const char *text() const { return m_text; }
private:
// internal state
item * m_next; // next item in list
astring m_text; // name of the item
number_and_format m_value; // value of the item
};
// internal state
number_and_format m_minval; // minimum value
number_and_format m_maxval; // maximum value
number_and_format m_stepval; // step value
UINT64 m_value; // live value of the parameter
astring m_curtext; // holding for a value string
simple_list<item> m_itemlist; // list of items
};
// ======================> cheat_script
// a script entry, specifying which state to execute under
class cheat_script
{
friend class simple_list<cheat_script>;
public:
// construction/destruction
cheat_script(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &scriptnode);
// getters
script_state state() const { return m_state; }
// actions
void execute(cheat_manager &manager, UINT64 &argindex);
void save(mame_file &cheatfile) const;
private:
// an entry within the script
class script_entry
{
friend class simple_list<script_entry>;
public:
// construction/destruction
script_entry(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &entrynode, bool isaction);
~script_entry();
// getters
script_entry *next() const { return m_next; }
// actions
void execute(cheat_manager &manager, UINT64 &argindex);
void save(mame_file &cheatfile) const;
private:
// an argument for output
class output_argument
{
friend class simple_list<output_argument>;
public:
// construction/destruction
output_argument(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &argnode);
~output_argument();
// getters
output_argument *next() const { return m_next; }
int count() const { return m_count; }
int values(UINT64 &argindex, UINT64 *result);
// actions
void save(mame_file &cheatfile) const;
private:
// internal state
output_argument * m_next; // link to next argument
parsed_expression * m_expression; // expression for argument
UINT64 m_count; // number of repetitions
};
// internal helpers
void validate_format(const char *filename, int line);
// internal state
script_entry * m_next; // link to next entry
parsed_expression * m_condition; // condition under which this is executed
parsed_expression * m_expression; // expression to execute
astring m_format; // string format to print
simple_list<output_argument> m_arglist; // list of arguments
INT8 m_line; // which line to print on
UINT8 m_justify; // justification when printing
// constants
static const int MAX_ARGUMENTS = 32;
};
// internal state
simple_list<script_entry> m_entrylist; // list of actions to perform
script_state m_state; // which state this script is for
};
// ======================> cheat_entry
// a single cheat
class cheat_entry
{
friend class simple_list<cheat_entry>;
public:
// construction/destruction
cheat_entry(cheat_manager &manager, symbol_table &globaltable, const char *filename, xml_data_node &cheatnode);
~cheat_entry();
// getters
cheat_manager &manager() const { return m_manager; }
cheat_entry *next() const { return m_next; }
script_state state() const { return m_state; }
const char *description() const { return m_description; }
const char *comment() const { return m_comment; }
// script detection
bool has_run_script() const { return (m_run_script != NULL); }
bool has_on_script() const { return (m_on_script != NULL); }
bool has_off_script() const { return (m_off_script != NULL); }
bool has_change_script() const { return (m_change_script != NULL); }
// script execution
void execute_off_script() { if (has_off_script()) m_off_script->execute(m_manager, m_argindex); }
void execute_on_script() { if (has_on_script()) m_on_script->execute(m_manager, m_argindex); }
void execute_run_script() { if (has_run_script()) m_run_script->execute(m_manager, m_argindex); }
void execute_change_script() { if (has_change_script()) m_change_script->execute(m_manager, m_argindex); }
// cheat classification
bool is_text_only() const { return (m_parameter == NULL && !has_run_script() && !has_off_script() && !has_on_script()); }
bool is_oneshot() const { return (m_parameter == NULL && !has_run_script() && !has_off_script() && has_on_script()); }
bool is_onoff() const { return (m_parameter == NULL && (has_run_script() || (has_off_script() && has_on_script()))); }
bool is_value_parameter() const { return (m_parameter != NULL && !m_parameter->has_itemlist()); }
bool is_itemlist_parameter() const { return (m_parameter != NULL && m_parameter->has_itemlist()); }
bool is_oneshot_parameter() const { return (m_parameter != NULL && !has_run_script() && !has_off_script() && has_change_script()); }
// actions
bool activate();
bool select_default_state();
bool select_previous_state();
bool select_next_state();
void save(mame_file &cheatfile) const;
// UI helpers
void menu_text(astring &description, astring &state, UINT32 &flags);
// per-frame update
void frame_update() { if (m_state == SCRIPT_STATE_RUN) execute_run_script(); }
private:
// internal helpers
bool set_state(script_state newstate);
cheat_script *&script_for_state(script_state state);
// internal state
cheat_manager & m_manager; // reference to our manager
cheat_entry * m_next; // next cheat entry
astring m_description; // string description/menu title
astring m_comment; // comment data
cheat_parameter * m_parameter; // parameter
cheat_script * m_on_script; // script to run when turning on
cheat_script * m_off_script; // script to run when turning off
cheat_script * m_change_script; // script to run when value changes
cheat_script * m_run_script; // script to run each frame when on
symbol_table * m_symbols; // symbol table for this cheat
script_state m_state; // current cheat state
UINT32 m_numtemp; // number of temporary variables
UINT64 m_argindex; // argument index variable
UINT64 * m_tempvar; // value of the temporary variables
// constants
static const int DEFAULT_TEMP_VARIABLES = 10;
};
// ======================> cheat_manager
// private machine-global data
class cheat_manager
{
public:
// construction/destruction
cheat_manager(running_machine &machine);
~cheat_manager();
// getters
running_machine &machine() const { return m_machine; }
bool enabled() const { return !m_disabled; }
cheat_entry *first() const { return m_cheatlist.first(); }
// setters
void set_enable(bool enable = true);
// actions
void reload();
bool save_all(const char *filename);
void render_text(render_container &container);
// output helpers
astring &get_output_astring(int row, int justify);
// global helpers
static const char *quote_expression(astring &string, parsed_expression &expression);
static UINT64 variable_get(void *globalref, void *ref);
static void variable_set(void *globalref, void *ref, UINT64 value);
static UINT64 execute_frombcd(void *globalref, void *ref, UINT32 params, const UINT64 *param);
static UINT64 execute_tobcd(void *globalref, void *ref, UINT32 params, const UINT64 *param);
private:
// internal helpers
static void frame_update_static(running_machine &machine);
void frame_update();
void load_cheats(const char *filename);
// internal state
running_machine & m_machine; // reference to our machine
simple_list<cheat_entry> m_cheatlist; // cheat list
UINT64 m_framecount; // frame count
astring m_output[UI_TARGET_FONT_ROWS*2]; // array of output strings
UINT8 m_justify[UI_TARGET_FONT_ROWS*2]; // justification for each string
UINT8 m_numlines; // number of lines available for output
INT8 m_lastline; // last line used for output
bool m_disabled; // true if the cheat engine is disabled
symbol_table * m_symtable; // global symbol table
// constants
static const int CHEAT_VERSION = 1;
};
#endif /* __CHEAT_H__ */

View File

@ -168,7 +168,6 @@ running_machine::running_machine(const machine_config &_config, osd_interface &o
input_data(NULL),
input_port_data(NULL),
ui_input_data(NULL),
cheat_data(NULL),
debugcpu_data(NULL),
generic_machine_data(NULL),
generic_video_data(NULL),
@ -191,6 +190,7 @@ running_machine::running_machine(const machine_config &_config, osd_interface &o
m_saveload_searchpath(NULL),
m_rand_seed(0x9d14abd7),
m_driver_device(NULL),
m_cheat(NULL),
m_render(NULL),
m_debug_view(NULL)
{
@ -344,8 +344,7 @@ void running_machine::start()
schedule_load("auto");
// set up the cheat engine
if (options_get_bool(&m_options, OPTION_CHEAT))
cheat_init(this);
m_cheat = auto_alloc(this, cheat_manager(*this));
// disallow save state registrations starting here
state_save_allow_registration(this, false);

View File

@ -180,8 +180,9 @@ const int DEBUG_FLAG_OSD_ENABLED = 0x00001000; // The OSD debugger is enabled
// forward declarations
class gfx_element;
class colortable_t;
class debug_view_manager;
class cheat_manager;
class render_manager;
class debug_view_manager;
class osd_interface;
typedef struct _mame_private mame_private;
@ -198,7 +199,6 @@ typedef struct _sound_private sound_private;
typedef struct _input_private input_private;
typedef struct _input_port_private input_port_private;
typedef struct _ui_input_private ui_input_private;
typedef struct _cheat_private cheat_private;
typedef struct _debugcpu_private debugcpu_private;
typedef struct _debugvw_private debugvw_private;
typedef struct _generic_machine_private generic_machine_private;
@ -388,6 +388,7 @@ public:
void region_free(const char *name);
// managers
cheat_manager &cheat() const { assert(m_cheat != NULL); return *m_cheat; }
render_manager &render() const { assert(m_render != NULL); return *m_render; }
debug_view_manager &debug_view() const { assert(m_debug_view != NULL); return *m_debug_view; }
@ -452,7 +453,6 @@ public:
input_private * input_data; // internal data from input.c
input_port_private * input_port_data; // internal data from inptport.c
ui_input_private * ui_input_data; // internal data from uiinput.c
cheat_private * cheat_data; // internal data from cheat.c
debugcpu_private * debugcpu_data; // internal data from debugcpu.c
generic_machine_private *generic_machine_data; // internal data from machine/generic.c
generic_video_private * generic_video_data; // internal data from video/generic.c
@ -528,6 +528,7 @@ private:
time_t m_base_time;
driver_device * m_driver_device;
cheat_manager * m_cheat; // internal data from cheat.c
render_manager * m_render; // internal data from render.c
debug_view_manager * m_debug_view; // internal data from debugvw.c
};

View File

@ -385,7 +385,8 @@ void ui_update_and_render(running_machine *machine, render_container *container)
}
/* render any cheat stuff at the bottom */
cheat_render_text(machine, container);
if (machine->phase() >= MACHINE_PHASE_RESET)
machine->cheat().render_text(*container);
/* call the current UI handler */
assert(ui_handler_callback != NULL);
@ -726,7 +727,7 @@ void ui_draw_text_box(render_container *container, const char *text, int justify
float max_width = 2.0f * ((xpos <= 0.5f) ? xpos : 1.0f - xpos) - 2.0f * UI_BOX_LR_BORDER;
float target_width = max_width;
float target_height = line_height;
float target_x, target_y;
float target_x = 0, target_y = 0;
float last_target_height = 0;
// limit this iteration to a finite number of passes
@ -1427,7 +1428,7 @@ static UINT32 handler_ingame(running_machine *machine, render_container *contain
/* handle a toggle cheats request */
if (ui_input_pressed(machine, IPT_UI_TOGGLE_CHEAT))
cheat_set_global_enable(machine, !cheat_get_global_enable(machine));
machine->cheat().set_enable(!machine->cheat().enabled());
/* toggle movie recording */
if (ui_input_pressed(machine, IPT_UI_RECORD_MOVIE))

View File

@ -1244,7 +1244,7 @@ static void ui_menu_handle_keys(ui_menu *menu, UINT32 flags)
/* handle a toggle cheats request */
if (ui_input_pressed_repeat(menu->machine, IPT_UI_TOGGLE_CHEAT, 0))
cheat_set_global_enable(menu->machine, !cheat_get_global_enable(menu->machine));
menu->machine->cheat().set_enable(!menu->machine->cheat().enabled());
/* see if any other UI keys are pressed */
if (menu->event.iptkey == IPT_INVALID)
@ -1569,7 +1569,7 @@ static void menu_main_populate(running_machine *machine, ui_menu *menu, void *st
ui_menu_item_append(menu, "Crosshair Options", NULL, 0, (void *)menu_crosshair);
/* add cheat menu */
if (options_get_bool(machine->options(), OPTION_CHEAT) && cheat_get_next_menu_entry(machine, NULL, NULL, NULL, NULL) != NULL)
if (options_get_bool(machine->options(), OPTION_CHEAT) && machine->cheat().first() != NULL)
ui_menu_item_append(menu, "Cheat", NULL, 0, (void *)menu_cheat);
/* add memory card menu */
@ -2535,7 +2535,7 @@ static void menu_cheat(running_machine *machine, ui_menu *menu, void *parameter,
/* handle events */
if (event != NULL && event->itemref != NULL)
{
int changed = FALSE;
bool changed = false;
/* clear cheat comment on any movement or keypress */
popmessage(NULL);
@ -2543,47 +2543,46 @@ static void menu_cheat(running_machine *machine, ui_menu *menu, void *parameter,
/* handle reset all + reset all cheats for reload all option */
if ((FPTR)event->itemref < 3 && event->iptkey == IPT_UI_SELECT)
{
void *curcheat;
for (curcheat = cheat_get_next_menu_entry(machine, NULL, NULL, NULL, NULL);
curcheat != NULL;
curcheat = cheat_get_next_menu_entry(machine, curcheat, NULL, NULL, NULL))
{
changed |= cheat_select_default_state(machine, curcheat);
}
for (cheat_entry *curcheat = machine->cheat().first(); curcheat != NULL; curcheat = curcheat->next())
if (curcheat->select_default_state())
changed = true;
}
/* handle individual cheats */
else if ((FPTR)event->itemref > 2)
{
cheat_entry *curcheat = reinterpret_cast<cheat_entry *>(event->itemref);
const char *string;
switch (event->iptkey)
{
/* if selected, activate a oneshot */
case IPT_UI_SELECT:
changed = cheat_activate(machine, event->itemref);
changed = curcheat->activate();
break;
/* if cleared, reset to default value */
case IPT_UI_CLEAR:
changed = cheat_select_default_state(machine, event->itemref);
changed = curcheat->select_default_state();
break;
/* left decrements */
case IPT_UI_LEFT:
changed = cheat_select_previous_state(machine, event->itemref);
changed = curcheat->select_previous_state();
break;
/* right increments */
case IPT_UI_RIGHT:
changed = cheat_select_next_state(machine, event->itemref);
changed = curcheat->select_next_state();
break;
/* bring up display comment if one exists */
case IPT_UI_DISPLAY_COMMENT:
case IPT_UI_UP:
case IPT_UI_DOWN:
if (cheat_get_comment(event->itemref))
popmessage("Cheat Comment:\n%s", cheat_get_comment(event->itemref).cstr());
string = curcheat->comment();
if (string != NULL && string[0] != 0)
popmessage("Cheat Comment:\n%s", string);
break;
}
}
@ -2592,7 +2591,7 @@ static void menu_cheat(running_machine *machine, ui_menu *menu, void *parameter,
if ((FPTR)event->itemref == 2 && event->iptkey == IPT_UI_SELECT)
{
/* re-init cheat engine and thus reload cheats/cheats have already been turned off by here */
cheat_reload(machine);
machine->cheat().reload();
/* display the reloaded cheats */
ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_REF);
@ -2612,15 +2611,13 @@ static void menu_cheat(running_machine *machine, ui_menu *menu, void *parameter,
static void menu_cheat_populate(running_machine *machine, ui_menu *menu)
{
const char *text, *subtext;
void *curcheat;
UINT32 flags;
/* iterate over cheats */
for (curcheat = cheat_get_next_menu_entry(machine, NULL, &text, &subtext, &flags);
curcheat != NULL;
curcheat = cheat_get_next_menu_entry(machine, curcheat, &text, &subtext, &flags))
astring text;
astring subtext;
for (cheat_entry *curcheat = machine->cheat().first(); curcheat != NULL; curcheat = curcheat->next())
{
UINT32 flags;
curcheat->menu_text(text, subtext, flags);
ui_menu_item_append(menu, text, subtext, flags, curcheat);
}