From 983eb7ee6fc95d044606310ce8b6e0193a9636a3 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sun, 10 Aug 2025 11:02:20 +0200 Subject: [PATCH] Ja es poden conectar i desconectar mandos en calent, que tot el mon s'entera --- data/lang/ba_BA.json | 15 ++++++++------ data/lang/en_UK.json | 41 ++++++++++++++++++++------------------ data/lang/es_ES.json | 19 ++++++++++-------- source/global_events.cpp | 30 +++++++++++++++++++++++----- source/input.cpp | 29 +++++++++++++++------------ source/input.h | 6 +++--- source/options.h | 15 +++++++------- source/sections/game.cpp | 2 +- source/ui/service_menu.cpp | 13 ++++++++++-- source/ui/service_menu.h | 3 +++ 10 files changed, 109 insertions(+), 64 deletions(-) diff --git a/data/lang/ba_BA.json b/data/lang/ba_BA.json index 76ba1a9..a579d2a 100644 --- a/data/lang/ba_BA.json +++ b/data/lang/ba_BA.json @@ -2,7 +2,7 @@ "[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMAT I DISSENYAT PER", "[CREDITS] PIXELART_DRAWN_BY": "GRAFICS DIBUIXATS PER", "[CREDITS] MUSIC_COMPOSED_BY": "MUSICA COMPOSADA PER", - "[CREDITS] SOUND_EFFECTS": "EFECTES DE SO", + "[CREDITS] SOUND_EFFECTS": "EFECTES DE SO PER", "[DEFINE_BUTTONS] TITLE": "define buttons title", "[DEFINE_BUTTONS] FIRE_LEFT": "Disparar cap a l'esquerra", @@ -17,8 +17,9 @@ "[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Prem un boto per a", "[DEFINE_BUTTONS] CONFIGURED" : "configurat", - "[GAME_TEXT] 1": "Felicitats!!", - "[GAME_TEXT] 2": " fases mes!", + "[GAME_TEXT] 1": "Felicitats!", + "[GAME_TEXT] 2": "Queden ", + "[GAME_TEXT] 2A": " fases mes!", "[GAME_TEXT] 3": "Ultima fase!", "[GAME_TEXT] 4": "SuperPoder!", "[GAME_TEXT] 5": "+1 Colp", @@ -29,11 +30,11 @@ "[HIGHSCORE_TABLE] CAPTION": "Millors puntuacions", "[INSTRUCTIONS] 01": "Objectiu", - "[INSTRUCTIONS] 02": "HAS D'EXPLOTAR", - "[INSTRUCTIONS] 03": "TANTS GLOBUS COM PUGUES", + "[INSTRUCTIONS] 02": "HAS D'EXPLOTAR TANTS", + "[INSTRUCTIONS] 03": "GLOBOS COM PUGUES", "[INSTRUCTIONS] 04": "LA DIFICULTAT AUGMENTA", "[INSTRUCTIONS] 05": "A MESURA QUE VAS PUNTUANT", - "[INSTRUCTIONS] 06": "Objectes", + "[INSTRUCTIONS] 06": "Objectes de bonus", "[INSTRUCTIONS] 07": "1.000 PUNTS", "[INSTRUCTIONS] 08": "2.500 PUNTS", "[INSTRUCTIONS] 09": "5.000 PUNTS", @@ -65,6 +66,8 @@ "[NOTIFICATIONS] 13": "Filtre", "[NOTIFICATIONS] 14": "Sincronisme vertical", "[NOTIFICATIONS] 15": "Reiniciar", + "[NOTIFICATIONS] CONNECTED": "conectat", + "[NOTIFICATIONS] DISCONNECTED": "desconectat", "[RESOURCE] LOADING": "Carregant", diff --git a/data/lang/en_UK.json b/data/lang/en_UK.json index 48ab655..3f1f2d9 100644 --- a/data/lang/en_UK.json +++ b/data/lang/en_UK.json @@ -1,8 +1,8 @@ { "[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMMED AND DESIGNED BY", - "[CREDITS] PIXELART_DRAWN_BY" : "PIXELART DRAWN BY", + "[CREDITS] PIXELART_DRAWN_BY" : "PIXELART BY", "[CREDITS] MUSIC_COMPOSED_BY" : "MUSIC COMPOSED BY", - "[CREDITS] SOUND_EFFECTS" : "SOUND EFFECTS", + "[CREDITS] SOUND_EFFECTS" : "SOUND EFFECTS BY", "[DEFINE_BUTTONS] FIRE_LEFT" : "Fire left", "[DEFINE_BUTTONS] FIRE_UP" : "Fire up", @@ -13,30 +13,31 @@ "[DEFINE_BUTTONS] KEYBOARD" : "Keyboard", "[DEFINE_BUTTONS] CONFIGURATION_COMPLETE": "Configuration complete", "[DEFINE_BUTTONS] CONFIGURING" : "Configuring", - "[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Press button for", + "[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Press a button for", "[DEFINE_BUTTONS] CONFIGURED" : "Configured", - "[GAME_TEXT] 1": "Congratulations!!", - "[GAME_TEXT] 2": " stages left!", + "[GAME_TEXT] 1": "Congratulations!", + "[GAME_TEXT] 2": "", + "[GAME_TEXT] 2A": " stages left!", "[GAME_TEXT] 3": "Last stage!", "[GAME_TEXT] 4": "PowerUp", "[GAME_TEXT] 5": "+1 Hit", "[GAME_TEXT] 6": "Stop!", "[GAME_TEXT] 7": "Get Ready!", - "[GAME_TEXT] 8": "1.000.000 points!", + "[GAME_TEXT] 8": "1,000,000 points!", "[HIGHSCORE_TABLE] CAPTION": "Best scores", "[INSTRUCTIONS] 01": "OBJECTIVE", - "[INSTRUCTIONS] 02": "YOU HAVE TO POP AS MANY", - "[INSTRUCTIONS] 03": "BALLOONS AS YOU CAN", - "[INSTRUCTIONS] 04": "DIFFICULTY WILL BE INCREASED", - "[INSTRUCTIONS] 05": "AS YOU SCORE POINTS", - "[INSTRUCTIONS] 06": "ITEMS", + "[INSTRUCTIONS] 02": "POP AS MANY BALLOONS", + "[INSTRUCTIONS] 03": "AS YOU CAN", + "[INSTRUCTIONS] 04": "DIFFICULTY INCREASES", + "[INSTRUCTIONS] 05": "AS YOU EARN POINTS", + "[INSTRUCTIONS] 06": "BONUS ITEMS", "[INSTRUCTIONS] 07": "1.000 POINTS", "[INSTRUCTIONS] 08": "2.500 POINTS", "[INSTRUCTIONS] 09": "5.000 POINTS", - "[INSTRUCTIONS] 10": "TIME STOPPER", + "[INSTRUCTIONS] 10": "TTIME FREEZE", "[INSTRUCTIONS] 11": "EXTRA HIT", "[INTRO] 1": "Any day of the year 2000", @@ -50,29 +51,31 @@ "[INTRO] 9": "Blop... blop... blop...", "[NOTIFICATIONS] 01": "Press again to quit", - "[NOTIFICATIONS] 02": "Press again to shutdown system", + "[NOTIFICATIONS] 02": "Press again to shut down the system", "[NOTIFICATIONS] 03": "Press again to reset", "[NOTIFICATIONS] 04": "Press again to change language to", - "[NOTIFICATIONS] 05": "Language set to", + "[NOTIFICATIONS] 05": "Language changed to", "[NOTIFICATIONS] 06": "on", "[NOTIFICATIONS] 07": "off", "[NOTIFICATIONS] 08": "Autofire", "[NOTIFICATIONS] 09": "Window zoom", "[NOTIFICATIONS] 10": "Window mode", "[NOTIFICATIONS] 11": "Fullscreen mode", - "[NOTIFICATIONS] 12": "Integer scale", + "[NOTIFICATIONS] 12": "Pixel-perfect scale", "[NOTIFICATIONS] 13": "Filter", "[NOTIFICATIONS] 14": "Vertical Sync", "[NOTIFICATIONS] 15": "Reset", + "[NOTIFICATIONS] CONNECTED": "connected", + "[NOTIFICATIONS] DISCONNECTED": "disconnected", "[RESOURCE] LOADING": "Loading", "[SERVICE_MENU] TITLE": "Service Menu", "[SERVICE_MENU] RESET": "Reset", - "[SERVICE_MENU] QUIT": "Quit Game", + "[SERVICE_MENU] QUIT": "Exit Game", "[SERVICE_MENU] SHUTDOWN": "Shutdown System", "[SERVICE_MENU] FULLSCREEN": "Fullscreen", - "[SERVICE_MENU] WINDOW_SIZE": "Window Size", + "[SERVICE_MENU] WINDOW_SIZE": "Window Zoom", "[SERVICE_MENU] SHADERS": "Shaders", "[SERVICE_MENU] VSYNC": "V-Sync", "[SERVICE_MENU] INTEGER_SCALE": "Integer Scale", @@ -95,7 +98,7 @@ "[SERVICE_MENU] NORMAL": "Normal", "[SERVICE_MENU] HARD": "Hard", "[SERVICE_MENU] NEED_RESTART_MESSAGE": "Restart to apply changes", - "[SERVICE_MENU] ENABLE_SHUTDOWN": "Enable shutdown", + "[SERVICE_MENU] ENABLE_SHUTDOWN": "Allow system shutdown", "[SERVICE_MENU] CONTROLS": "Controls", "[SERVICE_MENU] KEYBOARD": "Keyboard", "[SERVICE_MENU] PLAYER1": "Player 1", @@ -104,7 +107,7 @@ "[SERVICE_MENU] CONTROLLER2": "Controller 2", "[SERVICE_MENU] CONFIGURE1": "Configure Controller 1", "[SERVICE_MENU] CONFIGURE2": "Configure Controller 2", - "[SERVICE_MENU] NO_CONTROLLER": "[No controller]", + "[SERVICE_MENU] NO_CONTROLLER": "[ No controller ]", "[SERVICE_MENU] SWAP_CONTROLLERS": "Swap Controllers", "[SCOREBOARD] 1" : "Player 1", diff --git a/data/lang/es_ES.json b/data/lang/es_ES.json index 1e3dbd7..9ca8d11 100644 --- a/data/lang/es_ES.json +++ b/data/lang/es_ES.json @@ -2,7 +2,7 @@ "[CREDITS] PROGRAMMED_AND_DESIGNED_BY": "PROGRAMADO Y DISENADO POR", "[CREDITS] PIXELART_DRAWN_BY" : "GRAFICOS DIBUJADOS POR", "[CREDITS] MUSIC_COMPOSED_BY" : "MUSICA COMPUESTA POR", - "[CREDITS] SOUND_EFFECTS" : "EFECTOS DE SONIDO", + "[CREDITS] SOUND_EFFECTS" : "EFECTOS DE SONIDO POR", "[DEFINE_BUTTONS] FIRE_LEFT" : "Disparar a la izquierda", "[DEFINE_BUTTONS] FIRE_UP" : "Disparar hacia arriba", @@ -16,8 +16,9 @@ "[DEFINE_BUTTONS] PRESS_BUTTON_FOR" : "Pulsa un boton para", "[DEFINE_BUTTONS] CONFIGURED" : "Configurado", - "[GAME_TEXT] 1": "Felicidades!!", - "[GAME_TEXT] 2": " fases mas!", + "[GAME_TEXT] 1": "Felicidades!", + "[GAME_TEXT] 2": "!Quedan ", + "[GAME_TEXT] 2A": " fases!", "[GAME_TEXT] 3": "Ultima fase!", "[GAME_TEXT] 4": "Potenciador", "[GAME_TEXT] 5": "+1 Golpe", @@ -32,7 +33,7 @@ "[INSTRUCTIONS] 03": "TANTOS GLOBOS COMO PUEDAS", "[INSTRUCTIONS] 04": "LA DIFICULTAD SE INCREMENTA", "[INSTRUCTIONS] 05": "A MEDIDA QUE VAS PUNTUANDO", - "[INSTRUCTIONS] 06": "OBJETOS", + "[INSTRUCTIONS] 06": "OBJETOS DE BONUS", "[INSTRUCTIONS] 07": "1.000 PUNTOS", "[INSTRUCTIONS] 08": "2.500 PUNTOS", "[INSTRUCTIONS] 09": "5.000 PUNTOS", @@ -64,6 +65,8 @@ "[NOTIFICATIONS] 13": "Filtro", "[NOTIFICATIONS] 14": "Sincronismo vertical", "[NOTIFICATIONS] 15": "Reiniciar", + "[NOTIFICATIONS] CONNECTED": "conectado", + "[NOTIFICATIONS] DISCONNECTED": "desconectado", "[RESOURCE] LOADING": "Cargando", @@ -73,9 +76,9 @@ "[SERVICE_MENU] SHUTDOWN": "Apagar el sistema", "[SERVICE_MENU] FULLSCREEN": "Pantalla completa", "[SERVICE_MENU] WINDOW_SIZE": "Zoom de ventana", - "[SERVICE_MENU] SHADERS": "Filtro", + "[SERVICE_MENU] SHADERS": "Filtro grafico", "[SERVICE_MENU] VSYNC": "Sincronismo vertical", - "[SERVICE_MENU] INTEGER_SCALE": "Escalado entero", + "[SERVICE_MENU] INTEGER_SCALE": "Escalado proporcional", "[SERVICE_MENU] MAIN_VOLUME": "Volumen general", "[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica", "[SERVICE_MENU] SFX_VOLUME": "Volumen de los efectos", @@ -104,8 +107,8 @@ "[SERVICE_MENU] CONTROLLER2": "Mando 2", "[SERVICE_MENU] CONFIGURE1": "Configurar Mando 1", "[SERVICE_MENU] CONFIGURE2": "Configurar Mando 2", - "[SERVICE_MENU] NO_CONTROLLER": "[Desconectat]", - "[SERVICE_MENU] SWAP_CONTROLLERS": "Intercambia mandos", + "[SERVICE_MENU] NO_CONTROLLER": "[ Desconectado ]", + "[SERVICE_MENU] SWAP_CONTROLLERS": "Intercambiar mandos", "[SCOREBOARD] 1": "Jugador 1", "[SCOREBOARD] 2": "Jugador 2", diff --git a/source/global_events.cpp b/source/global_events.cpp index 5d01d5a..e29c446 100644 --- a/source/global_events.cpp +++ b/source/global_events.cpp @@ -3,13 +3,37 @@ #include // Para SDL_LogInfo, SDL_LogCategory #include "input.h" // Para Input +#include "lang.h" // Para Lang #include "mouse.h" // Para handleEvent #include "options.h" // Para Options #include "screen.h" // Para Screen #include "section.hpp" // Para Name, Options, name, options +#include "ui/notifier.h" // Para Notifier #include "ui/service_menu.h" // Para ServiceMenu namespace GlobalEvents { +// Comprueba los eventos de Input y muestra notificaciones +void handleInputEvents(const SDL_Event &event) { + static auto *input_ = Input::get(); + auto message = input_->handleEvent(event); + + if (message.empty()) return; + + // Reemplazo de palabras clave por texto localizado + size_t pos; + while ((pos = message.find(" CONNECTED")) != std::string::npos) { + message.replace(pos, std::string(" CONNECTED").length(), " " + Lang::getText("[NOTIFICATIONS] CONNECTED")); + } + while ((pos = message.find(" DISCONNECTED")) != std::string::npos) { + message.replace(pos, std::string(" DISCONNECTED").length(), " " + Lang::getText("[NOTIFICATIONS] DISCONNECTED")); + } + + Options::gamepad_manager.assignAndLinkGamepads(); + Options::gamepad_manager.resyncGamepadsWithPlayers(); + Notifier::get()->show({message}); + ServiceMenu::get()->refresh(); +} + // Comprueba los eventos que se pueden producir en cualquier sección del juego void check(const SDL_Event &event) { switch (event.type) { @@ -33,10 +57,6 @@ void check(const SDL_Event &event) { ServiceMenu::get()->handleEvent(event); Mouse::handleEvent(event); - - static auto *input_ = Input::get(); - if (input_->handleEvent(event)) { - Options::gamepad_manager.assignAndLinkGamepads(); - } + handleInputEvents(event); } } // namespace GlobalEvents \ No newline at end of file diff --git a/source/input.cpp b/source/input.cpp index 0710fd0..553dd6b 100644 --- a/source/input.cpp +++ b/source/input.cpp @@ -308,42 +308,45 @@ void Input::update() { } } -auto Input::handleEvent(const SDL_Event &event) -> bool { +auto Input::handleEvent(const SDL_Event &event) -> std::string { switch (event.type) { case SDL_EVENT_GAMEPAD_ADDED: - addGamepad(event.gdevice.which); - return true; + return addGamepad(event.gdevice.which); case SDL_EVENT_GAMEPAD_REMOVED: - removeGamepad(event.gdevice.which); - return true; + return removeGamepad(event.gdevice.which); } - return false; + return std::string(); } -void Input::addGamepad(int device_index) { +auto Input::addGamepad(int device_index) -> std::string { SDL_Gamepad *pad = SDL_OpenGamepad(device_index); if (pad == nullptr) { std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << std::endl; - return; + return std::string(); } auto gamepad = std::make_shared(pad); - std::cout << "Gamepad connected (" << gamepad->name << ")" << std::endl; + auto name = gamepad->name; + std::cout << "Gamepad connected (" << name << ")" << std::endl; applyGamepadConfig(gamepad); saveGamepadConfigFromGamepad(gamepad); gamepads_.push_back(std::move(gamepad)); + return name + " CONNECTED"; } -void Input::removeGamepad(SDL_JoystickID id) { - auto it = std::remove_if(gamepads_.begin(), gamepads_.end(), [id](const std::shared_ptr &gamepad) { +auto Input::removeGamepad(SDL_JoystickID id) -> std::string { + auto it = std::find_if(gamepads_.begin(), gamepads_.end(), [id](const std::shared_ptr &gamepad) { return gamepad->instance_id == id; }); if (it != gamepads_.end()) { - std::cout << "Gamepad disconnected (" << (*it)->name << ")" << std::endl; - gamepads_.erase(it, gamepads_.end()); + std::string name = (*it)->name; + std::cout << "Gamepad disconnected (" << name << ")" << std::endl; + gamepads_.erase(it); + return name + " DISCONNECTED"; } else { std::cerr << "No se encontró el gamepad con ID " << id << std::endl; + return {}; } } diff --git a/source/input.h b/source/input.h index 85e276a..2fa089f 100644 --- a/source/input.h +++ b/source/input.h @@ -168,7 +168,7 @@ class Input { void resetInputStates(); // --- Eventos --- - auto handleEvent(const SDL_Event &event) -> bool; + auto handleEvent(const SDL_Event &event) -> std::string; void printConnectedGamepads() const; @@ -190,8 +190,8 @@ class Input { // --- Métodos internos --- void initSDLGamePad(); static auto checkAxisInput(Action action, std::shared_ptr gamepad, bool repeat) -> bool; - void addGamepad(int device_index); - void removeGamepad(SDL_JoystickID id); + auto addGamepad(int device_index) -> std::string; + auto removeGamepad(SDL_JoystickID id) -> std::string; void addGamepadMappingsFromFile(); void discoverGamepads(); diff --git a/source/options.h b/source/options.h index 8d67d57..b0f8b8a 100644 --- a/source/options.h +++ b/source/options.h @@ -157,10 +157,12 @@ class GamepadManager { std::swap(gamepads_[0].name, gamepads_[1].name); std::swap(gamepads_[0].path, gamepads_[1].path); - for (auto player: players) - { - switch (player->getId()) - { + resyncGamepadsWithPlayers(); + } + + void resyncGamepadsWithPlayers() { + for (auto player : players) { + switch (player->getId()) { case Player::Id::PLAYER1: player->setGamepad(gamepads_[0].instance); break; @@ -168,7 +170,7 @@ class GamepadManager { player->setGamepad(gamepads_[1].instance); break; default: - break; + break; } } } @@ -229,7 +231,6 @@ class GamepadManager { // Asigna el mando a un jugador void assignTo(Input::Gamepad gamepad, Player::Id player_id) { - } // Asigna los mandos físicos basándose en la configuración actual de nombres. @@ -246,7 +247,7 @@ class GamepadManager { private: static constexpr std::string_view UNASSIGNED_TEXT = "---"; static constexpr size_t MAX_PLAYERS = 2; - std::array gamepads_; // Punteros a las estructuras de mandos de Options + std::array gamepads_; // Punteros a las estructuras de mandos de Options std::vector> players; // Punteros a los jugadores // Convierte Player::Id a índice del array diff --git a/source/sections/game.cpp b/source/sections/game.cpp index 5ae53e8..387640c 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -258,7 +258,7 @@ void Game::updateStage() { createMessage(paths, Resource::get()->getTexture("game_text_last_stage")); } else { auto text = Resource::get()->getText("04b_25_2x"); - const std::string CAPTION = std::to_string(10 - Stage::number) + Lang::getText("[GAME_TEXT] 2"); + const std::string CAPTION = Lang::getText("[GAME_TEXT] 2") + std::to_string(10 - Stage::number) + Lang::getText("[GAME_TEXT] 2A"); createMessage(paths, text->writeToTexture(CAPTION, 1, -4)); } } diff --git a/source/ui/service_menu.cpp b/source/ui/service_menu.cpp index 674e376..206ad0b 100644 --- a/source/ui/service_menu.cpp +++ b/source/ui/service_menu.cpp @@ -49,13 +49,12 @@ void ServiceMenu::toggle() { if (enabled_) { // Primero resetea el estado y luego muestra la animación - // reset(); + reset(); Options::gamepad_manager.assignAndLinkGamepads(); renderer_->show(this); } else { // Al cerrar, solo inicia la animación de ocultar renderer_->hide(); - // NO llames a reset() aquí } } @@ -614,4 +613,14 @@ auto ServiceMenu::isAnimating() const -> bool { auto ServiceMenu::isDefiningButtons() const -> bool { return define_buttons_ && define_buttons_->isEnabled(); +} + +void ServiceMenu::refresh() { + // Este método está diseñado para ser llamado desde fuera, por ejemplo, + // cuando un mando se conecta o desconecta mientras el menú está abierto. + + // La función updateMenu() es la forma más completa de refrescar, ya que + // sincroniza los valores, actualiza la lista de opciones visibles y notifica + // al renderer de cualquier cambio de layout que pueda haber ocurrido. + updateMenu(); } \ No newline at end of file diff --git a/source/ui/service_menu.h b/source/ui/service_menu.h index 426b6d0..4e7202d 100644 --- a/source/ui/service_menu.h +++ b/source/ui/service_menu.h @@ -45,6 +45,9 @@ class ServiceMenu { // --- Método para manejar eventos --- void handleEvent(const SDL_Event &event); bool checkInput(); + + // --- Método principal para refresco externo --- + void refresh(); // Refresca los valores y el layout del menú bajo demanda // --- Getters para el estado --- [[nodiscard]] auto isDefiningButtons() const -> bool;