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 <fstream>
20 #include <sstream>
21 #include <vector>
22 #include "scene_title.h"
23 #include "audio.h"
24 #include "audio_secache.h"
25 #include "cache.h"
26 #include "game_battle.h"
27 #include "game_ineluki.h"
28 #include "game_screen.h"
29 #include "game_system.h"
30 #include "transition.h"
31 #include "input.h"
32 #include "main_data.h"
33 #include "meta.h"
34 #include "output.h"
35 #include "player.h"
36 #include "translation.h"
37 #include "scene_battle.h"
38 #include "scene_import.h"
39 #include "scene_load.h"
40 #include "window_command.h"
41 #include "baseui.h"
42 #include <lcf/reader_util.h>
43 
Scene_Title()44 Scene_Title::Scene_Title() {
45 	type = Scene::Title;
46 }
47 
Start()48 void Scene_Title::Start() {
49 	Main_Data::game_system->ResetSystemGraphic();
50 
51 	// Skip background image and music if not used
52 	if (CheckEnableTitleGraphicAndMusic()) {
53 		CreateTitleGraphic();
54 		PlayTitleMusic();
55 	}
56 
57 	CreateCommandWindow();
58 	CreateTranslationWindow();
59 	CreateHelpWindow();
60 }
61 
CreateHelpWindow()62 void Scene_Title::CreateHelpWindow() {
63 	help_window.reset(new Window_Help(0, 0, SCREEN_TARGET_WIDTH, 32));
64 	help_window->SetVisible(false);
65 	translate_window->SetHelpWindow(help_window.get());
66 }
67 
68 
Continue(SceneType prev_scene)69 void Scene_Title::Continue(SceneType prev_scene) {
70 	Main_Data::game_system->ResetSystemGraphic();
71 
72 	if (restart_title_cache) {
73 		// Clear the cache when the game returns to the title screen
74 		// e.g. by pressing F12, except the Title Load menu
75 		Cache::Clear();
76 		AudioSeCache::Clear();
77 
78 		Player::ResetGameObjects();
79 		Main_Data::game_ineluki->ExecuteScriptList(FileFinder::Game().FindFile("autorun.script"));
80 
81 		Start();
82 
83 		restart_title_cache = false;
84 	} else if (CheckEnableTitleGraphicAndMusic()) {
85 		CreateTitleGraphic();
86 	}
87 
88 	if (prev_scene != Scene::Load && !Player::hide_title_flag) {
89 		command_window->SetOpenAnimation(8);
90 	}
91 }
92 
TransitionIn(SceneType prev_scene)93 void Scene_Title::TransitionIn(SceneType prev_scene) {
94 	if (Game_Battle::battle_test.enabled || !lcf::Data::system.show_title || Player::new_game_flag)
95 		return;
96 
97 	if (prev_scene == Scene::Load || Player::hide_title_flag) {
98 		Scene::TransitionIn(prev_scene);
99 		return;
100 	}
101 	Transition::instance().InitShow(Transition::TransitionFadeIn, this);
102 }
103 
Suspend(Scene::SceneType next_scene)104 void Scene_Title::Suspend(Scene::SceneType next_scene) {
105 	// Unload title graphic to save memory
106 	title.reset();
107 }
108 
Update()109 void Scene_Title::Update() {
110 	if (Game_Battle::battle_test.enabled) {
111 		Player::SetupBattleTest();
112 		return;
113 	}
114 
115 	if (!lcf::Data::system.show_title || Player::new_game_flag) {
116 		Player::SetupNewGame();
117 		if (Player::debug_flag && Player::hide_title_flag) {
118 			Scene::Push(std::make_shared<Scene_Load>());
119 		}
120 		return;
121 	}
122 
123 	if (active_window == 0) {
124 		command_window->Update();
125 	} else {
126 		translate_window->Update();
127 	}
128 
129 	if (Input::IsTriggered(Input::DECISION)) {
130 		if (active_window == 0) {
131 			int index = command_window->GetIndex();
132 			if (index == indices.new_game) {  // New Game
133 				CommandNewGame();
134 			} else if (index == indices.continue_game) {  // Load Game
135 				CommandContinue();
136 			} else if (index == indices.import) {  // Import (multi-part games)
137 				CommandImport();
138 			} else if (index == indices.translate) { // Choose a Translation (Language)
139 				CommandTranslation();
140 			} else if (index == indices.exit) {  // Exit Game
141 				CommandShutdown();
142 			}
143 		} else if (active_window == 1) {
144 			int index = translate_window->GetIndex();
145 			ChangeLanguage(lang_dirs.at(index));
146 		}
147 	} else if (Input::IsTriggered(Input::CANCEL)) {
148 		if (active_window == 1) {
149 			// Switch back
150 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel));
151 			HideTranslationWindow();
152 		}
153 	}
154 }
155 
CreateTitleGraphic()156 void Scene_Title::CreateTitleGraphic() {
157 	// Load Title Graphic
158 	if (!lcf::Data::system.title_name.empty()) {
159 		title.reset(new Sprite());
160 		FileRequestAsync* request = AsyncHandler::RequestFile("Title", lcf::Data::system.title_name);
161 		request->SetGraphicFile(true);
162 		request_id = request->Bind(&Scene_Title::OnTitleSpriteReady, this);
163 		request->Start();
164 	} else {
165 		title.reset(new Sprite());
166 		title->SetBitmap(Bitmap::Create(DisplayUi->GetWidth(), DisplayUi->GetHeight(), Color(0, 0, 0, 255)));
167 	}
168 }
169 
RepositionWindow(Window_Command & window,bool center_vertical)170 void Scene_Title::RepositionWindow(Window_Command& window, bool center_vertical) {
171 	if (!center_vertical) {
172 		window.SetX(SCREEN_TARGET_WIDTH / 2 - window.GetWidth() / 2);
173 		window.SetY(SCREEN_TARGET_HEIGHT * 53 / 60 - window.GetHeight());
174 	} else {
175 		window.SetX(SCREEN_TARGET_WIDTH / 2 - window.GetWidth() / 2);
176 		window.SetY(SCREEN_TARGET_HEIGHT / 2 - window.GetHeight() / 2);
177 	}
178 }
179 
CreateCommandWindow()180 void Scene_Title::CreateCommandWindow() {
181 	// Create Options Window
182 	std::vector<std::string> options;
183 	options.push_back(ToString(lcf::Data::terms.new_game));
184 	options.push_back(ToString(lcf::Data::terms.load_game));
185 
186 	// Reset index to fix issues on reuse.
187 	indices = CommandIndices();
188 
189 	// Set "Import" based on metadata
190 	if (Player::meta->IsImportEnabled()) {
191 		options.push_back(Player::meta->GetExVocabImportSaveTitleText());
192 		indices.import = indices.exit;
193 		indices.exit++;
194 	}
195 
196 	// Set "Translate" based on metadata
197 	if (Player::translation.HasTranslations()) {
198 		options.push_back(Player::meta->GetExVocabTranslateTitleText());
199 		indices.translate = indices.exit;
200 		indices.exit++;
201 	}
202 
203 	options.push_back(ToString(lcf::Data::terms.exit_game));
204 
205 	command_window.reset(new Window_Command(options));
206 	RepositionWindow(*command_window, Player::hide_title_flag);
207 
208 	// Enable load game if available
209 	continue_enabled = FileFinder::HasSavegame();
210 	if (continue_enabled) {
211 		command_window->SetIndex(1);
212 	} else {
213 		command_window->DisableItem(1);
214 	}
215 
216 	// Set the number of frames for the opening animation to last
217 	if (!Player::hide_title_flag) {
218 		command_window->SetOpenAnimation(8);
219 	}
220 
221 	if (Player::IsRPG2k3E() && lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_transparent) {
222 		command_window->SetBackOpacity(128);
223 	}
224 
225 	command_window->SetVisible(true);
226 }
227 
CreateTranslationWindow()228 void Scene_Title::CreateTranslationWindow() {
229 	// Build a list of 'Default' and all known languages.
230 	std::vector<std::string> lang_names;
231 	lang_names.push_back("Default Language");
232 	lang_dirs.push_back("");
233 	lang_helps.push_back("Play the game in its original language.");
234 
235 	// Push menu entries with the display name, but also save the directory location and help text.
236 	for (const Language& lg : Player::translation.GetLanguages()) {
237 		lang_names.push_back(lg.lang_name);
238 		lang_dirs.push_back(lg.lang_dir);
239 		lang_helps.push_back(lg.lang_desc);
240 	}
241 
242 	translate_window.reset(new Window_Command(lang_names));
243 	translate_window->UpdateHelpFn = [this](Window_Help& win, int index) {
244 		if (index >= 0 && index < static_cast<int>(lang_helps.size())) {
245 			win.SetText(lang_helps[index]);
246 		} else {
247 			win.SetText("");
248 		}
249 	};
250 	RepositionWindow(*translate_window, Player::hide_title_flag);
251 
252 	if (Player::IsRPG2k3E() && lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_transparent) {
253 		translate_window->SetBackOpacity(128);
254 	}
255 
256 	translate_window->SetVisible(false);
257 }
258 
PlayTitleMusic()259 void Scene_Title::PlayTitleMusic() {
260 	// Workaround Android problem: BGM doesn't start when game is started again
261 	Main_Data::game_system->BgmStop();
262 	// Play BGM
263 	Main_Data::game_system->BgmPlay(lcf::Data::system.title_music);
264 }
265 
CheckEnableTitleGraphicAndMusic()266 bool Scene_Title::CheckEnableTitleGraphicAndMusic() {
267 	return lcf::Data::system.show_title &&
268 		!Player::new_game_flag &&
269 		!Game_Battle::battle_test.enabled &&
270 		!Player::hide_title_flag;
271 }
272 
CheckValidPlayerLocation()273 bool Scene_Title::CheckValidPlayerLocation() {
274 	return (lcf::Data::treemap.start.party_map_id > 0);
275 }
276 
CommandNewGame()277 void Scene_Title::CommandNewGame() {
278 	if (!CheckValidPlayerLocation()) {
279 		Output::Warning("The game has no start location set.");
280 	} else {
281 		Output::Debug("Starting new game");
282 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
283 		Player::SetupNewGame();
284 	}
285 }
286 
CommandContinue()287 void Scene_Title::CommandContinue() {
288 	if (continue_enabled) {
289 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
290 	} else {
291 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Buzzer));
292 		return;
293 	}
294 
295 	Scene::Push(std::make_shared<Scene_Load>());
296 }
297 
CommandImport()298 void Scene_Title::CommandImport() {
299 	Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
300 
301 	Scene::Push(std::make_shared<Scene_Import>());
302 }
303 
CommandTranslation()304 void Scene_Title::CommandTranslation() {
305 	Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
306 
307 	// Switch windows
308 	active_window = 1;
309 	command_window->SetVisible(false);
310 	translate_window->SetVisible(true);
311 	help_window->SetVisible(true);
312 }
313 
ChangeLanguage(const std::string & lang_str)314 void Scene_Title::ChangeLanguage(const std::string& lang_str) {
315 	Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
316 
317 	// No-op?
318 	if (lang_str == Player::translation.GetCurrentLanguageId()) {
319 		HideTranslationWindow();
320 		return;
321 	}
322 
323 	// First change the language
324 	Player::translation.SelectLanguage(lang_str);
325 
326 	// Now reset the scene (force asset reload)
327 	Scene::Push(std::make_shared<Scene_Title>(), true);
328 }
329 
HideTranslationWindow()330 void Scene_Title::HideTranslationWindow() {
331 	active_window = 0;
332 	command_window->SetVisible(true);
333 	translate_window->SetVisible(false);
334 	help_window->SetVisible(false);
335 }
336 
CommandShutdown()337 void Scene_Title::CommandShutdown() {
338 	Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
339 	Transition::instance().InitErase(Transition::TransitionFadeOut, this);
340 	Scene::Pop();
341 }
342 
OnTitleSpriteReady(FileRequestResult * result)343 void Scene_Title::OnTitleSpriteReady(FileRequestResult* result) {
344 	title->SetBitmap(Cache::Title(result->file));
345 }
346 
OnGameStart()347 void Scene_Title::OnGameStart() {
348 	restart_title_cache = true;
349 }
350