From ac93cfa7d7572db8711215a5947cb95f7b82cc0a Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 14 May 2026 22:32:57 +0200 Subject: [PATCH 1/5] fix: enum class amb base std::uint8_t (33 troballes) --- source/core/audio/jail_audio.hpp | 4 ++-- source/core/input/input.cpp | 11 ++++------ source/core/input/input_types.hpp | 3 ++- source/core/rendering/palette_manager.hpp | 3 ++- source/core/rendering/pixel_reveal.hpp | 7 ++++--- source/core/rendering/render_info.hpp | 4 +++- source/core/rendering/screen.hpp | 3 ++- source/core/rendering/shader_backend.hpp | 3 ++- .../core/rendering/sprite/dissolve_sprite.hpp | 7 ++++--- source/core/resources/resource_cache.hpp | 7 ++++--- source/core/resources/resource_list.hpp | 2 +- source/core/resources/resource_pack.cpp | 9 ++++---- source/core/system/director.cpp | 3 ++- source/game/entities/player.hpp | 13 ++++++------ source/game/gameplay/collision_map.hpp | 5 +++-- source/game/gameplay/room.hpp | 11 +++++----- source/game/gameplay/room_loader.cpp | 3 +-- source/game/gameplay/scoreboard.cpp | 3 +-- source/game/scene_manager.hpp | 6 ++++-- source/game/scenes/credits.hpp | 9 ++++---- source/game/scenes/ending.hpp | 9 ++++---- source/game/scenes/ending2.cpp | 3 +-- source/game/scenes/ending2.hpp | 9 ++++---- source/game/scenes/game.cpp | 5 ++--- source/game/scenes/game.hpp | 5 +++-- source/game/scenes/game_over.cpp | 3 +-- source/game/scenes/game_over.hpp | 7 ++++--- source/game/scenes/loading_screen.hpp | 9 ++++---- source/game/scenes/logo.hpp | 3 ++- source/game/scenes/title.hpp | 11 +++++----- source/game/ui/console.cpp | 14 +++++-------- source/game/ui/console.hpp | 3 ++- source/game/ui/console_commands.cpp | 12 ++++------- source/game/ui/notifier.cpp | 3 +-- source/game/ui/notifier.hpp | 21 ++++++++++--------- 35 files changed, 120 insertions(+), 113 deletions(-) diff --git a/source/core/audio/jail_audio.hpp b/source/core/audio/jail_audio.hpp index a6289ac..c0e1bf7 100644 --- a/source/core/audio/jail_audio.hpp +++ b/source/core/audio/jail_audio.hpp @@ -24,14 +24,14 @@ struct SDLFreeDeleter { }; // --- Public Enums --- -enum JA_Channel_state { +enum JA_Channel_state : uint8_t { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED, }; -enum JA_Music_state { +enum JA_Music_state : uint8_t { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, diff --git a/source/core/input/input.cpp b/source/core/input/input.cpp index 597c373..8dcb3c3 100644 --- a/source/core/input/input.cpp +++ b/source/core/input/input.cpp @@ -2,9 +2,9 @@ #include // Para SDL_GetGamepadAxis, SDL_GamepadAxis, SDL_GamepadButton, SDL_GetError, SDL_JoystickID, SDL_AddGamepadMappingsFromFile, SDL_Event, SDL_EventType, SDL_GetGamepadButton, SDL_GetKeyboardState, SDL_INIT_GAMEPAD, SDL_InitSubSystem, SDL_LogError, SDL_OpenGamepad, SDL_PollEvent, SDL_WasInit, Sint16, SDL_Gamepad, SDL_LogCategory, SDL_Scancode +#include // Para ranges::any_of #include // Para basic_ostream, operator<<, cout, cerr #include // Para shared_ptr, __shared_ptr_access, allocator, operator==, make_shared -#include // Para ranges::any_of #include // Para __find_if_fn, find_if #include // Para unordered_map, _Node_iterator, operator==, _Node_iterator_base, _Node_const_iterator #include // Para pair, move @@ -184,8 +184,7 @@ auto Input::checkAnyInput(bool check_keyboard, const std::shared_ptr& g // --- Comprobación del Teclado --- // Llegim l'estat pre-calculat per Input::update() (sense tornar a cridar SDL_GetKeyboardState). - if (check_keyboard && std::ranges::any_of(keyboard_.bindings, - [](const auto& pair) { return pair.second.just_pressed; })) { + if (check_keyboard && std::ranges::any_of(keyboard_.bindings, [](const auto& pair) { return pair.second.just_pressed; })) { return true; } @@ -197,8 +196,7 @@ auto Input::checkAnyInput(bool check_keyboard, const std::shared_ptr& g // --- Comprobación del Mando --- // Iterem sobre totes les accions del mandos pre-calculades per Input::update(). - if (active_gamepad != nullptr && std::ranges::any_of(active_gamepad->bindings, - [](const auto& pair) { return pair.second.just_pressed; })) { + if (active_gamepad != nullptr && std::ranges::any_of(active_gamepad->bindings, [](const auto& pair) { return pair.second.just_pressed; })) { return true; } @@ -230,8 +228,7 @@ auto Input::getControllerName(const std::shared_ptr& gamepad) -> std::s auto Input::getControllerNames() const -> std::vector { std::vector names; names.reserve(gamepads_.size()); - std::ranges::transform(gamepads_, std::back_inserter(names), - [](const auto& gamepad) { return gamepad->name; }); + std::ranges::transform(gamepads_, std::back_inserter(names), [](const auto& gamepad) { return gamepad->name; }); return names; } diff --git a/source/core/input/input_types.hpp b/source/core/input/input_types.hpp index 90663c3..da5ac8f 100644 --- a/source/core/input/input_types.hpp +++ b/source/core/input/input_types.hpp @@ -2,11 +2,12 @@ #include +#include #include #include // --- Enums --- -enum class InputAction : int { // Acciones de entrada posibles en el juego +enum class InputAction : std::uint8_t { // Acciones de entrada posibles en el juego // Inputs de movimiento LEFT, RIGHT, diff --git a/source/core/rendering/palette_manager.hpp b/source/core/rendering/palette_manager.hpp index 7357eca..0a4613c 100644 --- a/source/core/rendering/palette_manager.hpp +++ b/source/core/rendering/palette_manager.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -14,7 +15,7 @@ using Palette = std::array; class Surface; // Modo de ordenación de paletas -enum class PaletteSortMode : int { +enum class PaletteSortMode : std::uint8_t { ORIGINAL = 0, // Paleta tal cual viene del fichero LUMINANCE = 1, // Ordenada por luminancia percibida SPECTRUM = 2, // Reordenada para imitar la paleta ZX Spectrum diff --git a/source/core/rendering/pixel_reveal.hpp b/source/core/rendering/pixel_reveal.hpp index 557abc7..0b049f4 100644 --- a/source/core/rendering/pixel_reveal.hpp +++ b/source/core/rendering/pixel_reveal.hpp @@ -1,7 +1,8 @@ #pragma once -#include // Para shared_ptr -#include // Para vector +#include // Para uint8_t +#include // Para shared_ptr +#include // Para vector class Surface; @@ -10,7 +11,7 @@ class Surface; class PixelReveal { public: // Modo de revelado: aleatorio por fila o en orden de bisección (dithering ordenado 1D) - enum class RevealMode { RANDOM, + enum class RevealMode : std::uint8_t { RANDOM, ORDERED }; // Constructor diff --git a/source/core/rendering/render_info.hpp b/source/core/rendering/render_info.hpp index 569e4e9..08f9a24 100644 --- a/source/core/rendering/render_info.hpp +++ b/source/core/rendering/render_info.hpp @@ -1,5 +1,7 @@ #pragma once +#include // Para uint8_t + class RenderInfo { public: // Singleton @@ -20,7 +22,7 @@ class RenderInfo { static constexpr float SLIDE_SPEED = 120.0F; private: - enum class Status { HIDDEN, + enum class Status : std::uint8_t { HIDDEN, RISING, ACTIVE, VANISHING }; diff --git a/source/core/rendering/screen.hpp b/source/core/rendering/screen.hpp index 5e71b48..2068185 100644 --- a/source/core/rendering/screen.hpp +++ b/source/core/rendering/screen.hpp @@ -4,6 +4,7 @@ #include // Para Uint32 #include // Para size_t +#include // Para uint8_t #include // Para shared_ptr, __shared_ptr_access #include // Para string #include // Para std::pair @@ -18,7 +19,7 @@ class Text; class Screen { public: // Tipos de filtro - enum class Filter : Uint32 { + enum class Filter : std::uint8_t { NEAREST = 0, LINEAR = 1, }; diff --git a/source/core/rendering/shader_backend.hpp b/source/core/rendering/shader_backend.hpp index df5427b..def2c60 100644 --- a/source/core/rendering/shader_backend.hpp +++ b/source/core/rendering/shader_backend.hpp @@ -2,13 +2,14 @@ #include +#include #include #include namespace Rendering { /** @brief Identificador del shader de post-procesado activo */ - enum class ShaderType { POSTFX, + enum class ShaderType : std::uint8_t { POSTFX, CRTPI }; /** diff --git a/source/core/rendering/sprite/dissolve_sprite.hpp b/source/core/rendering/sprite/dissolve_sprite.hpp index 7292852..fe1a951 100644 --- a/source/core/rendering/sprite/dissolve_sprite.hpp +++ b/source/core/rendering/sprite/dissolve_sprite.hpp @@ -2,14 +2,15 @@ #include -#include // Para shared_ptr +#include // Para uint8_t +#include // Para shared_ptr #include "core/rendering/sprite/animated_sprite.hpp" // Para SurfaceAnimatedSprite class Surface; // Direcció de la dissolució -enum class DissolveDirection { NONE, +enum class DissolveDirection : std::uint8_t { NONE, DOWN, UP }; @@ -41,7 +42,7 @@ class DissolveSprite : public AnimatedSprite { void setColorReplace(Uint8 source, Uint8 target); private: - enum class TransitionMode { NONE, + enum class TransitionMode : std::uint8_t { NONE, DISSOLVING, GENERATING }; diff --git a/source/core/resources/resource_cache.hpp b/source/core/resources/resource_cache.hpp index 92f3826..d292019 100644 --- a/source/core/resources/resource_cache.hpp +++ b/source/core/resources/resource_cache.hpp @@ -1,7 +1,8 @@ #pragma once -#include // Para shared_ptr -#include // Para string +#include // Para uint8_t +#include // Para shared_ptr +#include // Para string #include #include // Para vector @@ -54,7 +55,7 @@ namespace Resource { }; // Etapas del loader incremental - enum class LoadStage { + enum class LoadStage : std::uint8_t { SOUNDS, MUSICS, SURFACES, diff --git a/source/core/resources/resource_list.hpp b/source/core/resources/resource_list.hpp index 10ba6ba..731e0de 100644 --- a/source/core/resources/resource_list.hpp +++ b/source/core/resources/resource_list.hpp @@ -12,7 +12,7 @@ namespace Resource { class List { public: // --- Enums --- - enum class Type : int { + enum class Type : std::uint8_t { DATA, // Datos BITMAP, // Imágenes ANIMATION, // Animaciones diff --git a/source/core/resources/resource_pack.cpp b/source/core/resources/resource_pack.cpp index 431120c..9d6b9cc 100644 --- a/source/core/resources/resource_pack.cpp +++ b/source/core/resources/resource_pack.cpp @@ -6,19 +6,18 @@ #include #include -#include #include #include #include +#include namespace Resource { // Calculate CRC32 checksum for data verification auto Pack::calculateChecksum(const std::vector& data) -> uint32_t { // NOLINT(readability-convert-member-functions-to-static) - return std::accumulate(data.begin(), data.end(), uint32_t{0x12345678}, - [](uint32_t acc, unsigned char byte) -> uint32_t { - return ((acc << 5) + acc) + byte; - }); + return std::accumulate(data.begin(), data.end(), uint32_t{0x12345678}, [](uint32_t acc, unsigned char byte) -> uint32_t { + return ((acc << 5) + acc) + byte; + }); } // XOR encryption (symmetric - same function for encrypt/decrypt) diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index 0266ac6..9bf61de 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -61,7 +61,8 @@ namespace { } // namespace // Constructor -Director::Director() : executable_path_(getExecutablePath()) { +Director::Director() + : executable_path_(getExecutablePath()) { std::cout << "Game start" << '\n'; // Crea la carpeta del sistema donde guardar datos diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index 7a6f95e..b17b89c 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -2,10 +2,11 @@ #include -#include // Para array -#include // Para numeric_limits -#include // Para shared_ptr, __shared_ptr_access -#include // Para string +#include // Para array +#include // Para uint8_t +#include // Para numeric_limits +#include // Para shared_ptr, __shared_ptr_access +#include // Para string #include #include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite @@ -18,14 +19,14 @@ struct JA_Sound_t; // lines 13-13 class Player { public: // --- Enums y Structs --- - enum class State { + enum class State : std::uint8_t { ON_GROUND, // En suelo plano o conveyor belt ON_SLOPE, // En rampa/pendiente JUMPING, FALLING, }; - enum class Direction { + enum class Direction : std::uint8_t { LEFT, RIGHT, UP, diff --git a/source/game/gameplay/collision_map.hpp b/source/game/gameplay/collision_map.hpp index b4a6466..087f51c 100644 --- a/source/game/gameplay/collision_map.hpp +++ b/source/game/gameplay/collision_map.hpp @@ -2,7 +2,8 @@ #include -#include // Para vector +#include // Para uint8_t +#include // Para vector #include "utils/utils.hpp" // Para LineHorizontal, LineDiagonal, LineVertical @@ -18,7 +19,7 @@ class CollisionMap { public: // Enumeración de tipos de tile (para colisiones) - enum class Tile { + enum class Tile : std::uint8_t { EMPTY, WALL, PASSABLE, diff --git a/source/game/gameplay/room.hpp b/source/game/gameplay/room.hpp index 260d6cd..33a9f5f 100644 --- a/source/game/gameplay/room.hpp +++ b/source/game/gameplay/room.hpp @@ -2,9 +2,10 @@ #include -#include // Para shared_ptr -#include // Para string -#include // Para vector +#include // Para uint8_t +#include // Para shared_ptr +#include // Para string +#include // Para vector #include "game/entities/enemy.hpp" // Para EnemyData #include "game/entities/item.hpp" // Para ItemData @@ -20,7 +21,7 @@ class TilemapRenderer; class Room { public: // -- Enumeraciones y estructuras --- - enum class Border : int { + enum class Border : std::uint8_t { TOP = 0, RIGHT = 1, BOTTOM = 2, @@ -28,7 +29,7 @@ class Room { NONE = 4 }; - enum class Tile { + enum class Tile : std::uint8_t { EMPTY, WALL, PASSABLE, diff --git a/source/game/gameplay/room_loader.cpp b/source/game/gameplay/room_loader.cpp index 8afef58..2bc4bbe 100644 --- a/source/game/gameplay/room_loader.cpp +++ b/source/game/gameplay/room_loader.cpp @@ -133,8 +133,7 @@ void RoomLoader::parseTilemap(const fkyaml::node& yaml, Room::Data& room, const for (const auto& row_node : tilemap_node) { std::vector row; row.reserve(32); - std::ranges::transform(row_node, std::back_inserter(row), - [](const auto& tile_node) { return tile_node.template get_value(); }); + std::ranges::transform(row_node, std::back_inserter(row), [](const auto& tile_node) { return tile_node.template get_value(); }); tilemap_2d.push_back(std::move(row)); } diff --git a/source/game/gameplay/scoreboard.cpp b/source/game/gameplay/scoreboard.cpp index 8f74f47..c3ef969 100644 --- a/source/game/gameplay/scoreboard.cpp +++ b/source/game/gameplay/scoreboard.cpp @@ -37,8 +37,7 @@ Scoreboard::Scoreboard(std::shared_ptr data) // Inicializa el vector de colores const std::vector COLORS = {"blue", "magenta", "green", "cyan", "yellow", "white", "bright_blue", "bright_magenta", "bright_green", "bright_cyan", "bright_yellow", "bright_white"}; color_.reserve(COLORS.size()); - std::ranges::transform(COLORS, std::back_inserter(color_), - [](const auto& color) { return stringToColor(color); }); + std::ranges::transform(COLORS, std::back_inserter(color_), [](const auto& color) { return stringToColor(color); }); } // Pinta el objeto en pantalla diff --git a/source/game/scene_manager.hpp b/source/game/scene_manager.hpp index 81a98ec..0d95bbf 100644 --- a/source/game/scene_manager.hpp +++ b/source/game/scene_manager.hpp @@ -1,5 +1,7 @@ #pragma once +#include // Para uint8_t + /* Namespace SceneManager: gestiona el flujo entre las diferentes escenas del juego. @@ -10,7 +12,7 @@ namespace SceneManager { // --- Escenas del programa --- - enum class Scene { + enum class Scene : std::uint8_t { BOOT_LOADER, // Carga inicial de recursos dirigida por iterate() LOGO, // Pantalla del logo LOADING_SCREEN, // Pantalla de carga @@ -26,7 +28,7 @@ namespace SceneManager { }; // --- Opciones para transiciones entre escenas --- - enum class Options { + enum class Options : std::uint8_t { NONE, // Sin opciones especiales LOGO_TO_LOADING_SCREEN, // Del logo a la intro LOGO_TO_TITLE, // Del logo al título diff --git a/source/game/scenes/credits.hpp b/source/game/scenes/credits.hpp index 968307f..c494e80 100644 --- a/source/game/scenes/credits.hpp +++ b/source/game/scenes/credits.hpp @@ -2,9 +2,10 @@ #include -#include // Para shared_ptr -#include // Para string -#include // Para vector +#include // Para uint8_t +#include // Para shared_ptr +#include // Para string +#include // Para vector #include "game/scenes/scene.hpp" // Para Scene class AnimatedSprite; // lines 11-11 @@ -24,7 +25,7 @@ class Credits : public Scene { private: // --- Tipos anidados --- - enum class State { + enum class State : std::uint8_t { REVEALING_TEXT, PAUSE_1, REVEALING_TEXT_2, diff --git a/source/game/scenes/ending.hpp b/source/game/scenes/ending.hpp index b8e81f5..7251b52 100644 --- a/source/game/scenes/ending.hpp +++ b/source/game/scenes/ending.hpp @@ -2,9 +2,10 @@ #include -#include // Para shared_ptr -#include // Para string -#include // Para vector +#include // Para uint8_t +#include // Para shared_ptr +#include // Para string +#include // Para vector #include "game/scenes/scene.hpp" // Para Scene class Sprite; // lines 8-8 @@ -24,7 +25,7 @@ class Ending : public Scene { private: // --- Enumeraciones --- - enum class State { + enum class State : std::uint8_t { WARMING_UP, SCENE_0, SCENE_1, diff --git a/source/game/scenes/ending2.cpp b/source/game/scenes/ending2.cpp index 6c84815..82bd26e 100644 --- a/source/game/scenes/ending2.cpp +++ b/source/game/scenes/ending2.cpp @@ -32,8 +32,7 @@ Ending2::Ending2() // Inicializa el vector de colores const std::vector COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"}; colors_.reserve(COLORS.size()); - std::ranges::transform(COLORS, std::back_inserter(colors_), - [](const auto& color) { return stringToColor(color); }); + std::ranges::transform(COLORS, std::back_inserter(colors_), [](const auto& color) { return stringToColor(color); }); Screen::get()->setBorderColor(static_cast(PaletteColor::BLACK)); // Cambia el color del borde iniSpriteList(); // Inicializa la lista de sprites diff --git a/source/game/scenes/ending2.hpp b/source/game/scenes/ending2.hpp index 0e2580d..96dda7c 100644 --- a/source/game/scenes/ending2.hpp +++ b/source/game/scenes/ending2.hpp @@ -2,9 +2,10 @@ #include -#include // Para shared_ptr -#include // Para string -#include // Para vector +#include // Para uint8_t +#include // Para shared_ptr +#include // Para string +#include // Para vector #include "core/rendering/sprite/dissolve_sprite.hpp" // Para SurfaceDissolveSprite #include "game/scenes/scene.hpp" // Para Scene @@ -25,7 +26,7 @@ class Ending2 : public Scene { private: // --- Enumeraciones --- - enum class EndingState : int { + enum class EndingState : std::uint8_t { PRE_CREDITS, // Estado previo a los créditos CREDITS, // Estado de los créditos POST_CREDITS, // Estado posterior a los créditos diff --git a/source/game/scenes/game.cpp b/source/game/scenes/game.cpp index b53d68d..79ee9d9 100644 --- a/source/game/scenes/game.cpp +++ b/source/game/scenes/game.cpp @@ -2,7 +2,7 @@ #include -#include // Para std::sqrt, std::min +#include // Para std::sqrt, std::min #include // Para std::accumulate #include #include // Para vector @@ -867,8 +867,7 @@ auto Game::checkEndGame() -> bool { // Obtiene la cantidad total de items que hay en el mapeado del juego auto Game::getTotalItems() -> int { const auto& rooms = Resource::Cache::get()->getRooms(); - return static_cast(std::accumulate(rooms.begin(), rooms.end(), size_t{0}, - [](size_t acc, const auto& room) { return acc + room.room->items.size(); })); + return static_cast(std::accumulate(rooms.begin(), rooms.end(), size_t{0}, [](size_t acc, const auto& room) { return acc + room.room->items.size(); })); } // Pone el juego en pausa diff --git a/source/game/scenes/game.hpp b/source/game/scenes/game.hpp index 6c29525..41c1b7e 100644 --- a/source/game/scenes/game.hpp +++ b/source/game/scenes/game.hpp @@ -2,6 +2,7 @@ #include +#include // Para uint8_t #include // Para initializer_list #include // Para shared_ptr #include // Para string @@ -19,12 +20,12 @@ class Surface; class Game : public Scene { public: // --- Estructuras --- - enum class Mode { + enum class Mode : std::uint8_t { DEMO, GAME }; - enum class State { + enum class State : std::uint8_t { PLAYING, // Normal gameplay BLACK_SCREEN, // Black screen after death (0.30s) GAME_OVER, // Intermediate state before changing scene diff --git a/source/game/scenes/game_over.cpp b/source/game/scenes/game_over.cpp index 5fa8075..5c46b1d 100644 --- a/source/game/scenes/game_over.cpp +++ b/source/game/scenes/game_over.cpp @@ -39,8 +39,7 @@ GameOver::GameOver() // Inicializa el vector de colores (de brillante a oscuro para fade) const std::vector COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"}; colors_.reserve(COLORS.size()); - std::ranges::transform(COLORS, std::back_inserter(colors_), - [](const auto& color) { return stringToColor(color); }); + std::ranges::transform(COLORS, std::back_inserter(colors_), [](const auto& color) { return stringToColor(color); }); color_ = colors_.back(); // Empieza en black } diff --git a/source/game/scenes/game_over.hpp b/source/game/scenes/game_over.hpp index 4ad9e7e..5eb7c20 100644 --- a/source/game/scenes/game_over.hpp +++ b/source/game/scenes/game_over.hpp @@ -2,8 +2,9 @@ #include -#include // Para shared_ptr -#include // Para vector +#include // Para uint8_t +#include // Para shared_ptr +#include // Para vector #include "game/scenes/scene.hpp" // Para Scene class AnimatedSprite; // lines 7-7 @@ -21,7 +22,7 @@ class GameOver : public Scene { private: // --- Enumeraciones --- - enum class State { + enum class State : std::uint8_t { WAITING, // Espera inicial antes de empezar FADE_IN, // Fade in de colores desde black DISPLAY, // Mostrando contenido con color brillante diff --git a/source/game/scenes/loading_screen.hpp b/source/game/scenes/loading_screen.hpp index 4dcb68d..91383a9 100644 --- a/source/game/scenes/loading_screen.hpp +++ b/source/game/scenes/loading_screen.hpp @@ -2,8 +2,9 @@ #include -#include // Para std::array -#include // Para shared_ptr +#include // Para std::array +#include // Para uint8_t +#include // Para shared_ptr #include "game/scenes/scene.hpp" // Para Scene #include "utils/delta_timer.hpp" // Para DeltaTimer @@ -24,7 +25,7 @@ class LoadingScreen : public Scene { private: // --- Enumeraciones --- // Estados de la secuencia de carga - enum class State { + enum class State : std::uint8_t { SILENT1, // Pausa inicial antes de empezar HEADER1, // Cabecera DATA1, // Datos @@ -37,7 +38,7 @@ class LoadingScreen : public Scene { }; // Tipos de borde para la pantalla de carga - enum class Border { + enum class Border : std::uint8_t { NONE, YELLOW_AND_BLUE, RED_AND_CYAN, diff --git a/source/game/scenes/logo.hpp b/source/game/scenes/logo.hpp index d334ca5..8c86fc5 100644 --- a/source/game/scenes/logo.hpp +++ b/source/game/scenes/logo.hpp @@ -2,6 +2,7 @@ #include +#include // Para uint8_t #include // Para std::function #include // Para shared_ptr #include // Para vector @@ -17,7 +18,7 @@ class Logo : public Scene { using EasingFunction = std::function; // Función de easing (permite lambdas) // --- Enumeraciones --- - enum class State { + enum class State : std::uint8_t { INITIAL, // Espera inicial JAILGAMES_SLIDE_IN, // Las líneas de JAILGAMES se deslizan hacia el centro SINCE_1998_FADE_IN, // Aparición gradual del texto "Since 1998" diff --git a/source/game/scenes/title.hpp b/source/game/scenes/title.hpp index 23ecde5..4df6e4b 100644 --- a/source/game/scenes/title.hpp +++ b/source/game/scenes/title.hpp @@ -2,10 +2,11 @@ #include -#include // Para std::array -#include // Para shared_ptr -#include // Para string -#include // Para vector +#include // Para std::array +#include // Para uint8_t +#include // Para shared_ptr +#include // Para string +#include // Para vector #include "game/scene_manager.hpp" // Para SceneManager::Scene #include "game/scenes/scene.hpp" // Para Scene @@ -34,7 +35,7 @@ class Title : public Scene { bool enabled{false}; // Solo se escriben y mueven si estan habilitadas }; - enum class State { + enum class State : std::uint8_t { SHOW_LOADING_SCREEN, FADE_LOADING_SCREEN, MAIN_MENU, diff --git a/source/game/ui/console.cpp b/source/game/ui/console.cpp index 221256e..8483d99 100644 --- a/source/game/ui/console.cpp +++ b/source/game/ui/console.cpp @@ -3,8 +3,8 @@ #include #include // Para ranges::transform -#include // Para std::accumulate #include // Para toupper +#include // Para std::accumulate #include // Para std::istringstream #include // Para string #include // Para vector @@ -182,8 +182,7 @@ void Console::update(float delta_time) { // NOLINT(readability-function-cogniti // Efecto typewriter: revelar letras una a una (solo cuando ACTIVE) if (status_ == Status::ACTIVE) { - const int total_chars = std::accumulate(msg_lines_.begin(), msg_lines_.end(), 0, - [](int acc, const auto& line) { return acc + static_cast(line.size()); }); + const int total_chars = std::accumulate(msg_lines_.begin(), msg_lines_.end(), 0, [](int acc, const auto& line) { return acc + static_cast(line.size()); }); if (typewriter_chars_ < total_chars) { typewriter_timer_ += delta_time; while (typewriter_timer_ >= TYPEWRITER_CHAR_DELAY && typewriter_chars_ < total_chars) { @@ -339,8 +338,7 @@ void Console::handleEvent(const SDL_Event& event) { // NOLINT(readability-funct if (SPACE_POS == std::string::npos) { // Modo comando: ciclar keywords visibles que empiecen por el prefijo const auto KEYWORDS = registry_.getVisibleKeywords(); - std::ranges::copy_if(KEYWORDS, std::back_inserter(tab_matches_), - [&upper](const auto& kw) { return upper.empty() || kw.starts_with(upper); }); + std::ranges::copy_if(KEYWORDS, std::back_inserter(tab_matches_), [&upper](const auto& kw) { return upper.empty() || kw.starts_with(upper); }); } else { const std::string BASE_CMD = upper.substr(0, SPACE_POS); const std::string SUB_PREFIX = upper.substr(SPACE_POS + 1); @@ -356,8 +354,7 @@ void Console::handleEvent(const SDL_Event& event) { // NOLINT(readability-funct if (tab_matches_.empty()) { break; } tab_index_ = (tab_index_ + 1) % static_cast(tab_matches_.size()); std::string result = tab_matches_[static_cast(tab_index_)]; - std::ranges::transform(result, result.begin(), - [](char c) { return static_cast(std::tolower(static_cast(c))); }); + std::ranges::transform(result, result.begin(), [](char c) { return static_cast(std::tolower(static_cast(c))); }); input_line_ = result; break; } @@ -403,8 +400,7 @@ void Console::processCommand() { // Typewriter: instantáneo si el comando lo requiere, letra a letra si no if (instant) { - typewriter_chars_ = std::accumulate(msg_lines_.begin(), msg_lines_.end(), 0, - [](int acc, const auto& l) { return acc + static_cast(l.size()); }); + typewriter_chars_ = std::accumulate(msg_lines_.begin(), msg_lines_.end(), 0, [](int acc, const auto& l) { return acc + static_cast(l.size()); }); } else { typewriter_chars_ = 0; } diff --git a/source/game/ui/console.hpp b/source/game/ui/console.hpp index 26ff22b..92f4948 100644 --- a/source/game/ui/console.hpp +++ b/source/game/ui/console.hpp @@ -2,6 +2,7 @@ #include +#include // Para uint8_t #include // Para deque (historial) #include // Para function #include // Para shared_ptr @@ -43,7 +44,7 @@ class Console { std::function on_toggle; private: - enum class Status { + enum class Status : std::uint8_t { HIDDEN, RISING, ACTIVE, diff --git a/source/game/ui/console_commands.cpp b/source/game/ui/console_commands.cpp index 4117314..f2dd8a6 100644 --- a/source/game/ui/console_commands.cpp +++ b/source/game/ui/console_commands.cpp @@ -1013,8 +1013,7 @@ void CommandRegistry::registerHandlers() { // NOLINT(readability-function-cogni std::vector result = {"NEXT", "PREV", "SORT", "DEFAULT"}; if (Screen::get() != nullptr) { const auto NAMES = Screen::get()->getPaletteNames(); - std::ranges::transform(NAMES, std::back_inserter(result), - [](const auto& name) { return toUpper(name); }); + std::ranges::transform(NAMES, std::back_inserter(result), [](const auto& name) { return toUpper(name); }); } return result; }; @@ -1120,8 +1119,7 @@ void CommandRegistry::load(const std::string& yaml_path) { // NOLINT(readabilit if (cat_node.contains("scope")) { const auto& scope_node = cat_node["scope"]; if (scope_node.is_sequence()) { - std::ranges::transform(scope_node, std::back_inserter(cat_scopes), - [](const auto& s) { return s.template get_value(); }); + std::ranges::transform(scope_node, std::back_inserter(cat_scopes), [](const auto& s) { return s.template get_value(); }); } else { cat_scopes.push_back(scope_node.get_value()); } @@ -1162,8 +1160,7 @@ void CommandRegistry::load(const std::string& yaml_path) { // NOLINT(readabilit for (auto it = completions_node.begin(); it != completions_node.end(); ++it) { auto path = it.key().get_value(); std::vector opts; - std::ranges::transform(*it, std::back_inserter(opts), - [](const auto& opt) { return opt.template get_value(); }); + std::ranges::transform(*it, std::back_inserter(opts), [](const auto& opt) { return opt.template get_value(); }); def.completions[path] = std::move(opts); } } @@ -1182,8 +1179,7 @@ void CommandRegistry::load(const std::string& yaml_path) { // NOLINT(readabilit for (auto it = extras_completions.begin(); it != extras_completions.end(); ++it) { auto path = it.key().get_value(); std::vector opts; - std::ranges::transform(*it, std::back_inserter(opts), - [](const auto& opt) { return opt.template get_value(); }); + std::ranges::transform(*it, std::back_inserter(opts), [](const auto& opt) { return opt.template get_value(); }); def.completions[path] = std::move(opts); } } diff --git a/source/game/ui/notifier.cpp b/source/game/ui/notifier.cpp index acc2fc6..138449a 100644 --- a/source/game/ui/notifier.cpp +++ b/source/game/ui/notifier.cpp @@ -306,7 +306,6 @@ auto Notifier::getVisibleHeight() const -> int { auto Notifier::getCodes() -> std::vector { std::vector codes; codes.reserve(notifications_.size()); - std::ranges::transform(notifications_, std::back_inserter(codes), - [](const auto& notification) { return notification.code; }); + std::ranges::transform(notifications_, std::back_inserter(codes), [](const auto& notification) { return notification.code; }); return codes; } \ No newline at end of file diff --git a/source/game/ui/notifier.hpp b/source/game/ui/notifier.hpp index b22d671..a907fbd 100644 --- a/source/game/ui/notifier.hpp +++ b/source/game/ui/notifier.hpp @@ -2,24 +2,25 @@ #include -#include // Para shared_ptr -#include // Para string, basic_string -#include // Para vector -class Sprite; // lines 8-8 -class Surface; // lines 10-10 -class Text; // lines 9-9 -class DeltaTimer; // lines 11-11 +#include // Para uint8_t +#include // Para shared_ptr +#include // Para string, basic_string +#include // Para vector +class Sprite; // lines 8-8 +class Surface; // lines 10-10 +class Text; // lines 9-9 +class DeltaTimer; // lines 11-11 class Notifier { public: // Justificado para las notificaciones - enum class TextAlign { + enum class TextAlign : std::uint8_t { LEFT, CENTER, }; // Forma de las notificaciones - enum class Shape { + enum class Shape : std::uint8_t { ROUNDED, SQUARED, }; @@ -65,7 +66,7 @@ class Notifier { private: // Tipos anidados - enum class Status { + enum class Status : std::uint8_t { RISING, STAY, VANISHING, From b480a23c884539e4029f771a5917ce6962b52940 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 14 May 2026 22:36:48 +0200 Subject: [PATCH 2/5] fix: literal F, headers C++ i trailing return type --- source/core/audio/audio_adapter.cpp | 4 +- source/core/audio/audio_adapter.hpp | 4 +- source/core/audio/jail_audio.hpp | 58 ++++++++++++------------ source/core/resources/resource_cache.cpp | 2 +- source/game/ui/notifier.cpp | 6 +-- source/main.cpp | 6 +-- 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/source/core/audio/audio_adapter.cpp b/source/core/audio/audio_adapter.cpp index 9221e5a..5ce2d6c 100644 --- a/source/core/audio/audio_adapter.cpp +++ b/source/core/audio/audio_adapter.cpp @@ -3,11 +3,11 @@ #include "core/resources/resource_cache.hpp" namespace AudioResource { - JA_Music_t* getMusic(const std::string& name) { + auto getMusic(const std::string& name) -> JA_Music_t* { return Resource::Cache::get()->getMusic(name); } - JA_Sound_t* getSound(const std::string& name) { + auto getSound(const std::string& name) -> JA_Sound_t* { return Resource::Cache::get()->getSound(name); } } // namespace AudioResource diff --git a/source/core/audio/audio_adapter.hpp b/source/core/audio/audio_adapter.hpp index a5eb16e..9c95864 100644 --- a/source/core/audio/audio_adapter.hpp +++ b/source/core/audio/audio_adapter.hpp @@ -12,6 +12,6 @@ struct JA_Music_t; struct JA_Sound_t; namespace AudioResource { - JA_Music_t* getMusic(const std::string& name); - JA_Sound_t* getSound(const std::string& name); + auto getMusic(const std::string& name) -> JA_Music_t*; + auto getSound(const std::string& name) -> JA_Sound_t*; } // namespace AudioResource diff --git a/source/core/audio/jail_audio.hpp b/source/core/audio/jail_audio.hpp index c0e1bf7..4eba538 100644 --- a/source/core/audio/jail_audio.hpp +++ b/source/core/audio/jail_audio.hpp @@ -2,10 +2,10 @@ // --- Includes --- #include -#include // Para uint32_t, uint8_t -#include // Para NULL, fseek, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET -#include // Para free, malloc +#include // Para uint32_t, uint8_t +#include // Para NULL, fseek, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET +#include // Para free, malloc #include // Para std::cout #include // Para std::unique_ptr #include // Para std::string @@ -84,7 +84,7 @@ inline JA_Music_t* current_music{nullptr}; inline JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; inline SDL_AudioSpec JA_audioSpec{SDL_AUDIO_S16, 2, 48000}; -inline float JA_musicVolume{1.0f}; +inline float JA_musicVolume{1.0F}; inline float JA_soundVolume[JA_MAX_GROUPS]; inline bool JA_musicEnabled{true}; inline bool JA_soundEnabled{true}; @@ -95,7 +95,7 @@ struct JA_FadeState { bool active{false}; Uint64 start_time{0}; int duration_ms{0}; - float initial_volume{0.0f}; + float initial_volume{0.0F}; }; struct JA_OutgoingMusic { @@ -109,7 +109,7 @@ inline JA_FadeState incoming_fade; // --- Forward Declarations --- inline void JA_StopMusic(); inline void JA_StopChannel(const int channel); -inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop = 0, const int group = 0); +inline auto JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop = 0, const int group = 0) -> int; inline void JA_CrossfadeMusic(JA_Music_t* music, int crossfade_ms, int loop = -1); // --- Music streaming internals --- @@ -120,11 +120,11 @@ static constexpr int JA_MUSIC_BYTES_PER_SAMPLE = 2; static constexpr int JA_MUSIC_CHUNK_SHORTS = 8192; // Umbral d'audio per davant del cursor de reproducció. Mantenim ≥ 0.5 s a // l'SDL_AudioStream per absorbir jitter de frame i evitar underruns. -static constexpr float JA_MUSIC_LOW_WATER_SECONDS = 0.5f; +static constexpr float JA_MUSIC_LOW_WATER_SECONDS = 0.5F; // Decodifica un chunk del vorbis i el volca a l'stream. Retorna samples // decodificats per canal (0 = EOF de l'stream vorbis). -inline int JA_FeedMusicChunk(JA_Music_t* music) { +inline auto JA_FeedMusicChunk(JA_Music_t* music) -> int { if (!music || !music->vorbis || !music->stream) return 0; short chunk[JA_MUSIC_CHUNK_SHORTS]; @@ -192,7 +192,7 @@ inline void JA_Update() { outgoing_music.fade.active = false; } else { float percent = (float)elapsed / (float)outgoing_music.fade.duration_ms; - SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0f - percent)); + SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0F - percent)); } } @@ -241,7 +241,7 @@ inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_ sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec); if (sdlAudioDevice == 0) std::cout << "Failed to initialize SDL audio!" << '\n'; for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) channels[i].state = JA_CHANNEL_FREE; - for (int i = 0; i < JA_MAX_GROUPS; ++i) JA_soundVolume[i] = 0.5f; + for (int i = 0; i < JA_MAX_GROUPS; ++i) JA_soundVolume[i] = 0.5F; } inline void JA_Quit() { @@ -255,7 +255,7 @@ inline void JA_Quit() { // --- Music Functions --- -inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) { +inline auto JA_LoadMusic(const Uint8* buffer, Uint32 length) -> JA_Music_t* { if (!buffer || length == 0) return nullptr; // Allocem el JA_Music_t primer per aprofitar el seu `std::vector` @@ -287,13 +287,13 @@ inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) { // Overload amb filename — els callers l'usen per poder comparar la música // en curs amb JA_GetMusicFilename() i no rearrancar-la si ja és la mateixa. -inline JA_Music_t* JA_LoadMusic(Uint8* buffer, Uint32 length, const char* filename) { +inline auto JA_LoadMusic(Uint8* buffer, Uint32 length, const char* filename) -> JA_Music_t* { JA_Music_t* music = JA_LoadMusic(static_cast(buffer), length); if (music && filename) music->filename = filename; return music; } -inline JA_Music_t* JA_LoadMusic(const char* filename) { +inline auto JA_LoadMusic(const char* filename) -> JA_Music_t* { // Carreguem primer el arxiu en memòria i després el descomprimim. FILE* f = fopen(filename, "rb"); if (!f) return nullptr; @@ -351,7 +351,7 @@ inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) { } } -inline const char* JA_GetMusicFilename(const JA_Music_t* music = nullptr) { +inline auto JA_GetMusicFilename(const JA_Music_t* music = nullptr) -> const char* { if (!music) music = current_music; if (!music || music->filename.empty()) return nullptr; return music->filename.c_str(); @@ -455,15 +455,15 @@ inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const i current_music->state = JA_MUSIC_STOPPED; return; } - SDL_SetAudioStreamGain(current_music->stream, 0.0f); + SDL_SetAudioStreamGain(current_music->stream, 0.0F); JA_PumpMusic(current_music); // pre-carrega abans de bindejar SDL_BindAudioStream(sdlAudioDevice, current_music->stream); // Configurar fade-in - incoming_fade = {true, SDL_GetTicks(), crossfade_ms, 0.0f}; + incoming_fade = {true, SDL_GetTicks(), crossfade_ms, 0.0F}; } -inline JA_Music_state JA_GetMusicState() { +inline auto JA_GetMusicState() -> JA_Music_state { if (!JA_musicEnabled) return JA_MUSIC_DISABLED; if (!current_music) return JA_MUSIC_INVALID; @@ -483,8 +483,8 @@ inline void JA_DeleteMusic(JA_Music_t* music) { delete music; } -inline float JA_SetMusicVolume(float volume) { - JA_musicVolume = SDL_clamp(volume, 0.0f, 1.0f); +inline auto JA_SetMusicVolume(float volume) -> float { + JA_musicVolume = SDL_clamp(volume, 0.0F, 1.0F); if (current_music && current_music->stream) { SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); } @@ -495,8 +495,8 @@ inline void JA_SetMusicPosition(float /*value*/) { // No implementat amb el backend de streaming. } -inline float JA_GetMusicPosition() { - return 0.0f; +inline auto JA_GetMusicPosition() -> float { + return 0.0F; } inline void JA_EnableMusic(const bool value) { @@ -506,7 +506,7 @@ inline void JA_EnableMusic(const bool value) { // --- Sound Functions --- -inline JA_Sound_t* JA_LoadSound(uint8_t* buffer, uint32_t size) { +inline auto JA_LoadSound(uint8_t* buffer, uint32_t size) -> JA_Sound_t* { auto sound = std::make_unique(); Uint8* raw = nullptr; if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &raw, &sound->length)) { @@ -517,7 +517,7 @@ inline JA_Sound_t* JA_LoadSound(uint8_t* buffer, uint32_t size) { return sound.release(); } -inline JA_Sound_t* JA_LoadSound(const char* filename) { +inline auto JA_LoadSound(const char* filename) -> JA_Sound_t* { auto sound = std::make_unique(); Uint8* raw = nullptr; if (!SDL_LoadWAV(filename, &sound->spec, &raw, &sound->length)) { @@ -528,7 +528,7 @@ inline JA_Sound_t* JA_LoadSound(const char* filename) { return sound.release(); } -inline int JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = 0) { +inline auto JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = 0) -> int { if (!JA_soundEnabled || !sound) return -1; int channel = 0; @@ -541,7 +541,7 @@ inline int JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = return JA_PlaySoundOnChannel(sound, channel, loop, group); } -inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop, const int group) { +inline auto JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop, const int group) -> int { if (!JA_soundEnabled || !sound) return -1; if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; @@ -632,15 +632,15 @@ inline void JA_StopChannel(const int channel) { } } -inline JA_Channel_state JA_GetChannelState(const int channel) { +inline auto JA_GetChannelState(const int channel) -> JA_Channel_state { if (!JA_soundEnabled) return JA_SOUND_DISABLED; if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; return channels[channel].state; } -inline float JA_SetSoundVolume(float volume, const int group = -1) { - const float v = SDL_clamp(volume, 0.0f, 1.0f); +inline auto JA_SetSoundVolume(float volume, const int group = -1) -> float { + const float v = SDL_clamp(volume, 0.0F, 1.0F); if (group == -1) { for (int i = 0; i < JA_MAX_GROUPS; ++i) { @@ -672,7 +672,7 @@ inline void JA_EnableSound(const bool value) { JA_soundEnabled = value; } -inline float JA_SetVolume(float volume) { +inline auto JA_SetVolume(float volume) -> float { float v = JA_SetMusicVolume(volume); JA_SetSoundVolume(v, -1); return v; diff --git a/source/core/resources/resource_cache.cpp b/source/core/resources/resource_cache.cpp index 7ccfd4f..84c0d5b 100644 --- a/source/core/resources/resource_cache.cpp +++ b/source/core/resources/resource_cache.cpp @@ -379,7 +379,7 @@ namespace Resource { std::string text_file; // Nombre del archivo de texto }; - const std::vector& getTextObjectInfos() { + auto getTextObjectInfos() -> const std::vector& { static const std::vector info = { {.key = "aseprite", .texture_file = "aseprite.gif", .text_file = "aseprite.fnt"}, {.key = "gauntlet", .texture_file = "gauntlet.gif", .text_file = "gauntlet.fnt"}, diff --git a/source/game/ui/notifier.cpp b/source/game/ui/notifier.cpp index 138449a..6086dbf 100644 --- a/source/game/ui/notifier.cpp +++ b/source/game/ui/notifier.cpp @@ -75,7 +75,7 @@ void Notifier::render() { // Actualiza el estado de las notificaiones void Notifier::update(float delta_time) { // Base Y leída cada frame: cada notificación se dibuja en rect.y (relativo a BASE) + BASE - const float BASE = static_cast(getStackBaseY()); + const auto BASE = static_cast(getStackBaseY()); for (auto& notification : notifications_) { // Si la notificación anterior está "entrando", no hagas nada (stall del resto) @@ -88,7 +88,7 @@ void Notifier::update(float delta_time) { switch (notification.state) { case Status::RISING: { - const float TARGET = static_cast(notification.y); + const auto TARGET = static_cast(notification.y); notification.rect.y += SLIDE_SPEED * delta_time; if (notification.rect.y >= TARGET) { notification.rect.y = TARGET; @@ -107,7 +107,7 @@ void Notifier::update(float delta_time) { } case Status::VANISHING: { - const float TARGET_Y = static_cast(notification.y - notification.travel_dist); + const auto TARGET_Y = static_cast(notification.y - notification.travel_dist); notification.rect.y -= SLIDE_SPEED * delta_time; if (notification.rect.y <= TARGET_Y) { notification.rect.y = TARGET_Y; diff --git a/source/main.cpp b/source/main.cpp index c2b1c92..e46b416 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -10,16 +10,16 @@ Empezado en Castalla el 01/07/2022. #include "core/system/director.hpp" -SDL_AppResult SDL_AppInit(void** appstate, int /*argc*/, char* /*argv*/[]) { +auto SDL_AppInit(void** appstate, int /*argc*/, char* /*argv*/[]) -> SDL_AppResult { *appstate = new Director(); return SDL_APP_CONTINUE; } -SDL_AppResult SDL_AppIterate(void* appstate) { +auto SDL_AppIterate(void* appstate) -> SDL_AppResult { return static_cast(appstate)->iterate(); } -SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { +auto SDL_AppEvent(void* appstate, SDL_Event* event) -> SDL_AppResult { return static_cast(appstate)->handleEvent(*event); } From da317e707dfeb0fb7a55ff76f0478a3178c0aea7 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 14 May 2026 22:45:54 +0200 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20claus=20en=20una=20l=C3=ADnia=20i=20?= =?UTF-8?q?nullptr=20expl=C3=ADcit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/core/audio/audio.cpp | 8 ++++---- source/core/input/input.cpp | 8 ++++---- source/core/resources/resource_cache.cpp | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/source/core/audio/audio.cpp b/source/core/audio/audio.cpp index 633a767..18682c4 100644 --- a/source/core/audio/audio.cpp +++ b/source/core/audio/audio.cpp @@ -51,7 +51,7 @@ void Audio::update() { JA_Update(); // Sincronizar estado: detectar cuando la música se para (ej. fade-out completado) - if (instance && instance->music_.state == MusicState::PLAYING && JA_GetMusicState() != JA_MUSIC_PLAYING) { + if (instance != nullptr && instance->music_.state == MusicState::PLAYING && JA_GetMusicState() != JA_MUSIC_PLAYING) { instance->music_.state = MusicState::STOPPED; } } @@ -65,10 +65,10 @@ void Audio::playMusic(const std::string& name, const int loop, const int crossfa return; } - if (!music_enabled_) return; + if (!music_enabled_) { return; } auto* resource = AudioResource::getMusic(name); - if (resource == nullptr) return; + if (resource == nullptr) { return; } if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) { JA_CrossfadeMusic(resource, crossfade_ms, loop); @@ -86,7 +86,7 @@ void Audio::playMusic(const std::string& name, const int loop, const int crossfa // Reproduce la música por puntero (con crossfade opcional) void Audio::playMusic(JA_Music_t* music, const int loop, const int crossfade_ms) { - if (!music_enabled_ || music == nullptr) return; + if (!music_enabled_ || music == nullptr) { return; } if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) { JA_CrossfadeMusic(music, crossfade_ms, loop); diff --git a/source/core/input/input.cpp b/source/core/input/input.cpp index 8dcb3c3..567f842 100644 --- a/source/core/input/input.cpp +++ b/source/core/input/input.cpp @@ -406,10 +406,10 @@ void Input::update() { // NOLINT(readability-convert-member-functions-to-static // JUMP accepta qualsevol dels 4 botons frontals (South/East/North/West) if (action == Action::JUMP) { is_down_now = is_down_now || - (SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_SOUTH) != 0) || - (SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_EAST) != 0) || - (SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_NORTH) != 0) || - (SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_WEST) != 0); + SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_SOUTH) || + SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_EAST) || + SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_NORTH) || + SDL_GetGamepadButton(gamepad->pad, SDL_GAMEPAD_BUTTON_WEST); } // El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo diff --git a/source/core/resources/resource_cache.cpp b/source/core/resources/resource_cache.cpp index 84c0d5b..3e2cf95 100644 --- a/source/core/resources/resource_cache.cpp +++ b/source/core/resources/resource_cache.cpp @@ -88,7 +88,7 @@ namespace Resource { // Carga assets hasta agotar el presupuesto de tiempo o completar todas las etapas. // Devuelve true cuando ya no queda nada por cargar. auto Cache::loadStep(int budget_ms) -> bool { - if (stage_ == LoadStage::DONE) return true; + if (stage_ == LoadStage::DONE) { return true; } const Uint64 start_ns = SDL_GetTicksNS(); const Uint64 budget_ns = static_cast(budget_ms) * 1'000'000ULL; @@ -221,7 +221,7 @@ namespace Resource { break; } - if ((SDL_GetTicksNS() - start_ns) >= budget_ns) break; + if ((SDL_GetTicksNS() - start_ns) >= budget_ns) { break; } } return stage_ == LoadStage::DONE; @@ -553,21 +553,21 @@ namespace Resource { std::cout << "\n>> SOUND FILES" << '\n'; auto list = List::get()->getListByType(List::Type::SOUND); sounds_.clear(); - for (size_t i = 0; i < list.size(); ++i) loadOneSound(i); + for (size_t i = 0; i < list.size(); ++i) { loadOneSound(i); } } void Cache::loadMusics() { std::cout << "\n>> MUSIC FILES" << '\n'; auto list = List::get()->getListByType(List::Type::MUSIC); musics_.clear(); - for (size_t i = 0; i < list.size(); ++i) loadOneMusic(i); + for (size_t i = 0; i < list.size(); ++i) { loadOneMusic(i); } } void Cache::loadSurfaces() { std::cout << "\n>> SURFACES" << '\n'; auto list = List::get()->getListByType(List::Type::BITMAP); surfaces_.clear(); - for (size_t i = 0; i < list.size(); ++i) loadOneSurface(i); + for (size_t i = 0; i < list.size(); ++i) { loadOneSurface(i); } finalizeSurfaces(); } @@ -575,35 +575,35 @@ namespace Resource { std::cout << "\n>> PALETTES" << '\n'; auto list = List::get()->getListByType(List::Type::PALETTE); palettes_.clear(); - for (size_t i = 0; i < list.size(); ++i) loadOnePalette(i); + for (size_t i = 0; i < list.size(); ++i) { loadOnePalette(i); } } void Cache::loadTextFiles() { std::cout << "\n>> TEXT FILES" << '\n'; auto list = List::get()->getListByType(List::Type::FONT); text_files_.clear(); - for (size_t i = 0; i < list.size(); ++i) loadOneTextFile(i); + for (size_t i = 0; i < list.size(); ++i) { loadOneTextFile(i); } } void Cache::loadAnimations() { std::cout << "\n>> ANIMATIONS" << '\n'; auto list = List::get()->getListByType(List::Type::ANIMATION); animations_.clear(); - for (size_t i = 0; i < list.size(); ++i) loadOneAnimation(i); + for (size_t i = 0; i < list.size(); ++i) { loadOneAnimation(i); } } void Cache::loadRooms() { std::cout << "\n>> ROOMS" << '\n'; auto list = List::get()->getListByType(List::Type::ROOM); rooms_.clear(); - for (size_t i = 0; i < list.size(); ++i) loadOneRoom(i); + for (size_t i = 0; i < list.size(); ++i) { loadOneRoom(i); } } void Cache::createText() { std::cout << "\n>> CREATING TEXT_OBJECTS" << '\n'; texts_.clear(); const auto& infos = getTextObjectInfos(); - for (size_t i = 0; i < infos.size(); ++i) createOneText(i); + for (size_t i = 0; i < infos.size(); ++i) { createOneText(i); } } // Vacía el vector de sonidos From f047ae1a56f7172d62bee8bf8f74edab638d7994 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 14 May 2026 23:06:41 +0200 Subject: [PATCH 4/5] refactor: JA_* a namespace Ja:: (estil aee_arcade) --- source/core/audio/audio.cpp | 54 +- source/core/audio/audio.hpp | 23 +- source/core/audio/audio_adapter.cpp | 4 +- source/core/audio/audio_adapter.hpp | 14 +- source/core/audio/jail_audio.hpp | 1165 +++++++++++----------- source/core/resources/resource_cache.cpp | 32 +- source/core/resources/resource_cache.hpp | 4 +- source/core/resources/resource_types.hpp | 14 +- source/game/entities/player.hpp | 16 +- 9 files changed, 677 insertions(+), 649 deletions(-) diff --git a/source/core/audio/audio.cpp b/source/core/audio/audio.cpp index 18682c4..6e39c0a 100644 --- a/source/core/audio/audio.cpp +++ b/source/core/audio/audio.cpp @@ -43,15 +43,15 @@ Audio::Audio() { initSDLAudio(); } // Destructor Audio::~Audio() { - JA_Quit(); + Ja::quit(); } // Método principal void Audio::update() { - JA_Update(); + Ja::update(); // Sincronizar estado: detectar cuando la música se para (ej. fade-out completado) - if (instance != nullptr && instance->music_.state == MusicState::PLAYING && JA_GetMusicState() != JA_MUSIC_PLAYING) { + if (instance != nullptr && instance->music_.state == MusicState::PLAYING && Ja::getMusicState() != Ja::MusicState::PLAYING) { instance->music_.state = MusicState::STOPPED; } } @@ -71,12 +71,12 @@ void Audio::playMusic(const std::string& name, const int loop, const int crossfa if (resource == nullptr) { return; } if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) { - JA_CrossfadeMusic(resource, crossfade_ms, loop); + Ja::crossfadeMusic(resource, crossfade_ms, loop); } else { if (music_.state == MusicState::PLAYING) { - JA_StopMusic(); + Ja::stopMusic(); } - JA_PlayMusic(resource, loop); + Ja::playMusic(resource, loop); } music_.name = name; @@ -85,16 +85,16 @@ void Audio::playMusic(const std::string& name, const int loop, const int crossfa } // Reproduce la música por puntero (con crossfade opcional) -void Audio::playMusic(JA_Music_t* music, const int loop, const int crossfade_ms) { +void Audio::playMusic(Ja::Music* music, const int loop, const int crossfade_ms) { if (!music_enabled_ || music == nullptr) { return; } if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) { - JA_CrossfadeMusic(music, crossfade_ms, loop); + Ja::crossfadeMusic(music, crossfade_ms, loop); } else { if (music_.state == MusicState::PLAYING) { - JA_StopMusic(); + Ja::stopMusic(); } - JA_PlayMusic(music, loop); + Ja::playMusic(music, loop); } music_.name.clear(); // nom desconegut quan es passa per punter @@ -105,7 +105,7 @@ void Audio::playMusic(JA_Music_t* music, const int loop, const int crossfade_ms) // Pausa la música void Audio::pauseMusic() { if (music_enabled_ && music_.state == MusicState::PLAYING) { - JA_PauseMusic(); + Ja::pauseMusic(); music_.state = MusicState::PAUSED; } } @@ -113,7 +113,7 @@ void Audio::pauseMusic() { // Continua la música pausada void Audio::resumeMusic() { if (music_enabled_ && music_.state == MusicState::PAUSED) { - JA_ResumeMusic(); + Ja::resumeMusic(); music_.state = MusicState::PLAYING; } } @@ -121,7 +121,7 @@ void Audio::resumeMusic() { // Detiene la música void Audio::stopMusic() { if (music_enabled_) { - JA_StopMusic(); + Ja::stopMusic(); music_.state = MusicState::STOPPED; } } @@ -129,42 +129,42 @@ void Audio::stopMusic() { // Reproduce un sonido por nombre void Audio::playSound(const std::string& name, Group group) const { if (sound_enabled_) { - JA_PlaySound(AudioResource::getSound(name), 0, static_cast(group)); + Ja::playSound(AudioResource::getSound(name), 0, static_cast(group)); } } // Reproduce un sonido por puntero directo -void Audio::playSound(JA_Sound_t* sound, Group group) const { +void Audio::playSound(Ja::Sound* sound, Group group) const { if (sound_enabled_ && sound != nullptr) { - JA_PlaySound(sound, 0, static_cast(group)); + Ja::playSound(sound, 0, static_cast(group)); } } // Detiene todos los sonidos void Audio::stopAllSounds() const { if (sound_enabled_) { - JA_StopChannel(-1); + Ja::stopChannel(-1); } } // Realiza un fundido de salida de la música void Audio::fadeOutMusic(int milliseconds) const { if (music_enabled_ && getRealMusicState() == MusicState::PLAYING) { - JA_FadeOutMusic(milliseconds); + Ja::fadeOutMusic(milliseconds); } } // Consulta directamente el estado real de la música en jailaudio auto Audio::getRealMusicState() -> MusicState { - JA_Music_state ja_state = JA_GetMusicState(); + Ja::MusicState ja_state = Ja::getMusicState(); switch (ja_state) { - case JA_MUSIC_PLAYING: + case Ja::MusicState::PLAYING: return MusicState::PLAYING; - case JA_MUSIC_PAUSED: + case Ja::MusicState::PAUSED: return MusicState::PAUSED; - case JA_MUSIC_STOPPED: - case JA_MUSIC_INVALID: - case JA_MUSIC_DISABLED: + case Ja::MusicState::STOPPED: + case Ja::MusicState::INVALID: + case Ja::MusicState::DISABLED: default: return MusicState::STOPPED; } @@ -175,7 +175,7 @@ void Audio::setSoundVolume(float sound_volume, Group group) const { if (sound_enabled_) { sound_volume = std::clamp(sound_volume, MIN_VOLUME, MAX_VOLUME); const float CONVERTED_VOLUME = sound_volume * Options::audio.volume; - JA_SetSoundVolume(CONVERTED_VOLUME, static_cast(group)); + Ja::setSoundVolume(CONVERTED_VOLUME, static_cast(group)); } } @@ -184,7 +184,7 @@ void Audio::setMusicVolume(float music_volume) const { if (music_enabled_) { music_volume = std::clamp(music_volume, MIN_VOLUME, MAX_VOLUME); const float CONVERTED_VOLUME = music_volume * Options::audio.volume; - JA_SetMusicVolume(CONVERTED_VOLUME); + Ja::setMusicVolume(CONVERTED_VOLUME); } } @@ -206,7 +206,7 @@ void Audio::initSDLAudio() { if (!SDL_Init(SDL_INIT_AUDIO)) { std::cout << "SDL_AUDIO could not initialize! SDL Error: " << SDL_GetError() << '\n'; } else { - JA_Init(FREQUENCY, SDL_AUDIO_S16LE, 2); + Ja::init(FREQUENCY, SDL_AUDIO_S16LE, 2); enable(Options::audio.enabled); } } diff --git a/source/core/audio/audio.hpp b/source/core/audio/audio.hpp index 9c5ea6f..783afad 100644 --- a/source/core/audio/audio.hpp +++ b/source/core/audio/audio.hpp @@ -4,6 +4,11 @@ #include // Para string #include // Para move +namespace Ja { + struct Music; + struct Sound; +} // namespace Ja + // --- Clase Audio: gestor de audio (singleton) --- // Implementació canònica, byte-idèntica entre projectes. // Els volums es manegen internament com a float 0.0–1.0; la capa de @@ -41,17 +46,17 @@ class Audio { static void update(); // Actualización del sistema de audio // --- Control de música --- - void playMusic(const std::string& name, int loop = -1, int crossfade_ms = 0); // Reproducir música por nombre (con crossfade opcional) - void playMusic(struct JA_Music_t* music, int loop = -1, int crossfade_ms = 0); // Reproducir música por puntero (con crossfade opcional) - void pauseMusic(); // Pausar reproducción de música - void resumeMusic(); // Continua la música pausada - void stopMusic(); // Detener completamente la música - void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música + void playMusic(const std::string& name, int loop = -1, int crossfade_ms = 0); // Reproducir música por nombre (con crossfade opcional) + void playMusic(Ja::Music* music, int loop = -1, int crossfade_ms = 0); // Reproducir música por puntero (con crossfade opcional) + void pauseMusic(); // Pausar reproducción de música + void resumeMusic(); // Continua la música pausada + void stopMusic(); // Detener completamente la música + void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música // --- Control de sonidos --- - void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre - void playSound(struct JA_Sound_t* sound, Group group = Group::GAME) const; // Reproducir sonido puntual por puntero - void stopAllSounds() const; // Detener todos los sonidos + void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre + void playSound(Ja::Sound* sound, Group group = Group::GAME) const; // Reproducir sonido puntual por puntero + void stopAllSounds() const; // Detener todos los sonidos // --- Control de volumen (API interna: float 0.0..1.0) --- void setSoundVolume(float volume, Group group = Group::ALL) const; // Ajustar volumen de efectos diff --git a/source/core/audio/audio_adapter.cpp b/source/core/audio/audio_adapter.cpp index 5ce2d6c..ec0bec3 100644 --- a/source/core/audio/audio_adapter.cpp +++ b/source/core/audio/audio_adapter.cpp @@ -3,11 +3,11 @@ #include "core/resources/resource_cache.hpp" namespace AudioResource { - auto getMusic(const std::string& name) -> JA_Music_t* { + auto getMusic(const std::string& name) -> Ja::Music* { return Resource::Cache::get()->getMusic(name); } - auto getSound(const std::string& name) -> JA_Sound_t* { + auto getSound(const std::string& name) -> Ja::Sound* { return Resource::Cache::get()->getSound(name); } } // namespace AudioResource diff --git a/source/core/audio/audio_adapter.hpp b/source/core/audio/audio_adapter.hpp index 9c95864..7feda5a 100644 --- a/source/core/audio/audio_adapter.hpp +++ b/source/core/audio/audio_adapter.hpp @@ -1,17 +1,19 @@ #pragma once // --- Audio Resource Adapter --- -// Aquest fitxer exposa una interfície comuna a Audio per obtenir JA_Music_t* / -// JA_Sound_t* per nom. Cada projecte la implementa en audio_adapter.cpp +// Aquest fitxer exposa una interfície comuna a Audio per obtenir Ja::Music* / +// Ja::Sound* per nom. Cada projecte la implementa en audio_adapter.cpp // delegant al seu singleton de recursos (Resource::get(), Resource::Cache::get(), // etc.). Això permet que audio.hpp/audio.cpp siguin idèntics entre projectes. #include // Para string -struct JA_Music_t; -struct JA_Sound_t; +namespace Ja { + struct Music; + struct Sound; +} // namespace Ja namespace AudioResource { - auto getMusic(const std::string& name) -> JA_Music_t*; - auto getSound(const std::string& name) -> JA_Sound_t*; + auto getMusic(const std::string& name) -> Ja::Music*; + auto getSound(const std::string& name) -> Ja::Sound*; } // namespace AudioResource diff --git a/source/core/audio/jail_audio.hpp b/source/core/audio/jail_audio.hpp index 4eba538..52c910a 100644 --- a/source/core/audio/jail_audio.hpp +++ b/source/core/audio/jail_audio.hpp @@ -3,677 +3,692 @@ // --- Includes --- #include -#include // Para uint32_t, uint8_t -#include // Para NULL, fseek, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET -#include // Para free, malloc -#include // Para std::cout -#include // Para std::unique_ptr -#include // Para std::string -#include // Para std::vector +#include +#include +#include +#include +#include +#include +#include #define STB_VORBIS_HEADER_ONLY +// NOLINTNEXTLINE(bugprone-suspicious-include) — stb_vorbis és single-file: la macro de dalt limita a només-declaracions. #include "external/stb_vorbis.c" // Para stb_vorbis_open_memory i streaming // Deleter stateless per a buffers reservats amb `SDL_malloc` / `SDL_LoadWAV*`. -// Compatible amb `std::unique_ptr` — zero size +// Compatible amb `std::unique_ptr` — zero size // overhead gràcies a EBO, igual que un unique_ptr amb default_delete. -struct SDLFreeDeleter { +struct SdlFreeDeleter { void operator()(Uint8* p) const noexcept { - if (p) SDL_free(p); + if (p != nullptr) { SDL_free(p); } } }; -// --- Public Enums --- -enum JA_Channel_state : uint8_t { - JA_CHANNEL_INVALID, - JA_CHANNEL_FREE, - JA_CHANNEL_PLAYING, - JA_CHANNEL_PAUSED, - JA_SOUND_DISABLED, -}; -enum JA_Music_state : uint8_t { - JA_MUSIC_INVALID, - JA_MUSIC_PLAYING, - JA_MUSIC_PAUSED, - JA_MUSIC_STOPPED, - JA_MUSIC_DISABLED, -}; +namespace Ja { -// --- Struct Definitions --- -#define JA_MAX_SIMULTANEOUS_CHANNELS 20 -#define JA_MAX_GROUPS 2 + // --- Public Enums --- + enum class ChannelState : std::uint8_t { + INVALID, + FREE, + PLAYING, + PAUSED, + DISABLED, + }; -struct JA_Sound_t { - SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000}; - Uint32 length{0}; - // Buffer descomprimit (PCM) propietat del sound. Reservat per SDL_LoadWAV - // via SDL_malloc; el deleter `SDLFreeDeleter` allibera amb SDL_free. - std::unique_ptr buffer; -}; + enum class MusicState : std::uint8_t { + INVALID, + PLAYING, + PAUSED, + STOPPED, + DISABLED, + }; -struct JA_Channel_t { - JA_Sound_t* sound{nullptr}; - int pos{0}; - int times{0}; - int group{0}; - SDL_AudioStream* stream{nullptr}; - JA_Channel_state state{JA_CHANNEL_FREE}; -}; + // --- Constants --- + inline constexpr int MAX_SIMULTANEOUS_CHANNELS = 20; + inline constexpr int MAX_GROUPS = 2; + inline constexpr SDL_AudioSpec DEFAULT_SPEC{.format = SDL_AUDIO_S16, .channels = 2, .freq = 48000}; -struct JA_Music_t { - SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000}; + // --- Struct Definitions --- + struct Sound { + SDL_AudioSpec spec{DEFAULT_SPEC}; + Uint32 length{0}; + // Buffer descomprimit (PCM) propietat del sound. Reservat per SDL_LoadWAV + // via SDL_malloc; el deleter `SdlFreeDeleter` allibera amb SDL_free. + std::unique_ptr buffer; + }; - // OGG comprimit en memòria. Propietat nostra; es copia des del buffer - // d'entrada una sola vegada en JA_LoadMusic i es descomprimix en chunks - // per streaming. Com que stb_vorbis guarda un punter persistent al - // `.data()` d'aquest vector, no el podem resize'jar un cop establert - // (una reallocation invalidaria el punter que el decoder conserva). - std::vector ogg_data; - stb_vorbis* vorbis{nullptr}; // handle del decoder, viu tot el cicle del JA_Music_t + struct Channel { + Sound* sound{nullptr}; + int pos{0}; + int times{0}; + int group{0}; + SDL_AudioStream* stream{nullptr}; + ChannelState state{ChannelState::FREE}; + }; - std::string filename; + struct Music { + SDL_AudioSpec spec{DEFAULT_SPEC}; - int times{0}; // loops restants (-1 = infinit, 0 = un sol play) - SDL_AudioStream* stream{nullptr}; - JA_Music_state state{JA_MUSIC_INVALID}; -}; + // OGG comprimit en memòria. Propietat nostra; es copia des del buffer + // d'entrada una sola vegada en loadMusic i es descomprimix en chunks + // per streaming. Com que stb_vorbis guarda un punter persistent al + // `.data()` d'aquest vector, no el podem resize'jar un cop establert + // (una reallocation invalidaria el punter que el decoder conserva). + std::vector ogg_data; + stb_vorbis* vorbis{nullptr}; // handle del decoder, viu tot el cicle del Music -// --- Internal Global State (inline, C++17) --- + std::string filename; -inline JA_Music_t* current_music{nullptr}; -inline JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; + int times{0}; // loops restants (-1 = infinit, 0 = un sol play) + SDL_AudioStream* stream{nullptr}; + MusicState state{MusicState::INVALID}; + }; -inline SDL_AudioSpec JA_audioSpec{SDL_AUDIO_S16, 2, 48000}; -inline float JA_musicVolume{1.0F}; -inline float JA_soundVolume[JA_MAX_GROUPS]; -inline bool JA_musicEnabled{true}; -inline bool JA_soundEnabled{true}; -inline SDL_AudioDeviceID sdlAudioDevice{0}; + struct FadeState { + bool active{false}; + Uint64 start_time{0}; + int duration_ms{0}; + float initial_volume{0.0F}; + }; -// --- Crossfade / Fade State --- -struct JA_FadeState { - bool active{false}; - Uint64 start_time{0}; - int duration_ms{0}; - float initial_volume{0.0F}; -}; + struct OutgoingMusic { + SDL_AudioStream* stream{nullptr}; + FadeState fade; + }; -struct JA_OutgoingMusic { - SDL_AudioStream* stream{nullptr}; - JA_FadeState fade; -}; + // --- Internal Global State (inline, C++17) --- + inline Music* current_music{nullptr}; + inline Channel channels[MAX_SIMULTANEOUS_CHANNELS]; -inline JA_OutgoingMusic outgoing_music; -inline JA_FadeState incoming_fade; + inline SDL_AudioSpec audio_spec{DEFAULT_SPEC}; + inline float music_volume{1.0F}; + inline float sound_volume[MAX_GROUPS]; + inline bool music_enabled{true}; + inline bool sound_enabled{true}; + inline SDL_AudioDeviceID sdl_audio_device{0}; -// --- Forward Declarations --- -inline void JA_StopMusic(); -inline void JA_StopChannel(const int channel); -inline auto JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop = 0, const int group = 0) -> int; -inline void JA_CrossfadeMusic(JA_Music_t* music, int crossfade_ms, int loop = -1); + inline OutgoingMusic outgoing_music; + inline FadeState incoming_fade; -// --- Music streaming internals --- -// Bytes-per-sample per canal (sempre s16) -static constexpr int JA_MUSIC_BYTES_PER_SAMPLE = 2; -// Quants shorts decodifiquem per crida a get_samples_short_interleaved. -// 8192 shorts = 4096 samples/channel en estèreo ≈ 85ms de so a 48kHz. -static constexpr int JA_MUSIC_CHUNK_SHORTS = 8192; -// Umbral d'audio per davant del cursor de reproducció. Mantenim ≥ 0.5 s a -// l'SDL_AudioStream per absorbir jitter de frame i evitar underruns. -static constexpr float JA_MUSIC_LOW_WATER_SECONDS = 0.5F; + // --- Forward Declarations --- + inline void stopMusic(); + inline void stopChannel(int channel); + inline auto playSoundOnChannel(Sound* sound, int channel, int loop = 0, int group = 0) -> int; + inline void crossfadeMusic(Music* music, int crossfade_ms, int loop = -1); -// Decodifica un chunk del vorbis i el volca a l'stream. Retorna samples -// decodificats per canal (0 = EOF de l'stream vorbis). -inline auto JA_FeedMusicChunk(JA_Music_t* music) -> int { - if (!music || !music->vorbis || !music->stream) return 0; + // --- Music streaming internals --- + // Bytes-per-sample per canal (sempre s16) + inline constexpr int MUSIC_BYTES_PER_SAMPLE = 2; + // Quants shorts decodifiquem per crida a get_samples_short_interleaved. + // 8192 shorts = 4096 samples/channel en estèreo ≈ 85ms de so a 48kHz. + inline constexpr int MUSIC_CHUNK_SHORTS = 8192; + // Umbral d'audio per davant del cursor de reproducció. Mantenim ≥ 0.5 s a + // l'SDL_AudioStream per absorbir jitter de frame i evitar underruns. + inline constexpr float MUSIC_LOW_WATER_SECONDS = 0.5F; - short chunk[JA_MUSIC_CHUNK_SHORTS]; - const int num_channels = music->spec.channels; - const int samples_per_channel = stb_vorbis_get_samples_short_interleaved( - music->vorbis, - num_channels, - chunk, - JA_MUSIC_CHUNK_SHORTS); - if (samples_per_channel <= 0) return 0; + // Decodifica un chunk del vorbis i el volca a l'stream. Retorna samples + // decodificats per canal (0 = EOF de l'stream vorbis). + inline auto feedMusicChunk(Music* music) -> int { + if ((music == nullptr) || (music->vorbis == nullptr) || (music->stream == nullptr)) { return 0; } - const int bytes = samples_per_channel * num_channels * JA_MUSIC_BYTES_PER_SAMPLE; - SDL_PutAudioStreamData(music->stream, chunk, bytes); - return samples_per_channel; -} + short chunk[MUSIC_CHUNK_SHORTS]; + const int NUM_CHANNELS = music->spec.channels; + const int SAMPLES_PER_CHANNEL = stb_vorbis_get_samples_short_interleaved( + music->vorbis, + NUM_CHANNELS, + chunk, + MUSIC_CHUNK_SHORTS); + if (SAMPLES_PER_CHANNEL <= 0) { return 0; } -// Reompli l'stream fins que tinga ≥ JA_MUSIC_LOW_WATER_SECONDS bufferats. -// En arribar a EOF del vorbis, aplica el loop (times) o deixa drenar. -inline void JA_PumpMusic(JA_Music_t* music) { - if (!music || !music->vorbis || !music->stream) return; + const int BYTES = SAMPLES_PER_CHANNEL * NUM_CHANNELS * MUSIC_BYTES_PER_SAMPLE; + SDL_PutAudioStreamData(music->stream, chunk, BYTES); + return SAMPLES_PER_CHANNEL; + } - const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE; - const int low_water_bytes = static_cast(JA_MUSIC_LOW_WATER_SECONDS * static_cast(bytes_per_second)); + // Reompli l'stream fins que tinga ≥ MUSIC_LOW_WATER_SECONDS bufferats. + // En arribar a EOF del vorbis, aplica el loop (times) o deixa drenar. + inline void pumpMusic(Music* music) { + if ((music == nullptr) || (music->vorbis == nullptr) || (music->stream == nullptr)) { return; } - while (SDL_GetAudioStreamAvailable(music->stream) < low_water_bytes) { - const int decoded = JA_FeedMusicChunk(music); - if (decoded > 0) continue; + const int BYTES_PER_SECOND = music->spec.freq * music->spec.channels * MUSIC_BYTES_PER_SAMPLE; + const int LOW_WATER_BYTES = static_cast(MUSIC_LOW_WATER_SECONDS * static_cast(BYTES_PER_SECOND)); - // EOF: si queden loops, rebobinar; si no, tallar i deixar drenar. - if (music->times != 0) { - stb_vorbis_seek_start(music->vorbis); - if (music->times > 0) music->times--; - } else { - break; + while (SDL_GetAudioStreamAvailable(music->stream) < LOW_WATER_BYTES) { + const int DECODED = feedMusicChunk(music); + if (DECODED > 0) { continue; } + + // EOF: si queden loops, rebobinar; si no, tallar i deixar drenar. + if (music->times != 0) { + stb_vorbis_seek_start(music->vorbis); + if (music->times > 0) { music->times--; } + } else { + break; + } } } -} -// Pre-carrega `duration_ms` de so dins l'stream actual abans que l'stream -// siga robat per outgoing_music (crossfade o fade-out). Imprescindible amb -// streaming: l'stream robat no es pot re-alimentar perquè perd la referència -// al seu vorbis decoder. No aplica loop — si el vorbis s'esgota abans, parem. -inline void JA_PreFillOutgoing(JA_Music_t* music, int duration_ms) { - if (!music || !music->vorbis || !music->stream) return; + // Pre-carrega `duration_ms` de so dins l'stream actual abans que l'stream + // siga robat per outgoing_music (crossfade o fade-out). Imprescindible amb + // streaming: l'stream robat no es pot re-alimentar perquè perd la referència + // al seu vorbis decoder. No aplica loop — si el vorbis s'esgota abans, parem. + inline void preFillOutgoing(Music* music, int duration_ms) { + if ((music == nullptr) || (music->vorbis == nullptr) || (music->stream == nullptr)) { return; } - const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE; - const int needed_bytes = static_cast((static_cast(duration_ms) * bytes_per_second) / 1000); + const int BYTES_PER_SECOND = music->spec.freq * music->spec.channels * MUSIC_BYTES_PER_SAMPLE; + const int NEEDED_BYTES = static_cast((static_cast(duration_ms) * BYTES_PER_SECOND) / 1000); - while (SDL_GetAudioStreamAvailable(music->stream) < needed_bytes) { - const int decoded = JA_FeedMusicChunk(music); - if (decoded <= 0) break; // EOF: deixem drenar el que hi haja + while (SDL_GetAudioStreamAvailable(music->stream) < NEEDED_BYTES) { + const int DECODED = feedMusicChunk(music); + if (DECODED <= 0) { break; } // EOF: deixem drenar el que hi haja + } } -} -// --- Core Functions --- + // --- update() helpers --- + inline void updateOutgoingFade() { + if ((outgoing_music.stream == nullptr) || !outgoing_music.fade.active) { return; } -inline void JA_Update() { - // --- Outgoing music fade-out (crossfade o fade-out a silencio) --- - if (outgoing_music.stream && outgoing_music.fade.active) { - Uint64 now = SDL_GetTicks(); - Uint64 elapsed = now - outgoing_music.fade.start_time; - if (elapsed >= (Uint64)outgoing_music.fade.duration_ms) { + const Uint64 NOW = SDL_GetTicks(); + const Uint64 ELAPSED = NOW - outgoing_music.fade.start_time; + if (ELAPSED >= static_cast(outgoing_music.fade.duration_ms)) { SDL_DestroyAudioStream(outgoing_music.stream); outgoing_music.stream = nullptr; outgoing_music.fade.active = false; } else { - float percent = (float)elapsed / (float)outgoing_music.fade.duration_ms; - SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0F - percent)); + const float PERCENT = static_cast(ELAPSED) / static_cast(outgoing_music.fade.duration_ms); + SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0F - PERCENT)); } } - // --- Current music --- - if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) { - // Fade-in (parte de un crossfade) - if (incoming_fade.active) { - Uint64 now = SDL_GetTicks(); - Uint64 elapsed = now - incoming_fade.start_time; - if (elapsed >= (Uint64)incoming_fade.duration_ms) { - incoming_fade.active = false; - SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); - } else { - float percent = (float)elapsed / (float)incoming_fade.duration_ms; - SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * percent); - } + inline void updateIncomingFade() { + if (!incoming_fade.active) { return; } + + const Uint64 NOW = SDL_GetTicks(); + const Uint64 ELAPSED = NOW - incoming_fade.start_time; + if (ELAPSED >= static_cast(incoming_fade.duration_ms)) { + incoming_fade.active = false; + SDL_SetAudioStreamGain(current_music->stream, music_volume); + } else { + const float PERCENT = static_cast(ELAPSED) / static_cast(incoming_fade.duration_ms); + SDL_SetAudioStreamGain(current_music->stream, music_volume * PERCENT); } + } + + inline void updateCurrentMusic() { + if (!music_enabled || (current_music == nullptr) || current_music->state != MusicState::PLAYING) { return; } + + updateIncomingFade(); // Streaming: rellenem l'stream fins al low-water-mark i parem si el // vorbis s'ha esgotat i no queden loops. - JA_PumpMusic(current_music); + pumpMusic(current_music); if (current_music->times == 0 && SDL_GetAudioStreamAvailable(current_music->stream) == 0) { - JA_StopMusic(); + stopMusic(); } } - // --- Sound channels --- - if (JA_soundEnabled) { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) - if (channels[i].state == JA_CHANNEL_PLAYING) { - if (channels[i].times != 0) { - if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) { - SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer.get(), channels[i].sound->length); - if (channels[i].times > 0) channels[i].times--; - } - } else { - if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i); + inline void updateSoundChannels() { + if (!sound_enabled) { return; } + + for (int i = 0; i < MAX_SIMULTANEOUS_CHANNELS; ++i) { + auto& ch = channels[i]; + if (ch.state != ChannelState::PLAYING) { continue; } + + if (ch.times != 0) { + if (static_cast(SDL_GetAudioStreamAvailable(ch.stream)) < (ch.sound->length / 2)) { + SDL_PutAudioStreamData(ch.stream, ch.sound->buffer.get(), ch.sound->length); + if (ch.times > 0) { ch.times--; } } + } else { + if (SDL_GetAudioStreamAvailable(ch.stream) == 0) { stopChannel(i); } } - } -} - -inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) { - JA_audioSpec = {format, num_channels, freq}; - if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); - sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec); - if (sdlAudioDevice == 0) std::cout << "Failed to initialize SDL audio!" << '\n'; - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) channels[i].state = JA_CHANNEL_FREE; - for (int i = 0; i < JA_MAX_GROUPS; ++i) JA_soundVolume[i] = 0.5F; -} - -inline void JA_Quit() { - if (outgoing_music.stream) { - SDL_DestroyAudioStream(outgoing_music.stream); - outgoing_music.stream = nullptr; - } - if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); - sdlAudioDevice = 0; -} - -// --- Music Functions --- - -inline auto JA_LoadMusic(const Uint8* buffer, Uint32 length) -> JA_Music_t* { - if (!buffer || length == 0) return nullptr; - - // Allocem el JA_Music_t primer per aprofitar el seu `std::vector` - // com a propietari del OGG comprimit. stb_vorbis guarda un punter - // persistent al buffer; com que ací no el resize'jem, el .data() és - // estable durant tot el cicle de vida del music. - auto* music = new JA_Music_t(); - music->ogg_data.assign(buffer, buffer + length); - - int vorbis_error = 0; - music->vorbis = stb_vorbis_open_memory(music->ogg_data.data(), - static_cast(length), - &vorbis_error, - nullptr); - if (!music->vorbis) { - std::cout << "JA_LoadMusic: stb_vorbis_open_memory failed (error " << vorbis_error << ")" << '\n'; - delete music; - return nullptr; + } } - const stb_vorbis_info info = stb_vorbis_get_info(music->vorbis); - music->spec.channels = info.channels; - music->spec.freq = static_cast(info.sample_rate); - music->spec.format = SDL_AUDIO_S16; - music->state = JA_MUSIC_STOPPED; - - return music; -} - -// Overload amb filename — els callers l'usen per poder comparar la música -// en curs amb JA_GetMusicFilename() i no rearrancar-la si ja és la mateixa. -inline auto JA_LoadMusic(Uint8* buffer, Uint32 length, const char* filename) -> JA_Music_t* { - JA_Music_t* music = JA_LoadMusic(static_cast(buffer), length); - if (music && filename) music->filename = filename; - return music; -} - -inline auto JA_LoadMusic(const char* filename) -> JA_Music_t* { - // Carreguem primer el arxiu en memòria i després el descomprimim. - FILE* f = fopen(filename, "rb"); - if (!f) return nullptr; - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - auto* buffer = static_cast(malloc(fsize + 1)); - if (!buffer) { - fclose(f); - return nullptr; - } - if (fread(buffer, fsize, 1, f) != 1) { - fclose(f); - free(buffer); - return nullptr; - } - fclose(f); - - JA_Music_t* music = JA_LoadMusic(static_cast(buffer), static_cast(fsize)); - if (music) { - music->filename = filename; + inline void update() { + updateOutgoingFade(); + updateCurrentMusic(); + updateSoundChannels(); } - free(buffer); - - return music; -} - -inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) { - if (!JA_musicEnabled || !music || !music->vorbis) return; - - JA_StopMusic(); - - current_music = music; - current_music->state = JA_MUSIC_PLAYING; - current_music->times = loop; - - // Rebobinem l'stream de vorbis al principi. Cobreix tant play-per-primera- - // vegada com replays/canvis de track que tornen a la mateixa pista. - stb_vorbis_seek_start(current_music->vorbis); - - current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec); - if (!current_music->stream) { - std::cout << "Failed to create audio stream!" << '\n'; - current_music->state = JA_MUSIC_STOPPED; - return; + inline void init(int freq, SDL_AudioFormat format, int num_channels) { + audio_spec = {.format = format, .channels = num_channels, .freq = freq}; + if (sdl_audio_device != 0) { SDL_CloseAudioDevice(sdl_audio_device); } + sdl_audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio_spec); + if (sdl_audio_device == 0) { std::cout << "Failed to initialize SDL audio!" << '\n'; } + for (auto& ch : channels) { ch.state = ChannelState::FREE; } + for (float& v : sound_volume) { v = 0.5F; } } - SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); - // Pre-cargem el buffer abans de bindejar per evitar un underrun inicial. - JA_PumpMusic(current_music); - - if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) { - std::cout << "[ERROR] SDL_BindAudioStream failed!" << '\n'; + inline void quit() { + if (outgoing_music.stream != nullptr) { + SDL_DestroyAudioStream(outgoing_music.stream); + outgoing_music.stream = nullptr; + } + if (sdl_audio_device != 0) { SDL_CloseAudioDevice(sdl_audio_device); } + sdl_audio_device = 0; } -} -inline auto JA_GetMusicFilename(const JA_Music_t* music = nullptr) -> const char* { - if (!music) music = current_music; - if (!music || music->filename.empty()) return nullptr; - return music->filename.c_str(); -} + // --- Music Functions --- + inline auto loadMusic(const Uint8* buffer, Uint32 length) -> Music* { + if ((buffer == nullptr) || length == 0) { return nullptr; } -inline void JA_PauseMusic() { - if (!JA_musicEnabled) return; - if (!current_music || current_music->state != JA_MUSIC_PLAYING) return; + // Allocem el Music primer per aprofitar el seu `std::vector` + // com a propietari del OGG comprimit. stb_vorbis guarda un punter + // persistent al buffer; com que ací no el resize'jem, el .data() és + // estable durant tot el cicle de vida del music. + auto* music = new Music(); + music->ogg_data.assign(buffer, buffer + length); - current_music->state = JA_MUSIC_PAUSED; - SDL_UnbindAudioStream(current_music->stream); -} + int vorbis_error = 0; + music->vorbis = stb_vorbis_open_memory(music->ogg_data.data(), + static_cast(length), + &vorbis_error, + nullptr); + if (music->vorbis == nullptr) { + std::cout << "loadMusic: stb_vorbis_open_memory failed (error " << vorbis_error << ")" << '\n'; + delete music; + return nullptr; + } -inline void JA_ResumeMusic() { - if (!JA_musicEnabled) return; - if (!current_music || current_music->state != JA_MUSIC_PAUSED) return; + const stb_vorbis_info INFO = stb_vorbis_get_info(music->vorbis); + music->spec.channels = INFO.channels; + music->spec.freq = static_cast(INFO.sample_rate); + music->spec.format = SDL_AUDIO_S16; + music->state = MusicState::STOPPED; - current_music->state = JA_MUSIC_PLAYING; - SDL_BindAudioStream(sdlAudioDevice, current_music->stream); -} - -inline void JA_StopMusic() { - // Limpiar outgoing crossfade si existe - if (outgoing_music.stream) { - SDL_DestroyAudioStream(outgoing_music.stream); - outgoing_music.stream = nullptr; - outgoing_music.fade.active = false; + return music; } - incoming_fade.active = false; - if (!current_music || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) return; - - current_music->state = JA_MUSIC_STOPPED; - if (current_music->stream) { - SDL_DestroyAudioStream(current_music->stream); - current_music->stream = nullptr; + // Overload amb filename — els callers l'usen per poder comparar la música + // en curs amb getMusicFilename() i no rearrancar-la si ja és la mateixa. + inline auto loadMusic(Uint8* buffer, Uint32 length, const char* filename) -> Music* { + Music* music = loadMusic(static_cast(buffer), length); + if ((music != nullptr) && (filename != nullptr)) { music->filename = filename; } + return music; } - // Deixem el handle de vorbis viu — es tanca en JA_DeleteMusic. - // Rebobinem perquè un futur JA_PlayMusic comence des del principi. - if (current_music->vorbis) { + + inline auto loadMusic(const char* filename) -> Music* { + // Carreguem primer el arxiu en memòria i després el descomprimim. + FILE* f = std::fopen(filename, "rb"); + if (f == nullptr) { return nullptr; } + std::fseek(f, 0, SEEK_END); + const long FSIZE = std::ftell(f); + std::fseek(f, 0, SEEK_SET); + auto* buffer = static_cast(std::malloc(FSIZE + 1)); + if (buffer == nullptr) { + std::fclose(f); + return nullptr; + } + if (std::fread(buffer, FSIZE, 1, f) != 1) { + std::fclose(f); + std::free(buffer); + return nullptr; + } + std::fclose(f); + + Music* music = loadMusic(static_cast(buffer), static_cast(FSIZE)); + if (music != nullptr) { music->filename = filename; } + + std::free(buffer); + + return music; + } + + inline void playMusic(Music* music, int loop = -1) { + if (!music_enabled || (music == nullptr) || (music->vorbis == nullptr)) { return; } + + stopMusic(); + + current_music = music; + current_music->state = MusicState::PLAYING; + current_music->times = loop; + + // Rebobinem l'stream de vorbis al principi. Cobreix tant play-per-primera- + // vegada com replays/canvis de track que tornen a la mateixa pista. stb_vorbis_seek_start(current_music->vorbis); - } -} -inline void JA_FadeOutMusic(const int milliseconds) { - if (!JA_musicEnabled) return; - if (!current_music || current_music->state != JA_MUSIC_PLAYING) return; + current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &audio_spec); + if (current_music->stream == nullptr) { + std::cout << "Failed to create audio stream!" << '\n'; + current_music->state = MusicState::STOPPED; + return; + } + SDL_SetAudioStreamGain(current_music->stream, music_volume); - // Destruir outgoing anterior si existe - if (outgoing_music.stream) { - SDL_DestroyAudioStream(outgoing_music.stream); - outgoing_music.stream = nullptr; + // Pre-cargem el buffer abans de bindejar per evitar un underrun inicial. + pumpMusic(current_music); + + if (!SDL_BindAudioStream(sdl_audio_device, current_music->stream)) { + std::cout << "[ERROR] SDL_BindAudioStream failed!" << '\n'; + } } - // Pre-omplim l'stream amb `milliseconds` de so: un cop robat, ja no - // tindrà accés al vorbis decoder i només podrà drenar el que tinga. - JA_PreFillOutgoing(current_music, milliseconds); - - // Robar el stream del current_music al outgoing - outgoing_music.stream = current_music->stream; - outgoing_music.fade = {true, SDL_GetTicks(), milliseconds, JA_musicVolume}; - - // Dejar current_music sin stream (ya lo tiene outgoing) - current_music->stream = nullptr; - current_music->state = JA_MUSIC_STOPPED; - if (current_music->vorbis) stb_vorbis_seek_start(current_music->vorbis); - incoming_fade.active = false; -} - -inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const int loop) { - if (!JA_musicEnabled || !music || !music->vorbis) return; - - // Destruir outgoing anterior si existe (crossfade durante crossfade) - if (outgoing_music.stream) { - SDL_DestroyAudioStream(outgoing_music.stream); - outgoing_music.stream = nullptr; - outgoing_music.fade.active = false; + inline auto getMusicFilename(const Music* music = nullptr) -> const char* { + if (music == nullptr) { music = current_music; } + if ((music == nullptr) || music->filename.empty()) { return nullptr; } + return music->filename.c_str(); } - // Robar el stream de la musica actual al outgoing para el fade-out. - // Pre-omplim amb `crossfade_ms` de so perquè no es quede en silenci - // abans d'acabar el fade (l'stream robat ja no pot alimentar-se). - if (current_music && current_music->state == JA_MUSIC_PLAYING && current_music->stream) { - JA_PreFillOutgoing(current_music, crossfade_ms); + inline void pauseMusic() { + if (!music_enabled) { return; } + if ((current_music == nullptr) || current_music->state != MusicState::PLAYING) { return; } + + current_music->state = MusicState::PAUSED; + SDL_UnbindAudioStream(current_music->stream); + } + + inline void resumeMusic() { + if (!music_enabled) { return; } + if ((current_music == nullptr) || current_music->state != MusicState::PAUSED) { return; } + + current_music->state = MusicState::PLAYING; + SDL_BindAudioStream(sdl_audio_device, current_music->stream); + } + + inline void stopMusic() { + // Limpiar outgoing crossfade si existe + if (outgoing_music.stream != nullptr) { + SDL_DestroyAudioStream(outgoing_music.stream); + outgoing_music.stream = nullptr; + outgoing_music.fade.active = false; + } + incoming_fade.active = false; + + if ((current_music == nullptr) || current_music->state == MusicState::INVALID || current_music->state == MusicState::STOPPED) { return; } + + current_music->state = MusicState::STOPPED; + if (current_music->stream != nullptr) { + SDL_DestroyAudioStream(current_music->stream); + current_music->stream = nullptr; + } + // Deixem el handle de vorbis viu — es tanca en deleteMusic. + // Rebobinem perquè un futur playMusic comence des del principi. + if (current_music->vorbis != nullptr) { + stb_vorbis_seek_start(current_music->vorbis); + } + } + + inline void fadeOutMusic(int milliseconds) { + if (!music_enabled) { return; } + if ((current_music == nullptr) || current_music->state != MusicState::PLAYING) { return; } + + // Destruir outgoing anterior si existe + if (outgoing_music.stream != nullptr) { + SDL_DestroyAudioStream(outgoing_music.stream); + outgoing_music.stream = nullptr; + } + + // Pre-omplim l'stream amb `milliseconds` de so: un cop robat, ja no + // tindrà accés al vorbis decoder i només podrà drenar el que tinga. + preFillOutgoing(current_music, milliseconds); + + // Robar el stream del current_music al outgoing outgoing_music.stream = current_music->stream; - outgoing_music.fade = {true, SDL_GetTicks(), crossfade_ms, JA_musicVolume}; + outgoing_music.fade = {.active = true, .start_time = SDL_GetTicks(), .duration_ms = milliseconds, .initial_volume = music_volume}; + + // Dejar current_music sin stream (ya lo tiene outgoing) current_music->stream = nullptr; - current_music->state = JA_MUSIC_STOPPED; - if (current_music->vorbis) stb_vorbis_seek_start(current_music->vorbis); + current_music->state = MusicState::STOPPED; + if (current_music->vorbis != nullptr) { stb_vorbis_seek_start(current_music->vorbis); } + incoming_fade.active = false; } - // Iniciar la nueva pista con gain=0 (el fade-in la sube gradualmente) - current_music = music; - current_music->state = JA_MUSIC_PLAYING; - current_music->times = loop; + inline void crossfadeMusic(Music* music, int crossfade_ms, int loop) { + if (!music_enabled || (music == nullptr) || (music->vorbis == nullptr)) { return; } - stb_vorbis_seek_start(current_music->vorbis); - current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec); - if (!current_music->stream) { - std::cout << "Failed to create audio stream for crossfade!" << '\n'; - current_music->state = JA_MUSIC_STOPPED; - return; - } - SDL_SetAudioStreamGain(current_music->stream, 0.0F); - JA_PumpMusic(current_music); // pre-carrega abans de bindejar - SDL_BindAudioStream(sdlAudioDevice, current_music->stream); - - // Configurar fade-in - incoming_fade = {true, SDL_GetTicks(), crossfade_ms, 0.0F}; -} - -inline auto JA_GetMusicState() -> JA_Music_state { - if (!JA_musicEnabled) return JA_MUSIC_DISABLED; - if (!current_music) return JA_MUSIC_INVALID; - - return current_music->state; -} - -inline void JA_DeleteMusic(JA_Music_t* music) { - if (!music) return; - if (current_music == music) { - JA_StopMusic(); - current_music = nullptr; - } - if (music->stream) SDL_DestroyAudioStream(music->stream); - if (music->vorbis) stb_vorbis_close(music->vorbis); - // ogg_data (std::vector) i filename (std::string) s'alliberen sols - // al destructor de JA_Music_t. - delete music; -} - -inline auto JA_SetMusicVolume(float volume) -> float { - JA_musicVolume = SDL_clamp(volume, 0.0F, 1.0F); - if (current_music && current_music->stream) { - SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); - } - return JA_musicVolume; -} - -inline void JA_SetMusicPosition(float /*value*/) { - // No implementat amb el backend de streaming. -} - -inline auto JA_GetMusicPosition() -> float { - return 0.0F; -} - -inline void JA_EnableMusic(const bool value) { - if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING)) JA_StopMusic(); - JA_musicEnabled = value; -} - -// --- Sound Functions --- - -inline auto JA_LoadSound(uint8_t* buffer, uint32_t size) -> JA_Sound_t* { - auto sound = std::make_unique(); - Uint8* raw = nullptr; - if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &raw, &sound->length)) { - std::cout << "Failed to load WAV from memory: " << SDL_GetError() << '\n'; - return nullptr; - } - sound->buffer.reset(raw); // adopta el SDL_malloc'd buffer - return sound.release(); -} - -inline auto JA_LoadSound(const char* filename) -> JA_Sound_t* { - auto sound = std::make_unique(); - Uint8* raw = nullptr; - if (!SDL_LoadWAV(filename, &sound->spec, &raw, &sound->length)) { - std::cout << "Failed to load WAV file: " << SDL_GetError() << '\n'; - return nullptr; - } - sound->buffer.reset(raw); // adopta el SDL_malloc'd buffer - return sound.release(); -} - -inline auto JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = 0) -> int { - if (!JA_soundEnabled || !sound) return -1; - - int channel = 0; - while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; } - if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) { - // No hay canal libre, reemplazamos el primero - channel = 0; - } - - return JA_PlaySoundOnChannel(sound, channel, loop, group); -} - -inline auto JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop, const int group) -> int { - if (!JA_soundEnabled || !sound) return -1; - if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; - - JA_StopChannel(channel); - - channels[channel].sound = sound; - channels[channel].times = loop; - channels[channel].pos = 0; - channels[channel].group = group; - channels[channel].state = JA_CHANNEL_PLAYING; - channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); - - if (!channels[channel].stream) { - std::cout << "Failed to create audio stream for sound!" << '\n'; - channels[channel].state = JA_CHANNEL_FREE; - return -1; - } - - SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer.get(), channels[channel].sound->length); - SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume[group]); - SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); - - return channel; -} - -inline void JA_DeleteSound(JA_Sound_t* sound) { - if (!sound) return; - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if (channels[i].sound == sound) JA_StopChannel(i); - } - // buffer es destrueix automàticament via RAII (SDLFreeDeleter). - delete sound; -} - -inline void JA_PauseChannel(const int channel) { - if (!JA_soundEnabled) return; - - if (channel == -1) { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - if (channels[i].state == JA_CHANNEL_PLAYING) { - channels[i].state = JA_CHANNEL_PAUSED; - SDL_UnbindAudioStream(channels[i].stream); - } - } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { - if (channels[channel].state == JA_CHANNEL_PLAYING) { - channels[channel].state = JA_CHANNEL_PAUSED; - SDL_UnbindAudioStream(channels[channel].stream); + // Destruir outgoing anterior si existe (crossfade durante crossfade) + if (outgoing_music.stream != nullptr) { + SDL_DestroyAudioStream(outgoing_music.stream); + outgoing_music.stream = nullptr; + outgoing_music.fade.active = false; } - } -} -inline void JA_ResumeChannel(const int channel) { - if (!JA_soundEnabled) return; - - if (channel == -1) { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) - if (channels[i].state == JA_CHANNEL_PAUSED) { - channels[i].state = JA_CHANNEL_PLAYING; - SDL_BindAudioStream(sdlAudioDevice, channels[i].stream); - } - } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { - if (channels[channel].state == JA_CHANNEL_PAUSED) { - channels[channel].state = JA_CHANNEL_PLAYING; - SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); + // Robar el stream de la musica actual al outgoing para el fade-out. + // Pre-omplim amb `crossfade_ms` de so perquè no es quede en silenci + // abans d'acabar el fade (l'stream robat ja no pot alimentar-se). + if ((current_music != nullptr) && current_music->state == MusicState::PLAYING && (current_music->stream != nullptr)) { + preFillOutgoing(current_music, crossfade_ms); + outgoing_music.stream = current_music->stream; + outgoing_music.fade = {.active = true, .start_time = SDL_GetTicks(), .duration_ms = crossfade_ms, .initial_volume = music_volume}; + current_music->stream = nullptr; + current_music->state = MusicState::STOPPED; + if (current_music->vorbis != nullptr) { stb_vorbis_seek_start(current_music->vorbis); } } - } -} -inline void JA_StopChannel(const int channel) { - if (channel == -1) { - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if (channels[i].state != JA_CHANNEL_FREE) { - if (channels[i].stream) SDL_DestroyAudioStream(channels[i].stream); - channels[i].stream = nullptr; - channels[i].state = JA_CHANNEL_FREE; - channels[i].pos = 0; - channels[i].sound = nullptr; + // Iniciar la nueva pista con gain=0 (el fade-in la sube gradualmente) + current_music = music; + current_music->state = MusicState::PLAYING; + current_music->times = loop; + + stb_vorbis_seek_start(current_music->vorbis); + current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &audio_spec); + if (current_music->stream == nullptr) { + std::cout << "Failed to create audio stream for crossfade!" << '\n'; + current_music->state = MusicState::STOPPED; + return; + } + SDL_SetAudioStreamGain(current_music->stream, 0.0F); + pumpMusic(current_music); // pre-carrega abans de bindejar + SDL_BindAudioStream(sdl_audio_device, current_music->stream); + + // Configurar fade-in + incoming_fade = {.active = true, .start_time = SDL_GetTicks(), .duration_ms = crossfade_ms, .initial_volume = 0.0F}; + } + + inline auto getMusicState() -> MusicState { + if (!music_enabled) { return MusicState::DISABLED; } + if (current_music == nullptr) { return MusicState::INVALID; } + + return current_music->state; + } + + inline void deleteMusic(Music* music) { + if (music == nullptr) { return; } + if (current_music == music) { + stopMusic(); + current_music = nullptr; + } + if (music->stream != nullptr) { SDL_DestroyAudioStream(music->stream); } + if (music->vorbis != nullptr) { stb_vorbis_close(music->vorbis); } + // ogg_data (std::vector) i filename (std::string) s'alliberen sols + // al destructor de Music. + delete music; + } + + inline auto setMusicVolume(float volume) -> float { + music_volume = SDL_clamp(volume, 0.0F, 1.0F); + if ((current_music != nullptr) && (current_music->stream != nullptr)) { + SDL_SetAudioStreamGain(current_music->stream, music_volume); + } + return music_volume; + } + + inline void setMusicPosition(float /*value*/) { + // No implementat amb el backend de streaming. + } + + inline auto getMusicPosition() -> float { + return 0.0F; + } + + inline void enableMusic(bool value) { + if (!value && (current_music != nullptr) && (current_music->state == MusicState::PLAYING)) { stopMusic(); } + music_enabled = value; + } + + // --- Sound Functions --- + inline auto loadSound(std::uint8_t* buffer, std::uint32_t size) -> Sound* { + auto sound = std::make_unique(); + Uint8* raw = nullptr; + if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &raw, &sound->length)) { + std::cout << "Failed to load WAV from memory: " << SDL_GetError() << '\n'; + return nullptr; + } + sound->buffer.reset(raw); // adopta el SDL_malloc'd buffer + return sound.release(); + } + + inline auto loadSound(const char* filename) -> Sound* { + auto sound = std::make_unique(); + Uint8* raw = nullptr; + if (!SDL_LoadWAV(filename, &sound->spec, &raw, &sound->length)) { + std::cout << "Failed to load WAV file: " << SDL_GetError() << '\n'; + return nullptr; + } + sound->buffer.reset(raw); // adopta el SDL_malloc'd buffer + return sound.release(); + } + + inline auto playSound(Sound* sound, int loop = 0, int group = 0) -> int { + if (!sound_enabled || (sound == nullptr)) { return -1; } + + int channel = 0; + while (channel < MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != ChannelState::FREE) { channel++; } + if (channel == MAX_SIMULTANEOUS_CHANNELS) { + // No hi ha canal lliure, reemplacem el primer + channel = 0; + } + + return playSoundOnChannel(sound, channel, loop, group); + } + + inline auto playSoundOnChannel(Sound* sound, int channel, int loop, int group) -> int { + if (!sound_enabled || (sound == nullptr)) { return -1; } + if (channel < 0 || channel >= MAX_SIMULTANEOUS_CHANNELS) { return -1; } + + stopChannel(channel); + + channels[channel].sound = sound; + channels[channel].times = loop; + channels[channel].pos = 0; + channels[channel].group = group; + channels[channel].state = ChannelState::PLAYING; + channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &audio_spec); + + if (channels[channel].stream == nullptr) { + std::cout << "Failed to create audio stream for sound!" << '\n'; + channels[channel].state = ChannelState::FREE; + return -1; + } + + SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer.get(), channels[channel].sound->length); + SDL_SetAudioStreamGain(channels[channel].stream, sound_volume[group]); + SDL_BindAudioStream(sdl_audio_device, channels[channel].stream); + + return channel; + } + + inline void deleteSound(Sound* sound) { + if (sound == nullptr) { return; } + for (int i = 0; i < MAX_SIMULTANEOUS_CHANNELS; i++) { + if (channels[i].sound == sound) { stopChannel(i); } + } + // buffer es destrueix automàticament via RAII (SdlFreeDeleter). + delete sound; + } + + inline void pauseChannel(int channel) { + if (!sound_enabled) { return; } + + if (channel == -1) { + for (auto& ch : channels) { + if (ch.state == ChannelState::PLAYING) { + ch.state = ChannelState::PAUSED; + SDL_UnbindAudioStream(ch.stream); + } + } + } else if (channel >= 0 && channel < MAX_SIMULTANEOUS_CHANNELS) { + if (channels[channel].state == ChannelState::PLAYING) { + channels[channel].state = ChannelState::PAUSED; + SDL_UnbindAudioStream(channels[channel].stream); } } - } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { - if (channels[channel].state != JA_CHANNEL_FREE) { - if (channels[channel].stream) SDL_DestroyAudioStream(channels[channel].stream); - channels[channel].stream = nullptr; - channels[channel].state = JA_CHANNEL_FREE; - channels[channel].pos = 0; - channels[channel].sound = nullptr; - } - } -} - -inline auto JA_GetChannelState(const int channel) -> JA_Channel_state { - if (!JA_soundEnabled) return JA_SOUND_DISABLED; - if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; - - return channels[channel].state; -} - -inline auto JA_SetSoundVolume(float volume, const int group = -1) -> float { - const float v = SDL_clamp(volume, 0.0F, 1.0F); - - if (group == -1) { - for (int i = 0; i < JA_MAX_GROUPS; ++i) { - JA_soundVolume[i] = v; - } - } else if (group >= 0 && group < JA_MAX_GROUPS) { - JA_soundVolume[group] = v; - } else { - return v; } - // Aplicar volum als canals actius. - for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { - if ((channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED)) { - if (group == -1 || channels[i].group == group) { - if (channels[i].stream) { - SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume[channels[i].group]); + inline void resumeChannel(int channel) { + if (!sound_enabled) { return; } + + if (channel == -1) { + for (auto& ch : channels) { + if (ch.state == ChannelState::PAUSED) { + ch.state = ChannelState::PLAYING; + SDL_BindAudioStream(sdl_audio_device, ch.stream); + } + } + } else if (channel >= 0 && channel < MAX_SIMULTANEOUS_CHANNELS) { + if (channels[channel].state == ChannelState::PAUSED) { + channels[channel].state = ChannelState::PLAYING; + SDL_BindAudioStream(sdl_audio_device, channels[channel].stream); + } + } + } + + inline void stopChannel(int channel) { + if (channel == -1) { + for (auto& ch : channels) { + if (ch.state != ChannelState::FREE) { + if (ch.stream != nullptr) { SDL_DestroyAudioStream(ch.stream); } + ch.stream = nullptr; + ch.state = ChannelState::FREE; + ch.pos = 0; + ch.sound = nullptr; + } + } + } else if (channel >= 0 && channel < MAX_SIMULTANEOUS_CHANNELS) { + if (channels[channel].state != ChannelState::FREE) { + if (channels[channel].stream != nullptr) { SDL_DestroyAudioStream(channels[channel].stream); } + channels[channel].stream = nullptr; + channels[channel].state = ChannelState::FREE; + channels[channel].pos = 0; + channels[channel].sound = nullptr; + } + } + } + + inline auto getChannelState(int channel) -> ChannelState { + if (!sound_enabled) { return ChannelState::DISABLED; } + if (channel < 0 || channel >= MAX_SIMULTANEOUS_CHANNELS) { return ChannelState::INVALID; } + + return channels[channel].state; + } + + inline auto setSoundVolume(float volume, int group = -1) -> float { + const float V = SDL_clamp(volume, 0.0F, 1.0F); + + if (group == -1) { + for (float& sv : sound_volume) { + sv = V; + } + } else if (group >= 0 && group < MAX_GROUPS) { + sound_volume[group] = V; + } else { + return V; + } + + // Aplicar volum als canals actius. + for (auto& ch : channels) { + if ((ch.state == ChannelState::PLAYING) || (ch.state == ChannelState::PAUSED)) { + if (group == -1 || ch.group == group) { + if (ch.stream != nullptr) { + SDL_SetAudioStreamGain(ch.stream, sound_volume[ch.group]); + } } } } + return V; } - return v; -} -inline void JA_EnableSound(const bool value) { - if (!value) { - JA_StopChannel(-1); + inline void enableSound(bool value) { + if (!value) { + stopChannel(-1); + } + sound_enabled = value; } - JA_soundEnabled = value; -} -inline auto JA_SetVolume(float volume) -> float { - float v = JA_SetMusicVolume(volume); - JA_SetSoundVolume(v, -1); - return v; -} + inline auto setVolume(float volume) -> float { + const float V = setMusicVolume(volume); + setSoundVolume(V, -1); + return V; + } + +} // namespace Ja diff --git a/source/core/resources/resource_cache.cpp b/source/core/resources/resource_cache.cpp index 3e2cf95..42799f0 100644 --- a/source/core/resources/resource_cache.cpp +++ b/source/core/resources/resource_cache.cpp @@ -9,7 +9,7 @@ #include // Para runtime_error #include -#include "core/audio/jail_audio.hpp" // Para JA_DeleteMusic, JA_DeleteSound, JA_Loa... +#include "core/audio/jail_audio.hpp" // Para Ja::deleteMusic, Ja::deleteSound, JA_Loa... #include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/text.hpp" // Para Text, loadTextFile #include "core/resources/resource_helper.hpp" // Para Helper @@ -21,8 +21,10 @@ #include "utils/defines.hpp" // Para WINDOW_CAPTION #include "utils/utils.hpp" // Para getFileName, printWithDots, PaletteColor #include "version.h" // Para Version::GIT_HASH -struct JA_Music_t; // lines 17-17 -struct JA_Sound_t; // lines 18-18 +namespace Ja { + struct Music; + struct Sound; +} // namespace Ja namespace Resource { @@ -234,7 +236,7 @@ namespace Resource { } // Obtiene el sonido a partir de un nombre - auto Cache::getSound(const std::string& name) -> JA_Sound_t* { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getSound(const std::string& name) -> Ja::Sound* { // NOLINT(readability-convert-member-functions-to-static) auto it = std::ranges::find_if(sounds_, [&name](const auto& s) -> bool { return s.name == name; }); if (it != sounds_.end()) { @@ -246,7 +248,7 @@ namespace Resource { } // Obtiene la música a partir de un nombre - auto Cache::getMusic(const std::string& name) -> JA_Music_t* { // NOLINT(readability-convert-member-functions-to-static) + auto Cache::getMusic(const std::string& name) -> Ja::Music* { // NOLINT(readability-convert-member-functions-to-static) auto it = std::ranges::find_if(musics_, [&name](const auto& m) -> bool { return m.name == name; }); if (it != musics_.end()) { @@ -398,14 +400,14 @@ namespace Resource { try { auto name = getFileName(l); setCurrentLoading(name); - JA_Sound_t* sound = nullptr; + Ja::Sound* sound = nullptr; auto audio_data = Helper::loadFile(l); if (!audio_data.empty()) { - sound = JA_LoadSound(audio_data.data(), static_cast(audio_data.size())); + sound = Ja::loadSound(audio_data.data(), static_cast(audio_data.size())); } if (sound == nullptr) { - sound = JA_LoadSound(l.c_str()); + sound = Ja::loadSound(l.c_str()); } if (sound == nullptr) { throw std::runtime_error("Failed to decode audio file"); @@ -426,14 +428,14 @@ namespace Resource { try { auto name = getFileName(l); setCurrentLoading(name); - JA_Music_t* music = nullptr; + Ja::Music* music = nullptr; auto audio_data = Helper::loadFile(l); if (!audio_data.empty()) { - music = JA_LoadMusic(audio_data.data(), static_cast(audio_data.size())); + music = Ja::loadMusic(audio_data.data(), static_cast(audio_data.size())); } if (music == nullptr) { - music = JA_LoadMusic(l.c_str()); + music = Ja::loadMusic(l.c_str()); } if (music == nullptr) { throw std::runtime_error("Failed to decode music file"); @@ -608,10 +610,10 @@ namespace Resource { // Vacía el vector de sonidos void Cache::clearSounds() { - // Itera sobre el vector y libera los recursos asociados a cada JA_Sound_t + // Itera sobre el vector y libera los recursos asociados a cada Ja::Sound for (auto& sound : sounds_) { if (sound.sound != nullptr) { - JA_DeleteSound(sound.sound); + Ja::deleteSound(sound.sound); sound.sound = nullptr; } } @@ -620,10 +622,10 @@ namespace Resource { // Vacía el vector de musicas void Cache::clearMusics() { - // Itera sobre el vector y libera los recursos asociados a cada JA_Music_t + // Itera sobre el vector y libera los recursos asociados a cada Ja::Music for (auto& music : musics_) { if (music.music != nullptr) { - JA_DeleteMusic(music.music); + Ja::deleteMusic(music.music); music.music = nullptr; } } diff --git a/source/core/resources/resource_cache.hpp b/source/core/resources/resource_cache.hpp index d292019..4548e87 100644 --- a/source/core/resources/resource_cache.hpp +++ b/source/core/resources/resource_cache.hpp @@ -16,8 +16,8 @@ namespace Resource { static void destroy(); // Destrucción singleton static auto get() -> Cache*; // Acceso al singleton - auto getSound(const std::string& name) -> JA_Sound_t*; // Getters de recursos - auto getMusic(const std::string& name) -> JA_Music_t*; + auto getSound(const std::string& name) -> Ja::Sound*; // Getters de recursos + auto getMusic(const std::string& name) -> Ja::Music*; auto getSurface(const std::string& name) -> std::shared_ptr; auto getPalette(const std::string& name) -> Palette; auto getTextFile(const std::string& name) -> std::shared_ptr; diff --git a/source/core/resources/resource_types.hpp b/source/core/resources/resource_types.hpp index 58f8488..b835918 100644 --- a/source/core/resources/resource_types.hpp +++ b/source/core/resources/resource_types.hpp @@ -10,19 +10,21 @@ #include "game/gameplay/room.hpp" // Para Room::Data // Forward declarations -struct JA_Music_t; -struct JA_Sound_t; +namespace Ja { + struct Music; + struct Sound; +} // namespace Ja // Estructura para almacenar ficheros de sonido y su nombre struct SoundResource { - std::string name; // Nombre del sonido - JA_Sound_t* sound{nullptr}; // Objeto con el sonido + std::string name; // Nombre del sonido + Ja::Sound* sound{nullptr}; // Objeto con el sonido }; // Estructura para almacenar ficheros musicales y su nombre struct MusicResource { - std::string name; // Nombre de la musica - JA_Music_t* music{nullptr}; // Objeto con la música + std::string name; // Nombre de la musica + Ja::Music* music{nullptr}; // Objeto con la música }; // Estructura para almacenar objetos Surface y su nombre diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index b17b89c..1e96ed9 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -14,7 +14,9 @@ #include "game/options.hpp" // Para Cheat, Options, options #include "utils/defines.hpp" // Para BORDER_TOP, BLOCK #include "utils/utils.hpp" // Para Color -struct JA_Sound_t; // lines 13-13 +namespace Ja { + struct Sound; +} class Player { public: @@ -156,12 +158,12 @@ class Player { int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo (hace doble función: tracking de caída + altura inicial del salto) // --- Variables de renderizado y sonido --- - Uint8 color_ = 0; // Color del jugador - std::array jumping_sound_{}; // Array con todos los sonidos del salto - std::array falling_sound_{}; // Array con todos los sonidos de la caída - JumpSoundController jump_sound_ctrl_; // Controlador de sonidos de salto - FallSoundController fall_sound_ctrl_; // Controlador de sonidos de caída - int fall_start_position_ = 0; // Posición Y al iniciar la caída + Uint8 color_ = 0; // Color del jugador + std::array jumping_sound_{}; // Array con todos los sonidos del salto + std::array falling_sound_{}; // Array con todos los sonidos de la caída + JumpSoundController jump_sound_ctrl_; // Controlador de sonidos de salto + FallSoundController fall_sound_ctrl_; // Controlador de sonidos de caída + int fall_start_position_ = 0; // Posición Y al iniciar la caída void handleConveyorBelts(); void handleShouldFall(); From 8f5d897048cf40d3e29943c204f4d7a57e056022 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 14 May 2026 23:55:44 +0200 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20resta=20tidy=20(60=20troballes=20?= =?UTF-8?q?=E2=80=94=20empty-catch,=20widening,=20branch-clone,=20etc.)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/core/audio/audio.cpp | 1 + source/core/audio/audio.hpp | 5 +- source/core/audio/jail_audio.hpp | 12 +- source/core/input/input.cpp | 3 +- source/core/input/input.hpp | 4 +- source/core/rendering/gif.cpp | 4 +- source/core/rendering/screen.cpp | 8 +- .../core/rendering/sdl3gpu/sdl3gpu_shader.cpp | 2 +- source/core/rendering/sprite/sprite.hpp | 6 +- source/core/rendering/surface.cpp | 14 +- source/core/rendering/text.cpp | 12 +- source/core/resources/resource_cache.cpp | 170 ++++++------------ source/core/resources/resource_cache.hpp | 13 +- source/core/system/global_events.cpp | 8 +- source/game/entities/player.cpp | 2 - source/game/options.cpp | 45 +++-- source/game/scenes/logo.cpp | 3 - source/game/ui/console.cpp | 19 +- source/game/ui/console_commands.cpp | 6 +- source/game/ui/notifier.cpp | 8 +- source/game/ui/notifier.hpp | 6 +- source/utils/delta_timer.cpp | 3 +- source/utils/delta_timer.hpp | 2 +- 23 files changed, 163 insertions(+), 193 deletions(-) diff --git a/source/core/audio/audio.cpp b/source/core/audio/audio.cpp index 6e39c0a..ad58c6a 100644 --- a/source/core/audio/audio.cpp +++ b/source/core/audio/audio.cpp @@ -8,6 +8,7 @@ // Implementación de stb_vorbis (debe estar ANTES de incluir jail_audio.hpp). // clang-format off #undef STB_VORBIS_HEADER_ONLY +// NOLINTNEXTLINE(bugprone-suspicious-include) — stb_vorbis és single-file: el TU principal inclou el .c per portar la implementació. #include "external/stb_vorbis.c" // stb_vorbis.c filtra les macros L, C i R (i PLAYBACK_*) al TU. Les netegem // perquè xocarien amb noms de paràmetres de plantilla en altres headers. diff --git a/source/core/audio/audio.hpp b/source/core/audio/audio.hpp index 783afad..be490d4 100644 --- a/source/core/audio/audio.hpp +++ b/source/core/audio/audio.hpp @@ -1,5 +1,6 @@ #pragma once +#include // Para std::lround #include // Para int8_t, uint8_t #include // Para string #include // Para move @@ -64,8 +65,8 @@ class Audio { // --- Helpers de conversió per a la capa de presentació --- // UI (menús, notificacions) manega enters 0..100; internament viu float 0..1. - static constexpr auto toPercent(float volume) -> int { - return static_cast(volume * 100.0F + 0.5F); + static auto toPercent(float volume) -> int { + return static_cast(std::lround(volume * 100.0F)); } static constexpr auto fromPercent(int percent) -> float { return static_cast(percent) / 100.0F; diff --git a/source/core/audio/jail_audio.hpp b/source/core/audio/jail_audio.hpp index 52c910a..b1e7625 100644 --- a/source/core/audio/jail_audio.hpp +++ b/source/core/audio/jail_audio.hpp @@ -57,12 +57,14 @@ namespace Ja { std::unique_ptr buffer; }; + // L'ordre (punters primer, ints després, enum de 8 bits al final) minimitza + // el padding a 64-bit (evita avisos de clang-analyzer-optin.performance.Padding). struct Channel { Sound* sound{nullptr}; + SDL_AudioStream* stream{nullptr}; int pos{0}; int times{0}; int group{0}; - SDL_AudioStream* stream{nullptr}; ChannelState state{ChannelState::FREE}; }; @@ -314,7 +316,11 @@ namespace Ja { std::fseek(f, 0, SEEK_END); const long FSIZE = std::ftell(f); std::fseek(f, 0, SEEK_SET); - auto* buffer = static_cast(std::malloc(FSIZE + 1)); + if (FSIZE <= 0) { + std::fclose(f); + return nullptr; + } + auto* buffer = static_cast(std::malloc(static_cast(FSIZE) + 1)); if (buffer == nullptr) { std::fclose(f); return nullptr; @@ -520,7 +526,7 @@ namespace Ja { inline auto loadSound(std::uint8_t* buffer, std::uint32_t size) -> Sound* { auto sound = std::make_unique(); Uint8* raw = nullptr; - if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &raw, &sound->length)) { + if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), true, &sound->spec, &raw, &sound->length)) { std::cout << "Failed to load WAV from memory: " << SDL_GetError() << '\n'; return nullptr; } diff --git a/source/core/input/input.cpp b/source/core/input/input.cpp index 567f842..f6440c9 100644 --- a/source/core/input/input.cpp +++ b/source/core/input/input.cpp @@ -425,8 +425,9 @@ auto Input::handleEvent(const SDL_Event& event) -> std::string { // NOLINT(read return addGamepad(event.gdevice.which); case SDL_EVENT_GAMEPAD_REMOVED: return removeGamepad(event.gdevice.which); + default: + return {}; } - return {}; } auto Input::addGamepad(int device_index) -> std::string { // NOLINT(readability-convert-member-functions-to-static) diff --git a/source/core/input/input.hpp b/source/core/input/input.hpp index 152b906..3685016 100644 --- a/source/core/input/input.hpp +++ b/source/core/input/input.hpp @@ -55,8 +55,8 @@ class Input { // Evita nombres como "Retroid Controller (vendor: 1001) ..." en las notificaciones. static auto trimName(const char* raw) -> std::string { std::string s(raw != nullptr ? raw : ""); - const auto pos = s.find_first_of("(["); - if (pos != std::string::npos) { s.erase(pos); } + const auto POS = s.find_first_of("(["); + if (POS != std::string::npos) { s.erase(POS); } while (!s.empty() && s.back() == ' ') { s.pop_back(); } return s; } diff --git a/source/core/rendering/gif.cpp b/source/core/rendering/gif.cpp index 654090e..302138e 100644 --- a/source/core/rendering/gif.cpp +++ b/source/core/rendering/gif.cpp @@ -224,8 +224,8 @@ namespace GIF { if ((screen_descriptor.fields & 0x80) != 0) { int global_color_table_size = 1 << ((screen_descriptor.fields & 0x07) + 1); global_color_table.resize(global_color_table_size); - std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size); - buffer += 3 * global_color_table_size; + std::memcpy(global_color_table.data(), buffer, static_cast(3) * global_color_table_size); + buffer += static_cast(3) * global_color_table_size; } // Supongamos que 'buffer' es el puntero actual y TRAILER es 0x3B diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index 15063aa..c0e1e01 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -475,13 +475,13 @@ void Screen::textureToRenderer() { // Franjas superior e inferior (ancho completo) std::fill_n(border_pixel_buffer_.data(), OFF_Y * BORDER_W, border_argb_color_); - std::fill_n(&border_pixel_buffer_[(OFF_Y + GAME_H) * BORDER_W], + std::fill_n(&border_pixel_buffer_[static_cast(OFF_Y + GAME_H) * BORDER_W], (BORDER_H - OFF_Y - GAME_H) * BORDER_W, border_argb_color_); // Columnas laterales en las filas del área de juego for (int y = OFF_Y; y < OFF_Y + GAME_H; ++y) { - std::fill_n(&border_pixel_buffer_[y * BORDER_W], OFF_X, border_argb_color_); - std::fill_n(&border_pixel_buffer_[(y * BORDER_W) + OFF_X + GAME_W], + std::fill_n(&border_pixel_buffer_[static_cast(y) * BORDER_W], OFF_X, border_argb_color_); + std::fill_n(&border_pixel_buffer_[(static_cast(y) * BORDER_W) + OFF_X + GAME_W], BORDER_W - OFF_X - GAME_W, border_argb_color_); } @@ -494,7 +494,7 @@ void Screen::textureToRenderer() { // Overlay del juego sobre el centro del buffer (ambos paths) game_surface_->toARGBBuffer(game_pixel_buffer_.data()); for (int y = 0; y < GAME_H; ++y) { - const Uint32* src = &game_pixel_buffer_[y * GAME_W]; + const Uint32* src = &game_pixel_buffer_[static_cast(y) * GAME_W]; Uint32* dst = &border_pixel_buffer_[((OFF_Y + y) * BORDER_W) + OFF_X]; std::memcpy(dst, src, GAME_W * sizeof(Uint32)); } diff --git a/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp b/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp index cc43cc0..00ec21f 100644 --- a/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp +++ b/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp @@ -762,7 +762,7 @@ namespace Rendering { } // Copia directa — el upscale lo hace la GPU en el primer render pass - std::memcpy(mapped, pixels, static_cast(width * height * 4)); + std::memcpy(mapped, pixels, static_cast(width) * static_cast(height) * 4); SDL_UnmapGPUTransferBuffer(device_, upload_buffer_); } diff --git a/source/core/rendering/sprite/sprite.hpp b/source/core/rendering/sprite/sprite.hpp index ec5d153..ebcc56c 100644 --- a/source/core/rendering/sprite/sprite.hpp +++ b/source/core/rendering/sprite/sprite.hpp @@ -10,10 +10,10 @@ class Surface; // lines 5-5 class Sprite { public: // Constructores - Sprite(std::shared_ptr, float x, float y, float w, float h); - Sprite(std::shared_ptr, SDL_FRect rect); + Sprite(std::shared_ptr surface, float x, float y, float w, float h); + Sprite(std::shared_ptr surface, SDL_FRect rect); Sprite(); - explicit Sprite(std::shared_ptr); + explicit Sprite(std::shared_ptr surface); // Destructor virtual ~Sprite() = default; diff --git a/source/core/rendering/surface.cpp b/source/core/rendering/surface.cpp index a33263d..d18b3e5 100644 --- a/source/core/rendering/surface.cpp +++ b/source/core/rendering/surface.cpp @@ -180,7 +180,7 @@ void Surface::fillRect(const SDL_FRect* rect, Uint8 color) { // NOLINT(readabil const int SURF_WIDTH = surface_data_->width; const int ROW_WIDTH = static_cast(x_end) - static_cast(x_start); for (int y = static_cast(y_start); y < static_cast(y_end); ++y) { - std::memset(data_ptr + (y * SURF_WIDTH) + static_cast(x_start), color, ROW_WIDTH); + std::memset(data_ptr + (static_cast(y) * SURF_WIDTH) + static_cast(x_start), color, ROW_WIDTH); } } @@ -196,8 +196,8 @@ void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) { // NOLINT(re Uint8* data_ptr = surface_data_->data.get(); const int SURF_WIDTH = surface_data_->width; const int ROW_WIDTH = static_cast(x_end) - static_cast(x_start); - std::memset(data_ptr + (static_cast(y_start) * SURF_WIDTH) + static_cast(x_start), color, ROW_WIDTH); - std::memset(data_ptr + ((static_cast(y_end) - 1) * SURF_WIDTH) + static_cast(x_start), color, ROW_WIDTH); + std::memset(data_ptr + (static_cast(y_start) * SURF_WIDTH) + static_cast(x_start), color, ROW_WIDTH); + std::memset(data_ptr + ((static_cast(y_end) - 1) * SURF_WIDTH) + static_cast(x_start), color, ROW_WIDTH); // Dibujar bordes verticales for (int y = y_start; y < y_end; ++y) { @@ -539,8 +539,8 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) { // const int WIDTH = surface_data_->width; const int HEIGHT = surface_data_->height; for (int y = 0; y < HEIGHT; ++y) { - const Uint8* src_row = src + (y * WIDTH); - Uint32* dst_row = pixels + (y * row_stride); + const Uint8* src_row = src + (static_cast(y) * WIDTH); + Uint32* dst_row = pixels + (static_cast(y) * row_stride); for (int x = 0; x < WIDTH; ++x) { dst_row[x] = pal[src_row[x]]; } @@ -588,8 +588,8 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FR const int WIDTH = surface_data_->width; const int HEIGHT = surface_data_->height; for (int y = 0; y < HEIGHT; ++y) { - const Uint8* src_row = src + (y * WIDTH); - Uint32* dst_row = pixels + (y * row_stride); + const Uint8* src_row = src + (static_cast(y) * WIDTH); + Uint32* dst_row = pixels + (static_cast(y) * row_stride); for (int x = 0; x < WIDTH; ++x) { dst_row[x] = pal[src_row[x]]; } diff --git a/source/core/rendering/text.cpp b/source/core/rendering/text.cpp index 4a76380..36ef4d6 100644 --- a/source/core/rendering/text.cpp +++ b/source/core/rendering/text.cpp @@ -22,11 +22,11 @@ auto Text::nextCodepoint(const std::string& s, size_t& pos) -> uint32_t { // NO if (c < 0x80) { cp = c; extra = 0; - } else if (c < 0xC0) { - pos++; - return 0xFFFD; - } // byte de continuación suelto - else if (c < 0xE0) { + } else if (c < 0xE0) { + if (c < 0xC0) { + pos++; + return 0xFFFD; // byte de continuación suelto + } cp = c & 0x1F; extra = 1; } else if (c < 0xF0) { @@ -260,7 +260,7 @@ void Text::writeDX(Uint8 flags, int x, int y, const std::string& text, int kerni if (COLORED) { writeColored(x, y, text, text_color, kerning, lenght); } else { - writeColored(x, y, text, text_color, kerning, lenght); + write(x, y, text, kerning, lenght); } } diff --git a/source/core/resources/resource_cache.cpp b/source/core/resources/resource_cache.cpp index 42799f0..e836c97 100644 --- a/source/core/resources/resource_cache.cpp +++ b/source/core/resources/resource_cache.cpp @@ -87,148 +87,88 @@ namespace Resource { return stage_ == LoadStage::DONE; } + // Helper per a una etapa que itera una llista de recursos. + // Imprimeix la capçalera i neteja el vector al primer cop; després carrega + // un element per crida fins exhaurir la llista, moment en què passa a `next`. + void Cache::stepEachInList(List::Type type, const char* header, const std::function& clear_fn, LoadStage next, const std::function& load_fn) { + auto list = List::get()->getListByType(type); + if (stage_index_ == 0) { + std::cout << "\n>> " << header << '\n'; + clear_fn(); + } + if (stage_index_ >= list.size()) { + stage_ = next; + stage_index_ = 0; + return; + } + load_fn(stage_index_++); + } + // Carga assets hasta agotar el presupuesto de tiempo o completar todas las etapas. // Devuelve true cuando ya no queda nada por cargar. auto Cache::loadStep(int budget_ms) -> bool { if (stage_ == LoadStage::DONE) { return true; } - const Uint64 start_ns = SDL_GetTicksNS(); - const Uint64 budget_ns = static_cast(budget_ms) * 1'000'000ULL; - - auto listOf = [](List::Type t) { return List::get()->getListByType(t); }; + const Uint64 START_NS = SDL_GetTicksNS(); + const Uint64 BUDGET_NS = static_cast(budget_ms) * 1'000'000ULL; while (stage_ != LoadStage::DONE) { switch (stage_) { - case LoadStage::SOUNDS: { - auto list = listOf(List::Type::SOUND); - if (stage_index_ == 0) { - std::cout << "\n>> SOUND FILES" << '\n'; - sounds_.clear(); - } - if (stage_index_ >= list.size()) { - stage_ = LoadStage::MUSICS; - stage_index_ = 0; - break; - } - loadOneSound(stage_index_++); + case LoadStage::SOUNDS: + stepEachInList(List::Type::SOUND, "SOUND FILES", [this] { sounds_.clear(); }, LoadStage::MUSICS, [this](size_t i) { loadOneSound(i); }); break; - } - case LoadStage::MUSICS: { - auto list = listOf(List::Type::MUSIC); - if (stage_index_ == 0) { - std::cout << "\n>> MUSIC FILES" << '\n'; - musics_.clear(); - } - if (stage_index_ >= list.size()) { - stage_ = LoadStage::SURFACES; - stage_index_ = 0; - break; - } - loadOneMusic(stage_index_++); + case LoadStage::MUSICS: + stepEachInList(List::Type::MUSIC, "MUSIC FILES", [this] { musics_.clear(); }, LoadStage::SURFACES, [this](size_t i) { loadOneMusic(i); }); break; - } - case LoadStage::SURFACES: { - auto list = listOf(List::Type::BITMAP); - if (stage_index_ == 0) { - std::cout << "\n>> SURFACES" << '\n'; - surfaces_.clear(); - } - if (stage_index_ >= list.size()) { - stage_ = LoadStage::SURFACES_POST; - stage_index_ = 0; - break; - } - loadOneSurface(stage_index_++); + case LoadStage::SURFACES: + stepEachInList(List::Type::BITMAP, "SURFACES", [this] { surfaces_.clear(); }, LoadStage::SURFACES_POST, [this](size_t i) { loadOneSurface(i); }); break; - } - case LoadStage::SURFACES_POST: { + case LoadStage::SURFACES_POST: finalizeSurfaces(); stage_ = LoadStage::PALETTES; stage_index_ = 0; break; - } - case LoadStage::PALETTES: { - auto list = listOf(List::Type::PALETTE); - if (stage_index_ == 0) { - std::cout << "\n>> PALETTES" << '\n'; - palettes_.clear(); - } - if (stage_index_ >= list.size()) { - stage_ = LoadStage::TEXT_FILES; - stage_index_ = 0; - break; - } - loadOnePalette(stage_index_++); + case LoadStage::PALETTES: + stepEachInList(List::Type::PALETTE, "PALETTES", [this] { palettes_.clear(); }, LoadStage::TEXT_FILES, [this](size_t i) { loadOnePalette(i); }); break; - } - case LoadStage::TEXT_FILES: { - auto list = listOf(List::Type::FONT); - if (stage_index_ == 0) { - std::cout << "\n>> TEXT FILES" << '\n'; - text_files_.clear(); - } - if (stage_index_ >= list.size()) { - stage_ = LoadStage::ANIMATIONS; - stage_index_ = 0; - break; - } - loadOneTextFile(stage_index_++); + case LoadStage::TEXT_FILES: + stepEachInList(List::Type::FONT, "TEXT FILES", [this] { text_files_.clear(); }, LoadStage::ANIMATIONS, [this](size_t i) { loadOneTextFile(i); }); break; - } - case LoadStage::ANIMATIONS: { - auto list = listOf(List::Type::ANIMATION); - if (stage_index_ == 0) { - std::cout << "\n>> ANIMATIONS" << '\n'; - animations_.clear(); - } - if (stage_index_ >= list.size()) { - stage_ = LoadStage::ROOMS; - stage_index_ = 0; - break; - } - loadOneAnimation(stage_index_++); + case LoadStage::ANIMATIONS: + stepEachInList(List::Type::ANIMATION, "ANIMATIONS", [this] { animations_.clear(); }, LoadStage::ROOMS, [this](size_t i) { loadOneAnimation(i); }); break; - } - case LoadStage::ROOMS: { - auto list = listOf(List::Type::ROOM); - if (stage_index_ == 0) { - std::cout << "\n>> ROOMS" << '\n'; - rooms_.clear(); - } - if (stage_index_ >= list.size()) { - stage_ = LoadStage::TEXTS; - stage_index_ = 0; - break; - } - loadOneRoom(stage_index_++); + case LoadStage::ROOMS: + stepEachInList(List::Type::ROOM, "ROOMS", [this] { rooms_.clear(); }, LoadStage::TEXTS, [this](size_t i) { loadOneRoom(i); }); break; - } - case LoadStage::TEXTS: { - // createText itera sobre una lista fija de 5 fuentes - constexpr size_t TEXT_COUNT = 5; - if (stage_index_ == 0) { - std::cout << "\n>> CREATING TEXT_OBJECTS" << '\n'; - texts_.clear(); - } - if (stage_index_ >= TEXT_COUNT) { - stage_ = LoadStage::DONE; - stage_index_ = 0; - std::cout << "\n** RESOURCES LOADED" << '\n'; - break; - } - createOneText(stage_index_++); + case LoadStage::TEXTS: + stepTexts(); break; - } case LoadStage::DONE: break; } - if ((SDL_GetTicksNS() - start_ns) >= budget_ns) { break; } + if ((SDL_GetTicksNS() - START_NS) >= BUDGET_NS) { break; } } return stage_ == LoadStage::DONE; } + void Cache::stepTexts() { + // createText itera sobre una lista fija de 5 fuentes + constexpr size_t TEXT_COUNT = 5; + if (stage_index_ == 0) { + std::cout << "\n>> CREATING TEXT_OBJECTS" << '\n'; + texts_.clear(); + } + if (stage_index_ >= TEXT_COUNT) { + stage_ = LoadStage::DONE; + stage_index_ = 0; + std::cout << "\n** RESOURCES LOADED" << '\n'; + return; + } + createOneText(stage_index_++); + } + // Recarga todos los recursos (síncrono, solo para hot-reload de debug) void Cache::reload() { clear(); @@ -382,13 +322,13 @@ namespace Resource { }; auto getTextObjectInfos() -> const std::vector& { - static const std::vector info = { + static const std::vector INFO = { {.key = "aseprite", .texture_file = "aseprite.gif", .text_file = "aseprite.fnt"}, {.key = "gauntlet", .texture_file = "gauntlet.gif", .text_file = "gauntlet.fnt"}, {.key = "smb2", .texture_file = "smb2.gif", .text_file = "smb2.fnt"}, {.key = "subatomic", .texture_file = "subatomic.gif", .text_file = "subatomic.fnt"}, {.key = "8bithud", .texture_file = "8bithud.gif", .text_file = "8bithud.fnt"}}; - return info; + return INFO; } } // namespace diff --git a/source/core/resources/resource_cache.hpp b/source/core/resources/resource_cache.hpp index 4548e87..f9be4ed 100644 --- a/source/core/resources/resource_cache.hpp +++ b/source/core/resources/resource_cache.hpp @@ -1,11 +1,13 @@ #pragma once -#include // Para uint8_t -#include // Para shared_ptr -#include // Para string +#include // Para uint8_t +#include // Para std::function +#include // Para shared_ptr +#include // Para string #include #include // Para vector +#include "core/resources/resource_list.hpp" // Para List::Type #include "core/resources/resource_types.hpp" // Para structs de recursos namespace Resource { @@ -103,6 +105,11 @@ namespace Resource { // Helper para mensajes de error de carga static void logLoadError(const std::string& asset_type, const std::string& file_path, const std::exception& e); + // Helper d'iteració per a una etapa que recorre una llista de recursos. + // Crida `load_fn(i)` per a cada element i, en exhaurir-se, transiciona a `next`. + void stepEachInList(List::Type type, const char* header, const std::function& clear_fn, LoadStage next, const std::function& load_fn); + void stepTexts(); // Etapa especial: no usa List, itera sobre TEXT_COUNT fonts fixes. + // Constructor y destructor Cache(); ~Cache() = default; diff --git a/source/core/system/global_events.cpp b/source/core/system/global_events.cpp index 905ee7f..0cb3617 100644 --- a/source/core/system/global_events.cpp +++ b/source/core/system/global_events.cpp @@ -13,7 +13,7 @@ namespace GlobalEvents { namespace { // Flag per saber si en aquest frame s'ha rebut un button down del gamepad. // El consumeix GlobalInputs perquè un botó del comandament salti escenes. - bool gamepad_button_pressed_ = false; + bool gamepad_button_pressed = false; } // namespace // Comprueba los eventos que se pueden producir en cualquier sección del juego. @@ -56,7 +56,7 @@ namespace GlobalEvents { const bool RESERVE_BACK = IS_BACK; #endif if (!RESERVE_BACK && !IS_SHOULDER) { - gamepad_button_pressed_ = true; + gamepad_button_pressed = true; } } @@ -72,8 +72,8 @@ namespace GlobalEvents { } auto consumeGamepadButtonPressed() -> bool { - const bool RESULT = gamepad_button_pressed_; - gamepad_button_pressed_ = false; + const bool RESULT = gamepad_button_pressed; + gamepad_button_pressed = false; return RESULT; } } // namespace GlobalEvents \ No newline at end of file diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index 1efa930..6f11c4d 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -836,8 +836,6 @@ void Player::updateVelocity() { sprite_->setFlip(Flip::RIGHT); break; case Direction::NONE: - vx_ = 0.0F; - break; default: vx_ = 0.0F; break; diff --git a/source/game/options.cpp b/source/game/options.cpp index 67fd6d7..bcbdaaf 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -368,12 +368,14 @@ namespace Options { if (sh_node.contains("current_postfx_preset")) { try { video.shader.current_postfx_preset_name = sh_node["current_postfx_preset"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (sh_node.contains("current_crtpi_preset")) { try { video.shader.current_crtpi_preset_name = sh_node["current_crtpi_preset"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } } @@ -573,24 +575,28 @@ namespace Options { if (a.contains("enabled")) { try { audio.enabled = a["enabled"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (a.contains("volume")) { try { audio.volume = std::clamp(a["volume"].get_value(), 0.0F, 1.0F); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (a.contains("music")) { const auto& m = a["music"]; if (m.contains("enabled")) { try { audio.music.enabled = m["enabled"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (m.contains("volume")) { try { audio.music.volume = std::clamp(m["volume"].get_value(), 0.0F, 1.0F); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } } if (a.contains("sound")) { @@ -598,12 +604,14 @@ namespace Options { if (s.contains("enabled")) { try { audio.sound.enabled = s["enabled"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (s.contains("volume")) { try { audio.sound.volume = std::clamp(s["volume"].get_value(), 0.0F, 1.0F); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } } } @@ -891,7 +899,8 @@ namespace Options { if (node.contains(key)) { try { target = node[key].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } } @@ -1181,32 +1190,38 @@ namespace Options { if (p.contains("mask_type")) { try { preset.mask_type = p["mask_type"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (p.contains("enable_scanlines")) { try { preset.enable_scanlines = p["enable_scanlines"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (p.contains("enable_multisample")) { try { preset.enable_multisample = p["enable_multisample"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (p.contains("enable_gamma")) { try { preset.enable_gamma = p["enable_gamma"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (p.contains("enable_curvature")) { try { preset.enable_curvature = p["enable_curvature"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } if (p.contains("enable_sharper")) { try { preset.enable_sharper = p["enable_sharper"].get_value(); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } } crtpi_presets.push_back(preset); } diff --git a/source/game/scenes/logo.cpp b/source/game/scenes/logo.cpp index 39dd017..8601d14 100644 --- a/source/game/scenes/logo.cpp +++ b/source/game/scenes/logo.cpp @@ -238,9 +238,6 @@ void Logo::endSection() { break; case SceneManager::Options::LOGO_TO_LOADING_SCREEN: - SceneManager::current = SceneManager::Scene::LOADING_SCREEN; - break; - default: SceneManager::current = SceneManager::Scene::LOADING_SCREEN; break; diff --git a/source/game/ui/console.cpp b/source/game/ui/console.cpp index 8483d99..63144db 100644 --- a/source/game/ui/console.cpp +++ b/source/game/ui/console.cpp @@ -66,9 +66,11 @@ auto Console::wrapText(const std::string& text) const -> std::vector> word) { - const std::string TEST = current_line.empty() ? word : (current_line + ' ' + word); - if (text_->length(TEST) <= MAX_PX) { - current_line = TEST; + std::string test = current_line; + if (!test.empty()) { test += ' '; } + test += word; + if (text_->length(test) <= MAX_PX) { + current_line = std::move(test); } else { if (!current_line.empty()) { result.push_back(current_line); } current_line = word; @@ -182,10 +184,10 @@ void Console::update(float delta_time) { // NOLINT(readability-function-cogniti // Efecto typewriter: revelar letras una a una (solo cuando ACTIVE) if (status_ == Status::ACTIVE) { - const int total_chars = std::accumulate(msg_lines_.begin(), msg_lines_.end(), 0, [](int acc, const auto& line) { return acc + static_cast(line.size()); }); - if (typewriter_chars_ < total_chars) { + const int TOTAL_CHARS = std::accumulate(msg_lines_.begin(), msg_lines_.end(), 0, [](int acc, const auto& line) { return acc + static_cast(line.size()); }); + if (typewriter_chars_ < TOTAL_CHARS) { typewriter_timer_ += delta_time; - while (typewriter_timer_ >= TYPEWRITER_CHAR_DELAY && typewriter_chars_ < total_chars) { + while (typewriter_timer_ >= TYPEWRITER_CHAR_DELAY && typewriter_chars_ < TOTAL_CHARS) { typewriter_timer_ -= TYPEWRITER_CHAR_DELAY; ++typewriter_chars_; } @@ -345,7 +347,10 @@ void Console::handleEvent(const SDL_Event& event) { // NOLINT(readability-funct const auto OPTS = registry_.getCompletions(BASE_CMD); for (const auto& arg : OPTS) { if (SUB_PREFIX.empty() || std::string_view{arg}.starts_with(SUB_PREFIX)) { - tab_matches_.emplace_back(BASE_CMD + " " + arg); + std::string match = BASE_CMD; + match += ' '; + match += arg; + tab_matches_.push_back(std::move(match)); } } } diff --git a/source/game/ui/console_commands.cpp b/source/game/ui/console_commands.cpp index f2dd8a6..e886238 100644 --- a/source/game/ui/console_commands.cpp +++ b/source/game/ui/console_commands.cpp @@ -259,7 +259,8 @@ static auto cmdZoom(const std::vector& args) -> std::string { if (N == Options::window.zoom) { return "Zoom already " + std::to_string(N); } Screen::get()->setWindowZoom(N); return "Zoom " + std::to_string(Options::window.zoom); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } return "usage: zoom [up|down|<1-" + std::to_string(Screen::getMaxZoom()) + ">]"; } @@ -912,7 +913,8 @@ static auto cmdPlayer(const std::vector& args) -> std::string { int color = -1; try { color = std::stoi(args[1]); - } catch (...) {} + } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ + } if (color < 0 || color > 15) { return "usage: player color <0-15>|default"; } if (!GameControl::change_player_color) { return "Game not initialized"; } GameControl::change_player_color(color); diff --git a/source/game/ui/notifier.cpp b/source/game/ui/notifier.cpp index 6086dbf..32471ec 100644 --- a/source/game/ui/notifier.cpp +++ b/source/game/ui/notifier.cpp @@ -117,8 +117,6 @@ void Notifier::update(float delta_time) { } case Status::FINISHED: - break; - default: break; } @@ -172,7 +170,7 @@ void Notifier::show(std::vector texts, const Style& style, int icon const int ICON_SPACE = icon >= 0 ? ICON_SIZE + PADDING_IN_H : 0; const TextAlign TEXT_IS = ICON_SPACE > 0 ? TextAlign::LEFT : style.text_align; const float WIDTH = Options::game.width - (PADDING_OUT * 2); - const float HEIGHT = (TEXT_SIZE * texts.size()) + (PADDING_IN_V * 2); + const float HEIGHT = (TEXT_SIZE * static_cast(texts.size())) + (PADDING_IN_V * 2); const auto SHAPE = style.shape; // Posición horizontal @@ -287,7 +285,7 @@ void Notifier::clearNotifications() { } // Y absoluta de la base de la pila (justo debajo de Console, o 0 si no hay Console) -auto Notifier::getStackBaseY() const -> int { +auto Notifier::getStackBaseY() -> int { return Console::get() != nullptr ? Console::get()->getVisibleHeight() : 0; } @@ -297,7 +295,7 @@ auto Notifier::getVisibleHeight() const -> int { for (const auto& n : notifications_) { if (n.state == Status::FINISHED) { continue; } const int N_BOTTOM = static_cast(n.rect.y + n.rect.h); - if (N_BOTTOM > bottom) { bottom = N_BOTTOM; } + bottom = std::max(N_BOTTOM, bottom); } return bottom; } diff --git a/source/game/ui/notifier.hpp b/source/game/ui/notifier.hpp index a907fbd..af2236f 100644 --- a/source/game/ui/notifier.hpp +++ b/source/game/ui/notifier.hpp @@ -98,9 +98,9 @@ class Notifier { static Notifier* notifier; // Métodos privados - void clearFinishedNotifications(); // Elimina las notificaciones finalizadas - void clearNotifications(); // Finaliza y elimina todas las notificaciones activas - [[nodiscard]] auto getStackBaseY() const -> int; // Y absoluta de la base de la pila (leída de Console) + void clearFinishedNotifications(); // Elimina las notificaciones finalizadas + void clearNotifications(); // Finaliza y elimina todas las notificaciones activas + [[nodiscard]] static auto getStackBaseY() -> int; // Y absoluta de la base de la pila (leída de Console) // Constructor y destructor privados [SINGLETON] Notifier(const std::string& icon_file, const std::string& text); diff --git a/source/utils/delta_timer.cpp b/source/utils/delta_timer.cpp index 0e8d82e..620a51d 100644 --- a/source/utils/delta_timer.cpp +++ b/source/utils/delta_timer.cpp @@ -2,8 +2,7 @@ DeltaTimer::DeltaTimer() noexcept : last_counter_(SDL_GetPerformanceCounter()), - perf_freq_(static_cast(SDL_GetPerformanceFrequency())), - time_scale_(1.0F) { + perf_freq_(static_cast(SDL_GetPerformanceFrequency())) { } auto DeltaTimer::tick() noexcept -> float { diff --git a/source/utils/delta_timer.hpp b/source/utils/delta_timer.hpp index deb6f39..c5fa206 100644 --- a/source/utils/delta_timer.hpp +++ b/source/utils/delta_timer.hpp @@ -24,5 +24,5 @@ class DeltaTimer { private: Uint64 last_counter_; double perf_freq_; - float time_scale_; + float time_scale_{1.0F}; };