// 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, std::string 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 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, std::string 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, std::string 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, std::string 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(std::string 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> 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> 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, std::string const &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 &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 m_parameter; // parameter std::unique_ptr m_on_script; // script to run when turning on std::unique_ptr m_off_script; // script to run when turning off std::unique_ptr m_change_script; // script to run when value changes std::unique_ptr 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> const &entries() const { return m_cheatlist; } // setters void set_enable(bool enable); // actions void reload(); bool save_all(std::string const &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(std::string const &filename); // internal state running_machine & m_machine; // reference to our machine std::vector> m_cheatlist; // cheat list uint64_t m_framecount; // frame count std::vector m_output; // array of output strings std::vector 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 m_cpu; // debugger interface for cpus/memory // constants static constexpr int CHEAT_VERSION = 1; }; #endif /* MAME_FRONTEND_CHEAT_H */