From d33c1f5dc5ecdd3efe9ec4a834f0cd280f49725d Mon Sep 17 00:00:00 2001 From: Sergio Date: Wed, 23 Jul 2025 19:52:57 +0200 Subject: [PATCH] difficulty: mogut desde options a un fitxer propi --- CMakeLists.txt | 1 + source/difficulty.cpp | 39 +++++++++ source/difficulty.h | 52 ++++++++++++ source/director.cpp | 11 +-- source/lang.cpp | 27 +++--- source/options.cpp | 112 ++++++++++-------------- source/options.h | 43 +++------- source/sections/game.cpp | 8 +- source/sections/game.h | 3 +- source/ui/service_menu.cpp | 169 +++++++++++++++++++++++++++++++------ 10 files changed, 319 insertions(+), 146 deletions(-) create mode 100644 source/difficulty.cpp create mode 100644 source/difficulty.h diff --git a/CMakeLists.txt b/CMakeLists.txt index dd41ece..eb004c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ set(APP_SOURCES # --- Otros --- source/color.cpp source/define_buttons.cpp + source/difficulty.cpp source/mouse.cpp source/options.cpp source/stage.cpp diff --git a/source/difficulty.cpp b/source/difficulty.cpp new file mode 100644 index 0000000..83f0e39 --- /dev/null +++ b/source/difficulty.cpp @@ -0,0 +1,39 @@ +#include "difficulty.h" + +#include // Para vector + +namespace Difficulty { + +static std::vector difficulties_list; + +void init() { + difficulties_list = { + {Code::EASY, "Easy"}, + {Code::NORMAL, "Normal"}, + {Code::HARD, "Hard"} + }; +} + +auto getDifficulties() -> std::vector& { + return difficulties_list; +} + +auto getNameFromCode(Code code) -> std::string { + for (const auto& difficulty : difficulties_list) { + if (difficulty.code == code) { + return difficulty.name; + } + } + return !difficulties_list.empty() ? difficulties_list.front().name : "Unknown"; +} + +auto getCodeFromName(const std::string& name) -> Code { + for (const auto& difficulty : difficulties_list) { + if (difficulty.name == name) { + return difficulty.code; + } + } + return !difficulties_list.empty() ? difficulties_list.front().code : Code::NORMAL; +} + +} // namespace Difficulty \ No newline at end of file diff --git a/source/difficulty.h b/source/difficulty.h new file mode 100644 index 0000000..8b82a60 --- /dev/null +++ b/source/difficulty.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +namespace Difficulty { + +/** + * @brief Códigos que identifican unívocamente cada nivel de dificultad. + */ +enum class Code { + EASY = 0, + NORMAL = 1, + HARD = 2, +}; + +/** + * @brief Estructura que asocia un código de dificultad con su nombre traducible. + */ +struct Info { + Code code; + std::string name; +}; + +// --- Interfaz Pública --- + +/** + * @brief Inicializa la lista de dificultades con sus valores por defecto. + */ +void init(); + +/** + * @brief Devuelve una referencia al vector de todas las dificultades para su lectura o modificación. + * @return Referencia a `std::vector&`. + */ +auto getDifficulties() -> std::vector&; + +/** + * @brief Obtiene el nombre de una dificultad a partir de su código. + * @param code El código de la dificultad. + * @return El nombre de la dificultad. + */ +auto getNameFromCode(Code code) -> std::string; + +/** + * @brief Obtiene el código de una dificultad a partir de su nombre. + * @param name El nombre de la dificultad. + * @return El código de la dificultad. + */ +auto getCodeFromName(const std::string& name) -> Code; + +} // namespace Difficulty \ No newline at end of file diff --git a/source/director.cpp b/source/director.cpp index 6cbbad4..e1f5f67 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -82,11 +82,12 @@ Director::~Director() { // Inicializa todo void Director::init() { // Configuración inicial de recursos - Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos - setFileList(); // Crea el índice de archivos - Options::loadFromFile(); // Carga el archivo de configuración - loadParams(); // Carga los parámetros del programa - loadScoreFile(); // Carga el archivo de puntuaciones + Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos + setFileList(); // Crea el índice de archivos + Options::setFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración + Options::loadFromFile(); // Carga el archivo de configuración + loadParams(); // Carga los parámetros del programa + loadScoreFile(); // Carga el archivo de puntuaciones // Inicialización de subsistemas principales Lang::setLanguage(Options::settings.language); // Carga el archivo de idioma diff --git a/source/lang.cpp b/source/lang.cpp index 666e52e..fc2b35c 100644 --- a/source/lang.cpp +++ b/source/lang.cpp @@ -8,8 +8,9 @@ #include // Para vector #include "asset.h" // Para Asset +#include "difficulty.h" // Para Difficulty #include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper... -#include "options.h" // Para Difficulty, DifficultyCode, SettingsOpt... +#include "options.h" // Para SettingsOpt... using json = nlohmann::json; @@ -121,19 +122,21 @@ void updateLanguageNames() { // Actualiza los nombres de las dificultades void updateDifficultyNames() { - for (auto &difficulty : Options::difficulties) { - switch (difficulty.code) { - case Options::DifficultyCode::EASY: - difficulty.name = Lang::getText("[SERVICE_MENU] EASY"); + // 1. Pide una referencia MODIFICABLE a la lista de dificultades + auto &difficulties = Difficulty::getDifficulties(); + + // 2. Recorre la lista + for (auto &difficulty_info : difficulties) { + // 3. Para cada dificultad, usa su código para obtener el texto traducido y actualizar su nombre + switch (difficulty_info.code) { + case Difficulty::Code::EASY: + difficulty_info.name = Lang::getText("[SERVICE_MENU] EASY"); break; - case Options::DifficultyCode::NORMAL: - difficulty.name = Lang::getText("[SERVICE_MENU] NORMAL"); + case Difficulty::Code::NORMAL: + difficulty_info.name = Lang::getText("[SERVICE_MENU] NORMAL"); break; - case Options::DifficultyCode::HARD: - difficulty.name = Lang::getText("[SERVICE_MENU] HARD"); - break; - default: - difficulty.name = "Unknown"; + case Difficulty::Code::HARD: + difficulty_info.name = Lang::getText("[SERVICE_MENU] HARD"); break; } } diff --git a/source/options.cpp b/source/options.cpp index 36d394e..67d7562 100644 --- a/source/options.cpp +++ b/source/options.cpp @@ -4,19 +4,18 @@ #include // Para clamp, max #include // Para basic_ostream, operator<<, basic_ostream::operator<<, basic_ofstream, basic_istream, basic_ifstream, ifstream, ofstream -#include // Para swap -#include // Para vector +#include +#include +#include // Para excepciones de std::stoi +#include +#include // Para swap +#include // Para vector -#include "asset.h" // Para Asset +#include "difficulty.h" // Para Difficulty #include "input.h" // Para InputDevice #include "lang.h" // Para Code #include "utils.h" // Para boolToString, stringToBool, getFileName -#include -#include -#include -#include // Para excepciones de std::stoi - namespace Options { // --- Variables globales --- WindowOptions window; // Opciones de la ventana @@ -26,19 +25,16 @@ AudioOptions audio; // Opciones de audio std::vector controllers; // Opciones de mando para cada jugador PendingChanges pending_changes; // Opciones que se aplican al cerrar -// Vector con las dificultades -std::vector difficulties = { - {DifficultyCode::EASY, "Easy"}, - {DifficultyCode::NORMAL, "Normal"}, - {DifficultyCode::HARD, "Hard"}}; - // Declaraciones -auto set(const std::string &var, const std::string &value) -> bool; +auto set(const std::string& var, const std::string& value) -> bool; + +// Establece el fichero de configuración +void setFile(const std::string& file_path) { settings.config_file = file_path; }; // Inicializa las opciones del programa void init() { - // Settings - settings.config_file = Asset::get()->get("config.txt"); + // Dificultades + Difficulty::init(); // Opciones de control controllers.clear(); @@ -143,7 +139,7 @@ auto saveToFile() -> bool { // Opciones del juego file << "\n\n## GAME\n"; file << "## game.language [0: spanish, 1: valencian, 2: english]\n"; - file << "## game.difficulty [" << static_cast(DifficultyCode::EASY) << ": easy, " << static_cast(DifficultyCode::NORMAL) << ": normal, " << static_cast(DifficultyCode::HARD) << ": hard]\n"; + file << "## game.difficulty [" << static_cast(Difficulty::Code::EASY) << ": easy, " << static_cast(Difficulty::Code::NORMAL) << ": normal, " << static_cast(Difficulty::Code::HARD) << ": hard]\n"; file << "\n"; file << "game.language=" << static_cast(settings.language) << "\n"; @@ -155,7 +151,7 @@ auto saveToFile() -> bool { file << "\n\n## CONTROLLERS\n"; int controller_index = 0; - for (const auto &controller : controllers) { + for (const auto& controller : controllers) { file << "\n"; file << "controller." << controller_index << ".name=" << controller.name << "\n"; file << "controller." << controller_index << ".player=" << controller.player_id << "\n"; @@ -177,7 +173,7 @@ auto saveToFile() -> bool { } // Función auxiliar para analizar la configuración del mando y reducir duplicación -void parseAndSetController(const std::string &var, const std::string &value) { +void parseAndSetController(const std::string& var, const std::string& value) { // Lógica básica de análisis (puede hacerse más robusta) size_t first_dot = var.find('.'); size_t second_dot = var.find('.', first_dot + 1); @@ -206,7 +202,7 @@ void parseAndSetController(const std::string &var, const std::string &value) { } } -auto set(const std::string &var, const std::string &value) -> bool { +auto set(const std::string& var, const std::string& value) -> bool { // Clausula de protección: ignora líneas vacías o comentarios if (var.empty() || var.starts_with("#")) { return false; @@ -215,32 +211,31 @@ auto set(const std::string &var, const std::string &value) -> bool { // Un mapa estático asegura que se inicializa solo una vez static const std::map> settings_map = { // Ventana - {"window.zoom", [](const auto& val){ window.zoom = std::stoi(val); }}, + {"window.zoom", [](const auto& val) { window.zoom = std::stoi(val); }}, // Vídeo - {"video.fullscreen", [](const auto& val){ video.fullscreen = stringToBool(val); }}, - {"video.scale_mode", [](const auto& val){ video.scale_mode = static_cast(std::stoi(val)); }}, - {"video.shaders", [](const auto& val){ video.shaders = stringToBool(val); }}, - {"video.integer_scale", [](const auto& val){ video.integer_scale = stringToBool(val); }}, - {"video.vsync", [](const auto& val){ video.vsync = stringToBool(val); }}, + {"video.fullscreen", [](const auto& val) { video.fullscreen = stringToBool(val); }}, + {"video.scale_mode", [](const auto& val) { video.scale_mode = static_cast(std::stoi(val)); }}, + {"video.shaders", [](const auto& val) { video.shaders = stringToBool(val); }}, + {"video.integer_scale", [](const auto& val) { video.integer_scale = stringToBool(val); }}, + {"video.vsync", [](const auto& val) { video.vsync = stringToBool(val); }}, // Audio - {"audio.enabled", [](const auto& val){ audio.enabled = stringToBool(val); }}, - {"audio.volume", [](const auto& val){ audio.volume = std::clamp(std::stoi(val), 0, 100); }}, - {"audio.music.enabled", [](const auto& val){ audio.music.enabled = stringToBool(val); }}, - {"audio.music.volume", [](const auto& val){ audio.music.volume = std::clamp(std::stoi(val), 0, 100); }}, - {"audio.sound.enabled", [](const auto& val){ audio.sound.enabled = stringToBool(val); }}, - {"audio.sound.volume", [](const auto& val){ audio.sound.volume = std::clamp(std::stoi(val), 0, 100); }}, + {"audio.enabled", [](const auto& val) { audio.enabled = stringToBool(val); }}, + {"audio.volume", [](const auto& val) { audio.volume = std::clamp(std::stoi(val), 0, 100); }}, + {"audio.music.enabled", [](const auto& val) { audio.music.enabled = stringToBool(val); }}, + {"audio.music.volume", [](const auto& val) { audio.music.volume = std::clamp(std::stoi(val), 0, 100); }}, + {"audio.sound.enabled", [](const auto& val) { audio.sound.enabled = stringToBool(val); }}, + {"audio.sound.volume", [](const auto& val) { audio.sound.volume = std::clamp(std::stoi(val), 0, 100); }}, // Juego - {"game.language", [](const auto& val){ - settings.language = static_cast(std::stoi(val)); - pending_changes.new_language = settings.language; - }}, - {"game.difficulty", [](const auto& val){ - settings.difficulty = static_cast(std::stoi(val)); - pending_changes.new_difficulty = settings.difficulty; - }}, - {"game.autofire", [](const auto& val){ settings.autofire = stringToBool(val); }}, - {"game.shutdown_enabled", [](const auto& val){ settings.shutdown_enabled = stringToBool(val); }} - }; + {"game.language", [](const auto& val) { + settings.language = static_cast(std::stoi(val)); + pending_changes.new_language = settings.language; + }}, + {"game.difficulty", [](const auto& val) { + settings.difficulty = static_cast(std::stoi(val)); + pending_changes.new_difficulty = settings.difficulty; + }}, + {"game.autofire", [](const auto& val) { settings.autofire = stringToBool(val); }}, + {"game.shutdown_enabled", [](const auto& val) { settings.shutdown_enabled = stringToBool(val); }}}; // Maneja por separado la configuración general de los mandos if (var.starts_with("controller.")) { @@ -249,7 +244,7 @@ auto set(const std::string &var, const std::string &value) -> bool { return true; } catch (const std::out_of_range& e) { // Error: por ejemplo, índice de mando fuera de rango - return false; + return false; } catch (const std::invalid_argument& e) { // Error: por ejemplo, fallo en std::stoi return false; @@ -267,15 +262,14 @@ auto set(const std::string &var, const std::string &value) -> bool { return false; } } - + // Si la clave no se encontró en el mapa ni en la lógica de mandos return false; } - // Asigna el teclado al jugador void setKeyboardToPlayer(int player_id) { - for (auto &controller : controllers) { + for (auto& controller : controllers) { if (controller.player_id == player_id) { controller.type = InputDevice::ANY; } else { @@ -297,7 +291,7 @@ void swapControllers() { // Averigua quien está usando el teclado auto getPlayerWhoUsesKeyboard() -> int { - for (const auto &controller : controllers) { + for (const auto& controller : controllers) { if (controller.type == InputDevice::ANY) { return controller.player_id; } @@ -318,24 +312,4 @@ void checkPendingChanges() { pending_changes.has_pending_changes = settings.language != pending_changes.new_language || settings.difficulty != pending_changes.new_difficulty; } - -auto getDifficultyCodeFromName(const std::string &name) -> DifficultyCode { - for (const auto &difficulty : difficulties) { - if (difficulty.name == name) { - return difficulty.code; - } - } - // Si no se encuentra, devuelve el primero por defecto - return difficulties[0].code; -} - -auto getDifficultyNameFromCode(DifficultyCode code) -> std::string { - for (const auto &difficulty : difficulties) { - if (difficulty.code == code) { - return difficulty.name; - } - } - // Si no se encuentra, devuelve el nombre del primero por defecto - return difficulties[0].name; -} } // namespace Options \ No newline at end of file diff --git a/source/options.h b/source/options.h index 83e8a45..9c8c93c 100644 --- a/source/options.h +++ b/source/options.h @@ -7,6 +7,7 @@ #include // Para move #include // Para vector +#include "difficulty.h" //Para Difficulty #include "input.h" // Para InputAction, InputDevice #include "lang.h" // Para Code #include "manage_hiscore_table.h" // Para HiScoreEntry @@ -14,22 +15,6 @@ static constexpr int INVALID_INDEX = -1; namespace Options { -// --- Dificultad del juego --- -enum class DifficultyCode { - EASY = 0, - NORMAL = 1, - HARD = 2, -}; - -// --- Estructura que representa un nivel de dificultad -struct Difficulty { - DifficultyCode code; // Código que identifica la dificultad - std::string name; // Nombre que identifica la dificultad - - Difficulty(DifficultyCode c, std::string n) - : code(c), name(std::move(n)) {} -}; - // --- Opciones de ventana --- struct WindowOptions { std::string caption; // Texto que aparece en la barra de título de la ventana @@ -85,7 +70,7 @@ struct AudioOptions { // --- Opciones de configuración --- struct SettingsOptions { - DifficultyCode difficulty{DifficultyCode::NORMAL}; // Dificultad del juego + Difficulty::Code difficulty{Difficulty::Code::NORMAL}; // Dificultad del juego Lang::Code language{Lang::Code::VALENCIAN}; // Idioma usado en el juego bool autofire{true}; // Indicador de autofire bool shutdown_enabled{false}; // Especifica si se puede apagar el sistema @@ -135,7 +120,7 @@ struct GamepadOptions { // --- Opciones pendientes de aplicar --- struct PendingChanges { Lang::Code new_language{Lang::Code::VALENCIAN}; // Idioma en espera de aplicar - DifficultyCode new_difficulty{DifficultyCode::NORMAL}; // Dificultad en espera de aplicar + Difficulty::Code new_difficulty{Difficulty::Code::NORMAL}; // Dificultad en espera de aplicar bool has_pending_changes{false}; // Indica si hay cambios pendientes // Constructor por defecto con valores iniciales @@ -149,18 +134,16 @@ extern VideoOptions video; // Opciones de vídeo extern AudioOptions audio; // Opciones de audio extern std::vector controllers; // Opciones de mando para cada jugador extern PendingChanges pending_changes; // Opciones que se aplican al cerrar -extern std::vector difficulties; // Lista de los diferentes tipos de dificultad // --- Funciones de configuración --- -void init(); // Inicializa las opciones del programa -auto loadFromFile() -> bool; // Carga el fichero de configuración -auto saveToFile() -> bool; // Guarda el fichero de configuración -void setKeyboardToPlayer(int player_id); // Asigna el teclado al jugador -void swapKeyboard(); // Intercambia el teclado de jugador -void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos -auto getPlayerWhoUsesKeyboard() -> int; // Averigua quién está usando el teclado -void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables -void checkPendingChanges(); // Verifica si hay cambios pendientes -auto getDifficultyCodeFromName(const std::string &name) -> DifficultyCode; // Obtiene el código de dificultad a partir del nombre -auto getDifficultyNameFromCode(DifficultyCode code) -> std::string; // Obtiene el nombre de la dificultad a partir del código +void init(); // Inicializa las opciones del programa +void setFile(const std::string &file_path); // Establece el fichero de configuración +auto loadFromFile() -> bool; // Carga el fichero de configuración +auto saveToFile() -> bool; // Guarda el fichero de configuración +void setKeyboardToPlayer(int player_id); // Asigna el teclado al jugador +void swapKeyboard(); // Intercambia el teclado de jugador +void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos +auto getPlayerWhoUsesKeyboard() -> int; // Averigua quién está usando el teclado +void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables +void checkPendingChanges(); // Verifica si hay cambios pendientes } // namespace Options \ No newline at end of file diff --git a/source/sections/game.cpp b/source/sections/game.cpp index de3d3e9..307f723 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -1537,21 +1537,21 @@ void Game::initScoreboard() { void Game::initDifficultyVars() { // Variables relacionadas con la dificultad switch (difficulty_) { - case Options::DifficultyCode::EASY: { + case Difficulty::Code::EASY: { balloon_manager_->setDefaultBalloonSpeed(BALLOON_SPEED[0]); difficulty_score_multiplier_ = 0.5F; scoreboard_->setColor(param.scoreboard.easy_color); break; } - case Options::DifficultyCode::NORMAL: { + case Difficulty::Code::NORMAL: { balloon_manager_->setDefaultBalloonSpeed(BALLOON_SPEED[0]); difficulty_score_multiplier_ = 1.0F; scoreboard_->setColor(param.scoreboard.normal_color); break; } - case Options::DifficultyCode::HARD: { + case Difficulty::Code::HARD: { balloon_manager_->setDefaultBalloonSpeed(BALLOON_SPEED[4]); difficulty_score_multiplier_ = 1.5F; scoreboard_->setColor(param.scoreboard.hard_color); @@ -1759,7 +1759,7 @@ void Game::evaluateAndSetMenace() { // Actualiza la velocidad de los globos en funcion del poder acumulado de la fase void Game::checkAndUpdateBalloonSpeed() { - if (difficulty_ != Options::DifficultyCode::NORMAL) { + if (difficulty_ != Difficulty::Code::NORMAL) { return; } diff --git a/source/sections/game.h b/source/sections/game.h index afc66a9..e81a99d 100644 --- a/source/sections/game.h +++ b/source/sections/game.h @@ -6,6 +6,7 @@ #include // Para string #include // Para vector +#include "difficulty.h" // Para Difficulty #include "item.h" // Para Item, ItemType #include "manage_hiscore_table.h" // Para HiScoreEntry #include "options.h" // Para SettingsOptions, settings, DifficultyCode (ptr only) @@ -129,7 +130,7 @@ class Game { Options::settings.hi_score_table[0].score); // Máxima puntuación y nombre de quien la ostenta Demo demo_; // Variable con todas las variables relacionadas con el modo demo - Options::DifficultyCode difficulty_ = Options::settings.difficulty; // Dificultad del juego + Difficulty::Code difficulty_ = Options::settings.difficulty; // Dificultad del juego Helper helper_; // Variable para gestionar las ayudas Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa bool coffee_machine_enabled_ = false; // Indica si hay una máquina de café en el terreno de juego diff --git a/source/ui/service_menu.cpp b/source/ui/service_menu.cpp index bc5fa71..d925dbb 100644 --- a/source/ui/service_menu.cpp +++ b/source/ui/service_menu.cpp @@ -3,6 +3,7 @@ #include // Para max #include "audio.h" // Para Audio +#include "difficulty.h" // Para Difficulty #include "lang.h" // Para getText, getCodeFromName, getNameFromCode #include "menu_option.h" // Para MenuOption, BoolOption, ActionOption, IntOption, FolderOption, ListOption #include "menu_renderer.h" // Para MenuRenderer @@ -238,36 +239,154 @@ auto ServiceMenu::countOptionsInGroup(SettingsGroup group) const -> size_t { void ServiceMenu::initializeOptions() { options_.clear(); - // --- Video --- - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] FULLSCREEN"), SettingsGroup::VIDEO, &Options::video.fullscreen)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] WINDOW_SIZE"), SettingsGroup::VIDEO, &Options::window.zoom, 1, Options::window.max_zoom, 1)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] SHADERS"), SettingsGroup::VIDEO, &Options::video.shaders)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] VSYNC"), SettingsGroup::VIDEO, &Options::video.vsync)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] INTEGER_SCALE"), SettingsGroup::VIDEO, &Options::video.integer_scale)); + // VIDEO + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] FULLSCREEN"), + SettingsGroup::VIDEO, + &Options::video.fullscreen)); - // --- Audio --- - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] AUDIO"), SettingsGroup::AUDIO, &Options::audio.enabled)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] MAIN_VOLUME"), SettingsGroup::AUDIO, &Options::audio.volume, 0, 100, 5)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] MUSIC_VOLUME"), SettingsGroup::AUDIO, &Options::audio.music.volume, 0, 100, 5)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] SFX_VOLUME"), SettingsGroup::AUDIO, &Options::audio.sound.volume, 0, 100, 5)); + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] WINDOW_SIZE"), + SettingsGroup::VIDEO, + &Options::window.zoom, + 1, + Options::window.max_zoom, + 1)); - // --- Settings --- - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] AUTOFIRE"), SettingsGroup::SETTINGS, &Options::settings.autofire)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] LANGUAGE"), SettingsGroup::SETTINGS, std::vector{Lang::getText("[SERVICE_MENU] LANG_ES"), Lang::getText("[SERVICE_MENU] LANG_BA"), Lang::getText("[SERVICE_MENU] LANG_EN")}, []() { return Lang::getNameFromCode(Options::pending_changes.new_language); }, [](const std::string &val) { Options::pending_changes.new_language = Lang::getCodeFromName(val); Options::checkPendingChanges(); })); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] DIFFICULTY"), SettingsGroup::SETTINGS, std::vector{Lang::getText("[SERVICE_MENU] EASY"), Lang::getText("[SERVICE_MENU] NORMAL"), Lang::getText("[SERVICE_MENU] HARD")}, []() { return Options::getDifficultyNameFromCode(Options::pending_changes.new_difficulty); }, [](const std::string &val) { Options::pending_changes.new_difficulty = Options::getDifficultyCodeFromName(val); Options::checkPendingChanges(); })); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] ENABLE_SHUTDOWN"), SettingsGroup::SETTINGS, &Options::settings.shutdown_enabled)); + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] SHADERS"), + SettingsGroup::VIDEO, + &Options::video.shaders)); - // --- System --- - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] RESET"), SettingsGroup::SYSTEM, [this]() { Section::name = Section::Name::RESET; toggle(); })); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] QUIT"), SettingsGroup::SYSTEM, []() { Section::name = Section::Name::QUIT; Section::options = Section::Options::NONE; })); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] SHUTDOWN"), SettingsGroup::SYSTEM, []() { Section::name = Section::Name::QUIT; Section::options = Section::Options::SHUTDOWN; }, !Options::settings.shutdown_enabled)); + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] VSYNC"), + SettingsGroup::VIDEO, + &Options::video.vsync)); - // --- Main Menu --- - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] VIDEO"), SettingsGroup::MAIN, SettingsGroup::VIDEO)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] AUDIO"), SettingsGroup::MAIN, SettingsGroup::AUDIO)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] SETTINGS"), SettingsGroup::MAIN, SettingsGroup::SETTINGS)); - options_.push_back(std::make_unique(Lang::getText("[SERVICE_MENU] SYSTEM"), SettingsGroup::MAIN, SettingsGroup::SYSTEM)); + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] INTEGER_SCALE"), + SettingsGroup::VIDEO, + &Options::video.integer_scale)); + // AUDIO + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] AUDIO"), + SettingsGroup::AUDIO, + &Options::audio.enabled)); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] MAIN_VOLUME"), + SettingsGroup::AUDIO, + &Options::audio.volume, + 0, + 100, + 5)); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] MUSIC_VOLUME"), + SettingsGroup::AUDIO, + &Options::audio.music.volume, + 0, + 100, + 5)); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] SFX_VOLUME"), + SettingsGroup::AUDIO, + &Options::audio.sound.volume, + 0, + 100, + 5)); + + // SETTINGS + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] AUTOFIRE"), + SettingsGroup::SETTINGS, + &Options::settings.autofire)); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] LANGUAGE"), + SettingsGroup::SETTINGS, + std::vector{ + Lang::getText("[SERVICE_MENU] LANG_ES"), + Lang::getText("[SERVICE_MENU] LANG_BA"), + Lang::getText("[SERVICE_MENU] LANG_EN")}, + []() { + return Lang::getNameFromCode(Options::pending_changes.new_language); + }, + [](const std::string &val) { + Options::pending_changes.new_language = Lang::getCodeFromName(val); + Options::checkPendingChanges(); + })); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] DIFFICULTY"), + SettingsGroup::SETTINGS, + std::vector{ + Lang::getText("[SERVICE_MENU] EASY"), + Lang::getText("[SERVICE_MENU] NORMAL"), + Lang::getText("[SERVICE_MENU] HARD")}, + []() { + return Difficulty::getNameFromCode(Options::pending_changes.new_difficulty); + }, + [](const std::string &val) { + Options::pending_changes.new_difficulty = Difficulty::getCodeFromName(val); + Options::checkPendingChanges(); + })); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] ENABLE_SHUTDOWN"), + SettingsGroup::SETTINGS, + &Options::settings.shutdown_enabled)); + + // SYSTEM + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] RESET"), + SettingsGroup::SYSTEM, + [this]() { + Section::name = Section::Name::RESET; + toggle(); + })); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] QUIT"), + SettingsGroup::SYSTEM, + []() { + Section::name = Section::Name::QUIT; + Section::options = Section::Options::NONE; + })); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] SHUTDOWN"), + SettingsGroup::SYSTEM, + []() { + Section::name = Section::Name::QUIT; + Section::options = Section::Options::SHUTDOWN; + }, + !Options::settings.shutdown_enabled)); + + // MAIN MENU + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] VIDEO"), + SettingsGroup::MAIN, + SettingsGroup::VIDEO)); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] AUDIO"), + SettingsGroup::MAIN, + SettingsGroup::AUDIO)); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] SETTINGS"), + SettingsGroup::MAIN, + SettingsGroup::SETTINGS)); + + options_.push_back(std::make_unique( + Lang::getText("[SERVICE_MENU] SYSTEM"), + SettingsGroup::MAIN, + SettingsGroup::SYSTEM)); + + // Oculta opciones según configuración setHiddenOptions(); }