diff --git a/source/options.cpp b/source/options.cpp index 5358ae4..a7ec589 100644 --- a/source/options.cpp +++ b/source/options.cpp @@ -143,6 +143,10 @@ auto saveToFile() -> bool { file << "\n\n## CONTROLLERS\n"; gamepad_manager.saveToFile(file); + // Opciones de teclado + file << "\n\n## KEYBOARD\n"; + file << "keyboard.player=" << static_cast(keyboard.player_id) << "\n"; + // Cierra el fichero file.close(); @@ -207,7 +211,9 @@ auto set(const std::string& var, const std::string& value) -> bool { 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.shutdown_enabled", [](const auto& val) { settings.shutdown_enabled = stringToBool(val); }}, + // Teclado + {"keyboard.player", [](const auto& val) { keyboard.player_id = static_cast(stoi(val)); }}}; // Maneja por separado la configuración general de los mandos if (var.starts_with("controller.")) { @@ -317,7 +323,7 @@ void GamepadManager::assignAndLinkGamepads() { assignRemainingGamepads(physical_gamepads, assigned_instances); // Pasada 3: Limpia los datos de los slots que se quedaron sin mando. - clearUnassignedGamepadSlots(); + clearUnassignedGamepadSlots(); } // --- PRIMERA PASADA: Intenta asignar mandos basándose en la ruta guardada --- @@ -328,20 +334,19 @@ void GamepadManager::assignGamepadsByPath( for (size_t i = 0; i < MAX_PLAYERS; ++i) { const std::string& desired_path = desired_paths[i]; if (desired_path.empty()) { - continue; // No hay ruta guardada para este slot. + continue; // No hay ruta guardada para este slot. } // Buscamos un mando físico que coincida con la ruta y no esté ya asignado. for (const auto& physical_gamepad : physical_gamepads) { if (physical_gamepad->path == desired_path && !isGamepadAssigned(physical_gamepad, assigned_instances)) { - // Asignamos y actualizamos TODOS los datos. gamepads_[i].instance = physical_gamepad; - gamepads_[i].name = physical_gamepad->name; // <--- LA LÍNEA QUE FALTABA + gamepads_[i].name = physical_gamepad->name; // <--- LA LÍNEA QUE FALTABA // No es necesario actualizar la path aquí porque ya coincide. - + assigned_instances.push_back(physical_gamepad); - break; // Mando encontrado para este jugador, pasamos al siguiente. + break; // Mando encontrado para este jugador, pasamos al siguiente. } } } @@ -399,4 +404,27 @@ auto GamepadManager::isGamepadAssigned( } return false; // No se encontró en la lista. } + +// Convierte un player id a texto segun Lang +auto playerIdToString(Player::Id player_id) -> std::string { + switch (player_id) { + case Player::Id::PLAYER1: + return Lang::getText("[SERVICE_MENU] PLAYER1"); + case Player::Id::PLAYER2: + return Lang::getText("[SERVICE_MENU] PLAYER2"); + default: + return ""; + } +} + +// Convierte un texto a player id segun Lang +auto stringToPlayerId(std::string name) -> Player::Id { + if (name == Lang::getText("[SERVICE_MENU] PLAYER1")) { + return Player::Id::PLAYER1; + } else if (name == Lang::getText("[SERVICE_MENU] PLAYER2")) { + return Player::Id::PLAYER2; + } else { + return Player::Id::NO_PLAYER; + } +} } // namespace Options \ No newline at end of file diff --git a/source/options.h b/source/options.h index fe004bd..522accb 100644 --- a/source/options.h +++ b/source/options.h @@ -245,7 +245,19 @@ class GamepadManager { }; struct Keyboard { - Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado + Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado + std::vector> players; // Punteros a los jugadores + + void addPlayer(std::shared_ptr player) { players.push_back(player); } // Añade un jugador a la lista + void clearPlayers() { players.clear(); } // Limpia la lista de jugadores + + // Asigna el teclado a un jugador + void assignTo(Player::Id player_id) { + this->player_id = player_id; + for (auto& player : players) { + player->setUsesKeyboard(player->getId() == player_id); + } + } }; // --- Opciones pendientes de aplicar --- @@ -277,6 +289,8 @@ void setKeyboardToPlayer(Player::Id player_id); void swapKeyboard(); // Intercambia el teclado de jugador void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos auto getPlayerWhoUsesKeyboard() -> Player::Id; // Averigua quién está usando el teclado +auto playerIdToString(Player::Id player_id) -> std::string; // Convierte un player id a texto segun Lang +auto stringToPlayerId(std::string name) -> Player::Id; // Convierte un texto a player id segun Lang void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables void checkPendingChanges(); // Verifica si hay cambios pendientes auto assignGamepadByName(const std::string& gamepad_name, Player::Id player_id) -> bool; // Buscar y asignar un mando disponible por nombre diff --git a/source/sections/credits.cpp b/source/sections/credits.cpp index 9b6fc6e..47046f4 100644 --- a/source/sections/credits.cpp +++ b/source/sections/credits.cpp @@ -72,6 +72,9 @@ Credits::~Credits() { SDL_DestroyTexture(canvas_); resetVolume(); Audio::get()->stopMusic(); + + // Desregistra los jugadores de Options + Options::keyboard.clearPlayers(); } // Bucle principal @@ -326,36 +329,29 @@ void Credits::initPlayers() { std::vector> player_animations; // Vector con las animaciones del jugador // Texturas - Player1 - { - std::vector> player_texture; - player_texture.emplace_back(Resource::get()->getTexture("player1.gif")); - player_texture.emplace_back(Resource::get()->getTexture("player1_power.png")); - player_textures.push_back(player_texture); - } + std::vector> player1_textures; + player1_textures.emplace_back(Resource::get()->getTexture("player1.gif")); + player1_textures.emplace_back(Resource::get()->getTexture("player1_power.png")); + player_textures.push_back(player1_textures); // Texturas - Player2 - { - std::vector> player_texture; - player_texture.emplace_back(Resource::get()->getTexture("player2.gif")); - player_texture.emplace_back(Resource::get()->getTexture("player2_power.png")); - player_textures.push_back(player_texture); - } + std::vector> player2_textures; + player2_textures.emplace_back(Resource::get()->getTexture("player2.gif")); + player2_textures.emplace_back(Resource::get()->getTexture("player2_power.png")); + player_textures.push_back(player2_textures); // Animaciones -- Jugador - { - player_animations.emplace_back(Resource::get()->getAnimation("player.ani")); - player_animations.emplace_back(Resource::get()->getAnimation("player_power.ani")); - } + player_animations.emplace_back(Resource::get()->getAnimation("player.ani")); + player_animations.emplace_back(Resource::get()->getAnimation("player_power.ani")); // Crea los dos jugadores - constexpr int PLAYER_WIDTH = 32; - const int Y = play_area_.y + play_area_.h - PLAYER_WIDTH; + const int Y = play_area_.y + play_area_.h - Player::WIDTH; constexpr bool DEMO = false; constexpr int AWAY_DISTANCE = 700; Player::Config config_player1; config_player1.id = Player::Id::PLAYER1; - config_player1.x = play_area_.x - AWAY_DISTANCE - PLAYER_WIDTH; + config_player1.x = play_area_.x - AWAY_DISTANCE - Player::WIDTH; config_player1.y = Y; config_player1.demo = DEMO; config_player1.play_area = &play_area_; @@ -380,6 +376,10 @@ void Credits::initPlayers() { players_.emplace_back(std::make_unique(config_player2)); players_.back()->setWalkingState(Player::State::WALKING_LEFT); players_.back()->setPlayingState(Player::State::CREDITS); + + // Registra los jugadores en Options + Options::keyboard.addPlayer(players_.at(0)); + Options::keyboard.addPlayer(players_.at(1)); } // Actualiza los rectangulos negros diff --git a/source/sections/game.cpp b/source/sections/game.cpp index 14c0303..78a5863 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -121,6 +121,9 @@ Game::~Game() { Scoreboard::destroy(); SDL_DestroyTexture(canvas_); + + // Desregistra los jugadores de Options + Options::keyboard.clearPlayers(); } // Asigna texturas y animaciones @@ -1637,6 +1640,10 @@ void Game::initPlayers(Player::Id player_id) { player->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN); sendPlayerToTheFront(player); } + + // Registra los jugadores en Options + Options::keyboard.addPlayer(players_.at(0)); + Options::keyboard.addPlayer(players_.at(1)); } // Hace sonar la música diff --git a/source/sections/title.cpp b/source/sections/title.cpp index b20b017..18ac138 100644 --- a/source/sections/title.cpp +++ b/source/sections/title.cpp @@ -72,6 +72,9 @@ Title::~Title() { if (Section::name == Section::Name::LOGO) { Audio::get()->fadeOutMusic(300); } + + // Desregistra los jugadores de Options + Options::keyboard.clearPlayers(); } // Actualiza las variables del objeto @@ -208,11 +211,36 @@ void Title::checkInput() { if (!ServiceMenu::get()->isEnabled()) { processControllerInputs(); + processKeyboardStart(); } GlobalInputs::check(); } +void Title::processKeyboardStart() { + if (!canProcessStartButton()) { + return; + } + + const bool START_PRESSED = Input::get()->checkAction( + Input::Action::START, + Input::DO_NOT_ALLOW_REPEAT, + Input::CHECK_KEYBOARD); + + if (START_PRESSED) { + switch (Options::keyboard.player_id) { + case Player::Id::PLAYER1: + processPlayer1Start(); + break; + case Player::Id::PLAYER2: + processPlayer2Start(); + break; + default: + break; + } + } +} + void Title::processControllerInputs() { for (const auto& controller : Options::gamepad_manager) { if (isStartButtonPressed(&controller)) { @@ -225,7 +253,7 @@ auto Title::isStartButtonPressed(const Options::Gamepad* controller) -> bool { return Input::get()->checkAction( Input::Action::START, Input::DO_NOT_ALLOW_REPEAT, - Input::CHECK_KEYBOARD, + Input::DO_NOT_CHECK_KEYBOARD, controller->instance); } @@ -458,36 +486,28 @@ void Title::initPlayers() { std::vector> player_animations; // Vector con las animaciones del jugador // Texturas - Player1 - { - std::vector> player_texture; - player_texture.emplace_back(Resource::get()->getTexture("player1.gif")); - player_texture.emplace_back(Resource::get()->getTexture("player1_power.png")); - player_textures.push_back(player_texture); - } + std::vector> player1_textures; + player1_textures.emplace_back(Resource::get()->getTexture("player1.gif")); + player1_textures.emplace_back(Resource::get()->getTexture("player1_power.png")); + player_textures.push_back(player1_textures); // Texturas - Player2 - { - std::vector> player_texture; - player_texture.emplace_back(Resource::get()->getTexture("player2.gif")); - player_texture.emplace_back(Resource::get()->getTexture("player2_power.png")); - player_textures.push_back(player_texture); - } + std::vector> player2_textures; + player2_textures.emplace_back(Resource::get()->getTexture("player2.gif")); + player2_textures.emplace_back(Resource::get()->getTexture("player2_power.png")); + player_textures.push_back(player2_textures); // Animaciones -- Jugador - { - player_animations.emplace_back(Resource::get()->getAnimation("player.ani")); - player_animations.emplace_back(Resource::get()->getAnimation("player_power.ani")); - } + player_animations.emplace_back(Resource::get()->getAnimation("player.ani")); + player_animations.emplace_back(Resource::get()->getAnimation("player_power.ani")); // Crea los dos jugadores - constexpr int PLAYER_WIDTH = 32; - constexpr int PLAYER_HEIGHT = 32; - const int Y = param.title.press_start_position - (PLAYER_HEIGHT / 2); + const int Y = param.title.press_start_position - (Player::HEIGHT / 2); constexpr bool DEMO = false; Player::Config config_player1; config_player1.id = Player::Id::PLAYER1; - config_player1.x = param.game.game_area.center_x - (PLAYER_WIDTH / 2); + config_player1.x = param.game.game_area.center_x - (Player::WIDTH / 2); config_player1.y = Y; config_player1.demo = DEMO; config_player1.play_area = ¶m.game.play_area.rect; @@ -500,7 +520,7 @@ void Title::initPlayers() { Player::Config config_player2; config_player2.id = Player::Id::PLAYER2; - config_player2.x = param.game.game_area.center_x - (PLAYER_WIDTH / 2); + config_player2.x = param.game.game_area.center_x - (Player::WIDTH / 2); config_player2.y = Y; config_player2.demo = DEMO; config_player2.play_area = ¶m.game.play_area.rect; @@ -510,6 +530,10 @@ void Title::initPlayers() { config_player2.glowing_entry = &Options::settings.glowing_entries.at(static_cast(Player::Id::PLAYER2) - 1); players_.emplace_back(std::make_unique(config_player2)); players_.back()->setPlayingState(Player::State::TITLE_HIDDEN); + + // Registra los jugadores en Options + Options::keyboard.addPlayer(players_.at(0)); + Options::keyboard.addPlayer(players_.at(1)); } // Actualza los jugadores diff --git a/source/sections/title.h b/source/sections/title.h index 500be8f..b685b30 100644 --- a/source/sections/title.h +++ b/source/sections/title.h @@ -57,12 +57,12 @@ class Title { }; // --- Objetos y punteros --- - std::shared_ptr text_; // Objeto de texto para escribir en pantalla - std::unique_ptr fade_; // Fundido en pantalla - std::unique_ptr tiled_bg_; // Fondo animado de tiles - std::unique_ptr game_logo_; // Logo del juego - std::unique_ptr mini_logo_sprite_; // Logo JailGames mini - std::vector> players_; // Vector de jugadores + std::shared_ptr text_; // Objeto de texto para escribir en pantalla + std::unique_ptr fade_; // Fundido en pantalla + std::unique_ptr tiled_bg_; // Fondo animado de tiles + std::unique_ptr game_logo_; // Logo del juego + std::unique_ptr mini_logo_sprite_; // Logo JailGames mini + std::vector> players_; // Vector de jugadores // --- Variables de estado --- int counter_ = 0; // Temporizador para la pantalla de título @@ -88,6 +88,7 @@ class Title { void checkEvents(); // Comprueba los eventos void checkInput(); // Comprueba las entradas void handleKeyDownEvent(const SDL_Event& event); // Maneja el evento de tecla presionada + void processKeyboardStart(); // Procesa las entradas del teclado void processControllerInputs(); // Procesa las entradas de los mandos [[nodiscard]] static auto isStartButtonPressed(const Options::Gamepad* controller) -> bool; // Comprueba si se ha pulsado el botón Start void handleStartButtonPress(const Options::Gamepad* controller); // Maneja la pulsación del botón Start diff --git a/source/ui/service_menu.cpp b/source/ui/service_menu.cpp index 510f244..19f4297 100644 --- a/source/ui/service_menu.cpp +++ b/source/ui/service_menu.cpp @@ -319,13 +319,12 @@ void ServiceMenu::initializeOptions() { Lang::getText("[SERVICE_MENU] PLAYER1"), Lang::getText("[SERVICE_MENU] PLAYER2")}, []() { - // Aquí deberías devolver el jugador actual asignado al teclado - // Por ahora devuelvo "Jugador 1" como ejemplo - return Lang::getText("[SERVICE_MENU] PLAYER1"); + // Devolver el jugador actual asignado al teclado + return Options::playerIdToString(Options::getPlayerWhoUsesKeyboard()); }, [](const std::string &val) { - // Aquí asignarías el teclado al jugador seleccionado - // Implementación pendiente según tu sistema de input + // Asignar el teclado al jugador seleccionado + Options::keyboard.assignTo(Options::stringToPlayerId(val)); })); // CONTROLS - Acción para intercambiar mandos