1 /*
2  * This file is part of EasyRPG Player.
3  *
4  * EasyRPG Player is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * EasyRPG Player is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 // Headers
19 #include <cassert>
20 #include "scene_menu.h"
21 #include "audio.h"
22 #include "cache.h"
23 #include "game_party.h"
24 #include "game_system.h"
25 #include "input.h"
26 #include "player.h"
27 #include "scene_debug.h"
28 #include "scene_end.h"
29 #include "scene_equip.h"
30 #include "scene_item.h"
31 #include "scene_skill.h"
32 #include "scene_order.h"
33 #include "scene_save.h"
34 #include "scene_status.h"
35 #include "bitmap.h"
36 
Scene_Menu(int menu_index)37 Scene_Menu::Scene_Menu(int menu_index) :
38 	menu_index(menu_index) {
39 	type = Scene::Menu;
40 }
41 
Start()42 void Scene_Menu::Start() {
43 	CreateCommandWindow();
44 
45 	// Gold Window
46 	gold_window.reset(new Window_Gold(0, (SCREEN_TARGET_HEIGHT-32), 88, 32));
47 
48 	// Status Window
49 	menustatus_window.reset(new Window_MenuStatus(88, 0, (SCREEN_TARGET_WIDTH-88), SCREEN_TARGET_HEIGHT));
50 	menustatus_window->SetActive(false);
51 }
52 
Continue(SceneType)53 void Scene_Menu::Continue(SceneType /* prev_scene */) {
54 	menustatus_window->Refresh();
55 	gold_window->Refresh();
56 }
57 
Update()58 void Scene_Menu::Update() {
59 	command_window->Update();
60 	gold_window->Update();
61 	menustatus_window->Update();
62 
63 	if (command_window->GetActive()) {
64 		UpdateCommand();
65 	}
66 	else if (menustatus_window->GetActive()) {
67 		UpdateActorSelection();
68 	}
69 }
70 
CreateCommandWindow()71 void Scene_Menu::CreateCommandWindow() {
72 	// Create Options Window
73 	std::vector<std::string> options;
74 
75 	if (Player::IsRPG2k()) {
76 		command_options.push_back(Item);
77 		command_options.push_back(Skill);
78 		command_options.push_back(Equipment);
79 		command_options.push_back(Save);
80 		if (Player::debug_flag) {
81 			command_options.push_back(Debug);
82 		}
83 		command_options.push_back(Quit);
84 	} else {
85 		for (std::vector<int16_t>::iterator it = lcf::Data::system.menu_commands.begin();
86 			it != lcf::Data::system.menu_commands.end(); ++it) {
87 				command_options.push_back((CommandOptionType)*it);
88 		}
89 		if (Player::debug_flag) {
90 			command_options.push_back(Debug);
91 		}
92 		command_options.push_back(Quit);
93 	}
94 
95 	// Add all menu items
96 	std::vector<CommandOptionType>::iterator it;
97 	for (it = command_options.begin(); it != command_options.end(); ++it) {
98 		switch(*it) {
99 		case Item:
100 			options.push_back(ToString(lcf::Data::terms.command_item));
101 			break;
102 		case Skill:
103 			options.push_back(ToString(lcf::Data::terms.command_skill));
104 			break;
105 		case Equipment:
106 			options.push_back(ToString(lcf::Data::terms.menu_equipment));
107 			break;
108 		case Save:
109 			options.push_back(ToString(lcf::Data::terms.menu_save));
110 			break;
111 		case Status:
112 			options.push_back(ToString(lcf::Data::terms.status));
113 			break;
114 		case Row:
115 			options.push_back(ToString(lcf::Data::terms.row));
116 			break;
117 		case Order:
118 			options.push_back(ToString(lcf::Data::terms.order));
119 			break;
120 		case Wait:
121 			options.push_back(ToString(Main_Data::game_system->GetAtbMode() == lcf::rpg::SaveSystem::AtbMode_atb_wait ? lcf::Data::terms.wait_on : lcf::Data::terms.wait_off));
122 			break;
123 		case Debug:
124 			options.push_back("Debug");
125 			break;
126 		default:
127 			options.push_back(ToString(lcf::Data::terms.menu_quit));
128 			break;
129 		}
130 	}
131 
132 	command_window.reset(new Window_Command(options, 88));
133 	command_window->SetIndex(menu_index);
134 
135 	// Disable items
136 	for (it = command_options.begin(); it != command_options.end(); ++it) {
137 		switch(*it) {
138 		case Save:
139 			// If save is forbidden disable this item
140 			if (!Main_Data::game_system->GetAllowSave()) {
141 				command_window->DisableItem(it - command_options.begin());
142 			}
143 		case Wait:
144 		case Quit:
145 		case Debug:
146 			break;
147 		case Order:
148 			if (Main_Data::game_party->GetActors().size() <= 1) {
149 				command_window->DisableItem(it - command_options.begin());
150 			}
151 			break;
152 		default:
153 			if (Main_Data::game_party->GetActors().empty()) {
154 				command_window->DisableItem(it - command_options.begin());
155 			}
156 			break;
157 		}
158 	}
159 }
160 
UpdateCommand()161 void Scene_Menu::UpdateCommand() {
162 	if (Input::IsTriggered(Input::CANCEL)) {
163 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel));
164 		Scene::Pop();
165 	} else if (Input::IsTriggered(Input::DECISION)) {
166 		menu_index = command_window->GetIndex();
167 
168 		switch (command_options[menu_index]) {
169 		case Item:
170 			if (Main_Data::game_party->GetActors().empty()) {
171 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Buzzer));
172 			} else {
173 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
174 				Scene::Push(std::make_shared<Scene_Item>());
175 			}
176 			break;
177 		case Skill:
178 		case Equipment:
179 		case Status:
180 		case Row:
181 			if (Main_Data::game_party->GetActors().empty()) {
182 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Buzzer));
183 			} else {
184 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
185 				command_window->SetActive(false);
186 				menustatus_window->SetActive(true);
187 				menustatus_window->SetIndex(0);
188 			}
189 			break;
190 		case Save:
191 			if (!Main_Data::game_system->GetAllowSave()) {
192 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Buzzer));
193 			} else {
194 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
195 				Scene::Push(std::make_shared<Scene_Save>());
196 			}
197 			break;
198 		case Order:
199 			if (Main_Data::game_party->GetActors().size() <= 1) {
200 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Buzzer));
201 			} else {
202 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
203 				Scene::Push(std::make_shared<Scene_Order>());
204 			}
205 			break;
206 		case Wait:
207 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
208 			Main_Data::game_system->ToggleAtbMode();
209 			command_window->SetItemText(menu_index,
210 				Main_Data::game_system->GetAtbMode() == lcf::rpg::SaveSystem::AtbMode_atb_wait ? lcf::Data::terms.wait_on : lcf::Data::terms.wait_off);
211 			break;
212 		case Debug:
213 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
214 			Scene::Push(std::make_shared<Scene_Debug>());
215 			break;
216 		case Quit:
217 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
218 			Scene::Push(std::make_shared<Scene_End>());
219 			break;
220 		}
221 	}
222 }
223 
UpdateActorSelection()224 void Scene_Menu::UpdateActorSelection() {
225 	if (Input::IsTriggered(Input::CANCEL)) {
226 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel));
227 		command_window->SetActive(true);
228 		menustatus_window->SetActive(false);
229 		menustatus_window->SetIndex(-1);
230 	} else if (Input::IsTriggered(Input::DECISION)) {
231 		switch (command_options[command_window->GetIndex()]) {
232 		case Skill:
233 			if (!menustatus_window->GetActor()->CanAct()) {
234 				Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Buzzer));
235 				return;
236 			}
237 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
238 			Scene::Push(std::make_shared<Scene_Skill>(menustatus_window->GetIndex()));
239 			break;
240 		case Equipment:
241 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
242 			Scene::Push(std::make_shared<Scene_Equip>(*menustatus_window->GetActor()));
243 			break;
244 		case Status:
245 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
246 			Scene::Push(std::make_shared<Scene_Status>(menustatus_window->GetIndex()));
247 			break;
248 		case Row:
249 		{
250 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
251 			// Don't allow entire party in the back row.
252 			const auto& actors = Main_Data::game_party->GetActors();
253 			int num_in_back = 0;
254 			for (auto* actor: actors) {
255 				if (actor->GetBattleRow() == Game_Actor::RowType::RowType_back) {
256 					++num_in_back;
257 				}
258 			}
259 			Game_Actor* actor = actors[menustatus_window->GetIndex()];
260 			if (actor->GetBattleRow() == Game_Actor::RowType::RowType_front) {
261 				if (num_in_back < int(actors.size() - 1)) {
262 					actor->SetBattleRow(Game_Actor::RowType::RowType_back);
263 				}
264 			} else {
265 				actor->SetBattleRow(Game_Actor::RowType::RowType_front);
266 			}
267 			menustatus_window->Refresh();
268 			break;
269 		}
270 		default:
271 			assert(false);
272 			break;
273 		}
274 
275 		command_window->SetActive(true);
276 		menustatus_window->SetActive(false);
277 		menustatus_window->SetIndex(-1);
278 	}
279 }
280