diff --git a/CMakeLists.txt b/CMakeLists.txt index ac8def072c..a6b165adee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,8 +102,6 @@ add_library(${PROJECT_NAME} OBJECT src/drawable_list.h src/drawable_mgr.cpp src/drawable_mgr.h - src/dynrpg.cpp - src/dynrpg.h src/dynrpg_easyrpg.cpp src/dynrpg_easyrpg.h src/dynrpg_textplugin.cpp @@ -163,6 +161,8 @@ add_library(${PROJECT_NAME} OBJECT src/game_config.h src/game_config_game.cpp src/game_config_game.h + src/game_dynrpg.cpp + src/game_dynrpg.h src/game_enemy.cpp src/game_enemy.h src/game_enemyparty.cpp diff --git a/Makefile.am b/Makefile.am index 9426404206..d5baabd68c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -82,8 +82,6 @@ libeasyrpg_player_a_SOURCES = \ src/drawable_list.h \ src/drawable_mgr.cpp \ src/drawable_mgr.h \ - src/dynrpg.cpp \ - src/dynrpg.h \ src/dynrpg_easyrpg.cpp \ src/dynrpg_easyrpg.h \ src/dynrpg_textplugin.h \ @@ -143,6 +141,8 @@ libeasyrpg_player_a_SOURCES = \ src/game_config.h \ src/game_config_game.cpp \ src/game_config_game.h \ + src/game_dynrpg.cpp \ + src/game_dynrpg.h \ src/game_enemy.cpp \ src/game_enemy.h \ src/game_enemyparty.cpp \ diff --git a/src/dynrpg_easyrpg.cpp b/src/dynrpg_easyrpg.cpp index d5ba93e181..1767be3507 100644 --- a/src/dynrpg_easyrpg.cpp +++ b/src/dynrpg_easyrpg.cpp @@ -48,23 +48,23 @@ static bool EasyOput(dyn_arg_list args) { return true; } -static bool EasyCall(dyn_arg_list args) { - auto token = std::get<0>(DynRpg::ParseArgs("call", args)); +bool DynRpg::EasyRpgPlugin::EasyCall(dyn_arg_list args, bool& do_yield, Game_Interpreter* interpreter) { + auto func_name = std::get<0>(DynRpg::ParseArgs("call", args)); - if (token.empty()) { + if (func_name.empty()) { // empty function name Output::Warning("call: Empty RPGSS function name"); return true; } - if (!DynRpg::HasFunction(token)) { - // Not a supported function - Output::Warning("Unsupported RPGSS function: {}", token); - return true; + for (auto& plugin: instance.plugins) { + if (plugin->Invoke(func_name, args.subspan(1), do_yield, interpreter)) { + return true; + } } - return DynRpg::Invoke(token, args.subspan(1)); + return false; } static bool EasyAdd(dyn_arg_list args) { @@ -88,10 +88,15 @@ static bool EasyAdd(dyn_arg_list args) { return true; } -void DynRpg::EasyRpgPlugin::RegisterFunctions() { - DynRpg::RegisterFunction("call", EasyCall); - DynRpg::RegisterFunction("easyrpg_output", EasyOput); - DynRpg::RegisterFunction("easyrpg_add", EasyAdd); +bool DynRpg::EasyRpgPlugin::Invoke(StringView func, dyn_arg_list args, bool& do_yield, Game_Interpreter* interpreter) { + if (func == "call") { + return EasyCall(args, do_yield, interpreter); + } else if (func == "easyrpg_output") { + return EasyOput(args); + } else if (func == "easyrpg_add") { + return EasyAdd(args); + } + return false; } void DynRpg::EasyRpgPlugin::Load(const std::vector& buffer) { diff --git a/src/dynrpg_easyrpg.h b/src/dynrpg_easyrpg.h index 4afd71197b..6e2d9fe05b 100644 --- a/src/dynrpg_easyrpg.h +++ b/src/dynrpg_easyrpg.h @@ -18,7 +18,9 @@ #ifndef EP_DYNRPG_EASYRPG_H #define EP_DYNRPG_EASYRPG_H -#include "dynrpg.h" +#include "game_dynrpg.h" +#include "game_battle.h" +#include "game_map.h" namespace DynRpg { /** @@ -27,11 +29,14 @@ namespace DynRpg { */ class EasyRpgPlugin : public DynRpgPlugin { public: - EasyRpgPlugin() : DynRpgPlugin("EasyRpgPlugin") {} + EasyRpgPlugin(Game_DynRpg& instance) : DynRpgPlugin("EasyRpgPlugin", instance) {} - void RegisterFunctions() override; + bool Invoke(StringView func, dyn_arg_list args, bool& do_yield, Game_Interpreter* interpreter) override; void Load(const std::vector& buffer) override; std::vector Save() override; + + private: + bool EasyCall(dyn_arg_list args, bool& do_yield, Game_Interpreter* interpreter); }; } diff --git a/src/dynrpg_textplugin.cpp b/src/dynrpg_textplugin.cpp index 3a075f1b5a..b041b0353a 100644 --- a/src/dynrpg_textplugin.cpp +++ b/src/dynrpg_textplugin.cpp @@ -138,12 +138,12 @@ class DynRpgText : public Drawable { std::vector Save(const std::string& id) { std::stringstream ss; ss << x << "," << y << ","; - for (size_t i = 0; i < texts.size(); ++i) { + for (int i = 0; i < static_cast(texts.size()); ++i) { std::string t = texts[i]; // Replace , with a sentinel 0x01 to not mess up the tokenizer std::replace(t.begin(), t.end(), ',', '\1'); ss << t; - if (i < texts.size() - 1) { + if (i < static_cast(texts.size()) - 1) { ss << "\n"; } @@ -399,14 +399,23 @@ static bool RemoveAll(dyn_arg_list) { return true; } -void DynRpg::TextPlugin::RegisterFunctions() { - DynRpg::RegisterFunction("write_text", WriteText); - DynRpg::RegisterFunction("append_line", AppendLine); - DynRpg::RegisterFunction("append_text", AppendText); - DynRpg::RegisterFunction("change_text", ChangeText); - DynRpg::RegisterFunction("change_position", ChangePosition); - DynRpg::RegisterFunction("remove_text", RemoveText); - DynRpg::RegisterFunction("remove_all", RemoveAll); +bool DynRpg::TextPlugin::Invoke(StringView func, dyn_arg_list args, bool&, Game_Interpreter*) { + if (func == "write_text") { + return WriteText(args); + } else if (func == "append_line") { + return AppendLine(args); + } else if (func == "append_text") { + return AppendText(args); + } else if (func == "change_text") { + return ChangeText(args); + } else if (func == "change_position") { + return ChangePosition(args); + } else if (func == "remove_text") { + return RemoveText(args); + } else if (func == "remove_all") { + return RemoveAll(args); + } + return false; } void DynRpg::TextPlugin::Update() { diff --git a/src/dynrpg_textplugin.h b/src/dynrpg_textplugin.h index 14c2767218..4a2f165c02 100644 --- a/src/dynrpg_textplugin.h +++ b/src/dynrpg_textplugin.h @@ -18,15 +18,15 @@ #ifndef EP_DYNRPG_TEXTPLUGIN_H #define EP_DYNRPG_TEXTPLUGIN_H -#include "dynrpg.h" +#include "game_dynrpg.h" namespace DynRpg { class TextPlugin : public DynRpgPlugin { public: - TextPlugin() : DynRpgPlugin("DynTextPlugin") {} - ~TextPlugin(); + TextPlugin(Game_DynRpg& instance) : DynRpgPlugin("DynTextPlugin", instance) {} + ~TextPlugin() override; - void RegisterFunctions() override; + bool Invoke(StringView func, dyn_arg_list args, bool& do_yield, Game_Interpreter* interpreter) override; void Update() override; void Load(const std::vector&) override; std::vector Save() override; diff --git a/src/dynrpg.cpp b/src/game_dynrpg.cpp similarity index 82% rename from src/dynrpg.cpp rename to src/game_dynrpg.cpp index 8be59c4fb9..6610808401 100644 --- a/src/dynrpg.cpp +++ b/src/game_dynrpg.cpp @@ -16,9 +16,10 @@ */ // Headers -#include "dynrpg.h" +#include "game_dynrpg.h" #include "filefinder.h" #include "game_actors.h" +#include "game_strings.h" #include "game_variables.h" #include "main_data.h" #include "output.h" @@ -26,7 +27,6 @@ #include #include -#include #include "dynrpg_easyrpg.h" #include "dynrpg_textplugin.h" @@ -39,33 +39,13 @@ enum DynRpg_ParseMode { ParseMode_Token }; -typedef std::map dyn_rpg_func; - -namespace { - bool init = false; - - // Registered DynRpg Plugins - std::vector> plugins; - - // DynRpg Function table - dyn_rpg_func dyn_rpg_functions; -} - -void DynRpg::RegisterFunction(const std::string& name, dynfunc func) { - dyn_rpg_functions[name] = func; -} - -bool DynRpg::HasFunction(const std::string& name) { - return dyn_rpg_functions.find(name) != dyn_rpg_functions.end(); -} - // Var arg referenced by $n std::string DynRpg::ParseVarArg(StringView func_name, dyn_arg_list args, int index, bool& parse_okay) { parse_okay = true; if (index >= static_cast(args.size())) { parse_okay = false; Output::Warning("{}: Vararg {} out of range", func_name, index); - return ""; + return {}; } std::string::iterator text_index, end; @@ -97,7 +77,7 @@ std::string DynRpg::ParseVarArg(StringView func_name, dyn_arg_list args, int ind // $-ref out of range parse_okay = false; Output::Warning("{}: Vararg $-ref {} out of range", func_name, i); - return ""; + return {}; } ++text_index; @@ -113,11 +93,10 @@ std::string DynRpg::ParseVarArg(StringView func_name, dyn_arg_list args, int ind } -static std::string ParseToken(const std::string& token, const std::string& function_name) { +static std::string ParseToken(std::string token, StringView function_name) { std::string::iterator text_index, end; - std::string text = token; - text_index = text.begin(); - end = text.end(); + text_index = token.begin(); + end = token.end(); char chr = *text_index; @@ -129,6 +108,9 @@ static std::string ParseToken(const std::string& token, const std::string& funct std::stringstream number_part; for (;;) { + // This loop checks if the token is to be substituted + // If a token is (regex) [NT]?V+[0-9]+ it is resolved to a var or an actor + // T is an EasyRPG extension: It will return a Maniac Patch String Var if (text_index != end) { chr = *text_index; } @@ -147,11 +129,14 @@ static std::string ParseToken(const std::string& token, const std::string& funct if (*it == 'N') { if (!Main_Data::game_actors->ActorExists(number)) { Output::Warning("{}: Invalid actor id {} in {}", function_name, number, token); - return ""; + return {}; } - // N is last + // N (Actor Name) is last return ToString(Main_Data::game_actors->GetActor(number)->GetName()); + } else if (*it == 'T' && Player::IsPatchManiac()) { + // T (String Var) is last + return ToString(Main_Data::game_strings->Get(number)); } else { // Variable number = Main_Data::game_variables->Get(number); @@ -171,6 +156,11 @@ static std::string ParseToken(const std::string& token, const std::string& funct var_part << chr; } else if (chr == 'V') { var_part << chr; + } else if (chr == 'T' && Player::IsPatchManiac()) { + if (!first) { + break; + } + var_part << chr; } else { break; } @@ -180,36 +170,41 @@ static std::string ParseToken(const std::string& token, const std::string& funct } // Normal token - return Utils::LowerCase(token); + Utils::LowerCaseInPlace(token); + return token; } -void create_all_plugins() { - plugins.emplace_back(new DynRpg::EasyRpgPlugin()); - plugins.emplace_back(new DynRpg::TextPlugin()); - - for (auto& plugin : plugins) { - plugin->RegisterFunctions(); +void Game_DynRpg::InitPlugins() { + if (plugins_loaded) { + return; + } + + if (Player::IsPatchDynRpg() || Player::HasEasyRpgExtensions()) { + plugins.emplace_back(new DynRpg::EasyRpgPlugin(*this)); + } + + if (Player::IsPatchDynRpg()) { + plugins.emplace_back(new DynRpg::TextPlugin(*this)); } - init = true; + plugins_loaded = true; } -std::string DynRpg::ParseCommand(const std::string& command, std::vector& args) { +std::string DynRpg::ParseCommand(std::string command, std::vector& args) { if (command.empty()) { // Not a DynRPG function (empty comment) - return ""; + return {}; } std::string::iterator text_index, end; - std::string text = command; - text_index = text.begin(); - end = text.end(); + text_index = command.begin(); + end = command.end(); char chr = *text_index; if (chr != '@') { // Not a DynRPG function, normal comment - return ""; + return {}; } DynRpg_ParseMode mode = ParseMode_Function; @@ -223,7 +218,6 @@ std::string DynRpg::ParseCommand(const std::string& command, std::vector args; - std::string function_name = ParseCommand(command, args); + std::string function_name = DynRpg::ParseCommand(ToString(command), args); if (function_name.empty()) { return true; } - return Invoke(function_name, args); + return Invoke(function_name, args, interpreter); } -bool DynRpg::Invoke(const std::string& func, dyn_arg_list args) { - if (!init) { - create_all_plugins(); - } +bool Game_DynRpg::Invoke(StringView func, dyn_arg_list args, Game_Interpreter* interpreter) { + InitPlugins(); - if (!DynRpg::HasFunction(func)) { - // Not a supported function - Output::Warning("Unsupported DynRPG function: {}", func); - return true; + bool yield = false; + + for (auto& plugin: plugins) { + if (plugin->Invoke(func, args, yield, interpreter)) { + return !yield; + } } - return dyn_rpg_functions[func](args); + Output::Warning("Unsupported DynRPG function: {}", func); + return true; } std::string get_filename(int slot) { @@ -416,14 +409,12 @@ std::string get_filename(int slot) { return found; } -void DynRpg::Load(int slot) { +void Game_DynRpg::Load(int slot) { if (!Player::IsPatchDynRpg()) { return; } - if (!init) { - create_all_plugins(); - } + InitPlugins(); std::string filename = get_filename(slot); @@ -457,7 +448,7 @@ void DynRpg::Load(int slot) { bool have_one = false; for (auto &plugin : plugins) { - if (strncmp((char*)in_buffer.data(), plugin->GetIdentifier().c_str(), len) == 0) { + if (strncmp((char*)in_buffer.data(), plugin->GetIdentifier().data(), len) == 0) { // Chunk length in.read((char *) &len, 4); Utils::SwapByteOrder(len); @@ -485,14 +476,12 @@ void DynRpg::Load(int slot) { } } -void DynRpg::Save(int slot) { +void Game_DynRpg::Save(int slot) { if (!Player::IsPatchDynRpg()) { return; } - if (!init) { - create_all_plugins(); - } + InitPlugins(); std::string filename = get_filename(slot); @@ -512,7 +501,7 @@ void DynRpg::Save(int slot) { Utils::SwapByteOrder(len); out.write((char*)&len, 4); - out.write(plugin->GetIdentifier().c_str(), len); + out.write(plugin->GetIdentifier().data(), len); std::vector data = plugin->Save(); len = data.size(); @@ -523,14 +512,8 @@ void DynRpg::Save(int slot) { } } -void DynRpg::Update() { +void Game_DynRpg::Update() { for (auto& plugin : plugins) { plugin->Update(); } } - -void DynRpg::Reset() { - init = false; - dyn_rpg_functions.clear(); - plugins.clear(); -} diff --git a/src/dynrpg.h b/src/game_dynrpg.h similarity index 74% rename from src/dynrpg.h rename to src/game_dynrpg.h index adfe9e5a3b..591cf58e9c 100644 --- a/src/dynrpg.h +++ b/src/game_dynrpg.h @@ -15,8 +15,8 @@ * along with EasyRPG Player. If not, see . */ -#ifndef EP_DYNRPG_H -#define EP_DYNRPG_H +#ifndef EP_GAME_DYNRPG_H +#define EP_GAME_DYNRPG_H #include #include @@ -24,23 +24,28 @@ #include #include #include +#include #include "output.h" #include "utils.h" // Headers -namespace lcf { -namespace rpg { +namespace lcf::rpg { class EventCommand; } -} + +class DynRpgPlugin; +class Game_Interpreter; using dyn_arg_list = const Span; using dynfunc = bool(*)(dyn_arg_list); -/** - * DynRPG namespace - */ +/** Contains helper functions for parsing */ namespace DynRpg { + class EasyRpgPlugin; + + std::string ParseVarArg(StringView func_name, dyn_arg_list args, int index, bool& parse_okay); + std::string ParseCommand(std::string command, std::vector& params); + namespace detail { template inline bool parse_arg(StringView, dyn_arg_list, const int, T&, bool&) { @@ -101,16 +106,6 @@ namespace DynRpg { } } - void RegisterFunction(const std::string& name, dynfunc function); - bool HasFunction(const std::string& name); - std::string ParseVarArg(StringView func_name, dyn_arg_list args, int index, bool& parse_okay); - std::string ParseCommand(const std::string& command, std::vector& params); - bool Invoke(const std::string& command); - bool Invoke(const std::string& func, dyn_arg_list args); - void Update(); - void Reset(); - void Load(int slot); - void Save(int slot); template std::tuple ParseArgs(StringView func_name, dyn_arg_list args, bool* parse_okay = nullptr) { @@ -129,18 +124,49 @@ namespace DynRpg { } } +/** + * Implements DynRPG Patch (kinda, plugins cannot be executed directly and must be reimplemented) + */ +class Game_DynRpg { +public: + bool Invoke(StringView command, Game_Interpreter* interpreter = nullptr); + void Update(); + void Load(int slot); + void Save(int slot); + +private: + friend DynRpg::EasyRpgPlugin; + + bool Invoke(StringView func, dyn_arg_list args, Game_Interpreter* interpreter = nullptr); + void InitPlugins(); + + using dyn_rpg_func = std::unordered_map; + + bool plugins_loaded = false; + + // Registered DynRpg Plugins + std::vector> plugins; + + // DynRpg Function table + dyn_rpg_func dyn_rpg_functions; +}; + +/** Base class for implementing a DynRpg Plugins */ class DynRpgPlugin { public: - explicit DynRpgPlugin(std::string identifier) : identifier(std::move(identifier)) {} + explicit DynRpgPlugin(std::string identifier, Game_DynRpg& instance) : instance(instance), identifier(std::move(identifier)) {} DynRpgPlugin() = delete; - virtual ~DynRpgPlugin() {} + virtual ~DynRpgPlugin() = default; - const std::string& GetIdentifier() const { return identifier; } - virtual void RegisterFunctions() {} + StringView GetIdentifier() const { return identifier; } + virtual bool Invoke(StringView func, dyn_arg_list args, bool& do_yield, Game_Interpreter* interpreter) = 0; virtual void Update() {} virtual void Load(const std::vector&) {} virtual std::vector Save() { return {}; } +protected: + Game_DynRpg& instance; + private: std::string identifier; }; diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 98b9edef57..a1b1d589cf 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -27,7 +27,7 @@ #include "game_interpreter.h" #include "async_handler.h" #include "audio.h" -#include "dynrpg.h" +#include "game_dynrpg.h" #include "filefinder.h" #include "game_map.h" #include "game_event.h" @@ -2001,12 +2001,19 @@ bool Game_Interpreter::CommandEndEventProcessing(lcf::rpg::EventCommand const& / } bool Game_Interpreter::CommandComment(const lcf::rpg::EventCommand &com) { - if (Player::IsPatchDynRpg()) { + if (Player::IsPatchDynRpg() || Player::HasEasyRpgExtensions()) { if (com.string.empty() || com.string[0] != '@') { // Not a DynRPG command return true; } + if (!Player::IsPatchDynRpg() && Player::HasEasyRpgExtensions()) { + // Only accept commands starting with @easyrpg_ + if (!StringView(com.string).starts_with("@easyrpg_")) { + return true; + } + } + auto& frame = GetFrame(); const auto& list = frame.commands; auto& index = frame.current_command; @@ -2023,7 +2030,7 @@ bool Game_Interpreter::CommandComment(const lcf::rpg::EventCommand &com) { } } - return DynRpg::Invoke(command); + return Main_Data::game_dynrpg->Invoke(command, this); } return true; } diff --git a/src/main_data.cpp b/src/main_data.cpp index cb170499d8..89ae3602f6 100644 --- a/src/main_data.cpp +++ b/src/main_data.cpp @@ -25,6 +25,7 @@ #include "game_actors.h" #include "game_party.h" #include "game_enemyparty.h" +#include "game_dynrpg.h" #include "game_ineluki.h" #include "game_player.h" #include "game_screen.h" @@ -70,6 +71,7 @@ namespace Main_Data { std::unique_ptr game_enemyparty; std::unique_ptr game_targets; std::unique_ptr game_quit; + std::unique_ptr game_dynrpg; std::unique_ptr game_ineluki; bool global_save_opened = false; std::unique_ptr game_switches_global; @@ -125,6 +127,7 @@ void Main_Data::Cleanup() { game_targets.reset(); game_quit.reset(); game_system.reset(); + game_dynrpg.reset(); game_ineluki.reset(); global_save_opened = false; game_switches_global.reset(); diff --git a/src/main_data.h b/src/main_data.h index ced8e4228f..9f5ddd0843 100644 --- a/src/main_data.h +++ b/src/main_data.h @@ -39,6 +39,7 @@ class Game_Variables; class Game_Strings; class Game_Targets; class Game_Quit; +class Game_DynRpg; class Game_Ineluki; class FileFinder_RTP; @@ -57,6 +58,7 @@ namespace Main_Data { extern std::unique_ptr game_enemyparty; extern std::unique_ptr game_targets; extern std::unique_ptr game_quit; + extern std::unique_ptr game_dynrpg; extern std::unique_ptr game_ineluki; extern bool global_save_opened; extern std::unique_ptr game_switches_global; // Used by Global Save command diff --git a/src/player.cpp b/src/player.cpp index f78ba74e0d..3f7d17f3aa 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -37,7 +37,7 @@ #include "cache.h" #include "rand.h" #include "cmdline_parser.h" -#include "dynrpg.h" +#include "game_dynrpg.h" #include "filefinder.h" #include "filefinder_rtp.h" #include "fileext_guesser.h" @@ -410,7 +410,6 @@ void Player::Exit() { #endif Player::ResetGameObjects(); Font::Dispose(); - DynRpg::Reset(); Graphics::Quit(); Output::Quit(); FileFinder::Quit(); @@ -821,7 +820,7 @@ void Player::CreateGameObjects() { if (!FileFinder::Game().FindFile("dynloader.dll").empty()) { game_config.patch_dynrpg.Set(true); - Output::Warning("This game uses DynRPG and will not run properly."); + Output::Debug("This game uses DynRPG. Depending on the plugins used it will not run properly."); } if (!FileFinder::Game().FindFile("accord.dll").empty()) { @@ -919,10 +918,9 @@ void Player::ResetGameObjects() { Main_Data::game_quit = std::make_unique(); Main_Data::game_switches_global = std::make_unique(); Main_Data::game_variables_global = std::make_unique(min_var, max_var); + Main_Data::game_dynrpg = std::make_unique(); Main_Data::game_ineluki = std::make_unique(); - DynRpg::Reset(); - Game_Clock::ResetFrame(Game_Clock::now()); Main_Data::game_system->ReloadSystemGraphic(); diff --git a/src/scene_map.cpp b/src/scene_map.cpp index 68766c123f..b5bd4d3351 100644 --- a/src/scene_map.cpp +++ b/src/scene_map.cpp @@ -41,7 +41,7 @@ #include "screen.h" #include "scene_load.h" #include "output.h" -#include "dynrpg.h" +#include "game_dynrpg.h" using namespace std::chrono_literals; @@ -84,7 +84,7 @@ void Scene_Map::Start() { auto current_music = Main_Data::game_system->GetCurrentBGM(); Main_Data::game_system->BgmStop(); Main_Data::game_system->BgmPlay(current_music); - DynRpg::Load(from_save_id); + Main_Data::game_dynrpg->Load(from_save_id); } else { Game_Map::PlayBgm(); } diff --git a/src/scene_save.cpp b/src/scene_save.cpp index d2aa7dfcf4..c802b103ad 100644 --- a/src/scene_save.cpp +++ b/src/scene_save.cpp @@ -23,7 +23,7 @@ #endif #include -#include "dynrpg.h" +#include "game_dynrpg.h" #include "filefinder.h" #include "game_actor.h" #include "game_map.h" @@ -156,7 +156,8 @@ bool Scene_Save::Save(std::ostream& os, int slot_id, bool prepare_save) { auto lcf_engine = Player::IsRPG2k3() ? lcf::EngineVersion::e2k3 : lcf::EngineVersion::e2k; bool res = lcf::LSD_Reader::Save(os, save, lcf_engine, Player::encoding); - DynRpg::Save(slot_id); + Main_Data::game_dynrpg->Save(slot_id); + AsyncHandler::SaveFilesystem(); return res; diff --git a/src/spriteset_map.cpp b/src/spriteset_map.cpp index 8dce2e7cb6..c8be227b4e 100644 --- a/src/spriteset_map.cpp +++ b/src/spriteset_map.cpp @@ -18,7 +18,7 @@ // Headers #include "spriteset_map.h" #include "cache.h" -#include "dynrpg.h" +#include "game_dynrpg.h" #include "game_map.h" #include "main_data.h" #include "sprite_airshipshadow.h" @@ -114,7 +114,7 @@ void Spriteset_Map::Update() { shadow->Update(); } - DynRpg::Update(); + Main_Data::game_dynrpg->Update(); } void Spriteset_Map::ChipsetUpdated() { diff --git a/tests/dynrpg.cpp b/tests/dynrpg.cpp index ee5039f80b..0927d40683 100644 --- a/tests/dynrpg.cpp +++ b/tests/dynrpg.cpp @@ -1,6 +1,6 @@ #include #include "doctest.h" -#include "dynrpg.h" +#include "game_dynrpg.h" #include "game_variables.h" #include "test_mock_actor.h" @@ -148,39 +148,42 @@ TEST_CASE("Arg parse") { } TEST_CASE("easyrpg dynrpg invoke") { + Game_DynRpg dyn; const MockActor m; + Player::game_config.patch_dynrpg.Set(true); + std::vector vars = {-1}; Main_Data::game_variables->SetData(vars); Main_Data::game_variables->SetWarning(0); - DynRpg::Invoke("@easyrpg_add 1, 2, 4"); + dyn.Invoke("@easyrpg_add 1, 2, 4"); CHECK(Main_Data::game_variables->Get(1) == 6); // Invalid, stays 6 - DynRpg::Invoke("@easyrpg_add 1, 2, a"); + dyn.Invoke("@easyrpg_add 1, 2, a"); CHECK(Main_Data::game_variables->Get(1) == 6); // Not enough args, stays 6 - DynRpg::Invoke("@easyrpg_add 1"); + dyn.Invoke("@easyrpg_add 1"); CHECK(Main_Data::game_variables->Get(1) == 6); - DynRpg::Invoke("@easyrpg_add 1, 2"); + dyn.Invoke("@easyrpg_add 1, 2"); CHECK(Main_Data::game_variables->Get(1) == 2); - DynRpg::Invoke("@call easyrpg_add, 1, 4.3, 7.7"); + dyn.Invoke("@call easyrpg_add, 1, 4.3, 7.7"); CHECK(Main_Data::game_variables->Get(1) == 11); // Extra args ignored - DynRpg::Invoke("@call easyrpg_add, 1, 4, 8, -14.0"); + dyn.Invoke("@call easyrpg_add, 1, 4, 8, -14.0"); CHECK(Main_Data::game_variables->Get(1) == -2); // Invalid func, stays -2 - DynRpg::Invoke("@call easyrpg_xxx, 1, 4, 7"); + dyn.Invoke("@call easyrpg_xxx, 1, 4, 7"); CHECK(Main_Data::game_variables->Get(1) == -2); // does not crash - DynRpg::Invoke("@unknownfunc 1, 2, 3"); + dyn.Invoke("@unknownfunc 1, 2, 3"); } TEST_CASE("Incompatible changes") { diff --git a/tests/test_mock_actor.h b/tests/test_mock_actor.h index cd5b393711..963a2149ed 100644 --- a/tests/test_mock_actor.h +++ b/tests/test_mock_actor.h @@ -78,7 +78,7 @@ class MockActor { public: MockActor(int eng = Player::EngineRpg2k3 | Player::EngineEnglish) { - _engine = Player::game_config.engine; + _config = Player::game_config; Player::game_config.engine = eng; InitEmptyDB(); @@ -100,10 +100,10 @@ class MockActor { Main_Data::Cleanup(); lcf::Data::data = {}; - Player::game_config.engine = _engine; + Player::game_config = _config; } private: - int _engine = {}; + Game_ConfigGame _config = {}; }; struct MockBattle : public MockActor {