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
7 // and 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 #include "modes/menu/menu_windows/menu_battle_formation_window.h"
12 
13 #include "modes/menu/menu_mode.h"
14 
15 #include "engine/audio/audio.h"
16 #include "engine/input.h"
17 #include "engine/system.h"
18 
19 #include "common/global/actors/global_character.h"
20 
21 using namespace vt_menu::private_menu;
22 using namespace vt_utils;
23 using namespace vt_audio;
24 using namespace vt_video;
25 using namespace vt_gui;
26 using namespace vt_global;
27 using namespace vt_input;
28 using namespace vt_system;
29 
30 namespace vt_menu
31 {
32 
33 namespace private_menu
34 {
35 
BattleFormationWindow()36 BattleFormationWindow::BattleFormationWindow() :
37     _formation_select_active(false)
38 {
39     std::vector<GlobalCharacter *>* characters = GlobalManager->GetCharacterHandler().GetOrderedCharacters();
40     uint32_t characters_number = characters->size() > 4 ? 4 : characters->size();
41 
42     // Init the option box.
43     _formation_select.SetPosition(272.0f, 170.0f);
44     _formation_select.SetDimensions(360.0f, 330.0f,
45                                     1, characters_number,
46                                     1, characters_number);
47     _formation_select.SetCursorOffset(-50.0f, -6.0f);
48     _formation_select.SetTextStyle(TextStyle("text20"));
49     _formation_select.SetHorizontalWrapMode(VIDEO_WRAP_MODE_STRAIGHT);
50     _formation_select.SetVerticalWrapMode(VIDEO_WRAP_MODE_STRAIGHT);
51     _formation_select.SetOptionAlignment(VIDEO_X_LEFT, VIDEO_Y_CENTER);
52     std::vector<ustring> options;
53 
54     _characters_position.resize(characters_number);
55 
56     // Set up the characters animations
57     for(uint32_t i = 0; i < characters_number; ++i) {
58         GlobalCharacter* character = characters->at(i);
59         if (!character)
60             continue;
61 
62         options.push_back(UTranslate("Switch"));
63 
64         // Load a copy of the corresponding battle character sprite.
65         AnimatedImage anim;
66         if (character->IsAlive())
67             anim = *character->RetrieveBattleAnimation("idle");
68         else
69             anim = *character->RetrieveBattleAnimation("dead");
70         anim.SetDimensions(anim.GetWidth() * 0.7f, anim.GetHeight() * 0.7f);
71         _character_sprites.push_back(anim);
72 
73         // TODO: Get position from Save/Global data.
74         _characters_position[i] = true;
75     }
76 
77     _formation_select.SetOptions(options);
78     _formation_select.SetSelection(0);
79     _formation_select.SetCursorState(VIDEO_CURSOR_STATE_HIDDEN);
80 
81     _character_target_texts.resize(characters_number);
82 
83     // We set them here in case the language has changed since the game start
84     _help_text.SetStyle(TextStyle("text20"));
85     _help_text.SetText(UTranslate("Select a battle formation to change character placement."));
86 
87     _rear_front_txt.SetStyle(TextStyle("text24"));
88     _rear_front_txt.SetText(UTranslate("Rear - Front"));
89     _modifier_txt.SetStyle(TextStyle("text24"));
90     _modifier_txt.SetText("Modifiers");
91 
92     UpdateStatus();
93 }
94 
Activate(bool activated)95 void BattleFormationWindow::Activate(bool activated)
96 {
97     if(activated) {
98         _formation_select_active = true;
99         _formation_select.SetCursorState(VIDEO_CURSOR_STATE_VISIBLE);
100     } else {
101         _formation_select_active = false;
102         _formation_select.SetCursorState(VIDEO_CURSOR_STATE_HIDDEN);
103     }
104 }
105 
Update()106 void BattleFormationWindow::Update()
107 {
108     GlobalMedia& media = GlobalManager->Media();
109 
110     // Handle the appropriate input events
111     if(InputManager->ConfirmPress()) {
112         _formation_select.InputConfirm();
113         // Switch character position.
114         int32_t selection = _formation_select.GetSelection();
115         _characters_position[selection] = !_characters_position[selection];
116         UpdateStatus();
117     } else if(InputManager->CancelPress()) {
118         _formation_select.InputCancel();
119         Activate(false);
120         media.PlaySound("cancel");
121     } else if(InputManager->LeftPress()) {
122         media.PlaySound("bump");
123         _formation_select.InputLeft();
124     } else if(InputManager->RightPress()) {
125         media.PlaySound("bump");
126         _formation_select.InputRight();
127     } else if(InputManager->UpPress()) {
128         media.PlaySound("bump");
129         _formation_select.InputUp();
130     } else if(InputManager->DownPress()) {
131         media.PlaySound("bump");
132         _formation_select.InputDown();
133     }
134 
135     _formation_select.Update();
136 
137     // Update characters animations
138     for (uint32_t i = 0; i < _character_sprites.size(); ++i) {
139         _character_sprites[i].Update();
140     }
141 
142     // Update the status texts
143     if (InputManager->AnyRegisteredKeyPress())
144         UpdateStatus();
145 }
146 
UpdateStatus()147 void BattleFormationWindow::UpdateStatus()
148 {
149     _ComputeModificators();
150 }
151 
_ComputeModificators()152 void BattleFormationWindow::_ComputeModificators()
153 {
154     uint32_t characters_number = _character_sprites.size();
155     if (characters_number == 0)
156         return;
157     uint32_t chance_to_target = 100 / characters_number;
158 
159     // Compute whether everyone is on front or rear.
160     bool is_front = _characters_position.at(0);
161     bool all_front = true;
162     uint32_t number_in_front = 0;
163     for(uint32_t i = 0; i < characters_number; ++i) {
164         if (is_front != _characters_position[i])
165             all_front = false;
166         if (_characters_position[i])
167             ++number_in_front;
168     }
169 
170     std::string chance_to_target_txt;
171     // If all characters are in front/in rear, then everyone has the same chances.
172     if (all_front) {
173         for(uint32_t i = 0; i < characters_number; ++i) {
174             chance_to_target_txt = VTranslate("%d %%", chance_to_target);
175             _character_target_texts[i].SetStyle(TextStyle("text22"));
176             _character_target_texts[i].SetText(chance_to_target_txt);
177         }
178         return;
179     }
180 
181     // Otherwise the number of characters in front determines the protection
182     // of the characters in rear.
183     uint32_t pos_chance_modifier =
184         (chance_to_target / 2) / number_in_front;
185     uint32_t neg_chance_modifier =
186         (chance_to_target / 2) / (characters_number - number_in_front);
187     for(uint32_t i = 0; i < characters_number; ++i) {
188         if (_characters_position[i]) {
189             chance_to_target_txt =
190                VTranslate("%d %%", chance_to_target + pos_chance_modifier);
191         } else {
192             chance_to_target_txt =
193                VTranslate("%d %%", chance_to_target - neg_chance_modifier);
194         }
195         _character_target_texts[i].SetStyle(TextStyle("text22"));
196         _character_target_texts[i].SetText(chance_to_target_txt);
197     }
198 }
199 
_DrawBottomWindowInfo()200 void BattleFormationWindow::_DrawBottomWindowInfo()
201 {
202     if (!_formation_select_active)
203         return;
204     VideoManager->Move(110.0f, 560.0f);
205     _help_text.Draw();
206 }
207 
Draw()208 void BattleFormationWindow::Draw()
209 {
210     MenuWindow::Draw();
211     _formation_select.Draw();
212 
213     // Draw Info
214     VideoManager->Move(380.0f, 150.0f);
215     _rear_front_txt.Draw();
216     VideoManager->MoveRelative(160.0f, 0.0f);
217     _modifier_txt.Draw();
218 
219     // Draw characters depending on the formation chosen.
220     VideoManager->SetDrawFlags(VIDEO_X_LEFT, VIDEO_Y_TOP, VIDEO_BLEND, 0);
221     VideoManager->Move(440.0f, 170.0f);
222     for (uint32_t i = 0; i < _character_sprites.size(); ++i) {
223         if (!_characters_position[i])
224             VideoManager->MoveRelative(-80.0f, 0.0f);
225         _character_sprites[i].Draw();
226         if (!_characters_position[i])
227             VideoManager->MoveRelative(80.0f, 0.0f);
228         VideoManager->MoveRelative(100.0f, 20.0f);
229         _character_target_texts[i].Draw();
230         VideoManager->MoveRelative(-100.0f, -20.0f);
231         VideoManager->MoveRelative(0.0f, 80.0f);
232     }
233 
234     _DrawBottomWindowInfo();
235 }
236 
237 } // namespace private_menu
238 
239 } // namespace vt_menu
240