diff --git a/CMakeLists.txt b/CMakeLists.txt index 87859f18f0..b540a7229a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,8 @@ add_library(${PROJECT_NAME} OBJECT src/scene_import.h src/scene_item.cpp src/scene_item.h + src/scene_language.cpp + src/scene_language.h src/scene_load.cpp src/scene_load.h src/scene_logo.cpp diff --git a/Makefile.am b/Makefile.am index 02992d0f91..898137ccb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -287,6 +287,8 @@ libeasyrpg_player_a_SOURCES = \ src/scene_gameover.h \ src/scene_item.cpp \ src/scene_item.h \ + src/scene_language.cpp \ + src/scene_language.h \ src/scene_load.cpp \ src/scene_load.h \ src/scene_logo.cpp \ diff --git a/src/game_config.cpp b/src/game_config.cpp index 82bd6d8f92..1f70ff7213 100644 --- a/src/game_config.cpp +++ b/src/game_config.cpp @@ -525,6 +525,8 @@ void Game_Config::LoadFromStream(Filesystem_Stream::InputStream& is) { player.font1_size.FromIni(ini); player.font2.FromIni(ini); player.font2_size.FromIni(ini); + player.lang_select_on_start.FromIni(ini); + player.lang_select_in_title.FromIni(ini); } void Game_Config::WriteToStream(Filesystem_Stream::OutputStream& os) const { @@ -610,6 +612,8 @@ void Game_Config::WriteToStream(Filesystem_Stream::OutputStream& os) const { player.font1_size.ToIni(os); player.font2.ToIni(os); player.font2_size.ToIni(os); + player.lang_select_on_start.ToIni(os); + player.lang_select_in_title.ToIni(os); os << "\n"; } diff --git a/src/game_config.h b/src/game_config.h index 770bed5311..1d7a3f91e6 100644 --- a/src/game_config.h +++ b/src/game_config.h @@ -58,6 +58,14 @@ namespace ConfigEnum { All }; + enum class StartupLangSelect { + Never, + /* Shows language screen when no saves are found */ + FirstStartup, + /* Always show the language screen before the title */ + Always + }; + enum class ShowFps { /** Do not show */ OFF, @@ -89,6 +97,12 @@ struct Game_ConfigPlayer { RangeConfigParam font1_size { "Font 1 Size", "", "Player", "Font1Size", 12, 6, 16}; PathConfigParam font2 { "Font 2", "The game chooses whether it wants font 1 or 2", "Player", "Font2", "" }; RangeConfigParam font2_size { "Font 2 Size", "", "Player", "Font2Size", 12, 6, 16}; + EnumConfigParam lang_select_on_start { + "Startup Language Menu", "Show language menu before booting up a game", "Player", "StartupLangSelect", ConfigEnum::StartupLangSelect::FirstStartup, + Utils::MakeSvArray("Never", "First Start", "Always"), + Utils::MakeSvArray("never", "FirstStartup", "always"), + Utils::MakeSvArray("Never show language menu on start", "Show on first start (when no save files are found)", "Always show language menu prior to the title screen") }; + BoolConfigParam lang_select_in_title{ "Show language menu on title screen", "Display language menu item on the title screen", "Player", "LanguageInTitle", true }; void Hide(); }; diff --git a/src/game_interpreter_map.cpp b/src/game_interpreter_map.cpp index c0445e9402..49e316bdcd 100644 --- a/src/game_interpreter_map.cpp +++ b/src/game_interpreter_map.cpp @@ -51,6 +51,8 @@ #include "scene_shop.h" #include "scene_debug.h" #include "scene_gameover.h" +#include "scene_settings.h" +#include "scene_language.h" #include "scene.h" #include "graphics.h" #include "input.h" @@ -161,17 +163,14 @@ bool Game_Interpreter_Map::RequestMainMenuScene(int subscreen_id, int actor_inde Scene::instance->SetRequestedScene(std::make_shared()); return true; } - /* case 6: // Settings Scene::instance->SetRequestedScene(std::make_shared()); return true; case 7: // Language - Scene::instance->SetRequestedScene(std::make_shared()); - return true; - case 8: // Debug - Scene::instance->SetRequestedScene(std::make_shared()); + if (Player::translation.HasTranslations()) { + Scene::instance->SetRequestedScene(std::make_shared()); + } return true; - */ } Scene::instance->SetRequestedScene(std::make_shared()); diff --git a/src/player.cpp b/src/player.cpp index eedb575968..4902b1357e 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -122,6 +122,7 @@ namespace Player { std::string escape_symbol; uint32_t escape_char; std::string game_title; + std::string game_title_original; std::shared_ptr meta; FileExtGuesser::RPG2KFileExtRemap fileext_map; std::string startup_language; @@ -737,16 +738,7 @@ void Player::CreateGameObjects() { } } - std::stringstream title; - if (!game_title.empty()) { - Output::Debug("Loading game {}", game_title); - title << game_title << " - "; - Input::AddRecordingData(Input::RecordingData::GameTitle, game_title); - } else { - Output::Debug("Could not read game title."); - } - title << GAME_TITLE; - DisplayUi->SetTitle(title.str()); + UpdateTitle(game_title); if (no_rtp_warning_flag) { Output::Debug("Game does not need RTP (FullPackageFlag=1)"); @@ -852,6 +844,28 @@ void Player::CreateGameObjects() { } } +void Player::UpdateTitle(std::string new_game_title) { + if (!game_title.empty() && game_title != new_game_title) { + if (game_title_original == new_game_title) { + game_title_original = ""; + } else { + game_title_original = game_title; + } + game_title = new_game_title; + } + + std::stringstream title; + if (!game_title.empty()) { + Output::Debug("Loading game {}", game_title); + title << new_game_title << " - "; + Input::AddRecordingData(Input::RecordingData::GameTitle, game_title); + } else { + Output::Debug("Could not read game title."); + } + title << GAME_TITLE; + DisplayUi->SetTitle(title.str()); +} + bool Player::ChangeResolution(int width, int height) { if (!DisplayUi->ChangeDisplaySurfaceResolution(width, height)) { Output::Warning("Resolution change to {}x{} failed", width, height); diff --git a/src/player.h b/src/player.h index c8ab392c65..13575c7738 100644 --- a/src/player.h +++ b/src/player.h @@ -302,6 +302,11 @@ namespace Player { */ bool HasEasyRpgExtensions(); + /** + * Update the game title displayed in the Player's UI + */ + void UpdateTitle(std::string new_game_title); + /** * @return Running engine version. 2000 for RPG2k and 2003 for RPG2k3 */ @@ -395,6 +400,9 @@ namespace Player { /** Game title. */ extern std::string game_title; + /** Original game title, in case it was overriden by a translation. */ + extern std::string game_title_original; + /** Meta class containing additional external data for this game. */ extern std::shared_ptr meta; diff --git a/src/scene.cpp b/src/scene.cpp index cbc6c1d21a..bc95a3d3f4 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -24,12 +24,15 @@ #include "player.h" #include "output.h" #include "audio.h" +#include "filefinder.h" #include "transition.h" #include "game_actors.h" #include "game_interpreter.h" #include "game_system.h" #include "main_data.h" +#include "scene_language.h" #include "scene_settings.h" +#include "scene_title.h" #include "game_map.h" #ifndef NDEBUG @@ -64,7 +67,9 @@ const char Scene::scene_names[SceneMax][12] = "Logo", "Order", "GameBrowser", - "Teleport" + "Teleport", + "Settings", + "Language" }; enum PushPopOperation { @@ -95,6 +100,7 @@ lcf::rpg::SaveSystem::Scene Scene::rpgRtSceneFromSceneType(SceneType t) { case Order: case End: case Settings: + case LanguageMenu: return lcf::rpg::SaveSystem::Scene_menu; case File: case Save: @@ -265,6 +271,12 @@ void Scene::Push(std::shared_ptr const& new_scene, bool pop_stack_top) { DEBUG_VALIDATE("Push"); } +std::shared_ptr Scene::Peek() { + if (instances.size() == 1) + return nullptr; + return instances[instances.size() - 2]; +} + void Scene::Pop() { old_instances.push_back(instances.back()); instances.pop_back(); @@ -355,6 +367,25 @@ inline void Scene::DebugValidate(const char* caller) { } } +void Scene::PushTitleScene(bool pop_stack_top) { + auto title_scene = Scene::Find(Scene::Title); + if (title_scene) { + return; + } + + if (!Player::startup_language.empty()) { + Player::translation.SelectLanguage(Player::startup_language); + } else if (Player::translation.HasTranslations()) { + if (Player::player_config.lang_select_on_start.Get() == ConfigEnum::StartupLangSelect::Always + || (!FileFinder::HasSavegame() && Player::player_config.lang_select_on_start.Get() == ConfigEnum::StartupLangSelect::FirstStartup)) { + Scene::Push(std::make_shared(), pop_stack_top); + return; + } + } + + Scene::Push(std::make_shared(), pop_stack_top); +} + bool Scene::ReturnToTitleScene() { if (Scene::instance && Scene::instance->type == Scene::Title) { return false; diff --git a/src/scene.h b/src/scene.h index 4a393fcc30..7806b12f71 100644 --- a/src/scene.h +++ b/src/scene.h @@ -59,6 +59,7 @@ class Scene { GameBrowser, Teleport, Settings, + LanguageMenu, SceneMax }; @@ -160,6 +161,14 @@ class Scene { */ static void Push(std::shared_ptr const& new_scene, bool pop_stack_top = false); + /** + * Finds the the scene previous to the current, top-most one and + * returns it without popping it from the stack. + * + * @return the scene found, or NULL if the current scene is already the top. + */ + static std::shared_ptr Peek(); + /** * Removes the scene that is on the top of the stack. */ @@ -247,6 +256,12 @@ class Scene { /** Decrement delay frames by 1 if we're waiting */ void UpdateDelayFrames(); + /** + * Pushes the title screen onto the stack to boot up the game. + * If there already is a title scene ín the stack, this function exits without doing anything. + */ + static void PushTitleScene(bool pop_stack_top = false); + /** * Pops the stack until the title screen and sets proper delay. * diff --git a/src/scene_gamebrowser.cpp b/src/scene_gamebrowser.cpp index 1e3447d5b4..0299565395 100644 --- a/src/scene_gamebrowser.cpp +++ b/src/scene_gamebrowser.cpp @@ -28,7 +28,6 @@ #include "input.h" #include "player.h" #include "scene_logo.h" -#include "scene_title.h" #include "bitmap.h" #include "audio.h" #include "output.h" @@ -59,6 +58,7 @@ void Scene_GameBrowser::Continue(SceneType /* prev_scene */) { Player::RestoreBaseResolution(); Player::game_title = ""; + Player::game_title_original = ""; Font::ResetDefault(); @@ -242,8 +242,5 @@ void Scene_GameBrowser::BootGame() { return; } - if (!Player::startup_language.empty()) { - Player::translation.SelectLanguage(Player::startup_language); - } - Scene::Push(std::make_shared()); + Scene::PushTitleScene(); } diff --git a/src/scene_language.cpp b/src/scene_language.cpp new file mode 100644 index 0000000000..aef395a854 --- /dev/null +++ b/src/scene_language.cpp @@ -0,0 +1,184 @@ +/* + * This file is part of EasyRPG Player. + * + * EasyRPG Player is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Player is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Player. If not, see . + */ +#include "scene_language.h" +#include "scene_logo.h" +#include "audio.h" +#include "bitmap.h" +#include "input.h" +#include "game_system.h" +#include "cache.h" +#include "input_buttons.h" +#include "input_source.h" +#include "keys.h" +#include "main_data.h" +#include "options.h" +#include "player.h" +#include "baseui.h" +#include "output.h" +#include "utils.h" +#include "scene_end.h" +#include "window_about.h" +#include "window_command_horizontal.h" +#include "window_help.h" +#include "window_input_settings.h" +#include "window_numberinput.h" +#include "window_selectable.h" +#include "window_settings.h" +#include + +#ifdef EMSCRIPTEN +# include +#endif + +Scene_Language::Scene_Language() { + Scene::type = Scene::LanguageMenu; +} + +void Scene_Language::CreateTitleGraphic() { + // Load Title Graphic + if (lcf::Data::system.title_name.empty()) { + return; + } + title = std::make_unique(); + FileRequestAsync* request = AsyncHandler::RequestFile("Title", lcf::Data::system.title_name); + request->SetGraphicFile(true); + request_id = request->Bind(&Scene_Language::OnTitleSpriteReady, this); + request->Start(); +} + + +void Scene_Language::CreateTranslationWindow() { + // Build a list of 'Default' and all known languages. + std::vector lang_names; + lang_names.push_back("Default Language"); + lang_dirs.push_back(""); + lang_helps.push_back("Play the game in its original language."); + + // Push menu entries with the display name, but also save the directory location and help text. + for (const Language& lg : Player::translation.GetLanguages()) { + lang_names.push_back(lg.lang_name); + lang_dirs.push_back(lg.lang_dir); + lang_helps.push_back(lg.lang_desc); + } + + // Allow overwriting text of the default language + const Language& def = Player::translation.GetDefaultLanguage(); + if (!def.lang_name.empty()) { + lang_names.front() = def.lang_name; + } + if (!def.lang_desc.empty()) { + lang_helps.front() = def.lang_desc; + } + + translate_window = std::make_unique(lang_names, -1, lang_names.size() > 9 ? 9 : lang_names.size()); + translate_window->UpdateHelpFn = [this](Window_Help& win, int index) { + if (index >= 0 && index < static_cast(lang_helps.size())) { + win.SetText(lang_helps[index]); + } + else { + win.SetText(""); + } + }; + translate_window->SetX(Player::screen_width / 2 - translate_window->GetWidth() / 2); + translate_window->SetY(Player::screen_height / 2 - translate_window->GetHeight() / 2); + + if (Player::IsRPG2k3E() && lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_transparent) { + translate_window->SetBackOpacity(160); + } + + translate_window->SetVisible(false); +} + +void Scene_Language::CreateHelpWindow() { + help_window.reset(new Window_Help(0, 0, Player::screen_width, 32)); + + if (Player::IsRPG2k3E() && lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_transparent) { + help_window->SetBackOpacity(160); + } + + help_window->SetVisible(false); + translate_window->SetHelpWindow(help_window.get()); +} + +void Scene_Language::Start() { + CreateTitleGraphic(); + CreateTranslationWindow(); + CreateHelpWindow(); + + translate_window->SetActive(true); + translate_window->SetVisible(true); + help_window->SetVisible(true); +} + + +void Scene_Language::vUpdate() { + translate_window->Update(); + help_window->Update(); + + + if (Input::IsTriggered(Input::DECISION)) { + int index = translate_window->GetIndex(); + ChangeLanguage(lang_dirs.at(index)); + } + else if (Input::IsTriggered(Input::CANCEL)) { + Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel)); + + auto peek_scene = Scene::Peek(); + if (!peek_scene || peek_scene->type == SceneType::Null || peek_scene->type == SceneType::Logo) { + Transition::instance().InitErase(Transition::TransitionFadeOut, this); + } + Scene::Pop(); + } +} + +void Scene_Language::OnTitleSpriteReady(FileRequestResult* result) { + BitmapRef bitmapRef = Cache::Title(result->file); + + title->SetBitmap(bitmapRef); + + // If the title sprite doesn't fill the screen, center it to support custom resolutions + if (bitmapRef->GetWidth() < Player::screen_width) { + title->SetX(Player::menu_offset_x); + } + if (bitmapRef->GetHeight() < Player::screen_height) { + title->SetY(Player::menu_offset_y); + } +} + +void Scene_Language::ChangeLanguage(const std::string& lang_str) { + Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision)); + + // No-op? + if (lang_str == Player::translation.GetCurrentLanguage().lang_dir) { + PopOrTitle(); + return; + } + + // First change the language + Player::translation.SelectLanguage(lang_str); + + PopOrTitle(); +} + +void Scene_Language::PopOrTitle() { + auto peek_scene = Scene::Peek(); + if (!peek_scene || peek_scene->type == SceneType::Null || peek_scene->type == SceneType::Logo) { + Scene::Push(std::make_shared(), true); + } else { + Scene::Pop(); + } +} diff --git a/src/scene_language.h b/src/scene_language.h new file mode 100644 index 0000000000..fd53e4b124 --- /dev/null +++ b/src/scene_language.h @@ -0,0 +1,91 @@ +/* + * This file is part of EasyRPG Player. + * + * EasyRPG Player is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Player is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Player. If not, see . + */ + +#ifndef EP_SCENE_LANGUAGE_H +#define EP_SCENE_LANGUAGE_H + + // Headers +#include +#include "scene.h" +#include "window_command.h" +#include "window_command_horizontal.h" +#include "window_about.h" +#include "window_selectable.h" +#include "window_settings.h" +#include "window_input_settings.h" +#include "async_handler.h" +#include "sprite.h" +#include "game_config.h" + +/** + * Scene allowing configuration of system state. + */ +class Scene_Language : public Scene { + +public: + /** + * Constructor. + */ + Scene_Language(); + + void Start() override; + void vUpdate() override; + +private: + + /** + * Creates the Window displaying available translations. + */ + void CreateTranslationWindow(); + + /** + * Creates the Help window and hides it + */ + void CreateHelpWindow(); + + /** + * Picks a new language based and switches to it. + * @param lang_str If the empty string, switches the game to 'No Translation'. Otherwise, switch to that translation by name. + */ + void ChangeLanguage(const std::string& lang_str); + + void CreateTitleGraphic(); + void OnTitleSpriteReady(FileRequestResult* result); + + void PopOrTitle(); + + /** Displays all available translations (languages). */ + std::unique_ptr translate_window; + + /** Displays help text for a given language **/ + std::unique_ptr help_window; + + /** Contains directory names for each language; entry 0 is resverd for the default (no) translation */ + std::vector lang_dirs; + + /** Contains help strings for each language; entry 0 is resverd for the default (no) translation */ + std::vector lang_helps; + + std::unique_ptr title; + FileRequestBinding request_id; + int input_reset_counter = 0; + + Window_Settings::UiMode mode = Window_Settings::eNone; +}; + + +#endif diff --git a/src/scene_logo.cpp b/src/scene_logo.cpp index e63cc454ca..11f0ef53e3 100644 --- a/src/scene_logo.cpp +++ b/src/scene_logo.cpp @@ -25,7 +25,6 @@ #include "input.h" #include "options.h" #include "player.h" -#include "scene_title.h" #include "scene_gamebrowser.h" #include "scene_settings.h" #include "output.h" @@ -102,10 +101,8 @@ void Scene_Logo::vUpdate() { } } - if (!Player::startup_language.empty()) { - Player::translation.SelectLanguage(Player::startup_language); - } - Scene::Push(std::make_shared(), true); + Scene::PushTitleScene(true); + if (Player::load_game_id > 0) { auto save = FileFinder::Save(); diff --git a/src/scene_map.cpp b/src/scene_map.cpp index b5bd4d3351..9c9037af8c 100644 --- a/src/scene_map.cpp +++ b/src/scene_map.cpp @@ -183,7 +183,8 @@ void Scene_Map::TransitionOut(SceneType next_scene) { if (next_scene != Scene::Battle && next_scene != Scene::Debug - && next_scene != Scene::Settings) { + && next_scene != Scene::Settings + && next_scene != Scene::LanguageMenu) { screen_erased_by_event = false; } diff --git a/src/scene_settings.cpp b/src/scene_settings.cpp index bd5563f992..ecd73dbb1b 100644 --- a/src/scene_settings.cpp +++ b/src/scene_settings.cpp @@ -29,6 +29,7 @@ #include "baseui.h" #include "output.h" #include "utils.h" +#include "scene_language.h" #include "scene_end.h" #include "window_about.h" #include "window_command_horizontal.h" @@ -60,19 +61,28 @@ void Scene_Settings::CreateTitleGraphic() { } void Scene_Settings::CreateMainWindow() { - std::vector options = { - "Video", - "Audio", - "Input", - "Engine", - "License", - "" - }; + root_options.clear(); + root_options.insert(root_options.end(), { + { Window_Settings::eVideo, "Video" }, + { Window_Settings::eAudio, "Audio" }, + { Window_Settings::eInput, "Input"}, + { Window_Settings::eEngine, "Engine"}, + { Window_Settings::eLicense,"License"}, + { Window_Settings::eSave, ""} + }); + + if (Player::translation.HasTranslations() && Scene::Peek()->type != Scene::Title && Scene::Peek()->type != Scene::LanguageMenu) { + root_options.insert(root_options.begin() + 3, { Window_Settings::eLanguage, "Language" }); + } if (Scene::Find(Scene::Title)) { - options.push_back(""); + root_options.insert(root_options.end(), { Window_Settings::eEnd, "" }); } + std::vector options; + options.reserve(root_options.size()); + std::for_each(root_options.begin(), root_options.end(), [&](std::pair v) { options.emplace_back(v.second); }); + main_window = std::make_unique(std::move(options)); main_window->SetHeight(176); main_window->SetY((Player::screen_height - main_window->GetHeight()) / 2); @@ -302,15 +312,6 @@ void Scene_Settings::OnTitleSpriteReady(FileRequestResult* result) { } void Scene_Settings::UpdateMain() { - const auto modes = Utils::MakeArray( - Window_Settings::eVideo, - Window_Settings::eAudio, - Window_Settings::eInput, - Window_Settings::eEngine, - Window_Settings::eLicense, - Window_Settings::eSave, - Window_Settings::eEnd - ); if (Input::IsTriggered(Input::DECISION)) { auto idx = main_window->GetIndex(); @@ -322,10 +323,15 @@ void Scene_Settings::UpdateMain() { return; } - if (modes[idx] == Window_Settings::eSave) { + auto mode = root_options[idx].first; + + if (mode == Window_Settings::eLanguage) { + Scene::Push(std::make_shared()); + return; + } if (mode == Window_Settings::eSave) { SaveConfig(); return; - } else if (modes[idx] == Window_Settings::eEnd) { + } else if (mode == Window_Settings::eEnd) { if (Scene::Find(Scene::GameBrowser)) { Scene::Push(std::make_unique(Scene::GameBrowser)); } else { @@ -334,8 +340,8 @@ void Scene_Settings::UpdateMain() { return; } - SetMode(modes[idx]); - options_window->Push(modes[idx]); + SetMode(mode); + options_window->Push(mode); } } diff --git a/src/scene_settings.h b/src/scene_settings.h index 6919f6cc96..d62b488daa 100644 --- a/src/scene_settings.h +++ b/src/scene_settings.h @@ -90,6 +90,8 @@ class Scene_Settings : public Scene { int input_reset_counter = 0; Window_Settings::UiMode mode = Window_Settings::eNone; + + std::vector> root_options; }; diff --git a/src/scene_title.cpp b/src/scene_title.cpp index 4dc5280a58..d43c8d9835 100644 --- a/src/scene_title.cpp +++ b/src/scene_title.cpp @@ -23,6 +23,7 @@ #include "options.h" #include "scene_settings.h" #include "scene_title.h" +#include "scene_language.h" #include "audio.h" #include "audio_secache.h" #include "cache.h" @@ -77,20 +78,8 @@ void Scene_Title::Start() { } CreateCommandWindow(); - CreateTranslationWindow(); - CreateHelpWindow(); } -void Scene_Title::CreateHelpWindow() { - help_window.reset(new Window_Help(0, 0, Player::screen_width, 32)); - - if (Player::IsRPG2k3E() && lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_transparent) { - help_window->SetBackOpacity(160); - } - - help_window->SetVisible(false); - translate_window->SetHelpWindow(help_window.get()); -} void Scene_Title::Continue(SceneType prev_scene) { Main_Data::game_system->ResetSystemGraphic(); @@ -130,7 +119,7 @@ void Scene_Title::TransitionIn(SceneType prev_scene) { } void Scene_Title::Suspend(Scene::SceneType scene_type) { - if (scene_type == Scene::Settings) { + if (scene_type == Scene::Settings || scene_type == Scene::LanguageMenu) { restart_title_cache = true; } @@ -152,31 +141,22 @@ void Scene_Title::vUpdate() { return; } - if (active_window == 0) { - command_window->Update(); - } else { - translate_window->Update(); - } + command_window->Update(); if (Input::IsTriggered(Input::DECISION)) { - if (active_window == 0) { - int index = command_window->GetIndex(); - if (index == indices.new_game) { // New Game - CommandNewGame(); - } else if (index == indices.continue_game) { // Load Game - CommandContinue(); - } else if (index == indices.import) { // Import (multi-part games) - CommandImport(); - } else if (index == indices.settings) { - CommandSettings(); - } else if (index == indices.translate) { // Choose a Translation (Language) - CommandTranslation(); - } else if (index == indices.exit) { // Exit Game - CommandShutdown(); - } - } else if (active_window == 1) { - int index = translate_window->GetIndex(); - ChangeLanguage(lang_dirs.at(index)); + int index = command_window->GetIndex(); + if (index == indices.new_game) { // New Game + CommandNewGame(); + } else if (index == indices.continue_game) { // Load Game + CommandContinue(); + } else if (index == indices.import) { // Import (multi-part games) + CommandImport(); + } else if (index == indices.settings) { + CommandSettings(); + } else if (index == indices.translate) { // Choose a Translation (Language) + CommandTranslation(); + } else if (index == indices.exit) { // Exit Game + CommandShutdown(); } } else if (Input::IsTriggered(Input::SHIFT)) { // For emscripten: Allow accessing the load scene for file upload with Shift @@ -184,12 +164,6 @@ void Scene_Title::vUpdate() { if (index == indices.continue_game) { CommandContinue(); } - } else if (Input::IsTriggered(Input::CANCEL)) { - if (active_window == 1) { - // Switch back - Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel)); - HideTranslationWindow(); - } } } @@ -206,7 +180,6 @@ void Scene_Title::OnTranslationChanged() { Start(); command_window->SetIndex(indices.translate); - HideTranslationWindow(); Scene::OnTranslationChanged(); } @@ -260,7 +233,7 @@ void Scene_Title::CreateCommandWindow() { } // Set "Translate" based on metadata - if (Player::translation.HasTranslations()) { + if (Player::translation.HasTranslations() && Player::player_config.lang_select_in_title.Get()) { options.push_back(Player::meta->GetExVocabTranslateTitleText()); indices.translate = indices.exit; indices.exit++; @@ -285,46 +258,6 @@ void Scene_Title::CreateCommandWindow() { command_window->SetVisible(true); } -void Scene_Title::CreateTranslationWindow() { - // Build a list of 'Default' and all known languages. - std::vector lang_names; - lang_names.push_back("Default Language"); - lang_dirs.push_back(""); - lang_helps.push_back("Play the game in its original language."); - - // Push menu entries with the display name, but also save the directory location and help text. - for (const Language& lg : Player::translation.GetLanguages()) { - lang_names.push_back(lg.lang_name); - lang_dirs.push_back(lg.lang_dir); - lang_helps.push_back(lg.lang_desc); - } - - // Allow overwriting text of the default language - const Language& def = Player::translation.GetDefaultLanguage(); - if (!def.lang_name.empty()) { - lang_names.front() = def.lang_name; - } - if (!def.lang_desc.empty()) { - lang_helps.front() = def.lang_desc; - } - - translate_window = std::make_unique(lang_names, -1, lang_names.size() > 9 ? 9 : lang_names.size()); - translate_window->UpdateHelpFn = [this](Window_Help& win, int index) { - if (index >= 0 && index < static_cast(lang_helps.size())) { - win.SetText(lang_helps[index]); - } else { - win.SetText(""); - } - }; - RepositionWindow(*translate_window, Player::hide_title_flag); - - if (Player::IsRPG2k3E() && lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_transparent) { - translate_window->SetBackOpacity(160); - } - - translate_window->SetVisible(false); -} - void Scene_Title::PlayTitleMusic() { // Workaround Android problem: BGM doesn't start when game is started again Main_Data::game_system->BgmStop(); @@ -383,31 +316,7 @@ void Scene_Title::CommandSettings() { void Scene_Title::CommandTranslation() { Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision)); - // Switch windows - active_window = 1; - command_window->SetVisible(false); - translate_window->SetVisible(true); - help_window->SetVisible(true); -} - -void Scene_Title::ChangeLanguage(const std::string& lang_str) { - Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision)); - - // No-op? - if (lang_str == Player::translation.GetCurrentLanguage().lang_dir) { - HideTranslationWindow(); - return; - } - - // First change the language - Player::translation.SelectLanguage(lang_str); -} - -void Scene_Title::HideTranslationWindow() { - active_window = 0; - command_window->SetVisible(true); - translate_window->SetVisible(false); - help_window->SetVisible(false); + Scene::Push(std::make_unique()); } void Scene_Title::CommandShutdown() { diff --git a/src/scene_title.h b/src/scene_title.h index 1e9b721f57..6204d84f2d 100644 --- a/src/scene_title.h +++ b/src/scene_title.h @@ -54,16 +54,6 @@ class Scene_Title : public Scene { */ void CreateCommandWindow(); - /** - * Creates the Window displaying available translations. - */ - void CreateTranslationWindow(); - - /** - * Creates the Help window and hides it - */ - void CreateHelpWindow(); - /** * Plays the title music. */ @@ -139,39 +129,12 @@ class Scene_Title : public Scene { */ void RepositionWindow(Window_Command& window, bool center_vertical); - /** - * Picks a new language based and switches to it. - * @param lang_str If the empty string, switches the game to 'No Translation'. Otherwise, switch to that translation by name. - */ - void ChangeLanguage(const std::string& lang_str); - - void HideTranslationWindow(); - /** Displays the options of the title scene. */ std::unique_ptr command_window; - /** Displays all available translations (languages). */ - std::unique_ptr translate_window; - - /** Displays help text for a given language **/ - std::unique_ptr help_window; - - /** Contains directory names for each language; entry 0 is resverd for the default (no) translation */ - std::vector lang_dirs; - - /** Contains help strings for each language; entry 0 is resverd for the default (no) translation */ - std::vector lang_helps; - /** Background graphic. */ std::unique_ptr title; - /** - * Current active window - * 0 = command - * 1 = translate - */ - int active_window = 0; - /** * Offsets for each selection, in case "Import" or "Translate" is enabled. * Listed in the order they may appear; exit_index will always be last, diff --git a/src/translation.cpp b/src/translation.cpp index 2c101b6f55..68968817c8 100644 --- a/src/translation.cpp +++ b/src/translation.cpp @@ -26,6 +26,7 @@ #include #include "lcf/rpg/mapinfo.h" +#include "baseui.h" #include "cache.h" #include "font.h" #include "main_data.h" @@ -116,6 +117,7 @@ void Translation::InitTranslations() item.lang_desc = ini.GetString("Language", "Description", ""); item.lang_code = ini.GetString("Language", "Code", ""); item.lang_term = ini.GetString("Language", "Term", "Language"); + item.game_title = ini.GetString("Language", "GameTitle", ""); item.use_builtin_font = Utils::LowerCase(ini.GetString("Language", "Font", "")) == "builtin"; if (item.lang_dir == "default") { @@ -166,7 +168,7 @@ void Translation::SelectLanguage(StringView lang_id) if (!lang_id.empty()) { auto root = GetRootTree(); if (!root) { - Output::Error("Cannot load translation. 'Language' folder does not exist"); + Output::Warning("Cannot load translation. 'Language' folder does not exist"); return; } @@ -222,6 +224,12 @@ void Translation::SelectLanguageAsync(FileRequestResult*, StringView lang_id) { RewriteCommonEventMessages(); } + if (!current_language.game_title.empty()) { + Player::UpdateTitle(current_language.game_title); + } else if (!Player::game_title_original.empty()) { + Player::UpdateTitle(Player::game_title_original); + } + // Reset the cache, so that all images load fresh. Cache::Clear(); diff --git a/src/translation.h b/src/translation.h index 70b88ba9d1..30ecaf6faa 100644 --- a/src/translation.h +++ b/src/translation.h @@ -151,6 +151,7 @@ struct Language { std::string lang_desc; // Helper text to show when the menu is highlighted std::string lang_code; // Language code used by font selection and input scene std::string lang_term; // Term to use for "Language" + std::string game_title; // Translated game title bool use_builtin_font = false; }; diff --git a/src/window_settings.cpp b/src/window_settings.cpp index 82e20ee4ae..464c873c61 100644 --- a/src/window_settings.cpp +++ b/src/window_settings.cpp @@ -425,8 +425,10 @@ void Window_Settings::RefreshEngine() { AddOption(cfg.show_startup_logos, [this, &cfg](){ cfg.show_startup_logos.Set(static_cast(GetCurrentOption().current_value)); }); AddOption(cfg.settings_autosave, [&cfg](){ cfg.settings_autosave.Toggle(); }); - AddOption(cfg.settings_in_title, [&cfg](){ cfg.settings_in_title.Toggle(); }); - AddOption(cfg.settings_in_menu, [&cfg](){ cfg.settings_in_menu.Toggle(); }); + AddOption(cfg.settings_in_title, [&cfg]() { cfg.settings_in_title.Toggle(); }); + AddOption(cfg.settings_in_menu, [&cfg]() { cfg.settings_in_menu.Toggle(); }); + AddOption(cfg.lang_select_on_start, [this, &cfg]() { cfg.lang_select_on_start.Set(static_cast(GetCurrentOption().current_value)); }); + AddOption(cfg.lang_select_in_title, [&cfg](){ cfg.lang_select_in_title.Toggle(); }); } void Window_Settings::RefreshEngineFont(bool mincho) { diff --git a/src/window_settings.h b/src/window_settings.h index 26fb1988e1..21d2d3a420 100644 --- a/src/window_settings.h +++ b/src/window_settings.h @@ -51,6 +51,7 @@ class Window_Settings : public Window_Selectable { eSave, eEnd, eAbout, + eLanguage, eLastMode };