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