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