From 49df42610476dfeb52d77ebcb1e2636eecee5e1c Mon Sep 17 00:00:00 2001 From: Matthew Fioravante Date: Tue, 3 Sep 2019 20:34:01 -0400 Subject: [PATCH 1/4] Expose and Use Game_System::IsStopFilename() --- src/game_system.cpp | 53 ++++++++++++++++++++------------------------- src/game_system.h | 31 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/game_system.cpp b/src/game_system.cpp index 917180c271..e598854105 100644 --- a/src/game_system.cpp +++ b/src/game_system.cpp @@ -37,32 +37,6 @@ namespace { FileRequestBinding system_request_id; std::map se_request_ids; - /** - * Determines if the requested file is supposed to Stop BGM/SE play. - * For empty string and (OFF) this is always the case. - * Many RPG Maker translation overtranslated the (OFF) reserved string, - * e.g. (Brak) and (Kein Sound). - * A file is detected as "Stop BGM/SE" when the file is missing in the - * filesystem and the name is wrapped in (), otherwise it is a regular - * file. - * - * @param name File to find - * @param find_func Find function to use (FindSound or FindMusic) - * @param found_name Name of the found file to play - * @return true when the file is supposed to Stop playback. - * false otherwise and file to play is returned as found_name - */ - bool isStopFilename(const std::string& name, std::string (*find_func) (const std::string&), std::string& found_name) { - found_name = ""; - - if (name.empty() || name == "(OFF)") { - return true; - } - - found_name = find_func(name); - - return found_name.empty() && (Utils::StartsWith(name, "(") && Utils::EndsWith(name, ")")); - } } static RPG::SaveSystem& data = Main_Data::game_data.system; @@ -73,6 +47,27 @@ void Game_System::Init() { data.Setup(); } +bool Game_System::IsStopFilename(const std::string& name, std::string (*find_func) (const std::string&), std::string& found_name) { + found_name = ""; + + if (name.empty() || name == "(OFF)") { + return true; + } + + found_name = find_func(name); + + return found_name.empty() && (Utils::StartsWith(name, "(") && Utils::EndsWith(name, ")")); +} + + +bool Game_System::IsStopMusicFilename(const std::string& name, std::string& found_name) { + return IsStopFilename(name, FileFinder::FindMusic, found_name); +} + +bool Game_System::IsStopSoundFilename(const std::string& name, std::string& found_name) { + return IsStopFilename(name, FileFinder::FindSound, found_name); +} + int Game_System::GetSaveCount() { return data.save_count; } @@ -190,7 +185,7 @@ void Game_System::SePlay(const RPG::Sound& se, bool stop_sounds) { void Game_System::SePlay(const RPG::Animation &animation) { std::string path; for (const auto& anim : animation.timings) { - if (!isStopFilename(anim.se.name, FileFinder::FindSound, path)) { + if (!IsStopSoundFilename(anim.se.name, path)) { SePlay(anim.se); return; } @@ -439,7 +434,7 @@ void Game_System::OnBgmReady(FileRequestResult* result) { bgm_pending = false; std::string path; - if (isStopFilename(result->file, FileFinder::FindMusic, path)) { + if (IsStopMusicFilename(result->file, path)) { Audio().BGM_Stop(); return; } else if (path.empty()) { @@ -489,7 +484,7 @@ void Game_System::OnSeReady(FileRequestResult* result, int volume, int tempo, bo } std::string path; - if (isStopFilename(result->file, FileFinder::FindSound, path)) { + if (IsStopSoundFilename(result->file, path)) { if (stop_sounds) { Audio().SE_Stop(); } diff --git a/src/game_system.h b/src/game_system.h index 069d1b8cc0..be5a3d4fb0 100644 --- a/src/game_system.h +++ b/src/game_system.h @@ -269,6 +269,28 @@ namespace Game_System { void OnBgmReady(FileRequestResult* result); void OnSeReady(FileRequestResult* result, int volume, int tempo, bool stop_sounds); void ReloadSystemGraphic(); + + /** + * Determines if the requested file is supposed to Stop BGM/SE play. + * For empty string and (OFF) this is always the case. + * Many RPG Maker translation overtranslated the (OFF) reserved string, + * e.g. (Brak) and (Kein Sound). + * A file is detected as "Stop BGM/SE" when the file is missing in the + * filesystem and the name is wrapped in (), otherwise it is a regular + * file. + * + * @param name File to find + * @param find_func Find function to use (FindSound or FindMusic) + * @param found_name Name of the found file to play + * @return true when the file is supposed to Stop playback. + * false otherwise and file to play is returned as found_name + */ + bool IsStopFilename(const std::string& name, std::string (*find_func) (const std::string&), std::string& found_name); + + bool IsStopMusicFilename(const std::string& name, std::string& found_name); + bool IsStopMusicFilename(const std::string& name); + bool IsStopSoundFilename(const std::string& name, std::string& found_name); + bool IsStopSoundFilename(const std::string& name); } inline bool Game_System::HasSystemGraphic() { @@ -279,4 +301,13 @@ inline bool Game_System::HasSystem2Graphic() { return !GetSystem2Name().empty(); } +inline bool Game_System::IsStopMusicFilename(const std::string& name) { + std::string s; + return IsStopMusicFilename(name, s); +} +inline bool Game_System::IsStopSoundFilename(const std::string& name) { + std::string s; + return IsStopSoundFilename(name, s); +} + #endif From af1c70f314d1ca8d7750d22bd0ff3e95e446d89b Mon Sep 17 00:00:00 2001 From: Matthew Fioravante Date: Mon, 2 Sep 2019 21:18:21 -0400 Subject: [PATCH 2/4] Improved async logic * Add AsyncOp to encapsulate async operations info * Remove async globals from interpreter * Remove transition game_temp vars --- CMakeLists.txt | 1 + Makefile.am | 1 + src/async_op.h | 111 ++++++++++++++++++++ src/game_commonevent.cpp | 6 +- src/game_commonevent.h | 12 +-- src/game_event.cpp | 12 +-- src/game_event.h | 5 +- src/game_interpreter.cpp | 221 ++++++++++++++++++++------------------- src/game_interpreter.h | 36 ++----- src/game_map.cpp | 14 +-- src/game_map.h | 37 +++++-- src/game_temp.cpp | 6 -- src/game_temp.h | 4 - src/scene.cpp | 8 +- src/scene.h | 7 +- src/scene_battle.cpp | 9 +- src/scene_map.cpp | 29 ++--- src/scene_map.h | 2 +- 18 files changed, 316 insertions(+), 205 deletions(-) create mode 100644 src/async_op.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ce19c4cc8f..d88116fcf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(${PROJECT_NAME} src/3ds_ui.h src/async_handler.cpp src/async_handler.h + src/async_op.h src/audio_3ds.cpp src/audio_3ds.h src/audio_al.cpp diff --git a/Makefile.am b/Makefile.am index b489d76544..7fa053d2e2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,6 +11,7 @@ libeasyrpg_player_a_SOURCES = \ src/3ds_ui.h \ src/async_handler.cpp \ src/async_handler.h \ + src/async_op.h \ src/audio.cpp \ src/audio.h \ src/audio_3ds.cpp \ diff --git a/src/async_op.h b/src/async_op.h new file mode 100644 index 0000000000..6ee72bbc5e --- /dev/null +++ b/src/async_op.h @@ -0,0 +1,111 @@ +/* + * This file is part of EasyRPG Player. + * + * EasyRPG Player is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Player is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Player. If not, see . + */ + +#ifndef EP_ASYNC_OP_H +#define EP_ASYNC_OP_H + +#include +#include + +/** + * Represents an asynchronous game operation. These are usually created + * by event interpreters. When an async operation starts, the entire game + * loop is supposed to suspend, perform the async operation, and + * then resume from the suspension point. + **/ +class AsyncOp { + public: + /** The different types of async operations */ + enum Type { + eNone, + eShowScreen, + eEraseScreen, + eToTitle, + eExitGame + }; + + AsyncOp() = default; + + /** @return a ShowScreen async operation */ + static AsyncOp MakeShowScreen(int transition_type); + + /** @return an EraseScreen async operation */ + static AsyncOp MakeEraseScreen(int transition_type); + + /** @return a ToTitle async operation */ + static AsyncOp MakeToTitle(); + + /** @return an ExitGame async operation */ + static AsyncOp MakeExitGame(); + + /** @return the type of async operation */ + Type GetType() const; + + /** @return true if this AsyncOp is active */ + bool IsActive() const; + + /** + * @return the type of screen transition to perform + * @pre If GetType() is not eShowScreen or eEraseScreen, the return value is undefined. + **/ + int GetTransitionType() const; + + private: + Type _type = eNone; + int _args[1] = {}; + + template + explicit AsyncOp(Type type, Args&&... args); + +}; + +inline AsyncOp::Type AsyncOp::GetType() const { + return _type; +} + +inline bool AsyncOp::IsActive() const { + return GetType() != eNone; +} + +inline int AsyncOp::GetTransitionType() const { + assert(GetType() == eShowScreen || GetType() == eEraseScreen); + return _args[0]; +} + +template +inline AsyncOp::AsyncOp(Type type, Args&&... args) + : _type(type), _args{std::forward(args)...} +{} + +inline AsyncOp AsyncOp::MakeShowScreen(int transition_type) { + return AsyncOp(eShowScreen, transition_type); +} + +inline AsyncOp AsyncOp::MakeEraseScreen(int transition_type) { + return AsyncOp(eEraseScreen, transition_type); +} + +inline AsyncOp AsyncOp::MakeToTitle() { + return AsyncOp(eToTitle); +} + +inline AsyncOp AsyncOp::MakeExitGame() { + return AsyncOp(eExitGame); +} + +#endif + diff --git a/src/game_commonevent.cpp b/src/game_commonevent.cpp index e3b58f7b47..b2a8b6ad41 100644 --- a/src/game_commonevent.cpp +++ b/src/game_commonevent.cpp @@ -49,18 +49,18 @@ void Game_CommonEvent::SetSaveData(const RPG::SaveEventExecState& data) { } } -bool Game_CommonEvent::Update() { +AsyncOp Game_CommonEvent::Update() { if (interpreter && IsWaitingBackgroundExecution()) { assert(interpreter->IsRunning()); interpreter->Update(); // Suspend due to async op ... if (interpreter->IsAsyncPending()) { - return false; + return interpreter->GetAsyncOp(); } } - return true; + return {}; } int Game_CommonEvent::GetIndex() const { diff --git a/src/game_commonevent.h b/src/game_commonevent.h index 41c6aaddb7..1a1dc6a123 100644 --- a/src/game_commonevent.h +++ b/src/game_commonevent.h @@ -24,6 +24,7 @@ #include "game_interpreter_map.h" #include "rpg_commonevent.h" #include "rpg_saveeventexecstate.h" +#include "async_op.h" /** * Game_CommonEvent class. @@ -47,9 +48,9 @@ class Game_CommonEvent { /** * Updates common event parallel interpreter. * - * @return false if we must suspend due to an async operation. + * @return async operation if we should suspend, otherwise returns AsyncOp::eNone */ - bool Update(); + AsyncOp Update(); /** * Gets common event index. @@ -101,9 +102,6 @@ class Game_CommonEvent { /** @return true if waiting for background execution */ bool IsWaitingBackgroundExecution() const; - /** @return true if parallel event waiting for async op */ - bool IsAsyncPending() const; - private: int common_event_id; @@ -111,8 +109,4 @@ class Game_CommonEvent { std::unique_ptr interpreter; }; -inline bool Game_CommonEvent::IsAsyncPending() const { - return interpreter && interpreter->IsAsyncPending(); -} - #endif diff --git a/src/game_event.cpp b/src/game_event.cpp index bcd86b8a0b..93f192e37a 100644 --- a/src/game_event.cpp +++ b/src/game_event.cpp @@ -498,9 +498,9 @@ void Game_Event::MoveTypeAwayFromPlayer() { MoveTypeTowardsOrAwayPlayer(false); } -bool Game_Event::Update() { +AsyncOp Game_Event::Update() { if (!data()->active || page == NULL) { - return true; + return {}; } // RPG_RT runs the parallel interpreter everytime Update is called. @@ -516,18 +516,18 @@ bool Game_Event::Update() { // Suspend due to async op ... if (interpreter->IsAsyncPending()) { - return false; + return interpreter->GetAsyncOp(); } // RPG_RT only exits if active is false here, but not if there is // no active page... if (!data()->active) { - return true; + return {}; } } if (IsProcessed()) { - return true; + return {}; } SetProcessed(true); @@ -545,7 +545,7 @@ bool Game_Event::Update() { if (IsStopping()) { CheckEventCollision(); } - return true; + return {}; } const RPG::EventPage* Game_Event::GetPage(int page) const { diff --git a/src/game_event.h b/src/game_event.h index 98940666b7..abb42d02d6 100644 --- a/src/game_event.h +++ b/src/game_event.h @@ -25,6 +25,7 @@ #include "rpg_event.h" #include "rpg_savemapevent.h" #include "game_interpreter_map.h" +#include "async_op.h" /** * Game_Event class. @@ -111,9 +112,9 @@ class Game_Event : public Game_Character { /** * Update this for the current frame * - * @return false if we must suspend due to an async operation. + * @return async operation if we should suspend, otherwise returns AsyncOp::eNone */ - bool Update(); + AsyncOp Update(); bool AreConditionsMet(const RPG::EventPage& page); diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 785cff7a61..9b688255e4 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -52,9 +52,6 @@ #include "utils.h" #include "transition.h" -bool Game_Interpreter::to_title = false; -bool Game_Interpreter::exit_game = false; - enum BranchSubcommand { eOptionBranchElse = 1 }; @@ -79,6 +76,7 @@ void Game_Interpreter::Clear() { wait_messages = false; // wait if message window is visible _state = {}; _keyinput = {}; + _async_op = {}; } // Is interpreter running. @@ -300,6 +298,9 @@ void Game_Interpreter::Update(bool reset_loop_count) { loop_count = 0; } + // Always reset async status when we enter interpreter loop. + _async_op = {}; + if (!IsRunning()) { return; } @@ -311,6 +312,11 @@ void Game_Interpreter::Update(bool reset_loop_count) { break; } + // Previous command triggered an async operation. + if (IsAsyncPending()) { + break; + } + if (main_flag) { if (Main_Data::game_player->IsBoardingOrUnboarding()) break; @@ -325,10 +331,6 @@ void Game_Interpreter::Update(bool reset_loop_count) { break; } - if (Game_Temp::transition_processing) { - break; - } - if (_state.wait_time > 0) { _state.wait_time--; break; @@ -2020,159 +2022,164 @@ bool Game_Interpreter::CommandStoreEventID(RPG::EventCommand const& com) { // co } bool Game_Interpreter::CommandEraseScreen(RPG::EventCommand const& com) { // code 11010 - if (Game_Temp::transition_processing || Game_Message::visible) + if (Game_Message::visible) return false; - Game_Temp::transition_processing = true; - Game_Temp::transition_erase = true; + int tt = Transition::TransitionNone; switch (com.parameters[0]) { case -1: - Game_Temp::transition_type = (Transition::TransitionType)Game_System::GetTransition( + tt = (Transition::TransitionType)Game_System::GetTransition( Game_System::Transition_TeleportErase); - return true; + break; case 0: - Game_Temp::transition_type = Transition::TransitionFadeOut; - return true; + tt = Transition::TransitionFadeOut; + break; case 1: - Game_Temp::transition_type = Transition::TransitionRandomBlocks; - return true; + tt = Transition::TransitionRandomBlocks; + break; case 2: - Game_Temp::transition_type = Transition::TransitionRandomBlocksUp; - return true; + tt = Transition::TransitionRandomBlocksUp; + break; case 3: - Game_Temp::transition_type = Transition::TransitionRandomBlocksDown; - return true; + tt = Transition::TransitionRandomBlocksDown; + break; case 4: - Game_Temp::transition_type = Transition::TransitionBlindClose; - return true; + tt = Transition::TransitionBlindClose; + break; case 5: - Game_Temp::transition_type = Transition::TransitionVerticalStripesOut; - return true; + tt = Transition::TransitionVerticalStripesOut; + break; case 6: - Game_Temp::transition_type = Transition::TransitionHorizontalStripesOut; - return true; + tt = Transition::TransitionHorizontalStripesOut; + break; case 7: - Game_Temp::transition_type = Transition::TransitionBorderToCenterOut; - return true; + tt = Transition::TransitionBorderToCenterOut; + break; case 8: - Game_Temp::transition_type = Transition::TransitionCenterToBorderOut; - return true; + tt = Transition::TransitionCenterToBorderOut; + break; case 9: - Game_Temp::transition_type = Transition::TransitionScrollUpOut; - return true; + tt = Transition::TransitionScrollUpOut; + break; case 10: - Game_Temp::transition_type = Transition::TransitionScrollDownOut; - return true; + tt = Transition::TransitionScrollDownOut; + break; case 11: - Game_Temp::transition_type = Transition::TransitionScrollLeftOut; - return true; + tt = Transition::TransitionScrollLeftOut; + break; case 12: - Game_Temp::transition_type = Transition::TransitionScrollRightOut; - return true; + tt = Transition::TransitionScrollRightOut; + break; case 13: - Game_Temp::transition_type = Transition::TransitionVerticalDivision; - return true; + tt = Transition::TransitionVerticalDivision; + break; case 14: - Game_Temp::transition_type = Transition::TransitionHorizontalDivision; - return true; + tt = Transition::TransitionHorizontalDivision; + break; case 15: - Game_Temp::transition_type = Transition::TransitionCrossDivision; - return true; + tt = Transition::TransitionCrossDivision; + break; case 16: - Game_Temp::transition_type = Transition::TransitionZoomIn; - return true; + tt = Transition::TransitionZoomIn; + break; case 17: - Game_Temp::transition_type = Transition::TransitionMosaicOut; - return true; + tt = Transition::TransitionMosaicOut; + break; case 18: - Game_Temp::transition_type = Transition::TransitionWaveOut; - return true; + tt = Transition::TransitionWaveOut; + break; case 19: - Game_Temp::transition_type = Transition::TransitionErase; - return true; + tt = Transition::TransitionErase; + break; default: - Game_Temp::transition_type = Transition::TransitionNone; - return true; + tt = Transition::TransitionNone; + break; } + + _async_op = AsyncOp::MakeEraseScreen(tt); + + return true; } bool Game_Interpreter::CommandShowScreen(RPG::EventCommand const& com) { // code 11020 - if (Game_Temp::transition_processing || Game_Message::visible) + if (Game_Message::visible) return false; - Game_Temp::transition_processing = true; - Game_Temp::transition_erase = false; + int tt = Transition::TransitionNone; switch (com.parameters[0]) { case -1: - Game_Temp::transition_type = (Transition::TransitionType)Game_System::GetTransition( + tt = (Transition::TransitionType)Game_System::GetTransition( Game_System::Transition_TeleportShow); - return true; + break; case 0: - Game_Temp::transition_type = Transition::TransitionFadeIn; - return true; + tt = Transition::TransitionFadeIn; + break; case 1: - Game_Temp::transition_type = Transition::TransitionRandomBlocks; - return true; + tt = Transition::TransitionRandomBlocks; + break; case 2: - Game_Temp::transition_type = Transition::TransitionRandomBlocksUp; - return true; + tt = Transition::TransitionRandomBlocksUp; + break; case 3: - Game_Temp::transition_type = Transition::TransitionRandomBlocksDown; - return true; + tt = Transition::TransitionRandomBlocksDown; + break; case 4: - Game_Temp::transition_type = Transition::TransitionBlindOpen; - return true; + tt = Transition::TransitionBlindOpen; + break; case 5: - Game_Temp::transition_type = Transition::TransitionVerticalStripesIn; - return true; + tt = Transition::TransitionVerticalStripesIn; + break; case 6: - Game_Temp::transition_type = Transition::TransitionHorizontalStripesIn; - return true; + tt = Transition::TransitionHorizontalStripesIn; + break; case 7: - Game_Temp::transition_type = Transition::TransitionBorderToCenterIn; - return true; + tt = Transition::TransitionBorderToCenterIn; + break; case 8: - Game_Temp::transition_type = Transition::TransitionCenterToBorderIn; - return true; + tt = Transition::TransitionCenterToBorderIn; + break; case 9: - Game_Temp::transition_type = Transition::TransitionScrollUpIn; - return true; + tt = Transition::TransitionScrollUpIn; + break; case 10: - Game_Temp::transition_type = Transition::TransitionScrollDownIn; - return true; + tt = Transition::TransitionScrollDownIn; + break; case 11: - Game_Temp::transition_type = Transition::TransitionScrollLeftIn; - return true; + tt = Transition::TransitionScrollLeftIn; + break; case 12: - Game_Temp::transition_type = Transition::TransitionScrollRightIn; - return true; + tt = Transition::TransitionScrollRightIn; + break; case 13: - Game_Temp::transition_type = Transition::TransitionVerticalCombine; - return true; + tt = Transition::TransitionVerticalCombine; + break; case 14: - Game_Temp::transition_type = Transition::TransitionHorizontalCombine; - return true; + tt = Transition::TransitionHorizontalCombine; + break; case 15: - Game_Temp::transition_type = Transition::TransitionCrossCombine; - return true; + tt = Transition::TransitionCrossCombine; + break; case 16: - Game_Temp::transition_type = Transition::TransitionZoomOut; - return true; + tt = Transition::TransitionZoomOut; + break; case 17: - Game_Temp::transition_type = Transition::TransitionMosaicIn; - return true; + tt = Transition::TransitionMosaicIn; + break; case 18: - Game_Temp::transition_type = Transition::TransitionWaveIn; - return true; + tt = Transition::TransitionWaveIn; + break; case 19: - Game_Temp::transition_type = Transition::TransitionErase; - return true; + tt = Transition::TransitionErase; + break; default: - Game_Temp::transition_type = Transition::TransitionNone; - return true; + tt = Transition::TransitionNone; + break; } + + _async_op = AsyncOp::MakeShowScreen(tt); + return true; } bool Game_Interpreter::CommandTintScreen(RPG::EventCommand const& com) { // code 11030 @@ -3158,8 +3165,8 @@ bool Game_Interpreter::CommandCallEvent(RPG::EventCommand const& com) { // code } bool Game_Interpreter::CommandReturnToTitleScreen(RPG::EventCommand const& /* com */) { // code 12510 - to_title = true; - return false; + _async_op = AsyncOp::MakeToTitle(); + return true; } bool Game_Interpreter::CommandChangeClass(RPG::EventCommand const& com) { // code 1008 @@ -3314,8 +3321,8 @@ bool Game_Interpreter::CommandChangeBattleCommands(RPG::EventCommand const& com) } bool Game_Interpreter::CommandExitGame(RPG::EventCommand const& /* com */) { - exit_game = true; - return false; + _async_op = AsyncOp::MakeExitGame(); + return true; } bool Game_Interpreter::CommandToggleFullscreen(RPG::EventCommand const& /* com */) { @@ -3342,7 +3349,3 @@ bool Game_Interpreter::ContinuationShowInnStart(RPG::EventCommand const& /* com bool Game_Interpreter::ContinuationShowInnFinish(RPG::EventCommand const& /* com */) { return true; } bool Game_Interpreter::ContinuationEnemyEncounter(RPG::EventCommand const& /* com */) { return true; } - -bool Game_Interpreter::IsAsyncPending() { - return Game_Temp::transition_processing || to_title || exit_game; -} diff --git a/src/game_interpreter.h b/src/game_interpreter.h index 60938900f3..6fe69fc00d 100644 --- a/src/game_interpreter.h +++ b/src/game_interpreter.h @@ -29,6 +29,7 @@ #include "command_codes.h" #include "rpg_saveeventexecstate.h" #include "flag_set.h" +#include "async_op.h" class Game_Event; class Game_CommonEvent; @@ -90,28 +91,16 @@ class Game_Interpreter int GetOriginalEventId() const; /** Return true if the interpreter is waiting for an async operation and needs to be resumed */ - static bool IsAsyncPending(); + bool IsAsyncPending(); - /** @return true if any interpreter requested to return to title screen */ - static bool GetReturnToTitle(); - - /** Resets the return to title flag */ - static void ResetReturnToTitle(); - - /** @return true if any interpreter requested to return to title screen */ - static bool GetExitGame(); - - /** Resets the return to title flag */ - static void ResetExitGame(); + /** Return true if the interpreter is waiting for an async operation and needs to be resumed */ + AsyncOp GetAsyncOp() const; protected: static constexpr int loop_limit = 10000; static constexpr int call_stack_limit = 1000; static constexpr int subcommand_sentinel = 255; - static bool to_title; - static bool exit_game; - const RPG::SaveEventExecFrame* GetFrame() const; RPG::SaveEventExecFrame* GetFrame(); @@ -306,6 +295,7 @@ class Game_Interpreter RPG::SaveEventExecState _state; KeyInputState _keyinput; + AsyncOp _async_op = {}; }; inline const RPG::SaveEventExecFrame* Game_Interpreter::GetFrame() const { @@ -328,20 +318,12 @@ inline int Game_Interpreter::GetLoopCount() const { return loop_count; } -inline bool Game_Interpreter::GetReturnToTitle() { - return to_title; -} - -inline void Game_Interpreter::ResetReturnToTitle() { - to_title = false; -} - -inline bool Game_Interpreter::GetExitGame() { - return exit_game; +inline bool Game_Interpreter::IsAsyncPending() { + return GetAsyncOp().IsActive(); } -inline void Game_Interpreter::ResetExitGame() { - exit_game = false; +inline AsyncOp Game_Interpreter::GetAsyncOp() const { + return _async_op; } #endif diff --git a/src/game_map.cpp b/src/game_map.cpp index 986f40bbae..91c1abd88e 100644 --- a/src/game_map.cpp +++ b/src/game_map.cpp @@ -1015,9 +1015,10 @@ bool Game_Map::UpdateCommonEvents(MapUpdateAsyncContext& actx) { } } - if (!ev.Update()) { + auto aop = ev.Update(); + if (aop.IsActive()) { // Suspend due to this event .. - actx = MapUpdateAsyncContext::FromCommonEvent(ev.GetIndex()); + actx = MapUpdateAsyncContext::FromCommonEvent(ev.GetIndex(), aop); return false; } } @@ -1039,9 +1040,10 @@ bool Game_Map::UpdateMapEvents(MapUpdateAsyncContext& actx) { } } - if (!ev.Update()) { + auto aop = ev.Update(); + if (aop.IsActive()) { // Suspend due to this event .. - actx = MapUpdateAsyncContext::FromMapEvent(ev.GetId()); + actx = MapUpdateAsyncContext::FromMapEvent(ev.GetId(), aop); return false; } } @@ -1060,7 +1062,7 @@ bool Game_Map::UpdateForegroundEvents(MapUpdateAsyncContext& actx) { interp.Update(!resume_fg); if (interp.IsAsyncPending()) { // Suspend due to this event .. - actx = MapUpdateAsyncContext::FromForegroundEvent(); + actx = MapUpdateAsyncContext::FromForegroundEvent(interp.GetAsyncOp()); return false; } @@ -1109,7 +1111,7 @@ bool Game_Map::UpdateForegroundEvents(MapUpdateAsyncContext& actx) { interp.Update(false); if (interp.IsAsyncPending()) { // Suspend due to this event .. - actx = MapUpdateAsyncContext::FromForegroundEvent(); + actx = MapUpdateAsyncContext::FromForegroundEvent(interp.GetAsyncOp()); return false; } } diff --git a/src/game_map.h b/src/game_map.h index d0b87e0718..37156567d8 100644 --- a/src/game_map.h +++ b/src/game_map.h @@ -29,6 +29,7 @@ #include "rpg_encounter.h" #include "rpg_map.h" #include "rpg_mapinfo.h" +#include "async_op.h" class FileRequestAsync; @@ -41,9 +42,11 @@ class MapUpdateAsyncContext { public: MapUpdateAsyncContext() = default; - static MapUpdateAsyncContext FromCommonEvent(int ce); - static MapUpdateAsyncContext FromMapEvent(int ce); - static MapUpdateAsyncContext FromForegroundEvent(); + static MapUpdateAsyncContext FromCommonEvent(int ce, AsyncOp aop); + static MapUpdateAsyncContext FromMapEvent(int ce, AsyncOp aop); + static MapUpdateAsyncContext FromForegroundEvent(AsyncOp aop); + + AsyncOp GetAsyncOp() const; int GetParallelCommonEvent() const; int GetParallelMapEvent() const; @@ -55,6 +58,7 @@ class MapUpdateAsyncContext { private: int common_event = 0; int map_event = 0; + AsyncOp async_op = {}; bool foreground_event = 0; }; @@ -710,21 +714,34 @@ namespace Game_Map { } -inline MapUpdateAsyncContext MapUpdateAsyncContext::FromCommonEvent(int ce) { +inline AsyncOp MapUpdateAsyncContext::GetAsyncOp() const { + return async_op; +} + +inline MapUpdateAsyncContext MapUpdateAsyncContext::FromCommonEvent(int ce, AsyncOp aop) { MapUpdateAsyncContext actx; - actx.common_event = ce; + if (aop.IsActive()) { + actx.async_op = aop; + actx.common_event = ce; + } return actx; } -inline MapUpdateAsyncContext MapUpdateAsyncContext::FromMapEvent(int ev) { +inline MapUpdateAsyncContext MapUpdateAsyncContext::FromMapEvent(int ev, AsyncOp aop) { MapUpdateAsyncContext actx; - actx.map_event = ev; + if (aop.IsActive()) { + actx.async_op = aop; + actx.map_event = ev; + } return actx; } -inline MapUpdateAsyncContext MapUpdateAsyncContext::FromForegroundEvent() { +inline MapUpdateAsyncContext MapUpdateAsyncContext::FromForegroundEvent(AsyncOp aop) { MapUpdateAsyncContext actx; - actx.foreground_event = true; + if (aop.IsActive()) { + actx.async_op = aop; + actx.foreground_event = true; + } return actx; } @@ -750,7 +767,7 @@ inline bool MapUpdateAsyncContext::IsParallelMapEvent() const { inline bool MapUpdateAsyncContext::IsActive() const { - return IsParallelCommonEvent() || IsParallelMapEvent() || IsForegroundEvent(); + return GetAsyncOp().IsActive(); } #endif diff --git a/src/game_temp.cpp b/src/game_temp.cpp index 9e17855d8e..c7de817f3f 100644 --- a/src/game_temp.cpp +++ b/src/game_temp.cpp @@ -20,9 +20,6 @@ #include "transition.h" bool Game_Temp::inn_calling; -bool Game_Temp::transition_processing; -Transition::TransitionType Game_Temp::transition_type; -bool Game_Temp::transition_erase; bool Game_Temp::shop_buys; bool Game_Temp::shop_sells; int Game_Temp::shop_type; @@ -44,9 +41,6 @@ bool Game_Temp::battle_random_encounter; void Game_Temp::Init() { inn_calling = false; - transition_processing = false; - transition_type = Transition::TransitionNone; - transition_erase = false; shop_buys = true; shop_sells = true; shop_type = 0; diff --git a/src/game_temp.h b/src/game_temp.h index 5ff6f5b9cf..80970807dc 100644 --- a/src/game_temp.h +++ b/src/game_temp.h @@ -35,10 +35,6 @@ class Game_Temp { static bool inn_calling; - static bool transition_processing; - static Transition::TransitionType transition_type; - static bool transition_erase; - static bool shop_buys; static bool shop_sells; static int shop_type; // message set A, B, or C diff --git a/src/scene.cpp b/src/scene.cpp index 5b20fc214d..58bfa1b367 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -264,9 +264,8 @@ Graphics::State &Scene::GetGraphicsState() { return state; } -bool Scene::CheckInterpreterExit() { - if (Game_Interpreter::GetExitGame()) { - Game_Interpreter::ResetExitGame(); +bool Scene::CheckSceneExit(AsyncOp aop) { + if (aop.GetType() == AsyncOp::eExitGame) { if (Scene::Find(Scene::GameBrowser)) { Scene::PopUntil(Scene::GameBrowser); } else { @@ -275,8 +274,7 @@ bool Scene::CheckInterpreterExit() { return true; } - if (Game_Interpreter::GetReturnToTitle()) { - Game_Interpreter::ResetReturnToTitle(); + if (aop.GetType() == AsyncOp::eToTitle) { Scene::PopUntil(Scene::Title); return true; } diff --git a/src/scene.h b/src/scene.h index 5f8fea4009..e2625d106c 100644 --- a/src/scene.h +++ b/src/scene.h @@ -21,6 +21,7 @@ // Headers #include "graphics.h" #include "system.h" +#include "async_op.h" #include /** @@ -212,9 +213,11 @@ class Scene { void SetRequestedScene(SceneType scene); /** - * Check if the interpreter wants to end the game + * Check if the async operation wants to end the scene. + * + * @param aop The pending async operation */ - static bool CheckInterpreterExit(); + static bool CheckSceneExit(AsyncOp aop); protected: using AsyncContinuation = std::function; diff --git a/src/scene_battle.cpp b/src/scene_battle.cpp index e7f09073fe..1addc4da80 100644 --- a/src/scene_battle.cpp +++ b/src/scene_battle.cpp @@ -189,8 +189,13 @@ void Scene_Battle::Update() { // we need this so it can update automatically the status_window status_window->Refresh(); } - if (CheckInterpreterExit()) { - return; + if (interp.IsAsyncPending()) { + auto aop = interp.GetAsyncOp(); + if (CheckSceneExit(aop)) { + return; + } + + // Note: ShowScreen / HideScreen is ignored. } if (Game_Battle::IsTerminating()) { diff --git a/src/scene_map.cpp b/src/scene_map.cpp index 10d605a39c..27488bb9df 100644 --- a/src/scene_map.cpp +++ b/src/scene_map.cpp @@ -81,7 +81,7 @@ void Scene_Map::Start2(MapUpdateAsyncContext actx) { PreUpdate(actx); if (actx.IsActive()) { - OnAsyncSuspend([this,actx]() { Start2(actx); }, true); + OnAsyncSuspend([this,actx]() { Start2(actx); }, actx.GetAsyncOp(), true); return; } @@ -207,7 +207,7 @@ void Scene_Map::UpdateStage1(MapUpdateAsyncContext actx) { // Waiting for async operation from map update. if (actx.IsActive()) { - OnAsyncSuspend([this,actx]() { UpdateStage1(actx); }, false); + OnAsyncSuspend([this,actx]() { UpdateStage1(actx); }, actx.GetAsyncOp(), false); return; } @@ -319,7 +319,7 @@ void Scene_Map::FinishPendingTeleport2(MapUpdateAsyncContext actx, TeleportParam PreUpdate(actx); if (actx.IsActive()) { - OnAsyncSuspend([=] { FinishPendingTeleport2(actx, tp); }, true); + OnAsyncSuspend([=] { FinishPendingTeleport2(actx, tp); }, actx.GetAsyncOp(), true); return; } @@ -349,7 +349,7 @@ void Scene_Map::FinishPendingTeleport3(MapUpdateAsyncContext actx, TeleportParam PreUpdateForegroundEvents(actx); if (actx.IsActive()) { - OnAsyncSuspend([=] { FinishPendingTeleport3(actx, tp); }, true); + OnAsyncSuspend([=] { FinishPendingTeleport3(actx, tp); }, actx.GetAsyncOp(), true); return; } } @@ -418,21 +418,24 @@ void Scene_Map::AsyncNext(F&& f) { } template -void Scene_Map::OnAsyncSuspend(F&& f, bool is_preupdate) { - if (CheckInterpreterExit()) { +void Scene_Map::OnAsyncSuspend(F&& f, AsyncOp aop, bool is_preupdate) { + if (CheckSceneExit(aop)) { return; } - if (Game_Temp::transition_processing) { - Graphics::GetTransition().Init(Game_Temp::transition_type, this, 32, Game_Temp::transition_erase); - if (!Game_Temp::transition_erase || !is_preupdate) { + if (aop.GetType() == AsyncOp::eEraseScreen) { + auto tt = static_cast(aop.GetTransitionType()); + Graphics::GetTransition().Init(tt, this, 32, true); + if (!is_preupdate) { // RPG_RT behavior: EraseScreen commands performed during pre-update don't stick. - screen_erased_by_event = Game_Temp::transition_erase; + screen_erased_by_event = true; } + } - Game_Temp::transition_processing = false; - Game_Temp::transition_erase = false; - Game_Temp::transition_type = Transition::TransitionNone;; + if (aop.GetType() == AsyncOp::eShowScreen) { + auto tt = static_cast(aop.GetTransitionType()); + Graphics::GetTransition().Init(tt, this, 32, false); + screen_erased_by_event = false; } AsyncNext(std::forward(f)); diff --git a/src/scene_map.h b/src/scene_map.h index 61f1cdb840..3d1ceadd4d 100644 --- a/src/scene_map.h +++ b/src/scene_map.h @@ -87,7 +87,7 @@ class Scene_Map: public Scene { void UpdateSceneCalling(); template void AsyncNext(F&& f); - template void OnAsyncSuspend(F&& f, bool is_preupdate); + template void OnAsyncSuspend(F&& f, AsyncOp aop, bool is_preupdate); std::unique_ptr message_window; From 82549c1071868b16d20358f57538a3bb2a5263f4 Mon Sep 17 00:00:00 2001 From: Matthew Fioravante Date: Mon, 2 Sep 2019 22:22:34 -0400 Subject: [PATCH 3/4] Make Inn Sequence asynchronous --- src/async_op.h | 8 +++++ src/game_interpreter.cpp | 6 +++- src/game_interpreter.h | 1 - src/game_interpreter_map.cpp | 60 +++--------------------------------- src/game_interpreter_map.h | 2 -- src/scene_map.cpp | 53 +++++++++++++++++++++++++++++++ src/scene_map.h | 8 +++++ 7 files changed, 78 insertions(+), 60 deletions(-) diff --git a/src/async_op.h b/src/async_op.h index 6ee72bbc5e..f39f85c738 100644 --- a/src/async_op.h +++ b/src/async_op.h @@ -34,6 +34,7 @@ class AsyncOp { eNone, eShowScreen, eEraseScreen, + eCallInn, eToTitle, eExitGame }; @@ -46,6 +47,9 @@ class AsyncOp { /** @return an EraseScreen async operation */ static AsyncOp MakeEraseScreen(int transition_type); + /** @return an CallInn async operation */ + static AsyncOp MakeCallInn(); + /** @return a ToTitle async operation */ static AsyncOp MakeToTitle(); @@ -99,6 +103,10 @@ inline AsyncOp AsyncOp::MakeEraseScreen(int transition_type) { return AsyncOp(eEraseScreen, transition_type); } +inline AsyncOp AsyncOp::MakeCallInn() { + return AsyncOp(eCallInn); +} + inline AsyncOp AsyncOp::MakeToTitle() { return AsyncOp(eToTitle); } diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 9b688255e4..fb67917708 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -387,6 +387,11 @@ void Game_Interpreter::Update(bool reset_loop_count) { } } + // continuation triggered an async operation. + if (IsAsyncPending()) { + break; + } + if (Game_Map::GetNeedRefresh()) { Game_Map::Refresh(); } @@ -3346,6 +3351,5 @@ bool Game_Interpreter::DefaultContinuation(RPG::EventCommand const& /* com */) { bool Game_Interpreter::ContinuationOpenShop(RPG::EventCommand const& /* com */) { return true; } bool Game_Interpreter::ContinuationShowInnStart(RPG::EventCommand const& /* com */) { return true; } -bool Game_Interpreter::ContinuationShowInnFinish(RPG::EventCommand const& /* com */) { return true; } bool Game_Interpreter::ContinuationEnemyEncounter(RPG::EventCommand const& /* com */) { return true; } diff --git a/src/game_interpreter.h b/src/game_interpreter.h index 6fe69fc00d..996c43c693 100644 --- a/src/game_interpreter.h +++ b/src/game_interpreter.h @@ -256,7 +256,6 @@ class Game_Interpreter virtual bool ContinuationChoices(RPG::EventCommand const& com); virtual bool ContinuationOpenShop(RPG::EventCommand const& com); virtual bool ContinuationShowInnStart(RPG::EventCommand const& com); - virtual bool ContinuationShowInnFinish(RPG::EventCommand const& com); virtual bool ContinuationEnemyEncounter(RPG::EventCommand const& com); int DecodeInt(std::vector::const_iterator& it); diff --git a/src/game_interpreter_map.cpp b/src/game_interpreter_map.cpp index 356f532d61..99957786a7 100644 --- a/src/game_interpreter_map.cpp +++ b/src/game_interpreter_map.cpp @@ -366,8 +366,7 @@ bool Game_Interpreter_Map::CommandShowInn(RPG::EventCommand const& com) { // cod if (Game_Temp::inn_price == 0) { // Skip prompt. Game_Message::choice_result = 0; - SetContinuation(static_cast(&Game_Interpreter_Map::ContinuationShowInnStart)); - return false; + return ContinuationShowInnStart(com); } Game_Message::message_waiting = true; @@ -463,7 +462,7 @@ bool Game_Interpreter_Map::CommandShowInn(RPG::EventCommand const& com) { // cod // save game compatibility with RPG_RT ReserveSubcommandIndex(com.indent); - return false; + return true; } bool Game_Interpreter_Map::ContinuationShowInnStart(RPG::EventCommand const& com) { @@ -485,64 +484,13 @@ bool Game_Interpreter_Map::ContinuationShowInnStart(RPG::EventCommand const& com if (inn_stay) { Main_Data::game_party->GainGold(-Game_Temp::inn_price); - // Full heal - std::vector actors = Main_Data::game_party->GetActors(); - for (Game_Actor* actor : actors) { - actor->FullHeal(); - } - Graphics::GetTransition().Init(Transition::TransitionFadeOut, Scene::instance.get(), 36, true); - Game_System::BgmFade(800); - SetContinuation(static_cast(&Game_Interpreter_Map::ContinuationShowInnContinue)); - return false; + _async_op = AsyncOp::MakeCallInn(); + return true; } - ++index; return true; } -bool Game_Interpreter_Map::ContinuationShowInnContinue(RPG::EventCommand const& /* com */) { - if (Graphics::IsTransitionPending()) - return false; - - const RPG::Music& bgm_inn = Game_System::GetSystemBGM(Game_System::BGM_Inn); - // FIXME: Abusing before_battle_music (Which is unused when calling an Inn) - // Is there also before_inn_music in the savegame? - Main_Data::game_data.system.before_battle_music = Game_System::GetCurrentBGM(); - - Game_System::BgmPlay(bgm_inn); - - SetContinuation(static_cast(&Game_Interpreter_Map::ContinuationShowInnFinish)); - - return false; -} - -bool Game_Interpreter_Map::ContinuationShowInnFinish(RPG::EventCommand const& com) { - auto* frame = GetFrame(); - assert(frame); - auto& index = frame->current_command; - - if (Graphics::IsTransitionPending()) - return false; - - const RPG::Music& bgm_inn = Game_System::GetSystemBGM(Game_System::BGM_Inn); - if (bgm_inn.name.empty() || - bgm_inn.name == "(OFF)" || - bgm_inn.name == "(Brak)" || - !Audio().BGM_IsPlaying() || - Audio().BGM_PlayedOnce()) { - - Game_System::BgmStop(); - continuation = NULL; - Graphics::GetTransition().Init(Transition::TransitionFadeIn, Scene::instance.get(), 36, false); - Game_System::BgmPlay(Main_Data::game_data.system.before_battle_music); - - ++index; - return false; - } - - return false; -} - bool Game_Interpreter_Map::CommandStay(RPG::EventCommand const& com) { // code 20730 return CommandOptionGeneric(com, eOptionInnStay, {Cmd::NoStay, Cmd::EndInn}); } diff --git a/src/game_interpreter_map.h b/src/game_interpreter_map.h index 70e7fd874b..49ca33f2f6 100644 --- a/src/game_interpreter_map.h +++ b/src/game_interpreter_map.h @@ -84,8 +84,6 @@ class Game_Interpreter_Map : public Game_Interpreter bool ContinuationOpenShop(RPG::EventCommand const& com) override; bool ContinuationShowInnStart(RPG::EventCommand const& com) override; - bool ContinuationShowInnContinue(RPG::EventCommand const& com); - bool ContinuationShowInnFinish(RPG::EventCommand const& com) override; bool ContinuationEnemyEncounter(RPG::EventCommand const& com) override; static std::vector pending; diff --git a/src/scene_map.cpp b/src/scene_map.cpp index 27488bb9df..6cf4958837 100644 --- a/src/scene_map.cpp +++ b/src/scene_map.cpp @@ -197,6 +197,10 @@ void Scene_Map::PreUpdateForegroundEvents(MapUpdateAsyncContext& actx) { } void Scene_Map::Update() { + if (activate_inn) { + UpdateInn(); + return; + } MapUpdateAsyncContext actx; UpdateStage1(actx); } @@ -438,6 +442,55 @@ void Scene_Map::OnAsyncSuspend(F&& f, AsyncOp aop, bool is_preupdate) { screen_erased_by_event = false; } + if (aop.GetType() == AsyncOp::eCallInn) { + activate_inn = true; + music_before_inn = Game_System::GetCurrentBGM(); + inn_continuation = std::forward(f); + + Game_System::BgmFade(800); + + // FIXME: Is 36 correct here? + Graphics::GetTransition().Init(Transition::TransitionFadeOut, Scene::instance.get(), 36, true); + + AsyncNext([=]() { StartInn(); }); + return; + } + AsyncNext(std::forward(f)); } +void Scene_Map::StartInn() { + const RPG::Music& bgm_inn = Game_System::GetSystemBGM(Game_System::BGM_Inn); + if (Game_System::IsStopMusicFilename(bgm_inn.name)) { + FinishInn(); + return; + } + + Game_System::BgmPlay(bgm_inn); +} + +void Scene_Map::FinishInn() { + // RPG_RT will always transition in, regardless of whether an EraseScreen command + // was issued previously. + screen_erased_by_event = false; + + // FIXME: Is 36 correct here? + Graphics::GetTransition().Init(Transition::TransitionFadeIn, Scene::instance.get(), 36, false); + Game_System::BgmPlay(music_before_inn); + + // Full heal + std::vector actors = Main_Data::game_party->GetActors(); + for (Game_Actor* actor : actors) { + actor->FullHeal(); + } + + activate_inn = false; + AsyncNext(std::move(inn_continuation)); +} + +void Scene_Map::UpdateInn() { + if (!Audio().BGM_IsPlaying() || Audio().BGM_PlayedOnce()) { + Game_System::BgmStop(); + FinishInn(); + } +} diff --git a/src/scene_map.h b/src/scene_map.h index 3d1ceadd4d..0a9f080cc6 100644 --- a/src/scene_map.h +++ b/src/scene_map.h @@ -86,6 +86,10 @@ class Scene_Map: public Scene { void UpdateSceneCalling(); + void StartInn(); + void UpdateInn(); + void FinishInn(); + template void AsyncNext(F&& f); template void OnAsyncSuspend(F&& f, AsyncOp aop, bool is_preupdate); @@ -94,6 +98,10 @@ class Scene_Map: public Scene { int debug_menuoverwrite_counter = 0; bool from_save; bool screen_erased_by_event = false; + + RPG::Music music_before_inn = {}; + AsyncContinuation inn_continuation = {}; + bool activate_inn = false; }; #endif From 23ea69fa3158b1d867f5a794e8b137372967bc0d Mon Sep 17 00:00:00 2001 From: Matthew Fioravante Date: Mon, 2 Sep 2019 23:41:24 -0400 Subject: [PATCH 4/4] Fix Inn text rendering "It will be 1 Gfor the night" -> "It will be 1G for the night" --- src/game_interpreter_map.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/game_interpreter_map.cpp b/src/game_interpreter_map.cpp index 99957786a7..a95b220b4f 100644 --- a/src/game_interpreter_map.cpp +++ b/src/game_interpreter_map.cpp @@ -396,9 +396,8 @@ bool Game_Interpreter_Map::CommandShowInn(RPG::EventCommand const& com) { // cod } else { out << Data::terms.inn_a_greeting_1 - << " " << Game_Temp::inn_price - << " " << Data::terms.gold - << Data::terms.inn_a_greeting_2; + << " " << Game_Temp::inn_price << Data::terms.gold + << " " << Data::terms.inn_a_greeting_2; Game_Message::texts.push_back(out.str()); Game_Message::texts.push_back(Data::terms.inn_a_greeting_3); } @@ -423,9 +422,8 @@ bool Game_Interpreter_Map::CommandShowInn(RPG::EventCommand const& com) { // cod } else { out << Data::terms.inn_b_greeting_1 - << " " << Game_Temp::inn_price - << " " << Data::terms.gold - << Data::terms.inn_b_greeting_2; + << " " << Game_Temp::inn_price << Data::terms.gold + << " " << Data::terms.inn_b_greeting_2; Game_Message::texts.push_back(out.str()); Game_Message::texts.push_back(Data::terms.inn_b_greeting_3); }