cheat_script::cheat_script(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node &scriptnode) : m_entrylist(manager.machine().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); // iterate over nodes within the script for (xml_data_node *entrynode = scriptnode.child; entrynode != NULL; entrynode = entrynode->next) { // handle action nodes if (strcmp(entrynode->name, "action") == 0) m_entrylist.append(*auto_alloc(manager.machine(), script_entry(manager, symbols, filename, *entrynode, true))); // handle output nodes else if (strcmp(entrynode->name, "output") == 0) m_entrylist.append(*auto_alloc(manager.machine(), script_entry(manager, symbols, filename, *entrynode, 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; } } }
cheat_parameter::cheat_parameter(cheat_manager &manager, symbol_table &symbols, const char *filename, xml_data_node ¶mnode) : m_value(0), m_itemlist(manager.machine().respool()) { // read the core attributes m_minval = number_and_format(xml_get_attribute_int(¶mnode, "min", 0), xml_get_attribute_int_format(¶mnode, "min")); m_maxval = number_and_format(xml_get_attribute_int(¶mnode, "max", 0), xml_get_attribute_int_format(¶mnode, "max")); m_stepval = number_and_format(xml_get_attribute_int(¶mnode, "step", 1), xml_get_attribute_int_format(¶mnode, "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); // 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()); } // add a variable to the symbol table for our value symbols.add("param", symbol_table::READ_ONLY, &m_value); }
void cheat_script::execute(cheat_manager &manager, UINT64 &argindex) { // do nothing if disabled if (!manager.enabled()) return; // iterate over entries for (script_entry *entry = m_entrylist.first(); entry != NULL; entry = entry->next()) entry->execute(manager, argindex); }
void cheat_script::execute(cheat_manager &manager, uint64_t &argindex) { // do nothing if disabled if (!manager.enabled()) return; // iterate over entries for (auto &entry : m_entrylist) entry->execute(manager, argindex); }
void cheat_script::script_entry::execute(cheat_manager &manager, UINT64 &argindex) { // evaluate the condition if (!m_condition.is_empty()) { try { UINT64 result = m_condition.execute(); if (result == 0) return; } catch (expression_error &err) { mame_printf_warning("Error executing conditional expression \"%s\": %s\n", m_condition.original_string(), err.code_string()); return; } } // if there is an action, execute it if (!m_expression.is_empty()) { try { m_expression.execute(); } catch (expression_error &err) { mame_printf_warning("Error executing expression \"%s\": %s\n", m_expression.original_string(), err.code_string()); } } // if there is a string to display, compute it if (m_format) { // 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, ¶ms[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]); } }
void cheat_script::script_entry::execute(cheat_manager &manager, uint64_t &argindex) { // evaluate the condition if (!m_condition.is_empty()) { try { uint64_t result = m_condition.execute(); if (result == 0) return; } catch (expression_error &err) { osd_printf_warning("Error executing conditional expression \"%s\": %s\n", m_condition.original_string(), err.code_string()); return; } } // if there is an action, execute it if (!m_expression.is_empty()) { try { m_expression.execute(); } catch (expression_error &err) { osd_printf_warning("Error executing expression \"%s\": %s\n", m_expression.original_string(), err.code_string()); } } // if there is a string to display, compute it if (!m_format.empty()) { // iterate over arguments and evaluate them uint64_t params[MAX_ARGUMENTS]; int curarg = 0; for (auto &arg : m_arglist) curarg += arg->values(argindex, ¶ms[curarg]); // generate the astring manager.get_output_string(m_line, m_justify) = string_format(m_format, (uint32_t)params[0], (uint32_t)params[1], (uint32_t)params[2], (uint32_t)params[3], (uint32_t)params[4], (uint32_t)params[5], (uint32_t)params[6], (uint32_t)params[7], (uint32_t)params[8], (uint32_t)params[9], (uint32_t)params[10], (uint32_t)params[11], (uint32_t)params[12], (uint32_t)params[13], (uint32_t)params[14], (uint32_t)params[15], (uint32_t)params[16], (uint32_t)params[17], (uint32_t)params[18], (uint32_t)params[19], (uint32_t)params[20], (uint32_t)params[21], (uint32_t)params[22], (uint32_t)params[23], (uint32_t)params[24], (uint32_t)params[25], (uint32_t)params[26], (uint32_t)params[27], (uint32_t)params[28], (uint32_t)params[29], (uint32_t)params[30], (uint32_t)params[31]); } }
cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, const char *filename, xml_data_node &cheatnode) : m_manager(manager), m_next(NULL), m_on_script(NULL), m_off_script(NULL), m_change_script(NULL), m_run_script(NULL), m_symbols(&manager.machine(), &globaltable), m_state(SCRIPT_STATE_OFF), m_numtemp(DEFAULT_TEMP_VARIABLES), m_argindex(0) { // 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; // 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.add("argindex", symbol_table::READ_ONLY, &m_argindex); astring tempname; for (int curtemp = 0; curtemp < tempcount; curtemp++) m_symbols.add(tempname.format("temp%d", curtemp), symbol_table::READ_WRITE); // read the first comment node xml_data_node *commentnode = xml_get_sibling(cheatnode.child, "comment"); if (commentnode != NULL) { // 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); } // read the first parameter node xml_data_node *paramnode = xml_get_sibling(cheatnode.child, "parameter"); if (paramnode != NULL) { // load this parameter m_parameter.reset(global_alloc(cheat_parameter(manager, m_symbols, filename, *paramnode))); // 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); } // 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_script *curscript = global_alloc(cheat_script(manager, m_symbols, filename, *scriptnode)); // if we have a script already for this slot, it is an error auto_pointer<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.reset(curscript); } } catch (emu_fatalerror &) { // call our destructor to clean up and re-throw this->~cheat_entry(); throw; } }
cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, const char *filename, xml_data_node const &cheatnode) : m_manager(manager) , m_symbols(&manager.machine(), &globaltable) , m_state(SCRIPT_STATE_OFF) , m_numtemp(DEFAULT_TEMP_VARIABLES) , m_argindex(0) { // reset scripts try { // pull the variable count out ahead of things int tempcount = cheatnode.get_attribute_int("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; // get the description const char *description = cheatnode.get_attribute_string("desc", nullptr); if (description == nullptr || 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.add("argindex", symbol_table::READ_ONLY, &m_argindex); for (int curtemp = 0; curtemp < tempcount; curtemp++) { m_symbols.add(string_format("temp%d", curtemp).c_str(), symbol_table::READ_WRITE); } // read the first comment node xml_data_node const *commentnode = cheatnode.get_child("comment"); if (commentnode != nullptr) { // set the value if not nullptr if (commentnode->get_value() != nullptr && commentnode->get_value()[0] != 0) m_comment.assign(commentnode->get_value()); // only one comment is kept commentnode = commentnode->get_next_sibling("comment"); if (commentnode != nullptr) osd_printf_warning("%s.xml(%d): only one comment node is retained; ignoring additional nodes\n", filename, commentnode->line); } // read the first parameter node xml_data_node const *paramnode = cheatnode.get_child("parameter"); if (paramnode != nullptr) { // load this parameter m_parameter.reset(global_alloc(cheat_parameter(manager, m_symbols, filename, *paramnode))); // only one parameter allowed paramnode = paramnode->get_next_sibling("parameter"); if (paramnode != nullptr) osd_printf_warning("%s.xml(%d): only one parameter node allowed; ignoring additional nodes\n", filename, paramnode->line); } // read the script nodes for (xml_data_node const *scriptnode = cheatnode.get_child("script"); scriptnode != nullptr; scriptnode = scriptnode->get_next_sibling("script")) { // load this entry auto curscript = global_alloc(cheat_script(manager, m_symbols, filename, *scriptnode)); // if we have a script already for this slot, it is an error std::unique_ptr<cheat_script> &slot = script_for_state(curscript->state()); if (slot != nullptr) osd_printf_warning("%s.xml(%d): only one on script allowed; ignoring additional scripts\n", filename, scriptnode->line); else slot.reset(curscript); } } catch (emu_fatalerror &) { // call our destructor to clean up and re-throw this->~cheat_entry(); throw; } }
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(&symbols), m_expression(&symbols), m_arglist(manager.machine().respool()) { const char *expression = NULL; try { // read the condition if present expression = xml_get_attribute_string(&entrynode, "condition", NULL); if (expression != NULL) m_condition.parse(expression); // 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); m_expression.parse(expression); } // otherwise, parse the attributes and arguments else { // 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); } } catch (expression_error &err) { throw emu_fatalerror("%s.xml(%d): error parsing cheat expression \"%s\" (%s)\n", filename, entrynode.line, expression, err.code_string()); } }