From fa3e162dd4082774fc7c3c2077b9ae376674a441 Mon Sep 17 00:00:00 2001 From: Matthew Fioravante Date: Tue, 3 Sep 2019 23:49:21 -0400 Subject: [PATCH] Add Scene_Inn Use a separate scene for the inn logic. This refactors the Scene::MainFunction() to support resuming async callbacks between scene changes. The correct execution sequence is like this: 1. Scene_Map::Update(): Push(Inn), set async_continuation 2. Scene_Inn::Scene_Inn(): Remembers music 3. Scene_Map::Suspend(): 4. Scene_Map::TransitionOut(): FadeOut 5. Scene_Inn::Start(): Heal, start inn music 6. Scene_Inn::Update(): wait inn music 7. Scene_Inn::Suspend(): Play prev music 8. Scene_Map::Continue(): 9. Scene_Map::TransitionIn(): Fade In 10. Scene_Map::async_continuation(): Resume game loop after inn 11. Scene_Map::Update() --- CMakeLists.txt | 2 + Makefile.am | 2 + src/scene.cpp | 112 ++++++++++++++++++++++++++-------------------- src/scene.h | 7 ++- src/scene_inn.cpp | 56 +++++++++++++++++++++++ src/scene_inn.h | 45 +++++++++++++++++++ src/scene_map.cpp | 65 +++++++-------------------- src/scene_map.h | 8 ---- 8 files changed, 192 insertions(+), 105 deletions(-) create mode 100644 src/scene_inn.cpp create mode 100644 src/scene_inn.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d88116fcf47..c4abe9b4857 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,6 +204,8 @@ add_library(${PROJECT_NAME} src/scene_gameover.cpp src/scene_gameover.h src/scene.h + src/scene_inn.cpp + src/scene_inn.h src/scene_item.cpp src/scene_item.h src/scene_load.cpp diff --git a/Makefile.am b/Makefile.am index 7fa053d2e2a..764724fd5a8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -209,6 +209,8 @@ libeasyrpg_player_a_SOURCES = \ src/scene_gamebrowser.h \ src/scene_gameover.cpp \ src/scene_gameover.h \ + src/scene_inn.cpp \ + src/scene_inn.h \ src/scene_item.cpp \ src/scene_item.h \ src/scene_load.cpp \ diff --git a/src/scene.cpp b/src/scene.cpp index 58bfa1b3672..f24c9555e8d 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -75,66 +75,79 @@ Scene::Scene() { type = Scene::Null; } -void Scene::MainFunction() { - static bool init = false; +void Scene::MainResume() { + // Initialization after scene switch + switch (push_pop_operation) { + case ScenePushed: + Start(); + initialized = true; + break; + case ScenePopped: + if (!initialized) { + Start(); + initialized = true; + } else { + Continue(prev_scene); + } + break; + default:; + } + + push_pop_operation = 0; + + TransitionIn(prev_scene); + Resume(prev_scene); + resume = false; +} + +void Scene::MainSuspend() { + // Shutdown after scene switch + assert(Scene::instance == instances.back() && + "Don't set Scene::instance directly, use Push instead!"); + Graphics::Update(); + + Suspend(); + TransitionOut(instance ? instance->type : Null); + + // TransitionOut stored a screenshot of the last scene + Graphics::UpdateSceneCallback(); + resume = true; +} + +void Scene::MainFunction() { if (IsAsyncPending()) { Player::Update(false); return; - } else { - // This is used to provide a hook for Scene_Map to finish - // it's PreUpdate() and teleport logic after transition - // or asynchronous file load. - OnFinishAsync(); } - // The continuation could have caused a new async wait condition, or - // it could have changed the scene. - if (!IsAsyncPending() && Scene::instance.get() == this) { - if (!init) { - // Initialization after scene switch - switch (push_pop_operation) { - case ScenePushed: - Start(); - initialized = true; - break; - case ScenePopped: - if (!initialized) { - Start(); - initialized = true; - } else { - Continue(prev_scene); - } - break; - default:; - } + MainFunction2(); - push_pop_operation = 0; + // New scene was installed. Suspend this one. + if (Scene::instance.get() != this) { + MainSuspend(); + } +} - TransitionIn(prev_scene); - Resume(prev_scene); +void Scene::MainFunction2() { + if (resume) { + MainResume(); + return; + } - init = true; + // This is used to provide a hook for Scene_Map to finish + // it's PreUpdate() and teleport logic after transition + // or asynchronous file load. + if (OnFinishAsync()) { + if (IsAsyncPending()) { return; - } else { - Player::Update(); } } - if (Scene::instance.get() != this) { - // Shutdown after scene switch - assert(Scene::instance == instances.back() && - "Don't set Scene::instance directly, use Push instead!"); - - Graphics::Update(); - - Suspend(); - TransitionOut(instance ? instance->type : Null); - - // TransitionOut stored a screenshot of the last scene - Graphics::UpdateSceneCallback(); - - init = false; + // The continuation could have caused a new async wait condition, or + // it could have changed the scene. + if (Scene::instance.get() == this) { + Player::Update(); } } @@ -162,7 +175,8 @@ void Scene::SetAsyncFromMainLoop() { was_async_from_main_loop = true; } -void Scene::OnFinishAsync() { +bool Scene::OnFinishAsync() { + bool rc = false; if (async_continuation) { // The continuation could set another continuation, so move this // one out of the way first before we call it. @@ -170,6 +184,7 @@ void Scene::OnFinishAsync() { async_continuation.swap(continuation); continuation(); + rc = true; } // If we just finished an async operation that was @@ -179,6 +194,7 @@ void Scene::OnFinishAsync() { if (was_async_from_main_loop && !IsAsyncPending()) { Player::IncFrame(); } + return rc; } bool Scene::IsAsyncPending() { diff --git a/src/scene.h b/src/scene.h index e2625d106c1..be19c76064e 100644 --- a/src/scene.h +++ b/src/scene.h @@ -53,6 +53,7 @@ class Scene { Order, GameBrowser, Teleport, + Inn, SceneMax }; @@ -128,7 +129,7 @@ class Scene { /** * Called when a transition or async load is finished. */ - void OnFinishAsync(); + bool OnFinishAsync(); /** * Tell the scene we spawned an async operation from the main loop. @@ -235,6 +236,7 @@ class Scene { * other Continue(). This enforces calling Start(). */ bool initialized = false; + bool resume = true; bool was_async_from_main_loop = false; @@ -245,6 +247,9 @@ class Scene { static void DebugValidate(const char* caller); static void UpdatePrevScene(); + void MainResume(); + void MainSuspend(); + void MainFunction2(); Scene::SceneType request_scene = Null; }; diff --git a/src/scene_inn.cpp b/src/scene_inn.cpp new file mode 100644 index 00000000000..a03cf23bce3 --- /dev/null +++ b/src/scene_inn.cpp @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +// Headers +#include "scene_inn.h" +#include "game_system.h" +#include "transition.h" +#include "audio.h" +#include "main_data.h" +#include "game_party.h" + +Scene_Inn::Scene_Inn() { + Scene::type = Scene::Inn; + music_before_inn = Game_System::GetCurrentBGM(); + Game_System::BgmFade(800); +} + +void Scene_Inn::Start() { + // Full heal + std::vector actors = Main_Data::game_party->GetActors(); + for (Game_Actor* actor : actors) { + actor->FullHeal(); + } + + const RPG::Music& bgm_inn = Game_System::GetSystemBGM(Game_System::BGM_Inn); + if (Game_System::IsStopMusicFilename(bgm_inn.name)) { + Game_System::BgmStop(); + } else { + Game_System::BgmPlay(bgm_inn); + } +} + +void Scene_Inn::Update() { + if (!Audio().BGM_IsPlaying() || Audio().BGM_PlayedOnce()) { + Game_System::BgmStop(); + Scene::Pop(); + } +} + +void Scene_Inn::Suspend() { + Game_System::BgmPlay(music_before_inn); +} diff --git a/src/scene_inn.h b/src/scene_inn.h new file mode 100644 index 00000000000..22762943c44 --- /dev/null +++ b/src/scene_inn.h @@ -0,0 +1,45 @@ +/* + * 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_SCENE_INN_H +#define EP_SCENE_INN_H + +// Headers +#include "scene.h" +#include "rpg_music.h" + +/** + * Scene_Inn class. + */ +class Scene_Inn : public Scene { + +public: + Scene_Inn(); + + void Start() override; + void Update() override; + void Suspend() override; + + void TransitionIn(Scene::SceneType) override {} + void TransitionOut(Scene::SceneType) override {} + +private: + RPG::Music music_before_inn = {}; + AsyncContinuation inn_continuation = {}; +}; + +#endif diff --git a/src/scene_map.cpp b/src/scene_map.cpp index 54c5c1ab69e..ad6c4c5b178 100644 --- a/src/scene_map.cpp +++ b/src/scene_map.cpp @@ -26,6 +26,7 @@ #include "scene_save.h" #include "scene_battle.h" #include "scene_debug.h" +#include "scene_inn.h" #include "main_data.h" #include "game_map.h" #include "game_message.h" @@ -40,6 +41,7 @@ #include "input.h" #include "screen.h" #include "scene_load.h" +#include "output.h" static bool GetRunForegroundEvents(TeleportTarget::Type tt) { switch (tt) { @@ -156,6 +158,12 @@ void Scene_Map::TransitionIn(SceneType prev_scene) { return; } + if (prev_scene == Scene::Inn) { + // FIXME: Is 36 correct here? + Graphics::GetTransition().Init(Transition::TransitionFadeIn, this, 36, false); + return; + } + if (IsMenuScene(prev_scene)) { Scene::TransitionIn(prev_scene); return; @@ -175,10 +183,17 @@ void Scene_Map::TransitionOut(SceneType next_scene) { Graphics::GetTransition().AppendBefore(Color(255, 255, 255, 255), 12, 2); return; } + if (next_scene == Scene::Gameover) { Graphics::GetTransition().Init(Transition::TransitionFadeOut, this, 32, true); return; } + + if (next_scene == Scene::Inn) { + // FIXME: Is 36 correct here? + Graphics::GetTransition().Init(Transition::TransitionFadeOut, this, 36, true); + return; + } Scene::TransitionOut(next_scene); } @@ -199,10 +214,6 @@ void Scene_Map::PreUpdateForegroundEvents(MapUpdateAsyncContext& actx) { } void Scene_Map::Update() { - if (activate_inn) { - UpdateInn(); - return; - } MapUpdateAsyncContext actx; UpdateStage1(actx); } @@ -445,54 +456,12 @@ void Scene_Map::OnAsyncSuspend(F&& f, AsyncOp aop, bool is_preupdate) { } 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); + Scene::Push(std::make_shared()); - AsyncNext([=]() { StartInn(); }); + async_continuation = std::forward(f); 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 0a9f080cc63..3d1ceadd4db 100644 --- a/src/scene_map.h +++ b/src/scene_map.h @@ -86,10 +86,6 @@ 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); @@ -98,10 +94,6 @@ 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