// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
cheat.h
Cheat system.
***************************************************************************/
#ifndef MAME_FRONTEND_CHEAT_H
#define MAME_FRONTEND_CHEAT_H
#pragma once
#include "debug/express.h"
#include "debug/debugcpu.h"
#include "ui/text.h"
#include "xmlfile.h"
//**************************************************************************
// CONSTANTS
//**************************************************************************
enum script_state
{
SCRIPT_STATE_OFF = 0,
SCRIPT_STATE_ON,
SCRIPT_STATE_RUN,
SCRIPT_STATE_CHANGE,
SCRIPT_STATE_COUNT
};
DECLARE_ENUM_INCDEC_OPERATORS(script_state)
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class cheat_manager;
class mame_ui_manager;
// ======================> number_and_format
// helper class to remember a format along with a number
class number_and_format
{
public:
// construction/destruction
constexpr number_and_format(
uint64_t value = 0,
util::xml::data_node::int_format format = util::xml::data_node::int_format::DECIMAL)
: m_value(value)
, m_format(format)
{
}
// copyable/movable
constexpr number_and_format(number_and_format const &) = default;
number_and_format(number_and_format &&) = default;
number_and_format &operator=(number_and_format const &) = default;
number_and_format &operator=(number_and_format &&) = default;
// pass-through to look like a regular number
operator uint64_t &() { return m_value; }
operator const uint64_t &() const { return m_value; }
// format the number according to its format
std::string format() const;
private:
// internal state
uint64_t m_value;
util::xml::data_node::int_format 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,
char const *filename,
util::xml::data_node const ¶mnode);
// queries
char const *text();
bool has_itemlist() const { return !m_itemlist.empty(); }
bool is_minimum() const { return (m_itemlist.empty() ? m_minval : m_itemlist.front().value()) == m_value; }
bool is_maximum() const { return (m_itemlist.empty() ? m_maxval : m_itemlist.back().value()) == m_value; }
// state setters
bool set_minimum_state();
bool set_prev_state();
bool set_next_state();
// actions
void save(emu_file &cheatfile) const;
private:
// a single item in a parameter item list
class item
{
public:
// construction/destruction
item(const char *text, uint64_t value, util::xml::data_node::int_format valformat)
: m_text(text)
, m_value(value, valformat)
{
}
// copyable/movable
item(item const &) = default;
item(item &&) = default;
item &operator=(item const &) = default;
item &operator=(item &&) = default;
// getters
number_and_format const &value() const { return m_value; }
char const *text() const { return m_text.c_str(); }
private:
// internal state
std::string m_text; // name of the item
number_and_format m_value; // value of the item
};
// internal state
number_and_format m_minval; // minimum value
number_and_format m_maxval; // maximum value
number_and_format m_stepval; // step value
uint64_t m_value; // live value of the parameter
std::string m_curtext; // holding for a value string
std::vector<item> m_itemlist; // list of items
};
// ======================> cheat_script
// a script entry, specifying which state to execute under
class cheat_script
{
public:
// construction/destruction
cheat_script(
cheat_manager &manager,
symbol_table &symbols,
char const *filename,
util::xml::data_node const &scriptnode);
// getters
script_state state() const { return m_state; }
// actions
void execute(cheat_manager &manager, uint64_t &argindex);
void save(emu_file &cheatfile) const;
private:
// an entry within the script
class script_entry
{
public:
// construction/destruction
script_entry(
cheat_manager &manager,
symbol_table &symbols,
char const *filename,
util::xml::data_node const &entrynode,
bool isaction);
// actions
void execute(cheat_manager &manager, uint64_t &argindex);
void save(emu_file &cheatfile) const;
private:
// an argument for output
class output_argument
{
public:
// construction/destruction
output_argument(
cheat_manager &manager,
symbol_table &symbols,
char const *filename,
util::xml::data_node const &argnode);
// getters
int count() const { return m_count; }
int values(uint64_t &argindex, uint64_t *result);
// actions
void save(emu_file &cheatfile) const;
private:
// internal state
parsed_expression m_expression; // expression for argument
uint64_t m_count; // number of repetitions
};
// internal helpers
void validate_format(char const *filename, int line);
// internal state
parsed_expression m_condition; // condition under which this is executed
parsed_expression m_expression; // expression to execute
std::string m_format; // string format to print
std::vector<std::unique_ptr<output_argument>> m_arglist; // list of arguments
int8_t m_line; // which line to print on
ui::text_layout::text_justify m_justify; // justification when printing
// constants
static constexpr int MAX_ARGUMENTS = 32;
};
// internal state
std::vector<std::unique_ptr<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
{
public:
// construction/destruction
cheat_entry(cheat_manager &manager, symbol_table &globaltable, const char *filename, util::xml::data_node const &cheatnode);
~cheat_entry();
// getters
cheat_manager &manager() const { return m_manager; }
script_state state() const { return m_state; }
const char *description() const { return m_description.c_str(); }
const char *comment() const { return m_comment.c_str(); }
// script detection
bool has_run_script() const { return (m_run_script != nullptr); }
bool has_on_script() const { return (m_on_script != nullptr); }
bool has_off_script() const { return (m_off_script != nullptr); }
bool has_change_script() const { return (m_change_script != nullptr); }
// 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 == nullptr && !has_run_script() && !has_off_script() && !has_on_script()); }
bool is_oneshot() const { return (m_parameter == nullptr && !has_run_script() && !has_off_script() && has_on_script()); }
bool is_onoff() const { return (m_parameter == nullptr && (has_run_script() || (has_off_script() && has_on_script()))); }
bool is_value_parameter() const { return (m_parameter != nullptr && !m_parameter->has_itemlist()); }
bool is_itemlist_parameter() const { return (m_parameter != nullptr && m_parameter->has_itemlist()); }
bool is_oneshot_parameter() const { return (m_parameter != nullptr && !has_run_script() && !has_off_script() && has_change_script()); }
bool is_duplicate() const;
// actions
bool activate();
bool select_default_state();
bool select_previous_state();
bool select_next_state();
void save(emu_file &cheatfile) const;
// UI helpers
void menu_text(std::string &description, std::string &state, uint32_t &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);
std::unique_ptr<cheat_script> &script_for_state(script_state state);
// internal state
cheat_manager & m_manager; // reference to our manager
std::string m_description; // string description/menu title
std::string m_comment; // comment data
std::unique_ptr<cheat_parameter> m_parameter; // parameter
std::unique_ptr<cheat_script> m_on_script; // script to run when turning on
std::unique_ptr<cheat_script> m_off_script; // script to run when turning off
std::unique_ptr<cheat_script> m_change_script; // script to run when value changes
std::unique_ptr<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_t m_numtemp; // number of temporary variables
uint64_t m_argindex; // argument index variable
// constants
static constexpr int DEFAULT_TEMP_VARIABLES = 10;
};
// ======================> cheat_manager
// private machine-global data
class cheat_manager
{
public:
// construction/destruction
cheat_manager(running_machine &machine);
// getters
running_machine &machine() const { return m_machine; }
bool enabled() const { return !m_disabled; }
std::vector<std::unique_ptr<cheat_entry>> const &entries() const { return m_cheatlist; }
// setters
void set_enable(bool enable);
// actions
void reload();
bool save_all(const char *filename);
void render_text(mame_ui_manager &mui, render_container &container);
// output helpers
std::string &get_output_string(int row, ui::text_layout::text_justify justify);
// global helpers
static std::string quote_expression(parsed_expression const &expression);
static uint64_t execute_frombcd(symbol_table &table, int params, uint64_t const *param);
static uint64_t execute_tobcd(symbol_table &table, int params, uint64_t const *param);
private:
// internal helpers
void frame_update();
void load_cheats(char const *filename);
// internal state
running_machine & m_machine; // reference to our machine
std::vector<std::unique_ptr<cheat_entry>> m_cheatlist; // cheat list
uint64_t m_framecount; // frame count
std::vector<std::string> m_output; // array of output strings
std::vector<ui::text_layout::text_justify> m_justify; // justification for each string
uint8_t m_numlines; // number of lines available for output
int8_t m_lastline; // last line used for output
bool m_disabled; // true if the cheat engine is disabled
symbol_table m_symtable; // global symbol table
std::unique_ptr<debugger_cpu> m_cpu; // debugger interface for cpus/memory
// constants
static constexpr int CHEAT_VERSION = 1;
};
#endif /* MAME_FRONTEND_CHEAT_H */