1 ////////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2011 by The Allacrost Project
3 // Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 // All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software and
7 // you may modify it and/or redistribute it under the terms of this license.
8 // See https://www.gnu.org/copyleft/gpl.html for details.
9 ////////////////////////////////////////////////////////////////////////////////
10
11 /** ****************************************************************************
12 *** \file battle_sequence.cpp
13 *** \author Tyler Olsen, roots@allacrost.org
14 *** \author Yohann Ferreira, yohann ferreira orange fr
15 *** \brief Source file for battle sequence manager.
16 *** ***************************************************************************/
17
18 #include "modes/battle/battle_sequence.h"
19
20 #include "engine/audio/audio.h"
21 #include "engine/mode_manager.h"
22 #include "engine/system.h"
23 #include "engine/video/video.h"
24
25 #include "modes/battle/battle.h"
26 #include "modes/battle/objects/battle_character.h"
27 #include "modes/battle/objects/battle_enemy.h"
28
29 #include "common/global/media/battle_media.h"
30 #include "common/global/global.h"
31
32 using namespace vt_utils;
33 using namespace vt_audio;
34 using namespace vt_mode_manager;
35 using namespace vt_system;
36 using namespace vt_video;
37
38 namespace vt_battle
39 {
40
41 namespace private_battle
42 {
43
44 /** \brief Sequence step constants
45 ***
46 *** These are used by the SequenceSupervisor methods to progress through each step in a given sequence.
47 *** These constants should not need to be used in any other area of the battle code.
48 **/
49 //@{
50 static const uint32_t INIT_STEP_BACKGROUND_FADE = 1;
51 static const uint32_t INIT_STEP_SPRITE_MOVEMENT = 2;
52 static const uint32_t INIT_STEP_GUI_POSITIONING = 3;
53
54 static const uint32_t EXIT_STEP_GUI_POSITIONING = 1;
55 static const uint32_t EXIT_STEP_SCREEN_FADE = 2;
56 //@}
57
SequenceSupervisor(BattleMode * current_instance)58 SequenceSupervisor::SequenceSupervisor(BattleMode *current_instance) :
59 _battle(current_instance),
60 _one_is_dead(false),
61 _sequence_step(0),
62 _gui_position_offset(0.0f)
63 {}
64
~SequenceSupervisor()65 SequenceSupervisor::~SequenceSupervisor()
66 {}
67
Update()68 void SequenceSupervisor::Update()
69 {
70 switch(_battle->_state) {
71 case BATTLE_STATE_INITIAL:
72 _UpdateInitialSequence();
73 break;
74 case BATTLE_STATE_EXITING:
75 _UpdateExitingSequence();
76 break;
77 default:
78 IF_PRINT_WARNING(BATTLE_DEBUG) << "battle mode was not in a supported sequence state: " << _battle->_state << std::endl;
79 _battle->ChangeState(BATTLE_STATE_NORMAL);
80 break;
81 }
82 }
83
Draw()84 void SequenceSupervisor::Draw()
85 {
86 switch(_battle->_state) {
87 case BATTLE_STATE_INITIAL:
88 _DrawInitialSequence();
89 break;
90 case BATTLE_STATE_EXITING:
91 _DrawExitingSequence();
92 break;
93 default:
94 break;
95 }
96 }
97
DrawPostEffects()98 void SequenceSupervisor::DrawPostEffects()
99 {
100 switch(_battle->_state) {
101 case BATTLE_STATE_INITIAL:
102 _DrawInitialSequencePostEffects();
103 break;
104 case BATTLE_STATE_EXITING:
105 _DrawExitingSequencePostEffects();
106 break;
107 default:
108 break;
109 }
110 }
111
_UpdateInitialSequence()112 void SequenceSupervisor::_UpdateInitialSequence()
113 {
114 // Constants that define the time duration of each step in the sequence
115 const uint32_t STEP_01_TIME = 500;
116 const uint32_t STEP_02_TIME = 500;
117 const uint32_t STEP_03_TIME = 500;
118
119 // The furthest position offset we place the GUI objects when bringing them into view
120 const float MAX_GUI_OFFSET = 150.0f;
121 // The furtherst positions character ane enemy sprites are placed when animating them into view
122 const float MAX_CHARACTER_OFFSET = 250.0f;
123 const float MAX_ENEMY_OFFSET = 750.0f;
124
125 // Step 0: Initial entry, prepare members for the steps to follow
126 if(_sequence_step == 0) {
127 // Check whether one character is dead
128 _one_is_dead = _battle->isOneCharacterDead();
129
130 _gui_position_offset = MAX_GUI_OFFSET;
131 _sequence_timer.Initialize(STEP_01_TIME);
132 _sequence_timer.Run();
133
134 // The characters can't run when one of them is dead,
135 // as they wouldn't let him behind.
136 for(uint32_t i = 0; i < _battle->_character_actors.size(); i++) {
137 if(_one_is_dead) {
138 _battle->_character_actors[i]->SetXLocation(_battle->_character_actors[i]->GetXOrigin());
139 if(_battle->_character_actors[i]->IsAlive())
140 _battle->_character_actors[i]->ChangeSpriteAnimation("idle");
141 else
142 _battle->_character_actors[i]->ChangeSpriteAnimation("dead");
143 } else {
144 _battle->_character_actors[i]->SetXLocation(_battle->_character_actors[i]->GetXOrigin() - MAX_CHARACTER_OFFSET);
145 _battle->_character_actors[i]->ChangeSpriteAnimation("run");
146 }
147 }
148
149 for(uint32_t i = 0; i < _battle->_enemy_actors.size(); i++) {
150 _battle->_enemy_actors[i]->SetXLocation(_battle->_enemy_actors[i]->GetXOrigin() + MAX_ENEMY_OFFSET);
151 }
152
153 _sequence_step = INIT_STEP_BACKGROUND_FADE;
154 }
155 // Step 1: Fade in the background graphics
156 else if(_sequence_step == INIT_STEP_BACKGROUND_FADE) {
157 _sequence_timer.Update();
158
159 if(_sequence_timer.IsFinished()) {
160 _sequence_timer.Initialize(STEP_02_TIME);
161 _sequence_timer.Run();
162 _sequence_step = INIT_STEP_SPRITE_MOVEMENT;
163 }
164 }
165 // Step 2: Move character and enemy sprites from off screen to their positions
166 else if(_sequence_step == INIT_STEP_SPRITE_MOVEMENT) {
167 _sequence_timer.Update();
168
169 float percent_incomplete = 1.0f - _sequence_timer.PercentComplete();
170 if(!_one_is_dead) {
171 for(uint32_t i = 0; i < _battle->_character_actors.size(); i++) {
172 _battle->_character_actors[i]->SetXLocation(_battle->_character_actors[i]->GetXOrigin() - (MAX_CHARACTER_OFFSET * percent_incomplete));
173 }
174 }
175
176 for(uint32_t i = 0; i < _battle->_enemy_actors.size(); i++) {
177 _battle->_enemy_actors[i]->SetXLocation(_battle->_enemy_actors[i]->GetXOrigin() + (MAX_ENEMY_OFFSET * percent_incomplete));
178 }
179
180 if(_sequence_timer.IsFinished()) {
181 // Done to ensure that all actors are at their correct locations
182 for(uint32_t i = 0; i < _battle->_character_actors.size(); i++) {
183 _battle->_character_actors[i]->SetXLocation(_battle->_character_actors[i]->GetXOrigin());
184 if(_battle->_character_actors[i]->IsAlive())
185 _battle->_character_actors[i]->ChangeSpriteAnimation("idle");
186 else
187 _battle->_character_actors[i]->ChangeSpriteAnimation("dead");
188 }
189 for(uint32_t i = 0; i < _battle->_enemy_actors.size(); i++) {
190 _battle->_enemy_actors[i]->SetXLocation(_battle->_enemy_actors[i]->GetXOrigin());
191 }
192
193 _sequence_timer.Initialize(STEP_03_TIME);
194 _sequence_timer.Run();
195 _sequence_step = INIT_STEP_GUI_POSITIONING;
196 }
197 }
198 // Step 3: Bring in GUI objects from off screen
199 else if(_sequence_step == INIT_STEP_GUI_POSITIONING) {
200 _sequence_timer.Update();
201 _gui_position_offset = MAX_GUI_OFFSET - (_sequence_timer.PercentComplete() * MAX_GUI_OFFSET);
202
203 // Finished with the final step, reset the sequence step counter and begin normal battle state
204 if(_sequence_timer.IsFinished()) {
205 _sequence_step = 0;
206 BattleMode::CurrentInstance()->ChangeState(BATTLE_STATE_NORMAL);
207 }
208 }
209 // If we're in at an unknown step, reset the counter and resume normal battle operation
210 else {
211 IF_PRINT_DEBUG(BATTLE_DEBUG) << "invalid sequence step counter: " << _sequence_step << std::endl;
212 _sequence_step = 0;
213 BattleMode::CurrentInstance()->ChangeState(BATTLE_STATE_NORMAL);
214 }
215 }
216
_UpdateExitingSequence()217 void SequenceSupervisor::_UpdateExitingSequence()
218 {
219 // Constants that define the time duration of each step in the sequence
220 const uint32_t STEP_01_TIME = 500;
221 const uint32_t STEP_02_TIME = 1200;
222
223 // The furthest position offset we place the GUI objects when bringing them out of view
224 const float GUI_OFFSCREEN_OFFSET = 150.0f;
225
226 // Step 0: Initial entry, prepare members for the steps to follow
227 if(_sequence_step == 0) {
228 // Check whether one character is dead
229 _one_is_dead = _battle->isOneCharacterDead();
230
231 _gui_position_offset = 0.0f;
232 _sequence_timer.Initialize(STEP_01_TIME);
233 _sequence_timer.Run();
234
235 _sequence_step = EXIT_STEP_GUI_POSITIONING;
236 }
237 // Step 1: Shift GUI objects off screen
238 else if(_sequence_step == EXIT_STEP_GUI_POSITIONING) {
239 _sequence_timer.Update();
240 _gui_position_offset = GUI_OFFSCREEN_OFFSET * _sequence_timer.PercentComplete();
241
242 if(_sequence_timer.IsFinished()) {
243 _sequence_timer.Initialize(STEP_02_TIME);
244 _sequence_timer.Run();
245 _sequence_step = EXIT_STEP_SCREEN_FADE;
246
247 if(!_one_is_dead) {
248 for(uint32_t i = 0; i < _battle->_character_actors.size(); i++) {
249 BattleCharacter* character = _battle->_character_actors[i];
250 character->ChangeSpriteAnimation("run_after_victory");
251 // Set the current position as their origin one, so that it doesn't look odd
252 // if they end the battle in the middle of a skill.
253 character->SetXOrigin(character->GetXLocation());
254 character->SetYOrigin(character->GetYLocation());
255 }
256 }
257
258 // Trigger a fade out exit state.
259 ModeManager->Pop(true, true);
260 }
261 }
262 // Step 2: Run living characters right and fade screen to black
263 else if(_sequence_step == EXIT_STEP_SCREEN_FADE) {
264 _sequence_timer.Update();
265
266 // Make the character run only if they're all alive.
267 if(!_one_is_dead) {
268 for(uint32_t i = 0; i < _battle->_character_actors.size(); i++) {
269 _battle->_character_actors[i]->SetXLocation(_battle->_character_actors[i]->GetXOrigin() +
270 _sequence_timer.GetTimeExpired());
271 }
272 }
273 }
274 // If we're in at an unknown step, restart at sequence zero
275 else {
276 IF_PRINT_DEBUG(BATTLE_DEBUG) << "invalid sequence step counter: " << _sequence_step << std::endl;
277 _sequence_step = 0;
278 }
279 }
280
_DrawInitialSequence()281 void SequenceSupervisor::_DrawInitialSequence()
282 {
283 if(_sequence_step >= INIT_STEP_BACKGROUND_FADE)
284 _battle->_DrawBackgroundGraphics();
285
286 if(_one_is_dead || _sequence_step >= INIT_STEP_SPRITE_MOVEMENT)
287 _battle->_DrawSprites();
288
289 if(_sequence_step >= INIT_STEP_BACKGROUND_FADE)
290 _battle->_DrawForegroundGraphics();
291 }
292
_DrawInitialSequencePostEffects()293 void SequenceSupervisor::_DrawInitialSequencePostEffects()
294 {
295 if(_sequence_step >= INIT_STEP_GUI_POSITIONING) {
296 _DrawGUI();
297 }
298 }
299
_DrawExitingSequence()300 void SequenceSupervisor::_DrawExitingSequence()
301 {
302 _battle->_DrawBackgroundGraphics();
303 _battle->_DrawSprites();
304 _battle->_DrawForegroundGraphics();
305 }
306
_DrawExitingSequencePostEffects()307 void SequenceSupervisor::_DrawExitingSequencePostEffects()
308 {
309 if(_sequence_step <= EXIT_STEP_GUI_POSITIONING) {
310 _DrawGUI();
311 }
312 }
313
_DrawGUI()314 void SequenceSupervisor::_DrawGUI()
315 {
316 vt_global::BattleMedia& battle_media = vt_global::GlobalManager->GetBattleMedia();
317 // Draw all images that compose the bottom menu area
318 // Draw the static image for the lower menu
319 VideoManager->SetDrawFlags(VIDEO_X_LEFT, VIDEO_Y_BOTTOM, VIDEO_BLEND, 0);
320 VideoManager->Move(0.0f, VIDEO_STANDARD_RES_HEIGHT + _gui_position_offset);
321 battle_media.bottom_menu_image.Draw();
322 }
323
324 } // namespace private_battle
325
326 } // namespace vt_battle
327