summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2008-08-06 05:24:31 +0000
committer Aaron Giles <aaron@aarongiles.com>2008-08-06 05:24:31 +0000
commit4a36b515ed656ccdaffe01af527524503d2d7bf3 (patch)
treeaff4312b387c2f72fda3becc2a58b4bad4299ad4 /src/emu
parent2d165fe1c3e7d1a543b35673359214d2d44b77a2 (diff)
Changes to the cheat.xml format:
- new tag <comment> (within <cheat>) is read and preserved when saved - removed variable attribute from <parameter>; it is now assumed to be 'param' - added default attribute for <parameter> Added new variable 'frame' accessible from cheat scripts. This can be used in the conditional to prevent execution on every frame, or for other effects (like displaying temporary messages). Added new variable 'argindex' which is the index when processing an <argument> with a count attribute greater than 1. Can be used in expressions like: <argument count="3">main.pb@(1000+argindex)</argument> Reinstated the cheat menu. It now displays all loaded cheats and allows for them to be activated. All known cheat behaviors should be working now.
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/cheat.c512
-rw-r--r--src/emu/cheat.h27
-rw-r--r--src/emu/ui.c3
-rw-r--r--src/emu/ui.h3
-rw-r--r--src/emu/uimenu.c70
5 files changed, 571 insertions, 44 deletions
diff --git a/src/emu/cheat.c b/src/emu/cheat.c
index 26525b085fd..030febae428 100644
--- a/src/emu/cheat.c
+++ b/src/emu/cheat.c
@@ -13,7 +13,7 @@
<mamecheat version="1">
<cheat desc="blah">
- <parameter variable="varname(param)" min="minval(0)" max="maxval(numitems)" step="stepval(1)">
+ <parameter min="minval(0)" max="maxval(numitems)" step="stepval(1)" default="defvalue(minval)">
<item value="itemval(previtemval|minval+stepval)">text</item>
...
</parameter>
@@ -26,15 +26,37 @@
...
</script>
...
+ <comment>
+ ... text ...
+ </comment>
</cheat>
...
</mamecheat>
+**********************************************************************
+
+ Expressions are standard debugger expressions. Note that & and
+ < must be escaped per XML rules. Within attributes you must use
+ &amp; and &lt;. For tags, you can also use <![CDATA[ ... ]]>.
+
+ Each cheat has its own context-specific variables:
+
+ temp0-temp9 -- 10 temporary variables for any use
+ param -- the current value of the cheat parameter
+ frame -- the current frame index
+ argindex -- for arguments with multiple iterations, this is the index
+
+ By default, each cheat has 10 temporary variables that are
+ persistent while executing its scripts. Additional temporary
+ variables may be requested via the 'tempvariables' attribute
+ on the cheat.
+
*********************************************************************/
#include "driver.h"
#include "xmlfile.h"
#include "ui.h"
+#include "uimenu.h"
#include "debug/debugcpu.h"
#include "debug/express.h"
@@ -54,6 +76,7 @@
#define CHEAT_VERSION 1
#define DEFAULT_TEMP_VARIABLES 10
+#define MAX_ARGUMENTS 32
enum _script_state
{
@@ -85,11 +108,12 @@ struct _parameter_item
typedef struct _cheat_parameter cheat_parameter;
struct _cheat_parameter
{
- astring * name; /* name of the parameter */
UINT64 minval; /* minimum value */
UINT64 maxval; /* maximum value */
UINT64 stepval; /* step value */
+ UINT64 defval; /* default value */
UINT64 value; /* live value of the parameter */
+ char valuestring[32]; /* small space for a value string */
parameter_item * itemlist; /* list of items */
};
@@ -133,10 +157,13 @@ 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[1]; /* value of the temporary variables */
};
@@ -145,6 +172,11 @@ struct _cheat_entry
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; /* nnumber of lines available for output */
+ INT8 lastline; /* last line used for output */
};
@@ -154,11 +186,13 @@ struct _cheat_private
***************************************************************************/
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(const char *filename);
+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(cheat_entry *cheat);
-static cheat_entry *cheat_entry_load(const char *filename, xml_data_node *cheatnode);
+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(cheat_entry *cheat);
static cheat_parameter *cheat_parameter_load(const char *filename, xml_data_node *paramnode);
@@ -171,7 +205,7 @@ static script_entry *script_entry_load(const char *filename, xml_data_node *entr
static void script_entry_save(mame_file *cheatfile, const script_entry *entry);
static void script_entry_free(script_entry *entry);
-static astring *quote_astring(astring *string, int isattribute);
+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 *ref);
static void cheat_variable_set(void *ref, UINT64 value);
@@ -198,6 +232,7 @@ void cheat_init(running_machine *machine)
cheat_private *cheatinfo;
/* request a callback */
+ add_frame_callback(machine, cheat_frame);
add_exit_callback(machine, cheat_exit);
/* allocate memory */
@@ -206,7 +241,7 @@ void cheat_init(running_machine *machine)
machine->cheat_data = cheatinfo;
/* load the cheat file */
- cheatinfo->cheatlist = cheat_list_load(machine->basename);
+ cheatinfo->cheatlist = cheat_list_load(machine, machine->basename);
/* temporary: save the file back out as output.xml for comparison */
if (cheatinfo->cheatlist != NULL)
@@ -221,10 +256,353 @@ void cheat_init(running_machine *machine)
static void cheat_exit(running_machine *machine)
{
cheat_private *cheatinfo = machine->cheat_data;
+ int linenum;
/* free the list of cheats */
if (cheatinfo->cheatlist != NULL)
cheat_list_free(cheatinfo->cheatlist);
+
+ /* free any text strings */
+ for (linenum = 0; linenum < ARRAY_LENGTH(cheatinfo->output); linenum++)
+ if (cheatinfo->output[linenum] != NULL)
+ astring_free(cheatinfo->output[linenum]);
+}
+
+
+
+/***************************************************************************
+ CHEAT UI
+***************************************************************************/
+
+/*-------------------------------------------------
+ cheat_render_text - called by the UI system
+ to render text
+-------------------------------------------------*/
+
+void cheat_render_text(running_machine *machine)
+{
+ cheat_private *cheatinfo = machine->cheat_data;
+ if (cheatinfo != NULL)
+ {
+ int linenum;
+
+ /* render any text and free it along the way */
+ for (linenum = 0; linenum < ARRAY_LENGTH(cheatinfo->output); linenum++)
+ if (cheatinfo->output[linenum] != NULL)
+ {
+ /* output the text */
+ ui_draw_text_full(astring_c(cheatinfo->output[linenum]),
+ 0.0f, (float)linenum * ui_get_line_height(), 1.0f,
+ cheatinfo->justify[linenum], WRAP_NEVER, DRAW_OPAQUE,
+ ARGB_WHITE, ARGB_BLACK, NULL, NULL);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ 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 = previous;
+ cheat_entry *cheat;
+
+ /* NULL previous means get the first */
+ cheat = (preventry == NULL) ? cheatinfo->cheatlist : preventry->next;
+ if (cheat == NULL)
+ return NULL;
+
+ /* description is standard */
+ if (description != NULL)
+ *description = astring_c(cheat->description);
+
+ /* if we have no parameter, it's just on/off */
+ if (cheat->parameter == NULL)
+ {
+ 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;
+ }
+
+ /* if we have a value parameter, compute it */
+ else if (cheat->parameter->itemlist == NULL)
+ {
+ if (state != NULL)
+ {
+ sprintf(cheat->parameter->valuestring, "%d", (UINT32)cheat->parameter->value);
+ *state = cheat->parameter->valuestring;
+ }
+ if (flags != NULL)
+ {
+ *flags = 0;
+ if (cheat->parameter->value > cheat->parameter->minval)
+ *flags |= MENU_FLAG_LEFT_ARROW;
+ if (cheat->parameter->value < cheat->parameter->maxval)
+ *flags |= MENU_FLAG_RIGHT_ARROW;
+ }
+ }
+
+ /* if we have an item list, pick the index */
+ else
+ {
+ 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 (state != NULL)
+ *state = (item != NULL) ? astring_c(item->text) : "??Invalid??";
+ if (flags != NULL)
+ {
+ *flags = 0;
+ if (item == NULL || prev != NULL)
+ *flags |= MENU_FLAG_LEFT_ARROW;
+ if (item == NULL || item->next != NULL)
+ *flags |= MENU_FLAG_RIGHT_ARROW;
+ }
+ }
+
+ /* return a pointer to this item */
+ return cheat;
+}
+
+
+/*-------------------------------------------------
+ cheat_select_previous_state - select the
+ previous state for a cheat
+-------------------------------------------------*/
+
+int cheat_select_previous_state(running_machine *machine, void *entry)
+{
+ cheat_private *cheatinfo = machine->cheat_data;
+ cheat_entry *cheat = entry;
+ int changed = FALSE;
+
+ /* if we have no parameter, it's just on/off */
+ if (cheat->parameter == NULL)
+ {
+ if (cheat->state != SCRIPT_STATE_OFF)
+ {
+ cheat->state = SCRIPT_STATE_OFF;
+ cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_OFF);
+ changed = TRUE;
+ }
+ }
+
+ /* if we have a value parameter, compute it */
+ else if (cheat->parameter->itemlist == 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;
+ cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
+ changed = TRUE;
+ }
+ }
+
+ /* if we have an item list, pick the index */
+ else
+ {
+ 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)
+ {
+ cheat->parameter->value = prev->value;
+ cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
+ changed = TRUE;
+ }
+ }
+ return changed;
+}
+
+
+/*-------------------------------------------------
+ cheat_select_next_state - select the
+ next state for a cheat
+-------------------------------------------------*/
+
+int cheat_select_next_state(running_machine *machine, void *entry)
+{
+ cheat_private *cheatinfo = machine->cheat_data;
+ cheat_entry *cheat = entry;
+ int changed = FALSE;
+
+ /* if we have no parameter, it's just on/off */
+ if (cheat->parameter == NULL)
+ {
+ if (cheat->state != SCRIPT_STATE_RUN)
+ {
+ cheat->state = SCRIPT_STATE_RUN;
+ cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_ON);
+ changed = TRUE;
+ }
+ }
+
+ /* if we have a value parameter, compute it */
+ else if (cheat->parameter->itemlist == NULL)
+ {
+ 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;
+ cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
+ changed = TRUE;
+ }
+ }
+
+ /* if we have an item list, pick the index */
+ else
+ {
+ parameter_item *item;
+
+ 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;
+ cheat_execute_script(cheatinfo, cheat, SCRIPT_STATE_CHANGE);
+ changed = TRUE;
+ }
+ }
+ return changed;
+}
+
+
+
+/***************************************************************************
+ CHEAT EXECUTION
+***************************************************************************/
+
+/*-------------------------------------------------
+ cheat_frame - per-frame callback
+-------------------------------------------------*/
+
+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());
+ cheatinfo->numlines = MIN(cheatinfo->numlines, ARRAY_LENGTH(cheatinfo->output));
+ for (linenum = 0; linenum < ARRAY_LENGTH(cheatinfo->output); linenum++)
+ if (cheatinfo->output[linenum] != NULL)
+ {
+ astring_free(cheatinfo->output[linenum]);
+ cheatinfo->output[linenum] = NULL;
+ }
+
+ /* 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++;
+}
+
+
+/*-------------------------------------------------
+ cheat_execute_script - execute the
+ appropriate script
+-------------------------------------------------*/
+
+static void cheat_execute_script(cheat_private *cheatinfo, cheat_entry *cheat, script_state state)
+{
+ script_entry *entry;
+
+ /* if no script, bail */
+ if (cheat->script[state] == NULL)
+ return;
+
+ /* iterate over entries */
+ for (entry = cheat->script[state]->entrylist; entry != NULL; entry = entry->next)
+ {
+ EXPRERR error;
+ UINT64 result;
+
+ /* 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));
+
+ /* 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));
+ }
+
+ /* if there is a string to display, compute it */
+ if (entry->format != NULL)
+ {
+ UINT64 params[MAX_ARGUMENTS];
+ output_argument *arg;
+ astring *string;
+ 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 */
+ string = cheatinfo->output[row];
+ if (string == NULL)
+ string = cheatinfo->output[row] = astring_alloc();
+ cheatinfo->justify[row] = entry->justify;
+
+ /* generate the astring */
+ astring_printf(string, astring_c(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]);
+ }
+ }
}
@@ -238,7 +616,7 @@ static void cheat_exit(running_machine *machine)
memory and create the cheat entry list
-------------------------------------------------*/
-static cheat_entry *cheat_list_load(const char *filename)
+static cheat_entry *cheat_list_load(running_machine *machine, const char *filename)
{
xml_data_node *rootnode, *mamecheatnode, *cheatnode;
cheat_entry *cheatlist = NULL;
@@ -294,7 +672,7 @@ static cheat_entry *cheat_list_load(const char *filename)
for (cheatnode = xml_get_sibling(mamecheatnode->child, "cheat"); cheatnode != NULL; cheatnode = xml_get_sibling(cheatnode->next, "cheat"))
{
/* load this entry */
- cheat_entry *curcheat = cheat_entry_load(filename, cheatnode);
+ cheat_entry *curcheat = cheat_entry_load(machine, filename, cheatnode);
if (curcheat == NULL)
goto error;
@@ -371,9 +749,10 @@ static void cheat_list_free(cheat_entry *cheat)
structures
-------------------------------------------------*/
-static cheat_entry *cheat_entry_load(const char *filename, xml_data_node *cheatnode)
+static cheat_entry *cheat_entry_load(running_machine *machine, const char *filename, xml_data_node *cheatnode)
{
- xml_data_node *paramnode, *scriptnode;
+ cheat_private *cheatinfo = machine->cheat_data;
+ xml_data_node *paramnode, *scriptnode, *commentnode;
const char *description;
int tempcount, curtemp;
cheat_entry *cheat;
@@ -402,6 +781,8 @@ static cheat_entry *cheat_entry_load(const char *filename, xml_data_node *cheatn
/* create the symbol table */
cheat->symbols = symtable_alloc(NULL);
+ 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];
@@ -409,6 +790,19 @@ static cheat_entry *cheat_entry_load(const char *filename, xml_data_node *cheatn
symtable_add_register(cheat->symbols, tempname, &cheat->tempvar[curtemp], cheat_variable_get, cheat_variable_set);
}
+ /* 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 = astring_dupc(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);
+ }
+
/* read the first parameter node */
paramnode = xml_get_sibling(cheatnode->child, "parameter");
if (paramnode != NULL)
@@ -420,7 +814,7 @@ static cheat_entry *cheat_entry_load(const char *filename, xml_data_node *cheatn
/* set this as the parameter and add the symbol */
cheat->parameter = curparam;
- symtable_add_register(cheat->symbols, astring_c(curparam->name), &curparam->value, cheat_variable_get, cheat_variable_set);
+ symtable_add_register(cheat->symbols, "param", &curparam->value, cheat_variable_get, NULL);
/* only one parameter allowed */
paramnode = xml_get_sibling(paramnode->next, "parameter");
@@ -444,6 +838,9 @@ static cheat_entry *cheat_entry_load(const char *filename, xml_data_node *cheatn
else
cheat->script[curscript->state] = curscript;
}
+
+ /* set the initial state */
+ cheat->state = (cheat->parameter != NULL) ? SCRIPT_STATE_RUN : SCRIPT_STATE_OFF;
return cheat;
error:
@@ -453,8 +850,8 @@ error:
/*-------------------------------------------------
- cheat_entry_save - save a single cheat
- entry
+ cheat_entry_save - save a single cheat
+ entry
-------------------------------------------------*/
static void cheat_entry_save(mame_file *cheatfile, const cheat_entry *cheat)
@@ -466,6 +863,10 @@ static void cheat_entry_save(mame_file *cheatfile, const cheat_entry *cheat)
if (cheat->numtemp != DEFAULT_TEMP_VARIABLES)
mame_fprintf(cheatfile, " tempvariables=\"%d\"", cheat->numtemp);
mame_fprintf(cheatfile, ">\n");
+
+ /* save the comment */
+ if (cheat->comment != NULL)
+ mame_fprintf(cheatfile, "\t\t<comment><![CDATA[\n%s\n\t\t]]></comment>\n", astring_c(cheat->comment));
/* output the parameter, if present */
if (cheat->parameter != NULL)
@@ -482,7 +883,7 @@ static void cheat_entry_save(mame_file *cheatfile, const cheat_entry *cheat)
/*-------------------------------------------------
- cheat_entry_free - free a single cheat entry
+ cheat_entry_free - free a single cheat entry
-------------------------------------------------*/
static void cheat_entry_free(cheat_entry *cheat)
@@ -492,6 +893,9 @@ static void cheat_entry_free(cheat_entry *cheat)
if (cheat->description != NULL)
astring_free(cheat->description);
+ if (cheat->comment != NULL)
+ astring_free(cheat->comment);
+
if (cheat->parameter != NULL)
cheat_parameter_free(cheat->parameter);
@@ -507,9 +911,9 @@ static void cheat_entry_free(cheat_entry *cheat)
/*-------------------------------------------------
- cheat_parameter_load - load a single cheat
- parameter and create the underlying data
- structures
+ cheat_parameter_load - load a single cheat
+ parameter and create the underlying data
+ structures
-------------------------------------------------*/
static cheat_parameter *cheat_parameter_load(const char *filename, xml_data_node *paramnode)
@@ -523,10 +927,10 @@ static cheat_parameter *cheat_parameter_load(const char *filename, xml_data_node
memset(param, 0, sizeof(*param));
/* read the core attributes */
- param->name = astring_dupc(xml_get_attribute_string(paramnode, "variable", "param"));
param->minval = xml_get_attribute_int(paramnode, "min", 0);
param->maxval = xml_get_attribute_int(paramnode, "max", 0);
param->stepval = xml_get_attribute_int(paramnode, "step", 1);
+ param->defval = xml_get_attribute_int(paramnode, "default", param->minval);
/* iterate over items */
itemtailptr = &param->itemlist;
@@ -553,11 +957,20 @@ static cheat_parameter *cheat_parameter_load(const char *filename, xml_data_node
goto error;
}
curitem->value = xml_get_attribute_int(itemnode, "value", 0);
+
+ /* 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;
}
+
+ /* if no default, pick the minimum */
+ if (xml_get_attribute_string(paramnode, "default", NULL) == NULL)
+ param->defval = (param->itemlist != NULL) ? param->itemlist->value : param->minval;
+ param->value = param->defval;
+
return param;
error:
@@ -574,7 +987,7 @@ error:
static void cheat_parameter_save(mame_file *cheatfile, const cheat_parameter *param)
{
/* output the parameter tag */
- mame_fprintf(cheatfile, "\t\t<parameter variable=\"%s\"", astring_c(param->name));
+ mame_fprintf(cheatfile, "\t\t<parameter");
/* if no items, just output min/max/step */
if (param->itemlist == NULL)
@@ -585,6 +998,7 @@ static void cheat_parameter_save(mame_file *cheatfile, const cheat_parameter *pa
mame_fprintf(cheatfile, " max=\"%d\"", (UINT32)param->maxval);
if (param->stepval != 1)
mame_fprintf(cheatfile, " step=\"%d\"", (UINT32)param->stepval);
+ mame_fprintf(cheatfile, " default=\"%d\"", (UINT32)param->defval);
mame_fprintf(cheatfile, "/>\n");
}
@@ -593,7 +1007,7 @@ static void cheat_parameter_save(mame_file *cheatfile, const cheat_parameter *pa
{
const parameter_item *curitem;
- mame_fprintf(cheatfile, ">\n");
+ mame_fprintf(cheatfile, " default=\"%d\">\n", (UINT32)param->defval);
for (curitem = param->itemlist; curitem != NULL; curitem = curitem->next)
mame_fprintf(cheatfile, "\t\t\t<item value=\"%d\">%s</item>\n", (UINT32)curitem->value, astring_c(curitem->text));
mame_fprintf(cheatfile, "\t\t</parameter>\n");
@@ -608,9 +1022,6 @@ static void cheat_parameter_save(mame_file *cheatfile, const cheat_parameter *pa
static void cheat_parameter_free(cheat_parameter *param)
{
- if (param->name != NULL)
- astring_free(param->name);
-
while (param->itemlist != NULL)
{
parameter_item *item = param->itemlist;
@@ -674,8 +1085,8 @@ static cheat_script *cheat_script_load(const char *filename, xml_data_node *scri
/* anything else is ignored */
else
{
- mame_printf_warning("%s.xml(%d): unknown script item '%s' will be lost if saved\n", filename, curentry->line, entrynode->name);
- goto error;
+ 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)
@@ -792,6 +1203,7 @@ static script_entry *script_entry_load(const char *filename, xml_data_node *entr
output_argument **argtailptr;
const char *align, *format;
xml_data_node *argnode;
+ int totalargs = 0;
/* extract format */
format = xml_get_attribute_string(entrynode, "format", NULL);
@@ -828,6 +1240,7 @@ static script_entry *script_entry_load(const char *filename, xml_data_node *entr
/* first extract attributes */
curarg->count = xml_get_attribute_int(argnode, "count", 1);
+ totalargs += curarg->count;
/* read the expression */
expression = argnode->value;
@@ -847,6 +1260,13 @@ static script_entry *script_entry_load(const char *filename, xml_data_node *entr
*argtailptr = curarg;
argtailptr = &curarg->next;
}
+
+ /* 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;
+ }
/* validate the format against the arguments */
if (!validate_format(filename, entrynode->line, entry))
@@ -861,8 +1281,8 @@ error:
/*-------------------------------------------------
- script_entry_save - save a single action
- or output
+ script_entry_save - save a single action
+ or output
-------------------------------------------------*/
static void script_entry_save(mame_file *cheatfile, const script_entry *entry)
@@ -875,10 +1295,10 @@ static void script_entry_save(mame_file *cheatfile, const script_entry *entry)
mame_fprintf(cheatfile, "\t\t\t<action");
if (entry->condition != NULL)
{
- quote_astring(astring_cpyc(tempstring, expression_original_string(entry->condition)), TRUE);
+ quote_astring_expression(astring_cpyc(tempstring, expression_original_string(entry->condition)), TRUE);
mame_fprintf(cheatfile, " condition=\"%s\"", astring_c(tempstring));
}
- quote_astring(astring_cpyc(tempstring, expression_original_string(entry->expression)), FALSE);
+ quote_astring_expression(astring_cpyc(tempstring, expression_original_string(entry->expression)), FALSE);
mame_fprintf(cheatfile, ">%s</action>\n", astring_c(tempstring));
}
@@ -888,7 +1308,7 @@ static void script_entry_save(mame_file *cheatfile, const script_entry *entry)
mame_fprintf(cheatfile, "\t\t\t<output format=\"%s\"", astring_c(entry->format));
if (entry->condition != NULL)
{
- quote_astring(astring_cpyc(tempstring, expression_original_string(entry->condition)), TRUE);
+ quote_astring_expression(astring_cpyc(tempstring, expression_original_string(entry->condition)), TRUE);
mame_fprintf(cheatfile, " condition=\"%s\"", astring_c(tempstring));
}
if (entry->line != 0)
@@ -911,7 +1331,7 @@ static void script_entry_save(mame_file *cheatfile, const script_entry *entry)
mame_fprintf(cheatfile, "\t\t\t\t<argument");
if (curarg->count != 1)
mame_fprintf(cheatfile, " count=\"%d\"", (int)curarg->count);
- quote_astring(astring_cpyc(tempstring, expression_original_string(curarg->expression)), FALSE);
+ quote_astring_expression(astring_cpyc(tempstring, expression_original_string(curarg->expression)), FALSE);
mame_fprintf(cheatfile, ">%s</argument>\n", astring_c(tempstring));
}
mame_fprintf(cheatfile, "\t\t\t</output>\n");
@@ -923,8 +1343,8 @@ static void script_entry_save(mame_file *cheatfile, const script_entry *entry)
/*-------------------------------------------------
- script_entry_free - free a single script
- entry
+ script_entry_free - free a single script
+ entry
-------------------------------------------------*/
static void script_entry_free(script_entry *entry)
@@ -956,23 +1376,33 @@ static void script_entry_free(script_entry *entry)
***************************************************************************/
/*-------------------------------------------------
- quote_astring - quote a string so that it
- is valid to embed in an XML document
+ quote_astring_expression - quote an expression
+ string so that it is valid to embed in an XML
+ document
-------------------------------------------------*/
-static astring *quote_astring(astring *string, int isattribute)
+static astring *quote_astring_expression(astring *string, int isattribute)
{
- astring_replacec(string, 0, "&", "&amp;");
- astring_replacec(string, 0, "<", "&lt;");
if (isattribute)
- astring_replacec(string, 0, "\"", "&quot;");
+ {
+ astring_replacec(string, 0, "&", "&amp;");
+ astring_replacec(string, 0, "<", "&lt;");
+ }
+ else
+ {
+ if (astring_chr(string, 0, '&') != -1 || astring_chr(string, 0, '<') != -1)
+ {
+ astring_insc(string, 0, "<![CDATA[ ");
+ astring_catc(string, " ]]>");
+ }
+ }
return string;
}
/*-------------------------------------------------
- validate_format - check that a format string
- has the correct number and type of arguments
+ 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)
diff --git a/src/emu/cheat.h b/src/emu/cheat.h
index ee73cddf8ae..45f4197f434 100644
--- a/src/emu/cheat.h
+++ b/src/emu/cheat.h
@@ -16,6 +16,33 @@
#include "mamecore.h"
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- core system management ----- */
+
+/* initialize the cheat system, loading any cheat files */
void cheat_init(running_machine *machine);
+
+
+/* ----- cheat UI helpers ----- */
+
+/* render any text overlays */
+void cheat_render_text(running_machine *machine);
+
+/* 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);
+
+/* select the previous menu state */
+int cheat_select_previous_state(running_machine *machine, void *entry);
+
+/* select the next menu state */
+int cheat_select_next_state(running_machine *machine, void *entry);
+
+
#endif /* __CHEAT_H__ */
diff --git a/src/emu/ui.c b/src/emu/ui.c
index 1c648a8c5c5..f042ecfcf88 100644
--- a/src/emu/ui.c
+++ b/src/emu/ui.c
@@ -429,6 +429,9 @@ void ui_update_and_render(running_machine *machine)
if (alpha >= 0)
render_ui_add_rect(0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(alpha,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
+
+ /* render any cheat stuff at the bottom */
+ cheat_render_text(machine);
/* call the current UI handler */
assert(ui_handler_callback != NULL);
diff --git a/src/emu/ui.h b/src/emu/ui.h
index a512573ad62..18410b2de9e 100644
--- a/src/emu/ui.h
+++ b/src/emu/ui.h
@@ -24,7 +24,8 @@
***************************************************************************/
/* preferred font height; use ui_get_line_height() to get actual height */
-#define UI_TARGET_FONT_HEIGHT (1.0f / 25.0f)
+#define UI_TARGET_FONT_ROWS (25)
+#define UI_TARGET_FONT_HEIGHT (1.0f / (float)UI_TARGET_FONT_ROWS)
#define UI_MAX_FONT_HEIGHT (1.0f / 15.0f)
/* width of lines drawn in the UI */
diff --git a/src/emu/uimenu.c b/src/emu/uimenu.c
index 269e0348de2..408fc7d54f1 100644
--- a/src/emu/uimenu.c
+++ b/src/emu/uimenu.c
@@ -271,6 +271,8 @@ static void menu_bookkeeping(running_machine *machine, ui_menu *menu, void *para
static void menu_bookkeeping_populate(running_machine *machine, ui_menu *menu, attotime *curtime);
#endif
static void menu_game_info(running_machine *machine, ui_menu *menu, void *parameter, void *state);
+static void menu_cheat(running_machine *machine, ui_menu *menu, void *parameter, void *state);
+static void menu_cheat_populate(running_machine *machine, ui_menu *menu);
static void menu_memory_card(running_machine *machine, ui_menu *menu, void *parameter, void *state);
static void menu_memory_card_populate(running_machine *machine, ui_menu *menu, int cardnum);
static void menu_video_targets(running_machine *machine, ui_menu *menu, void *parameter, void *state);
@@ -1459,8 +1461,8 @@ static void menu_main_populate(running_machine *machine, ui_menu *menu, void *st
ui_menu_item_append(menu, "Video Options", NULL, 0, (render_target_get_indexed(1) != NULL) ? menu_video_targets : menu_video_options);
/* add cheat menu */
-// if (options_get_bool(mame_options(), OPTION_CHEAT))
-// ui_menu_item_append(menu, "Cheat", NULL, 0, menu_cheat);
+ if (options_get_bool(mame_options(), OPTION_CHEAT) && cheat_get_next_menu_entry(machine, NULL, NULL, NULL, NULL) != NULL)
+ ui_menu_item_append(menu, "Cheat", NULL, 0, menu_cheat);
/* add memory card menu */
if (machine->config->memcard_handler != NULL)
@@ -2416,6 +2418,70 @@ static void menu_game_info(running_machine *machine, ui_menu *menu, void *parame
/*-------------------------------------------------
+ menu_cheat - handle the cheat menu
+-------------------------------------------------*/
+
+static void menu_cheat(running_machine *machine, ui_menu *menu, void *parameter, void *state)
+{
+ const ui_menu_event *event;
+
+ /* if the menu isn't built, populate now */
+ if (!ui_menu_populated(menu))
+ menu_cheat_populate(machine, menu);
+
+ /* process the menu */
+ event = ui_menu_process(menu, UI_MENU_PROCESS_LR_REPEAT);
+
+ /* handle events */
+ if (event != NULL && event->itemref != NULL)
+ {
+ int changed = FALSE;
+
+ switch (event->iptkey)
+ {
+ /* if selected, reset to default value */
+ case IPT_UI_SELECT:
+ break;
+
+ /* left decrements */
+ case IPT_UI_LEFT:
+ changed = cheat_select_previous_state(machine, event->itemref);
+ break;
+
+ /* right increments */
+ case IPT_UI_RIGHT:
+ changed = cheat_select_next_state(machine, event->itemref);
+ break;
+ }
+
+ /* if things changed, update */
+ if (changed)
+ ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_REF);
+ }
+}
+
+
+/*-------------------------------------------------
+ menu_cheat_populate - populate the cheat menu
+-------------------------------------------------*/
+
+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))
+ {
+ ui_menu_item_append(menu, text, subtext, flags, curcheat);
+ }
+}
+
+
+/*-------------------------------------------------
menu_memory_card - handle the memory card
menu
-------------------------------------------------*/