Skip to content

Commit

Permalink
Add Scene_Inn
Browse files Browse the repository at this point in the history
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()
  • Loading branch information
mateofio committed Sep 4, 2019
1 parent 33e7502 commit fa3e162
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 105 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
112 changes: 64 additions & 48 deletions src/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -162,14 +175,16 @@ 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.
AsyncContinuation continuation;
async_continuation.swap(continuation);

continuation();
rc = true;
}

// If we just finished an async operation that was
Expand All @@ -179,6 +194,7 @@ void Scene::OnFinishAsync() {
if (was_async_from_main_loop && !IsAsyncPending()) {
Player::IncFrame();
}
return rc;
}

bool Scene::IsAsyncPending() {
Expand Down
7 changes: 6 additions & 1 deletion src/scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class Scene {
Order,
GameBrowser,
Teleport,
Inn,
SceneMax
};

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;

Expand All @@ -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;
};
Expand Down
56 changes: 56 additions & 0 deletions src/scene_inn.cpp
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

// 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<Game_Actor*> 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);
}
45 changes: 45 additions & 0 deletions src/scene_inn.h
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

#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
Loading

0 comments on commit fa3e162

Please sign in to comment.