summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2010-10-27 05:16:06 +0000
committer Aaron Giles <aaron@aarongiles.com>2010-10-27 05:16:06 +0000
commit354eec3124fc79f572ef517d9022636dac93a558 (patch)
tree4204c2b6109a4bc49f05fc98e38fd02a8711957d
parente56b4c9c02b0b02476226b4ae23beab3f75d27f2 (diff)
C++-ified the cheat engine.
-rw-r--r--src/emu/cheat.c2554
-rw-r--r--src/emu/cheat.h372
-rw-r--r--src/emu/machine.c5
-rw-r--r--src/emu/machine.h7
-rw-r--r--src/emu/ui.c7
-rw-r--r--src/emu/uimenu.c45
6 files changed, 1443 insertions, 1547 deletions
diff --git a/src/emu/cheat.c b/src/emu/cheat.c
index 23b3dd28804..151dbfc04ff 100644
--- a/src/emu/cheat.c
+++ b/src/emu/cheat.c
@@ -1,13 +1,41 @@
-/*********************************************************************
+/***************************************************************************
cheat.c
MAME 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.
+
+****************************************************************************
Cheat XML format:
@@ -33,7 +61,7 @@
...
</mamecheat>
-**********************************************************************
+****************************************************************************
Expressions are standard debugger expressions. Note that & and
< must be escaped per XML rules. Within attributes you must use
@@ -51,7 +79,7 @@
variables may be requested via the 'tempvariables' attribute
on the cheat.
-**********************************************************************
+****************************************************************************
Cheats are generally broken down into categories based on
which actions are defined and whether or not there is a
@@ -71,7 +99,7 @@
? Y ? ? List Item list parameter (off or a live value)
? ? Y ? List Item list parameter (off or a live value)
-*********************************************************************/
+***************************************************************************/
#include "emu.h"
#include "emuopts.h"
@@ -86,273 +114,43 @@
+//**************************************************************************
+// PARAMETERS
+//**************************************************************************
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* turn this on to enable removing duplicate cheats; not sure if we should */
+// turn this on to enable removing duplicate cheats; not sure if we should
#define REMOVE_DUPLICATE_CHEATS 0
-#define CHEAT_VERSION 1
-
-#define DEFAULT_TEMP_VARIABLES 10
-#define MAX_ARGUMENTS 32
-enum _script_state
-{
- SCRIPT_STATE_OFF = 0,
- SCRIPT_STATE_ON,
- SCRIPT_STATE_RUN,
- SCRIPT_STATE_CHANGE,
- SCRIPT_STATE_COUNT
-};
-typedef enum _script_state script_state;
-DECLARE_ENUM_OPERATORS(script_state)
+//**************************************************************************
+// NUMBER AND FORMAT
+//**************************************************************************
+//-------------------------------------------------
+// format - format an integer according to
+// the format
+//-------------------------------------------------
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/* a single item (string + value) for a cheat parameter */
-typedef struct _parameter_item parameter_item;
-struct _parameter_item
-{
- parameter_item * next; /* next item in list */
- astring text; /* name of the item */
- UINT64 value; /* value of the item */
- int valformat; /* format of value */
- astring curtext; /* name of the current item */
-};
-
-
-/* a parameter for a cheat, which can be set in the UI */
-typedef struct _cheat_parameter cheat_parameter;
-struct _cheat_parameter
-{
- UINT64 minval; /* minimum value */
- int minformat; /* format of minimum value */
- UINT64 maxval; /* maximum value */
- int maxformat; /* format of maximum value */
- UINT64 stepval; /* step value */
- int stepformat; /* format of step value */
- UINT64 value; /* live value of the parameter */
- char valuestring[32]; /* small space for a value string */
- parameter_item * itemlist; /* list of items */
-};
-
-
-/* a single argument for an output display */
-typedef struct _output_argument output_argument;
-struct _output_argument
+inline const char *number_and_format::format(astring &string) const
{
- output_argument * next; /* link to next argument */
- parsed_expression * expression; /* expression for argument */
- UINT64 count; /* number of repetitions */
-};
-
-
-/* a single entry within a script, either an expression to execute or a string to output */
-typedef struct _script_entry script_entry;
-struct _script_entry
-{
- script_entry * next; /* link to next entry */
- parsed_expression * condition; /* condition under which this is executed */
- parsed_expression * expression; /* expression to execute */
- astring format; /* string format to print */
- output_argument * arglist; /* list of arguments */
- INT8 line; /* which line to print on */
- UINT8 justify; /* justification when printing */
-};
-
-
-/* a script entry, specifying which state to execute under */
-typedef struct _cheat_script cheat_script;
-struct _cheat_script
-{
- script_entry * entrylist; /* list of actions to perform */
- script_state state; /* which state this script is for */
-};
-
-
-/* a single cheat */
-typedef struct _cheat_entry cheat_entry;
-struct _cheat_entry
-{
- cheat_entry * next; /* next cheat entry */
- astring description; /* string description/menu title */
- astring comment; /* comment data */
- cheat_parameter * parameter; /* parameter */
- cheat_script * script[SCRIPT_STATE_COUNT]; /* up to 1 script for each state */
- symbol_table * symbols; /* symbol table for this cheat */
- script_state state; /* current cheat state */
- UINT32 numtemp; /* number of temporary variables */
- UINT64 argindex; /* argument index variable */
- UINT64 * tempvar; /* value of the temporary variables */
-};
-
-
-/* private machine-global data */
-struct _cheat_private
-{
- cheat_entry * cheatlist; /* cheat list */
- UINT64 framecount; /* frame count */
- astring output[UI_TARGET_FONT_ROWS*2]; /* array of output strings */
- UINT8 justify[UI_TARGET_FONT_ROWS*2]; /* justification for each string */
- UINT8 numlines; /* number of lines available for output */
- INT8 lastline; /* last line used for output */
- UINT8 disabled; /* true if the cheat engine is disabled */
-};
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-static void cheat_exit(running_machine &machine);
-static void cheat_frame(running_machine &machine);
-static void cheat_execute_script(cheat_private *cheatinfo, cheat_entry *cheat, script_state state);
-
-static cheat_entry *cheat_list_load(running_machine *machine, const char *filename);
-static int cheat_list_save(const char *filename, const cheat_entry *cheatlist);
-static void cheat_list_free(running_machine *machine, cheat_entry *cheat);
-static cheat_entry *cheat_entry_load(running_machine *machine, const char *filename, xml_data_node *cheatnode);
-static void cheat_entry_save(mame_file *cheatfile, const cheat_entry *cheat);
-static void cheat_entry_free(running_machine *machine, cheat_entry *cheat);
-static cheat_parameter *cheat_parameter_load(running_machine *machine, const char *filename, xml_data_node *paramnode);
-static void cheat_parameter_save(mame_file *cheatfile, const cheat_parameter *param);
-static void cheat_parameter_free(running_machine *machine, cheat_parameter *param);
-static cheat_script *cheat_script_load(running_machine *machine, const char *filename, xml_data_node *scriptnode, cheat_entry *cheat);
-static void cheat_script_save(mame_file *cheatfile, const cheat_script *script);
-static void cheat_script_free(running_machine *machine, cheat_script *script);
-static script_entry *script_entry_load(running_machine *machine, const char *filename, xml_data_node *entrynode, cheat_entry *cheat, int isaction);
-static void script_entry_save(mame_file *cheatfile, const script_entry *entry);
-static void script_entry_free(running_machine *machine, script_entry *entry);
-
-static astring &quote_astring_expression(astring &string, int isattribute);
-static int validate_format(const char *filename, int line, const script_entry *entry);
-static UINT64 cheat_variable_get(void *globalref, void *ref);
-static void cheat_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);
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- is_text_only_cheat - return TRUE if this
- cheat entry is text-only (no actions)
--------------------------------------------------*/
-
-INLINE int is_text_only_cheat(const cheat_entry *cheat)
-{
- return (cheat->parameter == NULL &&
- cheat->script[SCRIPT_STATE_RUN] == NULL &&
- cheat->script[SCRIPT_STATE_OFF] == NULL &&
- cheat->script[SCRIPT_STATE_ON] == NULL);
-}
-
-
-/*-------------------------------------------------
- is_oneshot_cheat - return TRUE if this cheat
- entry is a one-shot cheat (no "run" or "off"
- action, but a valid "on" action)
--------------------------------------------------*/
-
-INLINE int is_oneshot_cheat(const cheat_entry *cheat)
-{
- return (cheat->parameter == NULL &&
- cheat->script[SCRIPT_STATE_RUN] == NULL &&
- cheat->script[SCRIPT_STATE_OFF] == NULL &&
- cheat->script[SCRIPT_STATE_ON] != NULL);
-}
-
-
-/*-------------------------------------------------
- is_onoff_cheat - return TRUE if this cheat
- entry is a simple on/off toggle (either the
- "run" or "off" actions are present)
--------------------------------------------------*/
-
-INLINE int is_onoff_cheat(const cheat_entry *cheat)
-{
- return (cheat->parameter == NULL &&
- (cheat->script[SCRIPT_STATE_RUN] != NULL ||
- (cheat->script[SCRIPT_STATE_OFF] != NULL &&
- cheat->script[SCRIPT_STATE_ON] != NULL)));
-}
-
-
-/*-------------------------------------------------
- is_value_parameter_cheat - return TRUE if this
- cheat entry has a parameter represented by an
- integer value
--------------------------------------------------*/
-
-INLINE int is_value_parameter_cheat(const cheat_entry *cheat)
-{
- return (cheat->parameter != NULL && cheat->parameter->itemlist == NULL);
-}
-
-
-/*-------------------------------------------------
- is_itemlist_parameter_cheat - return TRUE if
- this cheat entry has a parameter represented
- by an item list
--------------------------------------------------*/
-
-INLINE int is_itemlist_parameter_cheat(const cheat_entry *cheat)
-{
- return (cheat->parameter != NULL && cheat->parameter->itemlist != NULL);
-}
-
-
-/*-------------------------------------------------
- is_oneshot_parameter_cheat - return TRUE if
- this cheat entry is a one-shot cheat with a
- parameter (no "run" or "off" actions, but a
- valid "change" action)
--------------------------------------------------*/
-
-INLINE int is_oneshot_parameter_cheat(const cheat_entry *cheat)
-{
- return (cheat->parameter != NULL &&
- cheat->script[SCRIPT_STATE_RUN] == NULL &&
- cheat->script[SCRIPT_STATE_OFF] == NULL &&
- cheat->script[SCRIPT_STATE_CHANGE] != NULL);
-}
-
-
-/*-------------------------------------------------
- format_int - format an integer according to
- the format
--------------------------------------------------*/
-
-INLINE const char *format_int(astring &string, UINT64 value, int format)
-{
- switch (format)
+ switch (m_format)
{
default:
case XML_INT_FORMAT_DECIMAL:
- string.printf("%d", (UINT32)value);
+ string.printf("%d", (UINT32)m_value);
break;
case XML_INT_FORMAT_DECIMAL_POUND:
- string.printf("#%d", (UINT32)value);
+ string.printf("#%d", (UINT32)m_value);
break;
case XML_INT_FORMAT_HEX_DOLLAR:
- string.printf("$%X", (UINT32)value);
+ string.printf("$%X", (UINT32)m_value);
break;
case XML_INT_FORMAT_HEX_C:
- string.printf("0x%X", (UINT32)value);
+ string.printf("0x%X", (UINT32)m_value);
break;
}
return string;
@@ -360,1439 +158,1176 @@ INLINE const char *format_int(astring &string, UINT64 value, int format)
-/***************************************************************************
- SYSTEM INTERACTION
-***************************************************************************/
+//**************************************************************************
+// CHEAT PARAMETER
+//**************************************************************************
-/*-------------------------------------------------
- cheat_init - initialize the cheat engine,
- loading the cheat file
--------------------------------------------------*/
+//-------------------------------------------------
+// cheat_parameter - constructor
+//-------------------------------------------------
-void cheat_init(running_machine *machine)
+cheat_parameter::cheat_parameter(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &paramnode)
+ : m_value(0),
+ m_itemlist(manager.machine().m_respool)
{
- cheat_private *cheatinfo;
-
- /* request a callback */
- machine->add_notifier(MACHINE_NOTIFY_FRAME, cheat_frame);
- machine->add_notifier(MACHINE_NOTIFY_EXIT, cheat_exit);
-
- /* allocate memory */
- cheatinfo = auto_alloc_clear(machine, cheat_private);
- machine->cheat_data = cheatinfo;
+ // read the core attributes
+ m_minval = number_and_format(xml_get_attribute_int(&paramnode, "min", 0), xml_get_attribute_int_format(&paramnode, "min"));
+ m_maxval = number_and_format(xml_get_attribute_int(&paramnode, "max", 0), xml_get_attribute_int_format(&paramnode, "max"));
+ m_stepval = number_and_format(xml_get_attribute_int(&paramnode, "step", 1), xml_get_attribute_int_format(&paramnode, "step"));
+
+ // iterate over items
+ for (xml_data_node *itemnode = xml_get_sibling(paramnode.child, "item"); itemnode != NULL; itemnode = xml_get_sibling(itemnode->next, "item"))
+ {
+ // check for NULL text
+ if (itemnode->value == NULL || itemnode->value[0] == 0)
+ throw emu_fatalerror("%s.xml(%d): item is missing text\n", filename, itemnode->line);
- /* load the cheats */
- cheat_reload(machine);
+ // check for non-existant value
+ if (xml_get_attribute(itemnode, "value") == NULL)
+ throw emu_fatalerror("%s.xml(%d): item is value\n", filename, itemnode->line);
+
+ // extract the parameters
+ UINT64 value = xml_get_attribute_int(itemnode, "value", 0);
+ int format = xml_get_attribute_int_format(itemnode, "value");
+
+ // allocate and append a new item
+ item &curitem = m_itemlist.append(*auto_alloc(&manager.machine(), item(itemnode->value, value, format)));
+
+ // ensure the maximum expands to suit
+ m_maxval = MAX(m_maxval, curitem.value());
+ }
- /* we rely on the debugger expression callbacks; if the debugger isn't
- enabled, we must jumpstart them manually */
- if ((machine->debug_flags & DEBUG_FLAG_ENABLED) == 0)
- debug_cpu_init(machine);
+ // add a variable to the symbol table for our value
+ symtable_add_register(&symbols, "param", &m_value, cheat_manager::variable_get, NULL);
}
-/*-------------------------------------------------
- cheat_reload - re-initialize the cheat engine,
- and reload the cheat file(s)
--------------------------------------------------*/
+//-------------------------------------------------
+// text - return the current text for a parameter
+//-------------------------------------------------
-void cheat_reload(running_machine *machine)
+const char *cheat_parameter::text()
{
- cheat_private *cheatinfo = machine->cheat_data;
-
- /* free everything */
- cheat_exit(*machine);
-
- /* reset our memory */
- auto_free(machine, cheatinfo);
- cheatinfo = machine->cheat_data = auto_alloc_clear(machine, cheat_private);
-
- /* load the cheat file, MESS will load a crc32.xml ( eg. 01234567.xml )
- and MAME will load gamename.xml */
- device_image_interface *image = NULL;
- for (bool gotone = machine->m_devicelist.first(image); gotone; gotone = image->next(image))
- if (image->exists())
- {
- UINT32 crc = image->crc();
- if (crc != 0)
+ // are we a value cheat?
+ if (!has_itemlist())
+ m_curtext.format("%d (0x%X)", UINT32(m_value), UINT32(m_value));
+
+ // if not, we're an item cheat
+ else
+ {
+ m_curtext.format("??? (%d)", UINT32(m_value));
+ for (item *curitem = m_itemlist.first(); curitem != NULL; curitem = curitem->next())
+ if (curitem->value() == m_value)
{
- astring filename;
- filename.printf("%08X", crc);
- cheatinfo->cheatlist = cheat_list_load(machine, filename);
+ m_curtext.cpy(curitem->text());
break;
}
- }
-
- if (cheatinfo->cheatlist == NULL)
- cheatinfo->cheatlist = cheat_list_load(machine, machine->basename());
-
- /* temporary: save the file back out as output.xml for comparison */
- if (cheatinfo->cheatlist != NULL)
- cheat_list_save("output", cheatinfo->cheatlist);
+ }
+ return m_curtext;
}
-/*-------------------------------------------------
- cheat_exit - clean up on the way out
--------------------------------------------------*/
+//-------------------------------------------------
+// save - save a single cheat parameter
+//-------------------------------------------------
-static void cheat_exit(running_machine &machine)
+void cheat_parameter::save(mame_file &cheatfile) const
{
- cheat_private *cheatinfo = machine.cheat_data;
+ // output the parameter tag
+ mame_fprintf(&cheatfile, "\t\t<parameter");
+
+ // if no items, just output min/max/step
+ astring string;
+ if (!has_itemlist())
+ {
+ if (m_minval != 0)
+ mame_fprintf(&cheatfile, " min=\"%s\"", m_minval.format(string));
+ if (m_maxval != 0)
+ mame_fprintf(&cheatfile, " max=\"%s\"", m_maxval.format(string));
+ if (m_stepval != 1)
+ mame_fprintf(&cheatfile, " step=\"%s\"", m_stepval.format(string));
+ mame_fprintf(&cheatfile, "/>\n");
+ }
- /* free the list of cheats */
- if (cheatinfo->cheatlist != NULL)
- cheat_list_free(&machine, cheatinfo->cheatlist);
+ // iterate over items
+ else
+ {
+ for (const item *curitem = m_itemlist.first(); curitem != NULL; curitem = curitem->next())
+ mame_fprintf(&cheatfile, "\t\t\t<item value=\"%s\">%s</item>\n", curitem->value().format(string), curitem->text());
+ mame_fprintf(&cheatfile, "\t\t</parameter>\n");
+ }
}
-/*-------------------------------------------------
- cheat_get_global_enable - return the global
- enabled state of the cheat engine
--------------------------------------------------*/
+//-------------------------------------------------
+// set_minimum_state - set the minimum state
+//-------------------------------------------------
-int cheat_get_global_enable(running_machine *machine)
+bool cheat_parameter::set_minimum_state()
{
- cheat_private *cheatinfo = machine->cheat_data;
+ UINT64 origvalue = m_value;
- if (cheatinfo != NULL)
- return !cheatinfo->disabled;
+ // set based on whether we have an item list
+ m_value = (!has_itemlist()) ? m_minval : m_itemlist.first()->value();
- return 0;
+ return (m_value != origvalue);
}
-/*-------------------------------------------------
- cheat_set_global_enable - globally enable or
- disable the cheat engine
--------------------------------------------------*/
+//-------------------------------------------------
+// set_minimum_state - set the previous state
+//-------------------------------------------------
-void cheat_set_global_enable(running_machine *machine, int enable)
+bool cheat_parameter::set_prev_state()
{
- cheat_private *cheatinfo = machine->cheat_data;
- cheat_entry *cheat;
-
- if (cheatinfo != NULL)
+ UINT64 origvalue = m_value;
+
+ // are we a value cheat?
+ if (!has_itemlist())
{
- /* if we're enabled currently and we don't want to be, turn things off */
- if (!cheatinfo->disabled && !enable)
- {
- /* iterate over running cheats and execute any OFF Scripts */
- for (cheat = cheatinfo->cheatlist; cheat != NULL; cheat = cheat->next)
- if (cheat->state == SCRIPT_STATE_RUN)
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_OFF);
- popmessage("Cheats Disabled");
- cheatinfo->disabled = TRUE;
- }
-
- /* if we're disabled currently and we want to be enabled, turn things on */
- else if (cheatinfo->disabled && enable)
- {
- /* iterate over running cheats and execute any ON Scripts */
- cheatinfo->disabled = FALSE;
- for (cheat = cheatinfo->cheatlist; cheat != NULL; cheat = cheat->next)
- if (cheat->state == SCRIPT_STATE_RUN)
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_ON);
- popmessage("Cheats Enabled");
- }
+ if (m_value < m_minval + m_stepval)
+ m_value = m_minval;
+ else
+ m_value -= m_stepval;
}
+
+ // if not, we're an item cheat
+ else
+ {
+ item *curitem, *previtem = NULL;
+ for (curitem = m_itemlist.first(); curitem != NULL; previtem = curitem, curitem = curitem->next())
+ if (curitem->value() == m_value)
+ break;
+ if (previtem != NULL)
+ m_value = previtem->value();
+ }
+
+ return (m_value != origvalue);
}
+//-------------------------------------------------
+// set_next_state - advance to the next state
+//-------------------------------------------------
-/***************************************************************************
- CHEAT UI
-***************************************************************************/
-
-/*-------------------------------------------------
- cheat_render_text - called by the UI system
- to render text
--------------------------------------------------*/
-
-void cheat_render_text(running_machine *machine, render_container *container)
+bool cheat_parameter::set_next_state()
{
- cheat_private *cheatinfo = machine->cheat_data;
- if (cheatinfo != NULL)
+ UINT64 origvalue = m_value;
+
+ // are we a value cheat?
+ if (!has_itemlist())
{
- int linenum;
-
- /* render any text and free it along the way */
- for (linenum = 0; linenum < ARRAY_LENGTH(cheatinfo->output); linenum++)
- if (cheatinfo->output[linenum])
- {
- /* output the text */
- ui_draw_text_full(container, cheatinfo->output[linenum],
- 0.0f, (float)linenum * ui_get_line_height(*machine), 1.0f,
- cheatinfo->justify[linenum], WRAP_NEVER, DRAW_OPAQUE,
- ARGB_WHITE, ARGB_BLACK, NULL, NULL);
- }
+ if (m_value > m_maxval - m_stepval)
+ m_value = m_maxval;
+ else
+ m_value += m_stepval;
+ }
+
+ // if not, we're an item cheat
+ else
+ {
+ item *curitem;
+ for (curitem = m_itemlist.first(); curitem != NULL; curitem = curitem->next())
+ if (curitem->value() == m_value)
+ break;
+ if (curitem != NULL && curitem->next() != NULL)
+ m_value = curitem->next()->value();
}
+
+ return (m_value != origvalue);
}
-/*-------------------------------------------------
- cheat_get_next_menu_entry - return the
- text needed to display this cheat in a menu
- item
--------------------------------------------------*/
-void *cheat_get_next_menu_entry(running_machine *machine, void *previous, const char **description, const char **state, UINT32 *flags)
-{
- cheat_private *cheatinfo = machine->cheat_data;
- cheat_entry *preventry = (cheat_entry *)previous;
- cheat_entry *cheat;
-
- /* NULL previous means get the first */
- cheat = (preventry == NULL) ? cheatinfo->cheatlist : preventry->next;
- if (cheat == NULL)
- return NULL;
+//**************************************************************************
+// CHEAT SCRIPT
+//**************************************************************************
- /* description is standard */
- if (description != NULL)
- *description = cheat->description;
-
- /* some cheat entries are just text for display */
- if (is_text_only_cheat(cheat))
- {
- if (description != NULL)
- {
- while (isspace((UINT8)**description))
- *description += 1;
- if (**description == 0)
- *description = MENU_SEPARATOR_ITEM;
- }
- if (state != NULL)
- *state = NULL;
- if (flags != NULL)
- *flags = MENU_FLAG_DISABLE;
- }
+//-------------------------------------------------
+// cheat_script - constructor
+//-------------------------------------------------
- /* if we have no parameter and no run or off script, it's a oneshot cheat */
- else if (is_oneshot_cheat(cheat))
- {
- if (state != NULL)
- *state = "Set";
- if (flags != NULL)
- *flags = 0;
- }
+cheat_script::cheat_script(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &scriptnode)
+ : m_entrylist(manager.machine().m_respool),
+ m_state(SCRIPT_STATE_RUN)
+{
+ // read the core attributes
+ const char *state = xml_get_attribute_string(&scriptnode, "state", "run");
+ if (strcmp(state, "on") == 0)
+ m_state = SCRIPT_STATE_ON;
+ else if (strcmp(state, "off") == 0)
+ m_state = SCRIPT_STATE_OFF;
+ else if (strcmp(state, "change") == 0)
+ m_state = SCRIPT_STATE_CHANGE;
+ else if (strcmp(state, "run") != 0)
+ throw emu_fatalerror("%s.xml(%d): invalid script state '%s'\n", filename, scriptnode.line, state);
- /* if we have no parameter, it's just on/off */
- else if (is_onoff_cheat(cheat))
+ // iterate over nodes within the script
+ for (xml_data_node *entrynode = scriptnode.child; entrynode != NULL; entrynode = entrynode->next)
{
- if (state != NULL)
- *state = (cheat->state == SCRIPT_STATE_RUN) ? "On" : "Off";
- if (flags != NULL)
- *flags = cheat->state ? MENU_FLAG_LEFT_ARROW : MENU_FLAG_RIGHT_ARROW;
- }
+ // handle action nodes
+ if (strcmp(entrynode->name, "action") == 0)
+ m_entrylist.append(*auto_alloc(&manager.machine(), script_entry(manager, symbols, filename, *entrynode, true)));
- /* if we have a value parameter, compute it */
- else if (is_value_parameter_cheat(cheat))
- {
- if (cheat->state == SCRIPT_STATE_OFF)
- {
- if (state != NULL)
- *state = is_oneshot_parameter_cheat(cheat) ? "Set" : "Off";
- if (flags != NULL)
- *flags = MENU_FLAG_RIGHT_ARROW;
- }
- else
- {
- if (state != NULL)
- {
- sprintf(cheat->parameter->valuestring, "%d", (UINT32)cheat->parameter->value);
- *state = cheat->parameter->valuestring;
- }
- if (flags != NULL)
- {
- *flags = MENU_FLAG_LEFT_ARROW;
- if (cheat->parameter->value < cheat->parameter->maxval)
- *flags |= MENU_FLAG_RIGHT_ARROW;
- }
- }
- }
+ // handle output nodes
+ else if (strcmp(entrynode->name, "output") == 0)
+ m_entrylist.append(*auto_alloc(&manager.machine(), script_entry(manager, symbols, filename, *entrynode, false)));
- /* if we have an item list, pick the index */
- else if (is_itemlist_parameter_cheat(cheat))
- {
- if (cheat->state == SCRIPT_STATE_OFF)
- {
- if (state != NULL)
- *state = is_oneshot_parameter_cheat(cheat) ? "Set" : "Off";
- if (flags != NULL)
- *flags = MENU_FLAG_RIGHT_ARROW;
- }
+ // anything else is ignored
else
{
- parameter_item *item = NULL/*, *prev = NULL*/;
-
- for (item = cheat->parameter->itemlist; item != NULL; /*prev = item, */item = item->next)
- if (item->value == cheat->parameter->value)
- break;
- if (state != NULL)
- *state = (item != NULL) ? item->text.cstr() : "??Invalid??";
- if (flags != NULL)
- {
- *flags = MENU_FLAG_LEFT_ARROW;
- if (item == NULL || item->next != NULL)
- *flags |= MENU_FLAG_RIGHT_ARROW;
- cheat->parameter->itemlist->curtext = item->text; /* Take a copy of the most current parameter for the popmessage (if used) */
- }
+ mame_printf_warning("%s.xml(%d): unknown script item '%s' will be lost if saved\n", filename, entrynode->line, entrynode->name);
+ continue;
}
}
-
- /* return a pointer to this item */
- return cheat;
}
-/*-------------------------------------------------
- cheat_activate - activate a oneshot cheat
--------------------------------------------------*/
+//-------------------------------------------------
+// execute - execute ourself
+//-------------------------------------------------
-int cheat_activate(running_machine *machine, void *entry)
+void cheat_script::execute(cheat_manager &manager, UINT64 &argindex)
{
- cheat_private *cheatinfo = machine->cheat_data;
- cheat_entry *cheat = (cheat_entry *)entry;
- int changed = FALSE;
+ // do nothing if disabled
+ if (!manager.enabled())
+ return;
- /* if cheats have been toggled off no point in even trying to do anything */
- if (cheatinfo->disabled)
- return changed;
+ // iterate over entries
+ for (script_entry *entry = m_entrylist.first(); entry != NULL; entry = entry->next())
+ entry->execute(manager, argindex);
+}
- /* if we have no parameter and no run or off script, but we do have an on script, it's a oneshot cheat */
- if (is_oneshot_cheat(cheat))
- {
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_ON);
- changed = TRUE;
- popmessage("Activated %s", cheat->description.cstr());
- }
- /* if we have no run or off script, but we do have parameter and change scripts and it's not in the off state, it's a oneshot list or selectable value cheat */
- else if (is_oneshot_parameter_cheat(cheat) && cheat->state != SCRIPT_STATE_OFF)
+//-------------------------------------------------
+// save - save a single cheat script
+//-------------------------------------------------
+
+void cheat_script::save(mame_file &cheatfile) const
+{
+ // output the script tag
+ mame_fprintf(&cheatfile, "\t\t<script");
+ switch (m_state)
{
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
- changed = TRUE;
- if (cheat->parameter->itemlist != NULL)
- popmessage("Activated\n %s = %s", cheat->description.cstr(), cheat->parameter->itemlist->curtext.cstr() );
- else
- popmessage("Activated\n %s = %d (0x%X)", cheat->description.cstr(), (UINT32)cheat->parameter->value, (UINT32)cheat->parameter->value );
+ case SCRIPT_STATE_OFF: mame_fprintf(&cheatfile, " state=\"off\""); break;
+ case SCRIPT_STATE_ON: mame_fprintf(&cheatfile, " state=\"on\""); break;
+ default:
+ case SCRIPT_STATE_RUN: mame_fprintf(&cheatfile, " state=\"run\""); break;
+ case SCRIPT_STATE_CHANGE: mame_fprintf(&cheatfile, " state=\"change\""); break;
}
+ mame_fprintf(&cheatfile, ">\n");
- return changed;
+ // output entries
+ for (const script_entry *entry = m_entrylist.first(); entry != NULL; entry = entry->next())
+ entry->save(cheatfile);
+
+ // close the tag
+ mame_fprintf(&cheatfile, "\t\t</script>\n");
}
-/*-------------------------------------------------
- cheat_select_default_state - select the
- default state for a cheat, or activate a
- oneshot cheat
--------------------------------------------------*/
+//-------------------------------------------------
+// script_entry - constructor
+//-------------------------------------------------
-int cheat_select_default_state(running_machine *machine, void *entry)
+cheat_script::script_entry::script_entry(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &entrynode, bool isaction)
+ : m_next(NULL),
+ m_condition(NULL),
+ m_expression(NULL),
+ m_arglist(manager.machine().m_respool)
{
- cheat_private *cheatinfo = machine->cheat_data;
- cheat_entry *cheat = (cheat_entry *)entry;
- int changed = FALSE;
+ try
+ {
+ // read the condition if present
+ const char *expression = xml_get_attribute_string(&entrynode, "condition", NULL);
+ if (expression != NULL)
+ {
+ EXPRERR experr = expression_parse(expression, &symbols, &debug_expression_callbacks, &manager.machine(), &m_condition);
+ if (experr != EXPRERR_NONE)
+ throw emu_fatalerror("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode.line, expression, exprerr_to_string(experr));
+ }
- /* if we have no parameter and no run or off script, it's either text or a oneshot cheat */
- if (is_oneshot_cheat(cheat))
- ;
+ // if this is an action, parse the expression
+ if (isaction)
+ {
+ expression = entrynode.value;
+ if (expression == NULL || expression[0] == 0)
+ throw emu_fatalerror("%s.xml(%d): missing expression in action tag\n", filename, entrynode.line);
- /* if we have no parameter, it's just on/off; default to off */
- else
- {
- if (cheat->state != SCRIPT_STATE_OFF)
+ EXPRERR experr = expression_parse(expression, &symbols, &debug_expression_callbacks, &manager.machine(), &m_expression);
+ if (experr != EXPRERR_NONE)
+ throw emu_fatalerror("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode.line, expression, exprerr_to_string(experr));
+ }
+
+ // otherwise, parse the attributes and arguments
+ else
{
- cheat->state = SCRIPT_STATE_OFF;
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_OFF);
- changed = TRUE;
+ // extract format
+ const char *format = xml_get_attribute_string(&entrynode, "format", NULL);
+ if (format == NULL || format[0] == 0)
+ throw emu_fatalerror("%s.xml(%d): missing format in output tag\n", filename, entrynode.line);
+ m_format.cpy(format);
+
+ // extract other attributes
+ m_line = xml_get_attribute_int(&entrynode, "line", 0);
+ m_justify = JUSTIFY_LEFT;
+ const char *align = xml_get_attribute_string(&entrynode, "align", "left");
+ if (strcmp(align, "center") == 0)
+ m_justify = JUSTIFY_CENTER;
+ else if (strcmp(align, "right") == 0)
+ m_justify = JUSTIFY_RIGHT;
+ else if (strcmp(align, "left") != 0)
+ throw emu_fatalerror("%s.xml(%d): invalid alignment '%s' specified\n", filename, entrynode.line, align);
+
+ // then parse arguments
+ int totalargs = 0;
+ for (xml_data_node *argnode = xml_get_sibling(entrynode.child, "argument"); argnode != NULL; argnode = xml_get_sibling(argnode->next, "argument"))
+ {
+ output_argument &curarg = m_arglist.append(*auto_alloc(&manager.machine(), output_argument(manager, symbols, filename, *argnode)));
+
+ // verify we didn't overrun the argument count
+ totalargs += curarg.count();
+ if (totalargs > MAX_ARGUMENTS)
+ throw emu_fatalerror("%s.xml(%d): too many arguments (found %d, max is %d)\n", filename, argnode->line, totalargs, MAX_ARGUMENTS);
+ }
+
+ // validate the format against the arguments
+ validate_format(filename, entrynode.line);
}
}
- return changed;
+ catch (emu_fatalerror &)
+ {
+ // call our destructor and re-throw
+ this->~script_entry();
+ throw;
+ }
}
-/*-------------------------------------------------
- cheat_select_previous_state - select the
- previous state for a cheat
--------------------------------------------------*/
+//-------------------------------------------------
+// script_entry - destructor
+//-------------------------------------------------
-int cheat_select_previous_state(running_machine *machine, void *entry)
+cheat_script::script_entry::~script_entry()
{
- cheat_private *cheatinfo = machine->cheat_data;
- cheat_entry *cheat = (cheat_entry *)entry;
- int changed = FALSE;
+ if (m_condition != NULL)
+ expression_free(m_condition);
+ if (m_expression != NULL)
+ expression_free(m_expression);
+}
- /* if we have no parameter and no run or off script, it's either text or a oneshot cheat */
- if (is_oneshot_cheat(cheat))
- ;
- /* if we have no parameter, it's just on/off */
- else if (is_onoff_cheat(cheat))
+//-------------------------------------------------
+// execute - execute a single script entry
+//-------------------------------------------------
+
+void cheat_script::script_entry::execute(cheat_manager &manager, UINT64 &argindex)
+{
+ // evaluate the condition
+ if (m_condition != NULL)
{
- if (cheat->state != SCRIPT_STATE_OFF)
- {
- cheat->state = SCRIPT_STATE_OFF;
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_OFF);
- changed = TRUE;
- }
+ UINT64 result;
+ EXPRERR error = expression_execute(m_condition, &result);
+ if (error != EXPRERR_NONE)
+ mame_printf_warning("Error executing conditional expression \"%s\": %s\n", expression_original_string(m_condition), exprerr_to_string(error));
+
+ // if the condition is false, or we got an error, don't execute
+ if (error != EXPRERR_NONE || result == 0)
+ return;
}
- /* if we have a value parameter, compute it */
- else if (is_value_parameter_cheat(cheat))
+ // if there is an action, execute it
+ if (m_expression != NULL)
{
- if (cheat->parameter->value > cheat->parameter->minval)
- {
- if (cheat->parameter->value < cheat->parameter->minval + cheat->parameter->stepval)
- cheat->parameter->value = cheat->parameter->minval;
- else
- cheat->parameter->value -= cheat->parameter->stepval;
- if (!is_oneshot_parameter_cheat(cheat))
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
- changed = TRUE;
- }
- else if (cheat->state != SCRIPT_STATE_OFF)
- {
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_OFF);
- cheat->state = SCRIPT_STATE_OFF;
- changed = TRUE;
- }
+ UINT64 result;
+ EXPRERR error = expression_execute(m_expression, &result);
+ if (error != EXPRERR_NONE)
+ mame_printf_warning("Error executing expression \"%s\": %s\n", expression_original_string(m_expression), exprerr_to_string(error));
}
- /* if we have an item list, pick the index */
- else
+ // if there is a string to display, compute it
+ if (m_format)
{
- parameter_item *item, *prev = NULL;
-
- for (item = cheat->parameter->itemlist; item != NULL; prev = item, item = item->next)
- if (item->value == cheat->parameter->value)
- break;
- if (prev != NULL)
- {
- if (cheat->state == SCRIPT_STATE_OFF)
- {
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_ON);
- cheat->state = SCRIPT_STATE_RUN;
- }
- cheat->parameter->value = prev->value;
- if (!is_oneshot_parameter_cheat(cheat))
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
- changed = TRUE;
- }
- else if (cheat->state != SCRIPT_STATE_OFF)
- {
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_OFF);
- cheat->state = SCRIPT_STATE_OFF;
- changed = TRUE;
- }
+ // iterate over arguments and evaluate them
+ UINT64 params[MAX_ARGUMENTS];
+ int curarg = 0;
+ for (output_argument *arg = m_arglist.first(); arg != NULL; arg = arg->next())
+ curarg += arg->values(argindex, &params[curarg]);
+
+ // generate the astring
+ manager.get_output_astring(m_line, m_justify).printf(m_format,
+ (UINT32)params[0], (UINT32)params[1], (UINT32)params[2], (UINT32)params[3],
+ (UINT32)params[4], (UINT32)params[5], (UINT32)params[6], (UINT32)params[7],
+ (UINT32)params[8], (UINT32)params[9], (UINT32)params[10], (UINT32)params[11],
+ (UINT32)params[12], (UINT32)params[13], (UINT32)params[14], (UINT32)params[15],
+ (UINT32)params[16], (UINT32)params[17], (UINT32)params[18], (UINT32)params[19],
+ (UINT32)params[20], (UINT32)params[21], (UINT32)params[22], (UINT32)params[23],
+ (UINT32)params[24], (UINT32)params[25], (UINT32)params[26], (UINT32)params[27],
+ (UINT32)params[28], (UINT32)params[29], (UINT32)params[30], (UINT32)params[31]);
}
- return changed;
}
-/*-------------------------------------------------
- cheat_select_next_state - select the
- next state for a cheat
--------------------------------------------------*/
+//-------------------------------------------------
+// save - save a single action or output
+//-------------------------------------------------
-int cheat_select_next_state(running_machine *machine, void *entry)
+void cheat_script::script_entry::save(mame_file &cheatfile) const
{
- cheat_private *cheatinfo = machine->cheat_data;
- cheat_entry *cheat = (cheat_entry *)entry;
- int changed = FALSE;
-
- /* if we have no parameter and no run or off script, it's a oneshot cheat */
- if (is_oneshot_cheat(cheat))
- ;
-
- /* if we have no parameter, it's just on/off */
- else if (is_onoff_cheat(cheat))
- {
- if (cheat->state != SCRIPT_STATE_RUN)
- {
- cheat->state = SCRIPT_STATE_RUN;
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_ON);
- changed = TRUE;
- }
- }
+ astring tempstring;
- /* if we have a value parameter, compute it */
- else if (is_value_parameter_cheat(cheat))
+ // output an action
+ if (!m_format)
{
- if (cheat->state == SCRIPT_STATE_OFF)
- {
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_ON);
- cheat->state = SCRIPT_STATE_RUN;
- cheat->parameter->value = cheat->parameter->minval;
- if (!is_oneshot_parameter_cheat(cheat))
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
- changed = TRUE;
- }
- else if (cheat->parameter->value < cheat->parameter->maxval)
- {
- if (cheat->parameter->value > cheat->parameter->maxval - cheat->parameter->stepval)
- cheat->parameter->value = cheat->parameter->maxval;
- else
- cheat->parameter->value += cheat->parameter->stepval;
- if (!is_oneshot_parameter_cheat(cheat))
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
- changed = TRUE;
- }
+ mame_fprintf(&cheatfile, "\t\t\t<action");
+ if (m_condition != NULL)
+ mame_fprintf(&cheatfile, " condition=\"%s\"", cheat_manager::quote_expression(tempstring, *m_condition));
+ mame_fprintf(&cheatfile, ">%s</action>\n", cheat_manager::quote_expression(tempstring, *m_expression));
}
- /* if we have an item list, pick the index */
+ // output an output
else
{
- parameter_item *item;
-
- if (cheat->state == SCRIPT_STATE_OFF)
- {
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_ON);
- cheat->state = SCRIPT_STATE_RUN;
- cheat->parameter->value = cheat->parameter->itemlist->value;
- if (!is_oneshot_parameter_cheat(cheat))
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
- changed = TRUE;
- }
+ mame_fprintf(&cheatfile, "\t\t\t<output format=\"%s\"", m_format.cstr());
+ if (m_condition != NULL)
+ mame_fprintf(&cheatfile, " condition=\"%s\"", cheat_manager::quote_expression(tempstring, *m_condition));
+ if (m_line != 0)
+ mame_fprintf(&cheatfile, " line=\"%d\"", m_line);
+ if (m_justify == JUSTIFY_CENTER)
+ mame_fprintf(&cheatfile, " align=\"center\"");
+ else if (m_justify == JUSTIFY_RIGHT)
+ mame_fprintf(&cheatfile, " align=\"right\"");
+ if (m_arglist.count() == 0)
+ mame_fprintf(&cheatfile, " />\n");
+
+ // output arguments
else
{
- for (item = cheat->parameter->itemlist; item != NULL; item = item->next)
- if (item->value == cheat->parameter->value)
- break;
- if (item->next != NULL)
- {
- cheat->parameter->value = item->next->value;
- if (!is_oneshot_parameter_cheat(cheat))
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
- changed = TRUE;
- }
+ mame_fprintf(&cheatfile, ">\n");
+ for (const output_argument *curarg = m_arglist.first(); curarg != NULL; curarg = curarg->next())
+ curarg->save(cheatfile);
+ mame_fprintf(&cheatfile, "\t\t\t</output>\n");
}
}
- return changed;
}
-/*-------------------------------------------------
- cheat_get_comment - called by the UI system
- to help render displayable comments
--------------------------------------------------*/
+//-------------------------------------------------
+// validate_format - check that a format string
+// has the correct number and type of arguments
+//-------------------------------------------------
-astring &cheat_get_comment(void *entry)
+void cheat_script::script_entry::validate_format(const char *filename, int line)
{
- cheat_entry *cheat = (cheat_entry *)entry;
- return cheat->comment;
-}
-
-
+ // first count arguments
+ int argsprovided = 0;
+ for (const output_argument *curarg = m_arglist.first(); curarg != NULL; curarg = curarg->next())
+ argsprovided += curarg->count();
+
+ // now scan the string for valid argument usage
+ const char *p = strchr(m_format, '%');
+ int argscounted = 0;
+ while (p != NULL)
+ {
+ // skip past any valid attributes
+ p++;
+ while (strchr("lh0123456789.-+ #", *p) != NULL)
+ p++;
-/***************************************************************************
- CHEAT EXECUTION
-***************************************************************************/
+ // look for a valid type
+ if (strchr("cdiouxX", *p) == NULL)
+ throw emu_fatalerror("%s.xml(%d): invalid format specification \"%s\"\n", filename, line, m_format.cstr());
+ argscounted++;
-/*-------------------------------------------------
- cheat_frame - per-frame callback
--------------------------------------------------*/
+ // look for the next one
+ p = strchr(p, '%');
+ }
-static void cheat_frame(running_machine &machine)
-{
- cheat_private *cheatinfo = machine.cheat_data;
- cheat_entry *cheat;
- int linenum;
-
- /* set up for accumulating output */
- cheatinfo->lastline = 0;
- cheatinfo->numlines = floor(1.0f / ui_get_line_height(machine));
- cheatinfo->numlines = MIN(cheatinfo->numlines, ARRAY_LENGTH(cheatinfo->output));
- for (linenum = 0; linenum < ARRAY_LENGTH(cheatinfo->output); linenum++)
- cheatinfo->output[linenum].reset();
-
- /* iterate over running cheats and execute them */
- for (cheat = cheatinfo->cheatlist; cheat != NULL; cheat = cheat->next)
- if (cheat->state == SCRIPT_STATE_RUN)
- cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_RUN);
-
- /* increment the frame counter */
- cheatinfo->framecount++;
+ // did we match?
+ if (argscounted < argsprovided)
+ throw emu_fatalerror("%s.xml(%d): too many arguments provided (%d) for format \"%s\"\n", filename, line, argsprovided, m_format.cstr());
+ if (argscounted > argsprovided)
+ throw emu_fatalerror("%s.xml(%d): not enough arguments provided (%d) for format \"%s\"\n", filename, line, argsprovided, m_format.cstr());
}
-/*-------------------------------------------------
- cheat_execute_script - execute the
- appropriate script
--------------------------------------------------*/
+//-------------------------------------------------
+// output_argument - constructor
+//-------------------------------------------------
-static void cheat_execute_script(cheat_private *cheatinfo, cheat_entry *cheat, script_state state)
+cheat_script::script_entry::output_argument::output_argument(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &argnode)
+ : m_next(NULL),
+ m_expression(NULL),
+ m_count(0)
{
- script_entry *entry;
-
- /* if cheat engine has been temporarily disabled or no script, bail */
- if (cheatinfo->disabled || cheat->script[state] == NULL)
- return;
+ // first extract attributes
+ m_count = xml_get_attribute_int(&argnode, "count", 1);
- /* iterate over entries */
- for (entry = cheat->script[state]->entrylist; entry != NULL; entry = entry->next)
- {
- EXPRERR error;
- UINT64 result;
+ // read the expression
+ const char *expression = argnode.value;
+ if (expression == NULL || expression[0] == 0)
+ throw emu_fatalerror("%s.xml(%d): missing expression in argument tag\n", filename, argnode.line);
- /* evaluate the condition */
- if (entry->condition != NULL)
- {
- error = expression_execute(entry->condition, &result);
- if (error != EXPRERR_NONE)
- mame_printf_warning("Error executing conditional expression \"%s\": %s\n", expression_original_string(entry->condition), exprerr_to_string(error));
+ EXPRERR experr = expression_parse(expression, &symbols, &debug_expression_callbacks, &manager.machine(), &m_expression);
+ if (experr != EXPRERR_NONE)
+ throw emu_fatalerror("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, argnode.line, expression, exprerr_to_string(experr));
+}
- /* if the condition is false, or we got an error, don't execute */
- if (error != EXPRERR_NONE || result == 0)
- continue;
- }
- /* if there is an action, execute it */
- if (entry->expression != NULL)
- {
- error = expression_execute(entry->expression, &result);
- if (error != EXPRERR_NONE)
- mame_printf_warning("Error executing expression \"%s\": %s\n", expression_original_string(entry->expression), exprerr_to_string(error));
- }
+//-------------------------------------------------
+// output_argument - destructor
+//-------------------------------------------------
- /* if there is a string to display, compute it */
- if (entry->format)
- {
- UINT64 params[MAX_ARGUMENTS];
- output_argument *arg;
- int curarg = 0;
- int row;
-
- /* iterate over arguments and evaluate them */
- for (arg = entry->arglist; arg != NULL; arg = arg->next)
- for (cheat->argindex = 0; cheat->argindex < arg->count; cheat->argindex++)
- {
- error = expression_execute(arg->expression, &params[curarg++]);
- if (error != EXPRERR_NONE)
- mame_printf_warning("Error executing argument expression \"%s\": %s\n", expression_original_string(arg->expression), exprerr_to_string(error));
- }
-
- /* determine which row we belong to */
- row = entry->line;
- if (row == 0)
- row = (cheatinfo->lastline >= 0) ? cheatinfo->lastline + 1 : cheatinfo->lastline - 1;
- cheatinfo->lastline = row;
- row = (row < 0) ? cheatinfo->numlines + row : row - 1;
- row = MAX(row, 0);
- row = MIN(row, cheatinfo->numlines - 1);
-
- /* either re-use or allocate a string */
- astring &string = cheatinfo->output[row];
- cheatinfo->justify[row] = entry->justify;
-
- /* generate the astring */
- string.printf(entry->format,
- (UINT32)params[0], (UINT32)params[1], (UINT32)params[2], (UINT32)params[3],
- (UINT32)params[4], (UINT32)params[5], (UINT32)params[6], (UINT32)params[7],
- (UINT32)params[8], (UINT32)params[9], (UINT32)params[10], (UINT32)params[11],
- (UINT32)params[12], (UINT32)params[13], (UINT32)params[14], (UINT32)params[15],
- (UINT32)params[16], (UINT32)params[17], (UINT32)params[18], (UINT32)params[19],
- (UINT32)params[20], (UINT32)params[21], (UINT32)params[22], (UINT32)params[23],
- (UINT32)params[24], (UINT32)params[25], (UINT32)params[26], (UINT32)params[27],
- (UINT32)params[28], (UINT32)params[29], (UINT32)params[30], (UINT32)params[31]);
- }
- }
+cheat_script::script_entry::output_argument::~output_argument()
+{
+ if (m_expression != NULL)
+ expression_free(m_expression);
}
+//-------------------------------------------------
+// value - return the evaluated value of the
+// given output argument
+//-------------------------------------------------
-/***************************************************************************
- CHEAT FILE ACCESS
-***************************************************************************/
+int cheat_script::script_entry::output_argument::values(UINT64 &argindex, UINT64 *result)
+{
+ for (argindex = 0; argindex < m_count; argindex++)
+ {
+ EXPRERR error = expression_execute(m_expression, &result[argindex]);
+ if (error != EXPRERR_NONE)
+ mame_printf_warning("Error executing argument expression \"%s\": %s\n", expression_original_string(m_expression), exprerr_to_string(error));
+ }
+ return m_count;
+}
-/*-------------------------------------------------
- cheat_list_load - load a cheat file into
- memory and create the cheat entry list
--------------------------------------------------*/
-static cheat_entry *cheat_list_load(running_machine *machine, const char *filename)
-{
- xml_data_node *rootnode = NULL;
- cheat_entry *cheatlist = NULL;
- cheat_entry **cheattailptr = &cheatlist;
- mame_file *cheatfile = NULL;
- file_error filerr;
+//-------------------------------------------------
+// save - save a single output argument
+//-------------------------------------------------
- /* open the file with the proper name */
- astring fname(filename, ".xml");
- filerr = mame_fopen(SEARCHPATH_CHEAT, fname, OPEN_FLAG_READ, &cheatfile);
+void cheat_script::script_entry::output_argument::save(mame_file &cheatfile) const
+{
+ astring tempstring;
- /* loop over all instrances of the files found in our search paths */
- while (filerr == FILERR_NONE)
- {
- xml_data_node *mamecheatnode, *cheatnode;
- xml_parse_options options;
- xml_parse_error error;
- cheat_entry *scannode;
- int version;
+ mame_fprintf(&cheatfile, "\t\t\t\t<argument");
+ if (m_count != 1)
+ mame_fprintf(&cheatfile, " count=\"%d\"", (int)m_count);
+ mame_fprintf(&cheatfile, ">%s</argument>\n", cheat_manager::quote_expression(tempstring, *m_expression));
+}
- mame_printf_verbose("Loading cheats file from %s\n", mame_file_full_name(cheatfile).cstr());
- /* read the XML file into internal data structures */
- memset(&options, 0, sizeof(options));
- options.error = &error;
- rootnode = xml_file_read(mame_core_file(cheatfile), &options);
- /* if unable to parse the file, just bail */
- if (rootnode == NULL)
+//**************************************************************************
+// CHEAT ENTRY
+//**************************************************************************
+
+//-------------------------------------------------
+// cheat_entry - constructor
+//-------------------------------------------------
+
+cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, const char *filename, xml_data_node &cheatnode)
+ : m_manager(manager),
+ m_next(NULL),
+ m_parameter(NULL),
+ m_on_script(NULL),
+ m_off_script(NULL),
+ m_change_script(NULL),
+ m_run_script(NULL),
+ m_symbols(NULL),
+ m_state(SCRIPT_STATE_OFF),
+ m_numtemp(DEFAULT_TEMP_VARIABLES),
+ m_argindex(0),
+ m_tempvar(NULL)
+{
+ // reset scripts
+ try
+ {
+ // pull the variable count out ahead of things
+ int tempcount = xml_get_attribute_int(&cheatnode, "tempvariables", DEFAULT_TEMP_VARIABLES);
+ if (tempcount < 1)
+ throw emu_fatalerror("%s.xml(%d): invalid tempvariables attribute (%d)\n", filename, cheatnode.line, tempcount);
+
+ // allocate memory for the cheat
+ m_numtemp = tempcount;
+ m_tempvar = auto_alloc_array_clear(&manager.machine(), UINT64, tempcount);
+
+ // get the description
+ const char *description = xml_get_attribute_string(&cheatnode, "desc", NULL);
+ if (description == NULL || description[0] == 0)
+ throw emu_fatalerror("%s.xml(%d): empty or missing desc attribute on cheat\n", filename, cheatnode.line);
+ m_description = description;
+
+ // create the symbol table
+ m_symbols = symtable_alloc(&globaltable, &manager.machine());
+ symtable_add_register(m_symbols, "argindex", &m_argindex, cheat_manager::variable_get, NULL);
+ astring tempname;
+ for (int curtemp = 0; curtemp < tempcount; curtemp++)
+ symtable_add_register(m_symbols, tempname.format("temp%d", curtemp), &m_tempvar[curtemp], cheat_manager::variable_get, cheat_manager::variable_set);
+
+ // read the first comment node
+ xml_data_node *commentnode = xml_get_sibling(cheatnode.child, "comment");
+ if (commentnode != NULL)
{
- mame_printf_error("%s.xml(%d): error parsing XML (%s)\n", filename, error.error_line, error.error_message);
- goto error;
+ // set the value if not NULL
+ if (commentnode->value != NULL && commentnode->value[0] != 0)
+ m_comment.cpy(commentnode->value);
+
+ // only one comment is kept
+ commentnode = xml_get_sibling(commentnode->next, "comment");
+ if (commentnode != NULL)
+ mame_printf_warning("%s.xml(%d): only one comment node is retained; ignoring additional nodes\n", filename, commentnode->line);
}
- /* find the layout node */
- mamecheatnode = xml_get_sibling(rootnode->child, "mamecheat");
- if (mamecheatnode == NULL)
+ // read the first parameter node
+ xml_data_node *paramnode = xml_get_sibling(cheatnode.child, "parameter");
+ if (paramnode != NULL)
{
- mame_printf_error("%s.xml: missing mamecheatnode node", filename);
- goto error;
- }
+ // load this parameter
+ m_parameter = auto_alloc(&manager.machine(), cheat_parameter(manager, *m_symbols, filename, *paramnode));
- /* validate the config data version */
- version = xml_get_attribute_int(mamecheatnode, "version", 0);
- if (version != CHEAT_VERSION)
- {
- mame_printf_error("%s.xml(%d): Invalid cheat XML file: unsupported version", filename, mamecheatnode->line);
- goto error;
+ // only one parameter allowed
+ paramnode = xml_get_sibling(paramnode->next, "parameter");
+ if (paramnode != NULL)
+ mame_printf_warning("%s.xml(%d): only one parameter node allowed; ignoring additional nodes\n", filename, paramnode->line);
}
- /* parse all the elements */
- for (cheatnode = xml_get_sibling(mamecheatnode->child, "cheat"); cheatnode != NULL; cheatnode = xml_get_sibling(cheatnode->next, "cheat"))
+ // read the script nodes
+ for (xml_data_node *scriptnode = xml_get_sibling(cheatnode.child, "script"); scriptnode != NULL; scriptnode = xml_get_sibling(scriptnode->next, "script"))
{
- /* load this entry */
- cheat_entry *curcheat = cheat_entry_load(machine, filename, cheatnode);
- if (curcheat == NULL)
- goto error;
-
- /* make sure we're not a duplicate */
- scannode = NULL;
- if (REMOVE_DUPLICATE_CHEATS)
- for (scannode = cheatlist; scannode != NULL; scannode = scannode->next)
- if (scannode->description == curcheat->description)
- {
- mame_printf_verbose("Ignoring duplicate cheat '%s' from file %s\n", curcheat->description.cstr(), mame_file_full_name(cheatfile).cstr());
- break;
- }
-
- /* add to the end of the list */
- if (scannode == NULL)
- {
- *cheattailptr = curcheat;
- cheattailptr = &curcheat->next;
- }
- }
+ // load this entry
+ cheat_script *curscript = auto_alloc(&manager.machine(), cheat_script(manager, *m_symbols, filename, *scriptnode));
- /* free the file and loop for the next one */
- xml_file_free(rootnode);
-
- /* open the next file in sequence */
- filerr = mame_fclose_and_open_next(&cheatfile, fname, OPEN_FLAG_READ);
+ // if we have a script already for this slot, it is an error
+ cheat_script *&slot = script_for_state(curscript->state());
+ if (slot != NULL)
+ mame_printf_warning("%s.xml(%d): only one on script allowed; ignoring additional scripts\n", filename, scriptnode->line);
+ else
+ slot = curscript;
+ }
+ }
+ catch (emu_fatalerror &)
+ {
+ // call our destructor to clean up and re-throw
+ this->~cheat_entry();
+ throw;
}
-
- /* return the cheat list */
- return cheatlist;
-
-error:
- cheat_list_free(machine, cheatlist);
- xml_file_free(rootnode);
- if (cheatfile != NULL)
- mame_fclose(cheatfile);
- return NULL;
}
-/*-------------------------------------------------
- cheat_list_save - save a cheat file from
- memory to the given filename
--------------------------------------------------*/
+//-------------------------------------------------
+// ~cheat_entry - destructor
+//-------------------------------------------------
-static int cheat_list_save(const char *filename, const cheat_entry *cheatlist)
+cheat_entry::~cheat_entry()
{
- mame_file *cheatfile;
- file_error filerr;
-
- /* open the file with the proper name */
- astring fname(filename, ".xml");
- filerr = mame_fopen(SEARCHPATH_CHEAT, fname, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &cheatfile);
-
- /* if that failed, return nothing */
- if (filerr != FILERR_NONE)
- return FALSE;
-
- /* output the outer layers */
- mame_fprintf(cheatfile, "<?xml version=\"1.0\"?>\n");
- mame_fprintf(cheatfile, "<!-- This file is autogenerated; comments and unknown tags will be stripped -->\n");
- mame_fprintf(cheatfile, "<mamecheat version=\"%d\">\n", CHEAT_VERSION);
-
- /* iterate over cheats in the list and save them */
- for ( ; cheatlist != NULL; cheatlist = cheatlist->next)
- cheat_entry_save(cheatfile, cheatlist);
-
- /* close out the file */
- mame_fprintf(cheatfile, "</mamecheat>\n");
- mame_fclose(cheatfile);
- return TRUE;
+ if (m_symbols != NULL)
+ symtable_free(m_symbols);
+ auto_free(&m_manager.machine(), m_on_script);
+ auto_free(&m_manager.machine(), m_off_script);
+ auto_free(&m_manager.machine(), m_change_script);
+ auto_free(&m_manager.machine(), m_run_script);
+ auto_free(&m_manager.machine(), m_parameter);
+ auto_free(&m_manager.machine(), m_tempvar);
}
-/*-------------------------------------------------
- cheat_list_free - free a list of cheats
--------------------------------------------------*/
+//-------------------------------------------------
+// save - save a single cheat entry
+//-------------------------------------------------
-static void cheat_list_free(running_machine *machine, cheat_entry *cheat)
+void cheat_entry::save(mame_file &cheatfile) const
{
- while (cheat != NULL)
+ // determine if we have scripts
+ bool has_scripts = (m_off_script != NULL || m_on_script != NULL || m_run_script != NULL || m_change_script != NULL);
+
+ // output the cheat tag
+ mame_fprintf(&cheatfile, "\t<cheat desc=\"%s\"", m_description.cstr());
+ if (m_numtemp != DEFAULT_TEMP_VARIABLES)
+ mame_fprintf(&cheatfile, " tempvariables=\"%d\"", m_numtemp);
+ if (!m_comment && m_parameter == NULL && !has_scripts)
+ mame_fprintf(&cheatfile, " />\n");
+ else
{
- cheat_entry *entry = cheat;
- cheat = entry->next;
- cheat_entry_free(machine, entry);
+ mame_fprintf(&cheatfile, ">\n");
+
+ // save the comment
+ if (m_comment)
+ mame_fprintf(&cheatfile, "\t\t<comment><![CDATA[\n%s\n\t\t]]></comment>\n", m_comment.cstr());
+
+ // output the parameter, if present
+ if (m_parameter != NULL)
+ m_parameter->save(cheatfile);
+
+ // output the script nodes
+ if (m_on_script != NULL)
+ m_on_script->save(cheatfile);
+ if (m_off_script != NULL)
+ m_off_script->save(cheatfile);
+ if (m_change_script != NULL)
+ m_change_script->save(cheatfile);
+ if (m_run_script != NULL)
+ m_run_script->save(cheatfile);
+
+ // close the cheat tag
+ mame_fprintf(&cheatfile, "\t</cheat>\n");
}
}
-/*-------------------------------------------------
- cheat_entry_load - load a single cheat
- entry and create the underlying data
- structures
--------------------------------------------------*/
+//-------------------------------------------------
+// activate - activate a oneshot cheat
+//-------------------------------------------------
-static cheat_entry *cheat_entry_load(running_machine *machine, const char *filename, xml_data_node *cheatnode)
+bool cheat_entry::activate()
{
- cheat_private *cheatinfo = machine->cheat_data;
- xml_data_node *paramnode, *scriptnode, *commentnode;
- const char *description;
- int tempcount, curtemp;
- cheat_entry *cheat;
-
- /* pull the variable count out ahead of things */
- tempcount = xml_get_attribute_int(cheatnode, "tempvariables", DEFAULT_TEMP_VARIABLES);
- if (tempcount < 1)
- {
- mame_printf_error("%s.xml(%d): invalid tempvariables attribute (%d)\n", filename, cheatnode->line, tempcount);
- return NULL;
- }
-
- /* allocate memory for the cheat */
- cheat = auto_alloc_clear(machine, cheat_entry);
- cheat->tempvar = auto_alloc_array_clear(machine, UINT64, tempcount);
- cheat->numtemp = tempcount;
-
- /* get the description */
- description = xml_get_attribute_string(cheatnode, "desc", NULL);
- if (description == NULL || description[0] == 0)
- {
- mame_printf_error("%s.xml(%d): empty or missing desc attribute on cheat\n", filename, cheatnode->line);
- return NULL;
- }
- cheat->description = description;
-
- /* create the symbol table */
- cheat->symbols = symtable_alloc(NULL, machine);
- symtable_add_register(cheat->symbols, "frame", &cheatinfo->framecount, cheat_variable_get, NULL);
- symtable_add_register(cheat->symbols, "argindex", &cheat->argindex, cheat_variable_get, NULL);
- for (curtemp = 0; curtemp < tempcount; curtemp++)
- {
- char tempname[20];
- sprintf(tempname, "temp%d", curtemp);
- symtable_add_register(cheat->symbols, tempname, &cheat->tempvar[curtemp], cheat_variable_get, cheat_variable_set);
- }
- symtable_add_function(cheat->symbols, "frombcd", NULL, 1, 1, execute_frombcd);
- symtable_add_function(cheat->symbols, "tobcd", NULL, 1, 1, execute_tobcd);
-
- /* read the first comment node */
- commentnode = xml_get_sibling(cheatnode->child, "comment");
- if (commentnode != NULL)
- {
- if (commentnode->value != NULL && commentnode->value[0] != 0)
- cheat->comment = commentnode->value;
+ bool changed = false;
- /* only one comment is kept */
- commentnode = xml_get_sibling(commentnode->next, "comment");
- if (commentnode != NULL)
- mame_printf_warning("%s.xml(%d): only one comment node is retained; ignoring additional nodes\n", filename, commentnode->line);
- }
+ // if cheats have been toggled off no point in even trying to do anything
+ if (!m_manager.enabled())
+ return changed;
- /* read the first parameter node */
- paramnode = xml_get_sibling(cheatnode->child, "parameter");
- if (paramnode != NULL)
+ // if we're a oneshot cheat, execute the "on" script and indicate change
+ if (is_oneshot())
{
- /* load this parameter */
- cheat_parameter *curparam = cheat_parameter_load(machine, filename, paramnode);
- if (curparam == NULL)
- goto error;
-
- /* set this as the parameter and add the symbol */
- cheat->parameter = curparam;
- symtable_add_register(cheat->symbols, "param", &curparam->value, cheat_variable_get, NULL);
-
- /* only one parameter allowed */
- paramnode = xml_get_sibling(paramnode->next, "parameter");
- if (paramnode != NULL)
- mame_printf_warning("%s.xml(%d): only one parameter node allowed; ignoring additional nodes\n", filename, paramnode->line);
+ execute_on_script();
+ changed = true;
+ popmessage("Activated %s", m_description.cstr());
}
- /* read the script nodes */
- for (scriptnode = xml_get_sibling(cheatnode->child, "script"); scriptnode != NULL; scriptnode = xml_get_sibling(scriptnode->next, "script"))
+ // if we're a oneshot parameter cheat and we're active, execute the "state change" script and indicate change
+ else if (is_oneshot_parameter() && m_state != SCRIPT_STATE_OFF)
{
- /* load this entry */
- cheat_script *curscript = cheat_script_load(machine, filename, scriptnode, cheat);
- if (curscript == NULL)
- goto error;
-
- /* if we have a script already for this slot, it is an error */
- if (cheat->script[curscript->state] != NULL)
- mame_printf_warning("%s.xml(%d): only one script per state allowed; ignoring additional scripts\n", filename, scriptnode->line);
-
- /* otherwise, fill in the slot */
- else
- cheat->script[curscript->state] = curscript;
+ execute_change_script();
+ changed = true;
+ popmessage("Activated\n %s = %s", m_description.cstr(), m_parameter->text());
}
- /* set the initial state */
- cheat->state = SCRIPT_STATE_OFF;
- return cheat;
-
-error:
- cheat_entry_free(machine, cheat);
- return NULL;
+ return changed;
}
-/*-------------------------------------------------
- cheat_entry_save - save a single cheat
- entry
--------------------------------------------------*/
+//-------------------------------------------------
+// select_default_state - select the default
+// state for a cheat, or activate a oneshot cheat
+//-------------------------------------------------
-static void cheat_entry_save(mame_file *cheatfile, const cheat_entry *cheat)
+bool cheat_entry::select_default_state()
{
- script_state state;
- int scriptcount;
-
- /* count the scripts */
- scriptcount = 0;
- for (state = SCRIPT_STATE_OFF; state < SCRIPT_STATE_COUNT; state++)
- if (cheat->script[state] != NULL)
- scriptcount++;
-
- /* output the cheat tag */
- mame_fprintf(cheatfile, "\t<cheat desc=\"%s\"", cheat->description.cstr());
- if (cheat->numtemp != DEFAULT_TEMP_VARIABLES)
- mame_fprintf(cheatfile, " tempvariables=\"%d\"", cheat->numtemp);
- if (!cheat->comment && cheat->parameter == NULL && scriptcount == 0)
- mame_fprintf(cheatfile, " />\n");
- else
- {
- mame_fprintf(cheatfile, ">\n");
-
- /* save the comment */
- if (cheat->comment)
- mame_fprintf(cheatfile, "\t\t<comment><![CDATA[\n%s\n\t\t]]></comment>\n", cheat->comment.cstr());
+ bool changed = false;
- /* output the parameter, if present */
- if (cheat->parameter != NULL)
- cheat_parameter_save(cheatfile, cheat->parameter);
+ // if we're a oneshot cheat, there is no default state
+ if (is_oneshot())
+ ;
- /* output the script nodes */
- for (state = SCRIPT_STATE_OFF; state < SCRIPT_STATE_COUNT; state++)
- if (cheat->script[state] != NULL)
- cheat_script_save(cheatfile, cheat->script[state]);
+ // all other types switch to the "off" state
+ else
+ changed = set_state(SCRIPT_STATE_OFF);
- /* close the cheat tag */
- mame_fprintf(cheatfile, "\t</cheat>\n");
- }
+ return changed;
}
-/*-------------------------------------------------
- cheat_entry_free - free a single cheat entry
--------------------------------------------------*/
+//-------------------------------------------------
+// select_previous_state - select the previous
+// state for a cheat
+//-------------------------------------------------
-static void cheat_entry_free(running_machine *machine, cheat_entry *cheat)
+bool cheat_entry::select_previous_state()
{
- script_state state;
+ bool changed = false;
- if (cheat->parameter != NULL)
- cheat_parameter_free(machine, cheat->parameter);
-
- for (state = SCRIPT_STATE_OFF; state < SCRIPT_STATE_COUNT; state++)
- if (cheat->script[state] != NULL)
- cheat_script_free(machine, cheat->script[state]);
+ // if we're a oneshot, there is no previous state
+ if (is_oneshot())
+ ;
- if (cheat->symbols != NULL)
- symtable_free(cheat->symbols);
+ // if we're on/off, toggle to off
+ else if (is_onoff())
+ changed = set_state(SCRIPT_STATE_OFF);
- auto_free(machine, cheat->tempvar);
- auto_free(machine, cheat);
+ // if we have a parameter, set the previous state
+ else if (m_parameter != NULL)
+ {
+ // if we're at our minimum, turn off
+ if (m_parameter->is_minimum())
+ changed = set_state(SCRIPT_STATE_OFF);
+ else
+ {
+ // if we changed, ensure we are in the running state and signal state change
+ changed = m_parameter->set_prev_state();
+ if (changed)
+ {
+ set_state(SCRIPT_STATE_RUN);
+ if (!is_oneshot_parameter())
+ execute_change_script();
+ }
+ }
+ }
+ return changed;
}
-/*-------------------------------------------------
- cheat_parameter_load - load a single cheat
- parameter and create the underlying data
- structures
--------------------------------------------------*/
+//-------------------------------------------------
+// select_next_state - select the next state for
+// a cheat
+//-------------------------------------------------
-static cheat_parameter *cheat_parameter_load(running_machine *machine, const char *filename, xml_data_node *paramnode)
+bool cheat_entry::select_next_state()
{
- parameter_item **itemtailptr;
- xml_data_node *itemnode;
- cheat_parameter *param;
-
- /* allocate memory for it */
- param = auto_alloc_clear(machine, cheat_parameter);
-
- /* read the core attributes */
- param->minval = xml_get_attribute_int(paramnode, "min", 0);
- param->minformat = xml_get_attribute_int_format(paramnode, "min");
- param->maxval = xml_get_attribute_int(paramnode, "max", 0);
- param->maxformat = xml_get_attribute_int_format(paramnode, "max");
- param->stepval = xml_get_attribute_int(paramnode, "step", 1);
- param->stepformat = xml_get_attribute_int_format(paramnode, "step");
-
- /* iterate over items */
- itemtailptr = &param->itemlist;
- for (itemnode = xml_get_sibling(paramnode->child, "item"); itemnode != NULL; itemnode = xml_get_sibling(itemnode->next, "item"))
- {
- parameter_item *curitem;
+ bool changed = false;
- /* allocate memory for it */
- curitem = auto_alloc_clear(machine, parameter_item);
+ // if we're a oneshot, there is no next state
+ if (is_oneshot())
+ ;
- /* check for NULL text */
- if (itemnode->value == NULL || itemnode->value[0] == 0)
- {
- mame_printf_error("%s.xml(%d): item is missing text\n", filename, itemnode->line);
- goto error;
- }
- curitem->text.cpy(itemnode->value);
+ // if we're on/off, toggle to running state
+ else if (is_onoff())
+ changed = set_state(SCRIPT_STATE_RUN);
- /* read the attributes */
- if (xml_get_attribute(itemnode, "value") == NULL)
+ // if we have a parameter, set the next state
+ else if (m_parameter != NULL)
+ {
+ // if we're off, switch on to the minimum state
+ if (m_state == SCRIPT_STATE_OFF)
{
- mame_printf_error("%s.xml(%d): item is value\n", filename, itemnode->line);
- goto error;
+ changed = set_state(SCRIPT_STATE_RUN);
+ m_parameter->set_minimum_state();
}
- curitem->value = xml_get_attribute_int(itemnode, "value", 0);
- curitem->valformat = xml_get_attribute_int_format(itemnode, "value");
-
- /* ensure the maximum expands to suit */
- param->maxval = MAX(param->maxval, curitem->value);
-
- /* add to the end of the list */
- *itemtailptr = curitem;
- itemtailptr = &curitem->next;
+
+ // otherwise, switch to the next state
+ else
+ changed = m_parameter->set_next_state();
+
+ // if we changed, signal a state change
+ if (changed && !is_oneshot_parameter())
+ execute_change_script();
}
-
- /* start at the minimum */
- param->value = param->minval;
-
- return param;
-
-error:
- cheat_parameter_free(machine, param);
- return NULL;
+ return changed;
}
-/*-------------------------------------------------
- cheat_parameter_save - save a single cheat
- parameter
--------------------------------------------------*/
+//-------------------------------------------------
+// menu_text - return the text needed to display
+// this cheat in a menu item
+//-------------------------------------------------
-static void cheat_parameter_save(mame_file *cheatfile, const cheat_parameter *param)
+void cheat_entry::menu_text(astring &description, astring &state, UINT32 &flags)
{
- /* output the parameter tag */
- mame_fprintf(cheatfile, "\t\t<parameter");
+ // description is standard
+ description.cpy(m_description);
+ state.reset();
+ flags = 0;
- /* if no items, just output min/max/step */
- astring string;
- if (param->itemlist == NULL)
+ // some cheat entries are just text for display
+ if (is_text_only())
{
- if (param->minval != 0)
- mame_fprintf(cheatfile, " min=\"%s\"", format_int(string, param->minval, param->minformat));
- if (param->maxval != 0)
- mame_fprintf(cheatfile, " max=\"%s\"", format_int(string, param->maxval, param->maxformat));
- if (param->stepval != 1)
- mame_fprintf(cheatfile, " step=\"%s\"", format_int(string, param->stepval, param->stepformat));
- mame_fprintf(cheatfile, "/>\n");
+ if (description)
+ {
+ description.trimspace();
+ if (!description)
+ description.cpy(MENU_SEPARATOR_ITEM);
+ }
+ flags = MENU_FLAG_DISABLE;
}
- /* iterate over items */
- else
+ // if we have no parameter and no run or off script, it's a oneshot cheat
+ else if (is_oneshot())
+ state.cpy("Set");
+
+ // if we have no parameter, it's just on/off
+ else if (is_onoff())
{
- const parameter_item *curitem;
+ state.cpy((m_state == SCRIPT_STATE_RUN) ? "On" : "Off");
+ flags = (m_state != 0) ? MENU_FLAG_LEFT_ARROW : MENU_FLAG_RIGHT_ARROW;
+ }
- for (curitem = param->itemlist; curitem != NULL; curitem = curitem->next)
- mame_fprintf(cheatfile, "\t\t\t<item value=\"%s\">%s</item>\n", format_int(string, curitem->value, curitem->valformat), curitem->text.cstr());
- mame_fprintf(cheatfile, "\t\t</parameter>\n");
+ // if we have a value parameter, compute it
+ else if (m_parameter != NULL)
+ {
+ if (m_state == SCRIPT_STATE_OFF)
+ {
+ state.cpy(is_oneshot_parameter() ? "Set" : "Off");
+ flags = MENU_FLAG_RIGHT_ARROW;
+ }
+ else
+ {
+ state.cpy(m_parameter->text());
+ flags = MENU_FLAG_LEFT_ARROW;
+ if (!m_parameter->is_maximum())
+ flags |= MENU_FLAG_RIGHT_ARROW;
+ }
}
}
-/*-------------------------------------------------
- cheat_parameter_free - free a single cheat
- parameter
--------------------------------------------------*/
+//-------------------------------------------------
+// set_state - switch to the given state
+//-------------------------------------------------
-static void cheat_parameter_free(running_machine *machine, cheat_parameter *param)
+bool cheat_entry::set_state(script_state newstate)
{
- while (param->itemlist != NULL)
- {
- parameter_item *item = param->itemlist;
- param->itemlist = item->next;
-
- auto_free(machine, item);
- }
-
- auto_free(machine, param);
+ // if we're already in the state, indicate no change
+ if (m_state == newstate)
+ return false;
+
+ // change to the state and run the appropriate script
+ m_state = newstate;
+ if (newstate == SCRIPT_STATE_OFF)
+ execute_off_script();
+ else if (newstate == SCRIPT_STATE_ON || newstate == SCRIPT_STATE_RUN)
+ execute_on_script();
+ return true;
}
-/*-------------------------------------------------
- cheat_script_load - load a single cheat
- script and create the underlying data
- structures
--------------------------------------------------*/
+//-------------------------------------------------
+// script_for_state - get a reference to the
+// given script pointer
+//-------------------------------------------------
-static cheat_script *cheat_script_load(running_machine *machine, const char *filename, xml_data_node *scriptnode, cheat_entry *cheat)
+cheat_script *&cheat_entry::script_for_state(script_state state)
{
- script_entry **entrytailptr;
- xml_data_node *entrynode;
- cheat_script *script;
- const char *state;
-
- /* allocate memory for it */
- script = auto_alloc_clear(machine, cheat_script);
-
- /* read the core attributes */
- script->state = SCRIPT_STATE_RUN;
- state = xml_get_attribute_string(scriptnode, "state", "run");
- if (strcmp(state, "on") == 0)
- script->state = SCRIPT_STATE_ON;
- else if (strcmp(state, "off") == 0)
- script->state = SCRIPT_STATE_OFF;
- else if (strcmp(state, "change") == 0)
- script->state = SCRIPT_STATE_CHANGE;
- else if (strcmp(state, "run") != 0)
+ switch (state)
{
- mame_printf_error("%s.xml(%d): invalid script state '%s'\n", filename, scriptnode->line, state);
- goto error;
+ case SCRIPT_STATE_ON: return m_on_script;
+ case SCRIPT_STATE_OFF: return m_off_script;
+ case SCRIPT_STATE_CHANGE: return m_change_script;
+ default:
+ case SCRIPT_STATE_RUN: return m_run_script;
}
+}
- /* iterate over nodes within the script */
- entrytailptr = &script->entrylist;
- for (entrynode = scriptnode->child; entrynode != NULL; entrynode = entrynode->next)
- {
- script_entry *curentry = NULL;
-
- /* handle action nodes */
- if (strcmp(entrynode->name, "action") == 0)
- curentry = script_entry_load(machine, filename, entrynode, cheat, TRUE);
-
- /* handle output nodes */
- else if (strcmp(entrynode->name, "output") == 0)
- curentry = script_entry_load(machine, filename, entrynode, cheat, FALSE);
-
- /* anything else is ignored */
- else
- {
- mame_printf_warning("%s.xml(%d): unknown script item '%s' will be lost if saved\n", filename, entrynode->line, entrynode->name);
- continue;
- }
-
- if (curentry == NULL)
- goto error;
- /* add to the end of the list */
- *entrytailptr = curentry;
- entrytailptr = &curentry->next;
- }
- return script;
-
-error:
- cheat_script_free(machine, script);
- return NULL;
-}
+//**************************************************************************
+// CHEAT MANAGER
+//**************************************************************************
-/*-------------------------------------------------
- cheat_script_save - save a single cheat
- script
--------------------------------------------------*/
+//-------------------------------------------------
+// cheat_manager - constructor
+//-------------------------------------------------
-static void cheat_script_save(mame_file *cheatfile, const cheat_script *script)
+cheat_manager::cheat_manager(running_machine &machine)
+ : m_machine(machine),
+ m_cheatlist(machine.m_respool),
+ m_disabled(true)
{
- const script_entry *entry;
+ // if the cheat engine is disabled, we're done
+ if (!options_get_bool(machine.options(), OPTION_CHEAT))
+ return;
- /* output the script tag */
- mame_fprintf(cheatfile, "\t\t<script");
- switch (script->state)
- {
- case SCRIPT_STATE_OFF: mame_fprintf(cheatfile, " state=\"off\""); break;
- case SCRIPT_STATE_ON: mame_fprintf(cheatfile, " state=\"on\""); break;
- default:
- case SCRIPT_STATE_RUN: mame_fprintf(cheatfile, " state=\"run\""); break;
- case SCRIPT_STATE_CHANGE: mame_fprintf(cheatfile, " state=\"change\""); break;
- }
- mame_fprintf(cheatfile, ">\n");
+ // request a callback
+ machine.add_notifier(MACHINE_NOTIFY_FRAME, frame_update_static);
- /* output entries */
- for (entry = script->entrylist; entry != NULL; entry = entry->next)
- script_entry_save(cheatfile, entry);
+ // create a global symbol table
+ m_symtable = symtable_alloc(NULL, &machine);
+ symtable_add_register(m_symtable, "frame", &m_framecount, variable_get, NULL);
+ symtable_add_function(m_symtable, "frombcd", NULL, 1, 1, execute_frombcd);
+ symtable_add_function(m_symtable, "tobcd", NULL, 1, 1, execute_tobcd);
- /* close the tag */
- mame_fprintf(cheatfile, "\t\t</script>\n");
+ // load the cheats
+ reload();
+
+ // we rely on the debugger expression callbacks; if the debugger isn't
+ // enabled, we must jumpstart them manually
+ if ((machine.debug_flags & DEBUG_FLAG_ENABLED) == 0)
+ debug_cpu_init(&machine);
}
-/*-------------------------------------------------
- cheat_script_free - free a single cheat
- script
--------------------------------------------------*/
+//-------------------------------------------------
+// ~cheat_manager - destructor
+//-------------------------------------------------
-static void cheat_script_free(running_machine *machine, cheat_script *script)
+cheat_manager::~cheat_manager()
{
- while (script->entrylist != NULL)
- {
- script_entry *entry = script->entrylist;
- script->entrylist = entry->next;
- script_entry_free(machine, entry);
- }
-
- auto_free(machine, script);
}
-/*-------------------------------------------------
- script_entry_load - load a single action
- or output create the underlying data
- structures
--------------------------------------------------*/
+//-------------------------------------------------
+// set_enable - globally enable or disable the
+// cheat engine
+//-------------------------------------------------
-static script_entry *script_entry_load(running_machine *machine, const char *filename, xml_data_node *entrynode, cheat_entry *cheat, int isaction)
+void cheat_manager::set_enable(bool enable)
{
- const char *expression;
- script_entry *entry;
- EXPRERR experr;
-
- /* allocate memory for it */
- entry = auto_alloc_clear(machine, script_entry);
+ // if the cheat engine is disabled, we're done
+ if (!options_get_bool(m_machine.options(), OPTION_CHEAT))
+ return;
- /* read the condition if present */
- expression = xml_get_attribute_string(entrynode, "condition", NULL);
- if (expression != NULL)
+ // if we're enabled currently and we don't want to be, turn things off
+ if (!m_disabled && !enable)
{
- experr = expression_parse(expression, cheat->symbols, &debug_expression_callbacks, machine, &entry->condition);
- if (experr != EXPRERR_NONE)
- {
- mame_printf_error("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode->line, expression, exprerr_to_string(experr));
- goto error;
- }
+ // iterate over running cheats and execute any OFF Scripts
+ for (cheat_entry *cheat = m_cheatlist.first(); cheat != NULL; cheat = cheat->next())
+ if (cheat->state() == SCRIPT_STATE_RUN)
+ cheat->execute_off_script();
+ popmessage("Cheats Disabled");
+ m_disabled = true;
}
- /* if this is an action, parse the expression */
- if (isaction)
+ // if we're disabled currently and we want to be enabled, turn things on
+ else if (m_disabled && enable)
{
- expression = entrynode->value;
- if (expression == NULL || expression[0] == 0)
- {
- mame_printf_error("%s.xml(%d): missing expression in action tag\n", filename, entrynode->line);
- goto error;
- }
- experr = expression_parse(expression, cheat->symbols, &debug_expression_callbacks, machine, &entry->expression);
- if (experr != EXPRERR_NONE)
- {
- mame_printf_error("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode->line, expression, exprerr_to_string(experr));
- goto error;
- }
+ // iterate over running cheats and execute any ON Scripts
+ m_disabled = false;
+ for (cheat_entry *cheat = m_cheatlist.first(); cheat != NULL; cheat = cheat->next())
+ if (cheat->state() == SCRIPT_STATE_RUN)
+ cheat->execute_on_script();
+ popmessage("Cheats Enabled");
}
+}
- /* otherwise, parse the attributes and arguments */
- else
- {
- output_argument **argtailptr;
- const char *align, *format;
- xml_data_node *argnode;
- int totalargs = 0;
-
- /* extract format */
- format = xml_get_attribute_string(entrynode, "format", NULL);
- if (format == NULL || format[0] == 0)
- {
- mame_printf_error("%s.xml(%d): missing format in output tag\n", filename, entrynode->line);
- goto error;
- }
- entry->format.cpy(format);
-
- /* extract other attributes */
- entry->line = xml_get_attribute_int(entrynode, "line", 0);
- entry->justify = JUSTIFY_LEFT;
- align = xml_get_attribute_string(entrynode, "align", "left");
- if (strcmp(align, "center") == 0)
- entry->justify = JUSTIFY_CENTER;
- else if (strcmp(align, "right") == 0)
- entry->justify = JUSTIFY_RIGHT;
- else if (strcmp(align, "left") != 0)
- {
- mame_printf_error("%s.xml(%d): invalid alignment '%s' specified\n", filename, entrynode->line, align);
- goto error;
- }
-
- /* then parse arguments */
- argtailptr = &entry->arglist;
- for (argnode = xml_get_sibling(entrynode->child, "argument"); argnode != NULL; argnode = xml_get_sibling(argnode->next, "argument"))
- {
- output_argument *curarg;
-
- /* allocate memory for it */
- curarg = auto_alloc_clear(machine, output_argument);
- /* first extract attributes */
- curarg->count = xml_get_attribute_int(argnode, "count", 1);
- totalargs += curarg->count;
+//-------------------------------------------------
+// reload - re-initialize the cheat engine, and
+// and reload the cheat file(s)
+//-------------------------------------------------
- /* max out on arguments */
- if (totalargs > MAX_ARGUMENTS)
- {
- mame_printf_error("%s.xml(%d): too many arguments (found %d, max is %d)\n", filename, argnode->line, totalargs, MAX_ARGUMENTS);
- goto error;
- }
+void cheat_manager::reload()
+{
+ // if the cheat engine is disabled, we're done
+ if (!options_get_bool(m_machine.options(), OPTION_CHEAT))
+ return;
- /* read the expression */
- expression = argnode->value;
- if (expression == NULL || expression[0] == 0)
- {
- mame_printf_error("%s.xml(%d): missing expression in argument tag\n", filename, argnode->line);
- goto error;
- }
- experr = expression_parse(expression, cheat->symbols, &debug_expression_callbacks, machine, &curarg->expression);
- if (experr != EXPRERR_NONE)
+ // free everything
+ m_cheatlist.reset();
+
+ // reset state
+ m_framecount = 0;
+ m_numlines = 0;
+ m_lastline = 0;
+ m_disabled = false;
+
+ // load the cheat file, MESS will load a crc32.xml ( eg. 01234567.xml )
+ // and MAME will load gamename.xml
+ device_image_interface *image = NULL;
+ for (bool gotone = m_machine.m_devicelist.first(image); gotone; gotone = image->next(image))
+ if (image->exists())
+ {
+ UINT32 crc = image->crc();
+ if (crc != 0)
{
- mame_printf_error("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, argnode->line, expression, exprerr_to_string(experr));
- goto error;
+ astring filename;
+ filename.printf("%08X", crc);
+ load_cheats(filename);
+ break;
}
-
- /* add to the end of the list */
- *argtailptr = curarg;
- argtailptr = &curarg->next;
}
- /* validate the format against the arguments */
- if (!validate_format(filename, entrynode->line, entry))
- goto error;
- }
- return entry;
+ // if we haven't found the cheats yet, load by basename
+ if (m_cheatlist.count() == 0)
+ load_cheats(m_machine.basename());
-error:
- script_entry_free(machine, entry);
- return NULL;
+ // temporary: save the file back out as output.xml for comparison
+ if (m_cheatlist.count() != 0)
+ save_all("output");
}
-/*-------------------------------------------------
- script_entry_save - save a single action
- or output
--------------------------------------------------*/
+//-------------------------------------------------
+// cheat_list_save - save a cheat file from
+// memory to the given filename
+//-------------------------------------------------
-static void script_entry_save(mame_file *cheatfile, const script_entry *entry)
+bool cheat_manager::save_all(const char *filename)
{
- astring tempstring;
+ // open the file with the proper name
+ astring fname(filename, ".xml");
+ mame_file *cheatfile;
+ file_error filerr = mame_fopen(SEARCHPATH_CHEAT, fname, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &cheatfile);
- /* output an action */
- if (!entry->format)
+ // if that failed, return nothing
+ if (filerr != FILERR_NONE)
+ return false;
+
+ // wrap the rest of catch errors
+ try
{
- mame_fprintf(cheatfile, "\t\t\t<action");
- if (entry->condition != NULL)
- {
- quote_astring_expression(tempstring.cpy(expression_original_string(entry->condition)), TRUE);
- mame_fprintf(cheatfile, " condition=\"%s\"", tempstring.cstr());
- }
- quote_astring_expression(tempstring.cpy(expression_original_string(entry->expression)), FALSE);
- mame_fprintf(cheatfile, ">%s</action>\n", tempstring.cstr());
- }
+ // output the outer layers
+ mame_fprintf(cheatfile, "<?xml version=\"1.0\"?>\n");
+ mame_fprintf(cheatfile, "<!-- This file is autogenerated; comments and unknown tags will be stripped -->\n");
+ mame_fprintf(cheatfile, "<mamecheat version=\"%d\">\n", CHEAT_VERSION);
- /* output an output */
- else
- {
- mame_fprintf(cheatfile, "\t\t\t<output format=\"%s\"", entry->format.cstr());
- if (entry->condition != NULL)
- {
- quote_astring_expression(tempstring.cpy(expression_original_string(entry->condition)), TRUE);
- mame_fprintf(cheatfile, " condition=\"%s\"", tempstring.cstr());
- }
- if (entry->line != 0)
- mame_fprintf(cheatfile, " line=\"%d\"", entry->line);
- if (entry->justify == JUSTIFY_CENTER)
- mame_fprintf(cheatfile, " align=\"center\"");
- else if (entry->justify == JUSTIFY_RIGHT)
- mame_fprintf(cheatfile, " align=\"right\"");
- if (entry->arglist == NULL)
- mame_fprintf(cheatfile, " />\n");
-
- /* output arguments */
- else
- {
- const output_argument *curarg;
+ // iterate over cheats in the list and save them
+ for (cheat_entry *cheat = m_cheatlist.first(); cheat != NULL; cheat = cheat->next())
+ cheat->save(*cheatfile);
- mame_fprintf(cheatfile, ">\n");
- for (curarg = entry->arglist; curarg != NULL; curarg = curarg->next)
- {
- mame_fprintf(cheatfile, "\t\t\t\t<argument");
- if (curarg->count != 1)
- mame_fprintf(cheatfile, " count=\"%d\"", (int)curarg->count);
- quote_astring_expression(tempstring.cpy(expression_original_string(curarg->expression)), FALSE);
- mame_fprintf(cheatfile, ">%s</argument>\n", tempstring.cstr());
- }
- mame_fprintf(cheatfile, "\t\t\t</output>\n");
- }
+ // close out the file
+ mame_fprintf(cheatfile, "</mamecheat>\n");
+ mame_fclose(cheatfile);
+ return true;
+ }
+
+ // catch errors and cleanup
+ catch (emu_fatalerror &err)
+ {
+ mame_printf_error("%s\n", err.string());
+ mame_fclose(cheatfile);
+ osd_rmfile(filename);
}
+ return false;
}
-/*-------------------------------------------------
- script_entry_free - free a single script
- entry
--------------------------------------------------*/
+//-------------------------------------------------
+// render_text - called by the UI system to
+// render text
+//-------------------------------------------------
-static void script_entry_free(running_machine *machine, script_entry *entry)
+void cheat_manager::render_text(render_container &container)
{
- if (entry->condition != NULL)
- expression_free(entry->condition);
- if (entry->expression != NULL)
- expression_free(entry->expression);
+ // render any text and free it along the way
+ for (int linenum = 0; linenum < ARRAY_LENGTH(m_output); linenum++)
+ if (m_output[linenum])
+ {
+ // output the text
+ ui_draw_text_full(&container, m_output[linenum],
+ 0.0f, (float)linenum * ui_get_line_height(m_machine), 1.0f,
+ m_justify[linenum], WRAP_NEVER, DRAW_OPAQUE,
+ ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+ }
+}
- while (entry->arglist != NULL)
- {
- output_argument *curarg = entry->arglist;
- entry->arglist = curarg->next;
- if (curarg->expression != NULL)
- expression_free(curarg->expression);
- auto_free(machine, curarg);
- }
+//-------------------------------------------------
+// get_output_astring - return a reference to
+// the given row's string, and set the
+// justification
+//-------------------------------------------------
- auto_free(machine, entry);
+astring &cheat_manager::get_output_astring(int row, int justify)
+{
+ // if the row is not specified, grab the next one
+ if (row == 0)
+ row = (m_lastline >= 0) ? m_lastline + 1 : m_lastline - 1;
+
+ // remember the last request
+ m_lastline = row;
+
+ // invert if negative
+ row = (row < 0) ? m_numlines + row : row - 1;
+
+ // clamp within range
+ row = MAX(row, 0);
+ row = MIN(row, m_numlines - 1);
+
+ // return the appropriate string
+ m_justify[row] = justify;
+ return m_output[row];
}
+//-------------------------------------------------
+// quote_expression - quote an expression
+// string so that it is valid to embed in an XML
+// document
+//-------------------------------------------------
-/***************************************************************************
- MISC HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- quote_astring_expression - quote an expression
- string so that it is valid to embed in an XML
- document
--------------------------------------------------*/
-
-static astring &quote_astring_expression(astring &string, int isattribute)
+const char *cheat_manager::quote_expression(astring &string, parsed_expression &expression)
{
+ string.cpy(expression_original_string(&expression));
+
string.replace(0, " && ", " and ");
string.replace(0, " &&", " and ");
string.replace(0, "&& ", " and ");
@@ -1822,87 +1357,31 @@ static astring &quote_astring_expression(astring &string, int isattribute)
}
-/*-------------------------------------------------
- validate_format - check that a format string
- has the correct number and type of arguments
--------------------------------------------------*/
-
-static int validate_format(const char *filename, int line, const script_entry *entry)
-{
- const char *p = entry->format;
- const output_argument *curarg;
- int argsprovided;
- int argscounted;
-
- /* first count arguments */
- argsprovided = 0;
- for (curarg = entry->arglist; curarg != NULL; curarg = curarg->next)
- argsprovided += curarg->count;
-
- /* now scan the string for valid argument usage */
- p = strchr(p, '%');
- argscounted = 0;
- while (p != NULL)
- {
- /* skip past any valid attributes */
- p++;
- while (strchr("lh0123456789.-+ #", *p) != NULL)
- p++;
-
- /* look for a valid type */
- if (strchr("cdiouxX", *p) == NULL)
- {
- mame_printf_error("%s.xml(%d): invalid format specification \"%s\"\n", filename, line, entry->format.cstr());
- return FALSE;
- }
- argscounted++;
-
- /* look for the next one */
- p = strchr(p, '%');
- }
-
- /* did we match? */
- if (argscounted < argsprovided)
- {
- mame_printf_error("%s.xml(%d): too many arguments provided (%d) for format \"%s\"\n", filename, line, argsprovided, entry->format.cstr());
- return FALSE;
- }
- if (argscounted > argsprovided)
- {
- mame_printf_error("%s.xml(%d): not enough arguments provided (%d) for format \"%s\"\n", filename, line, argsprovided, entry->format.cstr());
- return FALSE;
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- cheat_variable_get - return the value of a
- cheat variable
--------------------------------------------------*/
+//-------------------------------------------------
+// variable_get - return the value of a variable
+//-------------------------------------------------
-static UINT64 cheat_variable_get(void *globalref, void *ref)
+UINT64 cheat_manager::variable_get(void *globalref, void *ref)
{
return *(UINT64 *)ref;
}
-/*-------------------------------------------------
- cheat_variable_set - set the value of a
- cheat variable
--------------------------------------------------*/
+//-------------------------------------------------
+// variable_set - set the value of a variable
+//-------------------------------------------------
-static void cheat_variable_set(void *globalref, void *ref, UINT64 value)
+void cheat_manager::variable_set(void *globalref, void *ref, UINT64 value)
{
*(UINT64 *)ref = value;
}
-/*-------------------------------------------------
- execute_frombcd - convert a value from BCD
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_frombcd - convert a value from BCD
+//-------------------------------------------------
-static UINT64 execute_frombcd(void *globalref, void *ref, UINT32 params, const UINT64 *param)
+UINT64 cheat_manager::execute_frombcd(void *globalref, void *ref, UINT32 params, const UINT64 *param)
{
UINT64 value = param[0];
UINT64 multiplier = 1;
@@ -1918,11 +1397,11 @@ static UINT64 execute_frombcd(void *globalref, void *ref, UINT32 params, const U
}
-/*-------------------------------------------------
- execute_tobcd - convert a value to BCD
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_tobcd - convert a value to BCD
+//-------------------------------------------------
-static UINT64 execute_tobcd(void *globalref, void *ref, UINT32 params, const UINT64 *param)
+UINT64 cheat_manager::execute_tobcd(void *globalref, void *ref, UINT32 params, const UINT64 *param)
{
UINT64 value = param[0];
UINT64 result = 0;
@@ -1938,3 +1417,112 @@ static UINT64 execute_tobcd(void *globalref, void *ref, UINT32 params, const UIN
}
+//-------------------------------------------------
+// frame_update - per-frame callback
+//-------------------------------------------------
+
+void cheat_manager::frame_update_static(running_machine &machine)
+{
+ machine.cheat().frame_update();
+}
+
+void cheat_manager::frame_update()
+{
+ // set up for accumulating output
+ m_lastline = 0;
+ m_numlines = floor(1.0f / ui_get_line_height(m_machine));
+ m_numlines = MIN(m_numlines, ARRAY_LENGTH(m_output));
+ for (int linenum = 0; linenum < ARRAY_LENGTH(m_output); linenum++)
+ m_output[linenum].reset();
+
+ // iterate over running cheats and execute them
+ for (cheat_entry *cheat = m_cheatlist.first(); cheat != NULL; cheat = cheat->next())
+ cheat->frame_update();
+
+ // increment the frame counter
+ m_framecount++;
+}
+
+
+//-------------------------------------------------
+// load_cheats - load a cheat file into memory
+// and create the cheat entry list
+//-------------------------------------------------
+
+void cheat_manager::load_cheats(const char *filename)
+{
+ xml_data_node *rootnode = NULL;
+ mame_file *cheatfile = NULL;
+ try
+ {
+ // open the file with the proper name
+ astring fname(filename, ".xml");
+ file_error filerr = mame_fopen(SEARCHPATH_CHEAT, fname, OPEN_FLAG_READ, &cheatfile);
+
+ // loop over all instrances of the files found in our search paths
+ while (filerr == FILERR_NONE)
+ {
+ mame_printf_verbose("Loading cheats file from %s\n", mame_file_full_name(cheatfile).cstr());
+
+ // read the XML file into internal data structures
+ xml_parse_options options = { 0 };
+ xml_parse_error error;
+ options.error = &error;
+ rootnode = xml_file_read(mame_core_file(cheatfile), &options);
+
+ // if unable to parse the file, just bail
+ if (rootnode == NULL)
+ throw emu_fatalerror("%s.xml(%d): error parsing XML (%s)\n", filename, error.error_line, error.error_message);
+
+ // find the layout node
+ xml_data_node *mamecheatnode = xml_get_sibling(rootnode->child, "mamecheat");
+ if (mamecheatnode == NULL)
+ throw emu_fatalerror("%s.xml: missing mamecheatnode node", filename);
+
+ // validate the config data version
+ int version = xml_get_attribute_int(mamecheatnode, "version", 0);
+ if (version != CHEAT_VERSION)
+ throw emu_fatalerror("%s.xml(%d): Invalid cheat XML file: unsupported version", filename, mamecheatnode->line);
+
+ // parse all the elements
+ for (xml_data_node *cheatnode = xml_get_sibling(mamecheatnode->child, "cheat"); cheatnode != NULL; cheatnode = xml_get_sibling(cheatnode->next, "cheat"))
+ {
+ // load this entry
+ cheat_entry *curcheat = auto_alloc(&m_machine, cheat_entry(*this, *m_symtable, filename, *cheatnode));
+
+ // make sure we're not a duplicate
+ cheat_entry *scannode = NULL;
+ if (REMOVE_DUPLICATE_CHEATS)
+ for (scannode = m_cheatlist.first(); scannode != NULL; scannode = scannode->next())
+ if (strcmp(scannode->description(), curcheat->description()) == 0)
+ {
+ mame_printf_verbose("Ignoring duplicate cheat '%s' from file %s\n", curcheat->description(), mame_file_full_name(cheatfile).cstr());
+ break;
+ }
+
+ // add to the end of the list
+ if (scannode == NULL)
+ m_cheatlist.append(*curcheat);
+ else
+ auto_free(&m_machine, curcheat);
+ }
+
+ // free the file and loop for the next one
+ xml_file_free(rootnode);
+
+ // open the next file in sequence
+ filerr = mame_fclose_and_open_next(&cheatfile, fname, OPEN_FLAG_READ);
+ }
+ }
+
+ // handle errors cleanly
+ catch (emu_fatalerror &err)
+ {
+ mame_printf_error("%s\n", err.string());
+ m_cheatlist.reset();
+ if (rootnode != NULL)
+ xml_file_free(rootnode);
+ if (cheatfile != NULL)
+ mame_fclose(cheatfile);
+ }
+}
diff --git a/src/emu/cheat.h b/src/emu/cheat.h
index 91b28181a29..2f04388b235 100644
--- a/src/emu/cheat.h
+++ b/src/emu/cheat.h
@@ -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
+//**************************************************************************
+
+enum script_state
+{
+ SCRIPT_STATE_OFF = 0,
+ SCRIPT_STATE_ON,
+ SCRIPT_STATE_RUN,
+ SCRIPT_STATE_CHANGE,
+ SCRIPT_STATE_COUNT
+};
+DECLARE_ENUM_OPERATORS(script_state)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class cheat_manager;
+typedef struct _symbol_table symbol_table;
+typedef struct _parsed_expression parsed_expression;
+
+
+// ======================> number_and_format
+
+// 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) { }
+
+ // 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;
+
+private:
+ // internal state
+ UINT64 m_value;
+ int m_format;
+};
+
+
+// ======================> 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) { }
-/* ----- core system management ----- */
+ // 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
+ };
-/* initialize the cheat system, loading any cheat files */
-void cheat_init(running_machine *machine);
+ // 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
+};
-/* 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);
+// ======================> cheat_script
-/* globally enable or disable the cheat engine */
-void cheat_set_global_enable(running_machine *machine, int enable);
+// 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; }
-/* ----- cheat UI helpers ----- */
+ // actions
+ void execute(cheat_manager &manager, UINT64 &argindex);
+ void save(mame_file &cheatfile) const;
-/* render any text overlays */
-void cheat_render_text(running_machine *machine, render_container *container);
+private:
+ // an entry within the script
+ class script_entry
+ {
+ friend class simple_list<script_entry>;
-/* 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);
+ public:
+ // construction/destruction
+ script_entry(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &entrynode, bool isaction);
+ ~script_entry();
-/* activate a oneshot cheat */
-int cheat_activate(running_machine *machine, void *entry);
+ // getters
+ script_entry *next() const { return m_next; }
-/* select the default menu state */
-int cheat_select_default_state(running_machine *machine, void *entry);
+ // actions
+ void execute(cheat_manager &manager, UINT64 &argindex);
+ void save(mame_file &cheatfile) const;
-/* select the previous menu state */
-int cheat_select_previous_state(running_machine *machine, void *entry);
+ private:
+ // an argument for output
+ class output_argument
+ {
+ friend class simple_list<output_argument>;
-/* select the next menu state */
-int cheat_select_next_state(running_machine *machine, void *entry);
+ public:
+ // construction/destruction
+ output_argument(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &argnode);
+ ~output_argument();
-/* return the displayable comment of the current cheat */
-astring &cheat_get_comment(void *entry);
+ // 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__ */
+
diff --git a/src/emu/machine.c b/src/emu/machine.c
index aeeed7d2a46..349c7241998 100644
--- a/src/emu/machine.c
+++ b/src/emu/machine.c
@@ -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);
diff --git a/src/emu/machine.h b/src/emu/machine.h
index cd7ee2d7056..a9fd8b815e3 100644
--- a/src/emu/machine.h
+++ b/src/emu/machine.h
@@ -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
};
diff --git a/src/emu/ui.c b/src/emu/ui.c
index 72e07ac432d..19aa346ede6 100644
--- a/src/emu/ui.c
+++ b/src/emu/ui.c
@@ -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))
diff --git a/src/emu/uimenu.c b/src/emu/uimenu.c
index dc2eacbc3f0..19ca511a7d2 100644
--- a/src/emu/uimenu.c
+++ b/src/emu/uimenu.c
@@ -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);
}