diff --git a/CLAUDE.md b/CLAUDE.md index 5da283a..ade2d48 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,90 +23,15 @@ Se han renombrado las referencias de `JailDoctor's Dilemma` → `Projecte 2026` - El publisher `jailgames` (carpeta de config de sistema: `~/.config/jailgames/projecte_2026`). - Los archivos `release/windows/jdd.rc` y `jdd.res` (solo bundlean el icono). -## Log de cambios realizados (sesiones de trabajo) +## Pendiente -### Eliminaciones -- **Clase `Stats` (persistencia CSV de muertes/visitas)** eliminada por completo: archivos `source/game/gameplay/stats.hpp/cpp`, entrada en CMakeLists, referencias en `Game` scene (`stats_`, `initStats()`, `addVisit/addDeath`), ficheros `stats.csv`/`stats_buffer.csv` en `config/assets.yaml`, patrón `*stats.txt` en `.gitignore`, campo `worst_nightmare` en `Options::Stats` + `Defaults::Stats::WORST_NIGHTMARE`, display de "worst nightmare" en `game_over.cpp`/`.hpp`, traducciones en locales, menciones en docs. -- **Mantenido:** `Options::stats.items` y `Options::stats.rooms` — son contadores de runtime del marcador/game_over, no tienen persistencia CSV. Coincidencia de nombre con la clase Stats eliminada. - -### Música -- Eliminadas las 10 pistas originales (14 MB) de `data/music/`. -- Copiadas 2 pistas de `../pollo/data/music/`: `574070_KUVO_Farewell_to_school.ogg` y `574071_EA_DTV.ogg` (7 MB total). -- `config/assets.yaml` reducido a esas 2 entradas. -- Las 10 llamadas `playMusic()` existentes (title/game/loading_*/ending*/game_over) remapeadas alternadamente a una de las 2 pistas. Mapeo concreto en esta misma documentación si hace falta consultarlo (ver git log del cambio). - -### Paleta -- Eliminadas las 23 paletas ZX Spectrum/otras de `data/palette/`. -- Traída `cpc.pal` de `../pollo/data/palettes/` (JASC-PAL, 28 entradas: CLEAR+27 colores CPC). -- `config/assets.yaml`: solo `cpc.pal`. -- `Defaults::Video::PALETTE_NAME = "cpc"`. -- Traída la clase `Color` de pollo a `source/utils/color.hpp` + `color.cpp` (enum `Color::Cpc` con 28 valores 0-27 + `Color::fromString()`). -- Struct RGB `Color` en `utils.hpp` **renombrada a `Rgb`** para evitar conflicto con la nueva clase. Propagado a `utils.cpp` (`colorAreEqual`), `screen.hpp`/`.cpp` (`clearRenderer`). -- Añadido `source/utils/color.cpp` a `CMakeLists.txt`. -- **Pendiente de revisar:** enum `PaletteColor` en `utils.hpp` sigue con los 16 índices antiguos (ZX Spectrum). Los índices 0-4 coinciden con CPC, pero 5+ mapean a colores diferentes (ej. `PaletteColor::BRIGHT_RED=5` ahora renderiza MAGENTA en CPC). `stringToColor()` también sin actualizar. `SPECTRUM_REFERENCE` en `palette_manager.cpp` sigue siendo la referencia ZX Spectrum de 16 colores. Falta decidir cómo migrar estos tres puntos cuando se vea el resultado visual. -- **`next()`/`previous()` en PaletteManager**: con una sola paleta hacen wrap al mismo índice (no crashean). El concepto de ciclar paletas queda desactivado de facto; posible futura reutilización para ciclar modos de ordenación. - -### Otros -- Añadidos `desktop.ini` y `Thumbs.db` al `.gitignore`. - -### Transiciones de pantalla (sesión abril 2026) -- **Cambio de pantalla por punto central:** `Player::handleBorders()` usa el centro del rectángulo del jugador para detectar cambio de pantalla (antes usaba bordes). -- **Conservación de momento:** `Player::switchBorders()` conserva velocidad y estado al cambiar de pantalla (antes forzaba ON_GROUND y reseteaba vy_). -- **Transición animada con scroll:** Al cambiar de habitación, ambas rooms se desplazan con easing `cubicInOut` durante 0.5s. - - Render offset global añadido a `Screen` (`setRenderOffset`) aplicado en los 6 métodos de `Surface::render()`. - - Enemigos de ambas habitaciones se actualizan durante la transición. - - El jugador puede moverse durante la transición. - - Estado en `Game`: `transitioning_`, `transition_timer_`, `transition_old_room_`, `transition_direction_`. - - Ficheros: `screen.hpp/cpp`, `surface.cpp`, `game.hpp/cpp`. - -### Impulso de salto -- `JUMP_VELOCITY` incrementado 5%: de -170.0 a -178.5. - -### Collision tilemap (sesión abril 2026) -- **Formato YAML nuevo:** `tilemap:` tiene dos sub-mapas: `draw:` (tilemap de dibujo, el original) y `collision:` (mapa de colisiones). `RoomLoader::parseTilemap()` lee ambos con fallback al formato antiguo. -- **`Room::Data::collision_tile_map`** — vector con tipos: 0=vacío, 1=muro, 2=plataforma, 3=slope_l, 4=slope_r, 5=kill, 6=conveyor. -- **CollisionMap migrado:** `getTile()` lee directamente del `collision_tile_map` (antes deducía el tipo por rangos de índice del tileset de dibujo). Constructor ya no necesita `tile_set_width`. -- **Editor de colisiones:** Tecla 7 o `EDIT DRAW`/`EDIT COLLISION` alterna entre editar el tilemap de dibujo y el de colisiones. En modo collision se superpone el `collision.gif` (7 tiles) sobre el mapa de dibujo. Right-click abre el tile picker del tileset correspondiente. `RoomSaver` guarda ambos sub-mapas. -- **`collision.gif`** registrado en `assets.yaml` (7 tiles: vacío, muro, plataforma, slope_l, slope_r, kill, conveyor). - -### Nuevo motor de colisiones tile-based (sesión abril 2026) -- **Clase `TileCollider`** (`source/game/gameplay/tile_collider.hpp/cpp`): queries directas contra el grid de tiles sin listas de superficies intermedias. API: `checkWallLeft/Right`, `checkCeiling`, `checkFloor` (con FloorHit struct), `hasGroundBelow`, `checkSlopeBelow` (con SlopeInfo struct), `getSlopeY`. -- Integrado en `CollisionMap` (miembro + getter) y expuesto via `Room::getTileCollider()`. -- **Player reescrito** con pipeline de 6 fases claras: - 1. `handleInput()` — leer input - 2. `updateVelocity()` + `applyGravity()` — calcular velocidades - 3. `handleJumpAndDrop()` — salto + drop-through (plataformas y slopes con DOWN) - 4. `moveHorizontal()` + `moveVertical()` — movimiento con colisión tile-based - 5. `checkFalling()` — detectar caída - 6. `syncSpriteAndCollider()` + `animate()` + `handleBorders()` -- **~20 métodos eliminados** del Player antiguo. Slopes gestionadas por tile (slope_tile_x/y/type) en vez de puntero a LineDiagonal. -- **Sistema antiguo de superficies preservado** en CollisionMap (no eliminado), simplemente ya no usado por Player. -- **Slopes — escalera diagonal de tiles:** - - Las slopes de 45° se pintan como escalera en el collision tilemap: cada tile una fila arriba/abajo y una columna al lado. - - `checkSlopeBelow`: escanea la fila de los pies Y la de arriba (la slope entry siempre está una fila arriba del suelo). - - `followSlope`: busca el siguiente tile de slope en la fila actual Y la de abajo (para descenso en escalera). - - `exitSlope`: comprueba suelo en `foot_y` y `foot_y+1` (boundary de fila al salir por abajo) y snapea al borde del tile. -- **Drop-through — sin flags, puramente posicional:** - - Al pulsar DOWN sobre slope/plataforma: `y_ += 1` y ON_AIR. No hay flags `dropping_through_`. - - `checkFloor` para PASSABLE: solo aterriza si `foot_y_current <= tile_top` (pies estaban por encima). - - `checkFloor` para slopes: solo aterriza si `foot_y_current <= slope_y` (pies por encima de la superficie). - - `isInsideAnySlope()`: si algún pie está por debajo de la superficie de cualquier slope que solape, bloquea TODOS los aterrizajes en slopes. Esto asegura que al hacer drop o saltar desde abajo, el jugador atraviesa toda la escalera de slopes sin quedarse pegado. -- **Kill tiles (tipo 5):** implementados en `TileCollider::touchesKillTile()`. Comprueba si el rectángulo del jugador solapa algún tile KILL. Se llama en `Player::update()` después del movimiento. -- **Motor antiguo eliminado:** - - `CollisionMap` reducido a wrapper mínimo: solo contiene `collision_tile_map_`, `conveyor_belt_direction_` y `TileCollider`. - - Eliminados de `CollisionMap`: enum `Tile` antiguo, `getTile()`, `getSlopeHeight()`, todas las listas de superficies (`bottom_floors_`, `top_floors_`, etc.), todos los `check*Surfaces()`, `initializeSurfaces()`, `collect*Tiles()`, `buildHorizontalLines()`, `set*Surfaces()`. - - Eliminados de `Room`: enum `Tile`, `getTile()`, `getSlopeHeight()`, `getTileSize()`, todos los `check*()` delegados, `getSlopeAtPoint()`. - - Eliminados de `utils.hpp/cpp`: structs `LineHorizontal`, `LineVertical`, `LineDiagonal`, `Line` y todos los `checkCollision` / `normalizeLine` que los usaban. - - `TilemapRenderer`: eliminado `renderDebugCollisionSurfaces()` (pintaba líneas de superficies). Modo debug (tecla 0) ahora renderiza el collision tilemap usando `collision.gif`. - - `TilemapRenderer::setAnimatedTiles()` ahora lee del `collision_tile_map` (valor 6 = conveyor) en vez de `CollisionMap::getTile()`. -- **Pendiente:** tile 6 (conveyor) no soportado aún en el nuevo motor de Player. - -### Otros -- Añadidos `desktop.ini` y `Thumbs.db` al `.gitignore`. +- **PaletteColor enum** en `utils.hpp` sigue con los 16 índices antiguos (ZX Spectrum). Los índices 0-4 coinciden con CPC, pero 5+ mapean a colores diferentes (ej. `PaletteColor::BRIGHT_RED=5` ahora renderiza MAGENTA en CPC). `stringToColor()` y `SPECTRUM_REFERENCE` en `palette_manager.cpp` tampoco están actualizados. Falta decidir cómo migrar cuando se vea el resultado visual. +- **Tile 6 (conveyor)** no soportado aún en el nuevo motor de Player. +- **`next()`/`previous()` en PaletteManager** desactivados de facto (solo 1 paleta). Posible futura reutilización para ciclar modos de ordenación. --- -## Overview (legacy) +## Overview **Projecte 2026** is a retro-style 2D puzzle platformer game built in C++20 using SDL3 for graphics and audio. The game features 60+ rooms, collectible items, enemies, and an achievement system. It targets multiple platforms (Windows, macOS, Linux) with a focus on retro aesthetics and precise collision detection. @@ -190,11 +115,13 @@ xvfb-run -a -s "-screen 0 1280x720x24" ./projecte_2026 - Debugging startup issues - Verifying configuration changes -### Static Analysis Tools (Linters) +--- + +## Static Analysis Tools (Linters) This project uses two complementary static analysis tools for code quality: -#### clang-tidy (Modernization & Best Practices) +### clang-tidy (Modernization & Best Practices) **Purpose:** Detects style issues, modernization opportunities, and potential bugs. Best for refactoring and applying C++20 best practices. @@ -214,18 +141,11 @@ tools/linter/run_clang-tidy.sh --fix source/game/entities/player.cpp tools/linter/run_clang-tidy.sh ``` -**Common clang-tidy Checks:** -- `modernize-*`: C++ modernization (use auto, range-for, etc.) -- `readability-*`: Code readability improvements -- `performance-*`: Performance optimizations -- `bugprone-*`: Potential bug detection - **Known False Positives:** - `defaults.hpp`: May report errors in constant definitions -- `readability-magic-numbers`: Acceptable for game constants (block sizes, speeds, etc.) -- `cppcoreguidelines-avoid-magic-numbers`: Same as above, acceptable in game code +- `readability-magic-numbers` / `cppcoreguidelines-avoid-magic-numbers`: Acceptable for game constants (block sizes, speeds, etc.) -#### cppcheck (Bug Detection & Memory Safety) +### cppcheck (Bug Detection & Memory Safety) **Purpose:** Detects bugs, memory leaks, undefined behavior, and style issues. Complementary to clang-tidy. @@ -245,19 +165,12 @@ tools/linter/run_cppcheck.sh -w **Output:** Results are saved in `tools/linter/cppcheck-result-*.txt` -**Common cppcheck Checks:** -- Memory leaks and resource management -- Null pointer dereferences -- Buffer overflows and array bounds -- Uninitialized variables -- Dead code and unused functions - **Known False Positives:** - `unusedFunction`: May report false positives for callback functions or public API methods - `passedByValue`: Acceptable for small types like SDL_FRect in game code - `constParameter`: Not always applicable for API consistency -#### When to Use Each Tool +### When to Use Each Tool | Scenario | Tool | Reason | |----------|------|--------| @@ -267,16 +180,7 @@ tools/linter/run_cppcheck.sh -w | **Hunting memory leaks** | cppcheck | Specialized detection | | **Code modernization** | clang-tidy --fix | Automatic C++20 upgrades | -#### Best Practices - -1. **Run linters after compilation succeeds** - Fix compile errors first -2. **Analyze specific files** - Faster feedback, avoids unrelated errors -3. **Review before applying --fix** - Understand changes before accepting -4. **Context matters** - Game code may legitimately have "magic numbers" for gameplay constants -5. **Use both tools** - They catch different issues and complement each other -6. **Check suppressions file** - `tools/linter/cppcheck_suppressions` excludes external/ and system headers - -#### Integration with Development Workflow +### Integration with Development Workflow When refactoring code (especially with `/refactor-class` command): 1. Make structural changes @@ -291,813 +195,7 @@ When refactoring code (especially with `/refactor-class` command): --- -## 1. High-Level Architecture Overview - -The architecture follows a **layered, modular design** with clear separation of concerns: - -``` -┌─────────────────────────────────────┐ -│ Application Layer │ -│ (Director, Scene Manager) │ -└─────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────┐ -│ Game Logic Layer │ -│ (Game Scene, Entities, Gameplay) │ -└─────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────┐ -│ Core Systems Layer │ -│ (Rendering, Audio, Input, Resources)│ -└─────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────┐ -│ SDL3 & External Libraries │ -│ (jail_audio, stb_image, stb_vorbis) │ -└─────────────────────────────────────┘ -``` - -### Key Design Principles - -- **Singleton Pattern:** Core systems (Director, Screen, Audio, Input, Resource, Asset) use singleton pattern for global access -- **Scene-Based Architecture:** Game flow managed through discrete scenes (Logo, Title, Loading, Game, Ending, etc.) -- **Component-Based Entities:** Player, enemies, and items are discrete entities with render/update patterns -- **Resource Management:** All assets (textures, sounds, animations, tilemaps) cached through Resource singleton -- **Delta Time:** Frame-rate independent physics using DeltaTimer class - ---- - -## 2. Directory Structure - -``` -source/ -├── core/ # Core engine systems -│ ├── audio/ # Audio management -│ │ ├── audio.hpp/cpp # Audio singleton (music, sounds, volumes) -│ │ └── jail_audio.hpp # Custom jail_audio library wrapper -│ ├── input/ # Input handling -│ │ ├── input.hpp/cpp # Input manager (keyboard, gamepad) -│ │ ├── input_types.hpp # Input type definitions -│ │ ├── global_inputs.hpp # Global input state -│ │ └── mouse.hpp # Mouse input -│ ├── locale/ # Localization -│ │ └── locale.hpp # Locale/language support -│ ├── rendering/ # Graphics rendering -│ │ ├── screen.hpp/cpp # Screen/window singleton, SDL renderer -│ │ ├── surface.hpp/cpp # 8-bit indexed color surface abstraction -│ │ ├── sprite/ # Sprite rendering classes -│ │ │ ├── sprite.hpp # Static sprite rendering -│ │ │ ├── animated_sprite.hpp # Animated sprite with frame data -│ │ │ ├── moving_sprite.hpp # Moving sprite with velocity -│ │ │ └── dissolve_sprite.hpp # Dissolve transition sprite -│ │ ├── text.hpp/cpp # Text rendering system -│ │ ├── gif.hpp/cpp # GIF image loader -│ │ ├── pixel_reveal.hpp # Pixel reveal effect -│ │ ├── render_info.hpp # Render information data -│ │ ├── palette_manager.hpp # Palette management -│ │ ├── sdl3gpu/ # SDL3 GPU shader backend -│ │ │ ├── sdl3gpu_shader.hpp/cpp # CRT/post-processing shader effects -│ │ │ └── *_spv.h # Pre-compiled SPIR-V shader headers -│ │ └── shader_backend.hpp # Abstract shader interface -│ ├── resources/ # Asset & Resource management -│ │ ├── resource_list.hpp # Asset path registry (O(1) lookups) -│ │ ├── resource_cache.hpp # Resource caching singleton -│ │ ├── resource_loader.hpp # Asset loading logic -│ │ ├── resource_pack.hpp # Resource pack handling -│ │ ├── resource_helper.hpp # Resource utility functions -│ │ └── resource_types.hpp # Resource type definitions -│ └── system/ # System management -│ ├── director.hpp/cpp # Main application controller -│ ├── debug.hpp/cpp # Debug info overlay -│ └── global_events.hpp/cpp # Global event broadcasting -├── game/ # Game-specific logic -│ ├── entities/ # Game objects -│ │ ├── player.hpp/cpp # Player entity with physics -│ │ ├── enemy.hpp/cpp # Enemy entities -│ │ └── item.hpp/cpp # Collectible items -│ ├── gameplay/ # Core gameplay systems -│ │ ├── room.hpp/cpp # Room/level logic, collision -│ │ ├── room_loader.hpp/cpp # Room loading from YAML files -│ │ ├── room_tracker.hpp/cpp # Tracks visited rooms -│ │ ├── collision_map.hpp/cpp # Collision map data -│ │ ├── tilemap_renderer.hpp/cpp # Tilemap rendering -│ │ ├── enemy_manager.hpp/cpp # Enemy lifecycle management -│ │ ├── item_manager.hpp/cpp # Item lifecycle management -│ │ ├── scoreboard.hpp/cpp # Score display & data -│ │ ├── item_tracker.hpp/cpp # Tracks collected items -│ │ └── cheevos.hpp/cpp # Achievement system -│ ├── scenes/ # Game scenes (flow states) -│ │ ├── logo.hpp/cpp # JailGames logo screen -│ │ ├── loading_screen.hpp/cpp # Resource loading progress -│ │ ├── title.hpp/cpp # Title screen & menus -│ │ ├── game.hpp/cpp # Main gameplay loop -│ │ ├── game_over.hpp/cpp # Game over screen -│ │ ├── ending.hpp/cpp # Ending sequence 1 -│ │ ├── ending2.hpp/cpp # Ending sequence 2 -│ │ └── credits.hpp/cpp # Credits screen -│ ├── ui/ # User interface -│ │ ├── notifier.hpp/cpp # Achievement/notification display -│ │ ├── console.hpp/cpp # In-game debug console -│ │ └── console_commands.hpp/cpp # Console command definitions -│ ├── options.hpp/cpp # Game configuration/options -│ ├── game_control.hpp # Game control logic -│ ├── scene_manager.hpp # Scene flow state machine -│ └── defaults.hpp # Game defaults constants -├── external/ # Third-party libraries -│ ├── fkyaml_node.hpp # YAML parsing library -│ ├── stb_image.h # Image loading library -│ └── stb_vorbis.h # OGG Vorbis audio decoding -├── utils/ # Utility code -│ ├── delta_timer.hpp/cpp # Frame-rate independent timing -│ ├── easing_functions.hpp # Easing/interpolation functions -│ ├── defines.hpp # Game constants (resolutions, block sizes) -│ └── utils.hpp/cpp # Helper functions (colors, math) -└── main.cpp # Application entry point - -config/ # Configuration files -└── assets.yaml # Asset registry (text-based configuration) - -data/ # Game assets -├── font/ # Bitmap fonts + descriptors -├── palette/ # Color palettes (.pal files) -├── shaders/ # GLSL vertex/fragment shaders -├── room/ # Tilemaps & room definitions (01.tmx-60.tmx) -├── tilesets/ # Tileset graphics -├── enemies/ # Enemy sprites & animations -├── player/ # Player sprites & animations -├── items/ # Item sprite sheets -├── music/ # Background music (OGG) -├── sound/ # Sound effects (WAV) -├── logo/ # Logo images -├── loading/ # Loading screen graphics -├── title/ # Title screen graphics -├── ending/ # Ending sequence images -└── credits/ # Credits screen assets -``` - ---- - -## 3. Key Architectural Patterns - -### 3.1 Singleton Pattern (Core Systems) - -Most core systems use thread-safe singleton pattern: - -```cpp -class Screen { - private: - static Screen* screen_; // Singleton instance - Screen(); // Private constructor - ~Screen(); - public: - static void init(); // Creates singleton - static void destroy(); // Destroys singleton - static Screen* get(); // Accesses singleton -}; -``` - -**Singleton Systems:** -- `Screen` - Rendering, window management, palette/shader effects -- `Input` - Keyboard & gamepad input binding and checking -- `Audio` - Music and sound effect playback -- `Resource::Cache` - Asset loading, caching, streaming (with error handling) -- `Resource::List` - Asset path registry from assets.yaml (O(1) lookups) -- `Director` - Main application controller -- `Cheevos` - Achievement state management -- `Debug` - Debug information overlay - -### 3.2 Scene-Based State Machine - -The game uses a scene manager to control application flow: - -```cpp -// namespace SceneManager -enum class Scene { - LOGO, LOADING_SCREEN, TITLE, CREDITS, GAME, DEMO, - GAME_OVER, ENDING, ENDING2, RESTART_CURRENT, QUIT -}; - -inline Scene current = Scene::LOGO; // Global scene state -inline Options options = ...; // Transition options -``` - -**Scene Hierarchy:** -- Each scene runs its own update/render loop -- `Director` switches between scenes based on `SceneManager::current` -- Scenes can request transitions via `SceneManager::current` assignment - -### 3.3 Entity-Component Pattern (Simplified) - -Entities (Player, Enemies, Items) have: -- **Update** - Logic, physics, animation -- **Render** - Draw to screen surface -- **Collision** - Hit detection (player collides with room, enemies, items) - -### 3.4 Surface-Based Rendering Pipeline - -The rendering system uses a **8-bit indexed color** pipeline: - -``` -SurfaceData (pixel buffer) - ↓ -Surface (palette + rendering operations) - ↓ -SDL_Texture (GPU texture) - ↓ -SDL_Renderer (to SDL_Window) - ↓ -Display -``` - -**Key Components:** -- `Surface` - 8-bit indexed pixel buffer with palette support -- `Sprite` - Renders a fixed region of a surface -- `AnimatedSprite` - Frame-based animation on top of sprite -- `MovingSprite` - Adds velocity/position to animated sprite -- `DissolveSprite` - Dissolve transition effect sprite -- Supports color replacement, palette swapping, and shader effects (CRT) - -### 3.5 Tile-Based Collision System - -Rooms use a sophisticated collision detection system: - -```cpp -class Room { - std::vector bottom_floors_; // Ground surfaces - std::vector top_floors_; // Ceiling surfaces - std::vector left_walls_; // Left walls - std::vector right_walls_; // Right walls - std::vector left_slopes_; // Ramps going left - std::vector right_slopes_; // Ramps going right - std::vector conveyor_belt_floors_; // Moving platforms -}; -``` - -**Collision Detection:** -- Player has collision points and "feet" points for fine-grained detection -- Room provides `check*Surfaces()` methods for collision resolution -- Supports ramps, slopes, conveyor belts, and auto-surfaces -- Enemies have axis-aligned bounding boxes - -### 3.6 Sprite Animation System - -Animation is data-driven: - -```cpp -struct AnimationData { - std::string name; - std::vector frames; // Frame rectangles - int speed; // Milliseconds per frame - int loop; // Frame to return to (-1 = no loop) - bool completed; - int current_frame; - int counter; -}; - -// Loaded from .yaml animation definition files -// Rendered with AnimatedSprite -``` - ---- - -## 4. System Interactions & Data Flow - -### 4.1 Application Lifecycle - -``` -main() - ↓ -Director::Director() [Initialization] - ├─ Resource::List::init() - Initialize asset registry singleton - ├─ Director::setFileList() - Load assets.yaml via Resource::List (no verification) - ├─ Options::loadFromFile() - Load game configuration - ├─ Audio::init() - Initialize SDL audio - ├─ Screen::init() - Create window, SDL renderer - ├─ Input::init() - Bind keyboard/gamepad controls - ├─ Resource::Cache::init() - Load ALL game resources (with verification) - │ └─ Throws exception if any required asset is missing - └─ Cheevos::init() - Load achievement state - -Director::run() [Main loop] - ├─ while (SceneManager::current != QUIT) - │ ├─ Logo::run() - │ ├─ LoadingScreen::run() - │ ├─ Title::run() - │ ├─ Game::run() - │ ├─ Ending::run() - │ └─ ... - └─ return 0 - -Director::~Director() [Cleanup] - ├─ Options::saveToFile() - Save game settings - ├─ Resource::Cache::destroy() - ├─ Audio::destroy() - ├─ Input::destroy() - ├─ Screen::destroy() - └─ Resource::List::destroy() -``` - -### 4.2 Game Scene Flow (Core Gameplay Loop) - -```cpp -Game::run() { - while (game is running) { - // Update - Input::checkInput() - Get player commands - Player::update() - Physics, animation, collision - Room::update() - Enemy AI, animated tiles - checkCollisions() - Player vs enemies, items, room - checkGameOver() - Win/lose conditions - - // Render - Screen::start() - Prepare for drawing - Room::renderMap() - Draw tilemap - Room::renderEnemies() - Draw enemy sprites - Room::renderItems() - Draw item sprites - Player::render() - Draw player sprite - renderScoreboard() - Draw HUD - Screen::render() - Flush to GPU - } -} -``` - -### 4.3 Resource Loading & Caching - -``` -Director::setFileList() - └─ Resource::List::loadFromFile(config_path, PREFIX, system_folder_) - ├─ Read config/assets.yaml - Parse text configuration file - ├─ Parse YAML structure: assets grouped by category - ├─ Replace variables (${PREFIX}, ${SYSTEM_FOLDER}) - └─ Store in unordered_map (O(1) lookup) - Fast asset path retrieval - -Game Scene initialization - └─ Resource::Cache::init() - Loads all resources - ├─ loadSounds() - WAV files (with error handling) - ├─ loadMusics() - OGG files (with error handling) - ├─ loadSurfaces() - GIF/PNG images (with error handling) - ├─ loadPalettes() - PAL palette files (with error handling) - ├─ loadTextFiles() - Font definition files (with error handling) - ├─ loadAnimations() - YAML animation definitions (with error handling) - └─ loadRooms() - Room YAML files (with error handling) - - Note: Asset verification happens during actual loading. - If a required file is missing, Cache::load() throws detailed exception. - -During gameplay - └─ Resource::Cache::get*(name) - Return cached resource -``` - -### 4.4 Input Flow - -``` -SDL_Event (from OS) - ↓ -Input::checkInput(action) - ├─ Check keyboard bindings - SDL_Scancode → InputAction - ├─ Check gamepad bindings - SDL_GamepadButton → InputAction - └─ Return true if action active - -Game logic uses checked inputs - └─ Player responds to actions -``` - -### 4.5 Audio Control Flow - -``` -Game code - ├─ Audio::playMusic(name, loop) - ├─ Audio::playSound(name, group) - └─ Audio::stopMusic() - ↓ - Audio [wrapper/manager] - ├─ Resource::getMusic(name) - ├─ Resource::getSound(name) - └─ jail_audio C library - └─ SDL3 Audio device -``` - ---- - -## 5. Important Design Patterns & Conventions - -### 5.1 Naming Conventions - -**Classes:** -- `PascalCase` for classes: `Player`, `Room`, `Screen`, `Director` -- Suffix `Sprite` for sprite classes: `Sprite`, `AnimatedSprite`, `MovingSprite` - -**Methods:** -- `get*()` for getters: `getWidth()`, `getRect()` -- `set*()` for setters: `setColor()`, `setPos()` -- `check*()` for boolean checks: `checkInput()`, `checkCollision()` -- `update()` for game logic updates -- `render()` for drawing - -**Variables:** -- `snake_case` for member variables with `_` suffix: `x_`, `y_`, `sprite_` -- `UPPER_CASE` for constants: `BLOCK`, `MAX_VY`, `WIDTH` -- Private members: `private_member_` - -**Structs for Data:** -- `XxxData` suffix: `PlayerData`, `RoomData`, `AnimationData` -- Used as initialization structures passed to constructors - -### 5.2 Memory Management - -- **Smart Pointers:** Uses `std::shared_ptr` for shared ownership (Surfaces, Sprites, Rooms) -- **Unique Pointers:** Uses `std::unique_ptr` for sole ownership (Director, local objects) -- **Raw Pointers:** Minimal use, mainly for singleton access or SDL objects -- **Static Allocation:** Singletons use static pointer pattern for RAII - -### 5.3 Frame-Independent Physics - -Uses `DeltaTimer` for delta time calculation: - -```cpp -// In game loop -float delta = deltaTimer.tick(); // Get seconds since last frame - -// Apply to physics -player.vy_ += gravity * delta; -player.y_ += player.vy_ * delta; -``` - -Provides **time scaling** for slow-motion effects. - -### 5.4 Palette System - -- 8-bit indexed color (256 colors per palette) -- Multiple palettes can be loaded and swapped via `PaletteManager` -- `Screen::setPaletteByName()` changes the active palette -- Supports palette sort modes (by luminosity, similarity to Spectrum palette, etc.) -- Supports color replacement per-render: `renderWithColorReplace()` -- CRT shader effects can modify colors in real-time - -### 5.5 Configuration System - -Game settings stored in configuration file: - -```cpp -namespace Options { - inline Video video{}; // Screen resolution, fullscreen, etc. - inline Audio audio{}; // Music/sound volumes - inline Notification notifications{}; - inline Cheat cheats{}; // Cheat codes - inline ControlScheme keys{}; // Control mapping -} - -Options::loadFromFile(path); // Load from config.yaml -Options::saveToFile(path); // Save on exit -``` - -### 5.6 Achievement System - -```cpp -struct Achievement { - int id; - std::string caption; - std::string description; - int icon; - bool completed; - bool obtainable; -}; - -Cheevos::unlock(id); // Unlock achievement -Cheevos::setUnobtainable(id); // Lock achievement -Cheevos::saveToFile(); // Persist state -``` - -Achievements trigger notifications on unlock. - ---- - -## 6. Technology Stack - -### Core Technologies - -| Component | Technology | Version | Role | -|-----------|-----------|---------|------| -| **Graphics** | SDL3 | Latest | Window, rendering, input | -| **GPU Rendering** | SDL3 GPU | Latest | Shader effects (CRT, post-processing via SPIR-V) | -| **Audio** | SDL3 Audio | Latest | Audio device, mixing | -| **Audio Decoding** | jail_audio (custom) | 1.x | OGG/WAV playback | -| **Image Loading** | stb_image | v2.x | PNG/GIF image loading | -| **Audio Decoding** | stb_vorbis | v1.x | OGG Vorbis support | -| **Language** | C++ | C++20 | Standard library features | -| **Build System** | CMake | 3.10+ | Cross-platform building | - -### C++ Features Used - -- **Smart Pointers:** `std::shared_ptr`, `std::unique_ptr` -- **Standard Containers:** `std::vector`, `std::array` -- **Modern Features:** `std::move`, lambda functions, constexpr -- **Namespaces:** Extensive use for organization -- **Inline Variables:** C++17 `inline` for global game state - -### Platform Support - -- **Windows:** MinGW/MSVC with SDL3 -- **macOS:** Apple Clang, arm64 architecture, OpenGL -- **Linux:** GCC with SDL3 and OpenGL - ---- - -## 7. Key Classes & Their Responsibilities - -### Core System Classes - -| Class | Purpose | Pattern | -|-------|---------|---------| -| `Director` | Main application controller, scene manager | Singleton | -| `Screen` | Rendering, window, palette management | Singleton | -| `Input` | Keyboard & gamepad input | Singleton | -| `Audio` | Music and SFX playback | Singleton | -| `Resource::Cache` | Asset caching and loading (with detailed error messages) | Singleton | -| `Resource::List` | Asset path registry from config/assets.yaml, O(1) lookups, variable substitution | Singleton | -| `PaletteManager` | Palette loading, switching, and sorting | Managed by Screen | -| `Debug` | Debug overlay information | Singleton | -| `globalEvents` | Global SDL event handling (quit, device reset, mouse) | Namespace | - -### Game Logic Classes - -| Class | Purpose | -|-------|---------| -| `Game` | Main gameplay scene, orchestrates update/render | -| `Player` | Player entity with physics and animation | -| `Room` | Level data, collision detection | -| `RoomLoader` | Room loading from YAML files | -| `TilemapRenderer` | Tilemap rendering | -| `CollisionMap` | Collision map data | -| `EnemyManager` | Enemy lifecycle management | -| `ItemManager` | Item lifecycle management | -| `Enemy` | Enemy entity behavior and rendering | -| `Item` | Collectible items | -| `Scoreboard` | HUD display data | -| `Cheevos` | Achievement unlock and state | -| `ItemTracker` | Tracks collected items | -| `RoomTracker` | Tracks visited rooms | - -### Rendering Classes - -| Class | Purpose | -|-------|---------| -| `Surface` | 8-bit indexed color pixel buffer with palette | -| `Sprite` | Renders a sprite region | -| `AnimatedSprite` | Frame-based animation rendering | -| `MovingSprite` | Sprite with velocity/position | -| `DissolveSprite` | Dissolve transition sprite | -| `Text` | Text rendering system | -| `Sdl3gpuShader` | SDL3 GPU shader compilation and effects | -| `PaletteManager` | Palette loading and management | - -### Utility Classes - -| Class/Header | Purpose | -|-------|---------| -| `DeltaTimer` | Frame-rate independent timing | -| `easing_functions.hpp` | Easing/interpolation functions for animations | - ---- - -## 8. Common Development Workflows - -### Adding a New Input Action - -1. Add to `InputAction` enum in `core/input/input.hpp` -2. Bind in `Director::initInput()`: - ```cpp - Input::get()->bindKey(InputAction::NEW_ACTION, SDL_SCANCODE_X); - ``` -3. Check in game code: - ```cpp - if (Input::get()->checkInput(InputAction::NEW_ACTION)) { - // Handle action - } - ``` - -### Adding a New Scene - -1. Create class inheriting appropriate base (usually standalone `run()` method) -2. Add to `SceneManager::Scene` enum -3. Implement in `Director::run()` switch statement -4. Set `SceneManager::current` to transition - -### Adding Game Assets - -1. Place file in `data/` directory -2. Add entry to `config/assets.yaml` under the appropriate category: - ```yaml - assets: - category_name: # e.g., player, enemies, music, etc. - - type: BITMAP - path: ${PREFIX}/data/path/file.ext - ``` - Available types: `DATA`, `BITMAP`, `ANIMATION`, `MUSIC`, `SOUND`, `FONT`, `ROOM`, `PALETTE` -3. Optional flags can be added: - ```yaml - - type: DATA - path: ${SYSTEM_FOLDER}/file.txt - required: false # Don't fail if missing - absolute: true # Path is absolute - ``` -4. Resource loads automatically during `Resource::init()` -5. Access via: `Resource::Cache::get()->getSurface("name")` - -**Note:** No recompilation needed when adding/removing/modifying assets in `config/assets.yaml` - -### Modifying Collision Detection - -1. Update `Room::setBottomSurfaces()`, `setLeftSlopes()`, etc. -2. Modify Player collision point generation in `Player::updateColliderPoints()` -3. Adjust tile classification in `TileType` enum -4. Test with debug visualization (F12 key) - ---- - -## 9. Debug Features - -### Available at Runtime - -- **F12** - Toggle debug info overlay (FPS, player position, collision points) -- **F1/F2** - Decrease/increase window zoom -- **F3** - Toggle fullscreen mode -- **F4** - Toggle shader effects -- **F5/F6** - Next/previous palette -- **F7** - Toggle integer scaling -- **M** - Toggle music -- **B** - Toggle border display -- **P** - Pause game - -### Debug Mode Compilation - -In debug builds (`#ifdef DEBUG`), renders: -- Player collision boxes -- Collision point visualization -- Debug information overlay -- Special debug event handling - ---- - -## 10. Performance Considerations - -### Optimization Points - -1. **Rendering:** Uses indexed color (8-bit) to reduce memory bandwidth -2. **Surfaces:** Shared smart pointers reduce copying -3. **Collision:** Pre-computed tile surface lists avoid per-frame searches -4. **Animation:** Frame-based animation reduces computation vs. bone systems -5. **Audio:** Cached music and sound effects, no runtime decoding -6. **Delta Time:** Frame-rate independent logic for smooth gameplay - -### Known Limitations - -- Single-threaded architecture (SDL3 requires single-thread rendering) -- Surfaces stored entirely in CPU memory (not GPU-side textures) -- Palette system requires full surface redraw when changing colors - ---- - -## 11. File Format Reference - -### Asset Configuration File (config/assets.yaml) -YAML-based asset registry with grouped structure: -```yaml -# Projecte 2026 - Asset Configuration -# Variables: ${PREFIX}, ${SYSTEM_FOLDER} - -assets: - # FONTS - fonts: - - type: BITMAP - path: ${PREFIX}/data/font/smb2.gif - - type: FONT - path: ${PREFIX}/data/font/smb2.fnt - - # PLAYER - player: - - type: BITMAP - path: ${PREFIX}/data/player/player.gif - - type: ANIMATION - path: ${PREFIX}/data/player/player.yaml - - # MUSIC - music: - - type: MUSIC - path: ${PREFIX}/data/music/title.ogg - - # SYSTEM FILES (optional, absolute paths) - system: - - type: DATA - path: ${SYSTEM_FOLDER}/config.yaml - required: false - absolute: true -``` - -**Asset Structure:** -- Assets are organized into categories (fonts, palettes, shaders, player, enemies, etc.) -- Each asset entry contains: - - `type` - Asset type (required) - - `path` - File path with variable substitution (required) - - `required` - Whether file must exist (optional, default: `true`) - - `absolute` - Whether path is absolute (optional, default: `false`) - -**Available Asset Types:** -- `DATA` - General data files (text, JSON, etc.) -- `BITMAP` - Images (GIF, PNG) -- `ANIMATION` - Animation definition files (.yaml) -- `MUSIC` - Music files (OGG) -- `SOUND` - Sound effects (WAV) -- `FONT` - Font definition files -- `ROOM` - Room data files (.yaml) -- `PALETTE` - Color palette files (.pal) - -**Variables:** -- `${PREFIX}` - Replaced with `/../Resources` on macOS bundles, empty otherwise -- `${SYSTEM_FOLDER}` - Replaced with user's system config folder - -### Animation Files (.yaml) -YAML-based animation definitions with frame data: -```yaml -animations: - - name: default - frameWidth: 16 - frameHeight: 16 - speed: 100 - loop: 0 - frames: [...] -``` - -### Room Data Files (.yaml) -YAML-based room definitions: -```yaml -room: - name_en: Starting Room - bgColor: 0x000000 - connections: [...] - tilemap: [...] -``` - -### Tilemap Files (.tmx) -Tiled map format with tileset and collision data. - -### Palette Files (.pal) -Binary 256-color palette format (256 × 4 bytes RGBA). - ---- - -## 12. Quick Reference: Main Entry Points - -### For Graphics Issues -- `Screen::render()` - Main rendering method -- `Screen::setPaletteByName()` - Palette switching -- `PaletteManager` - Palette loading and sorting -- `Surface` class - Pixel buffer operations - -### For Input Issues -- `Input::checkInput()` - Input state checking -- `Director::initInput()` - Binding configuration - -### For Audio Issues -- `Audio::playMusic()` - Music playback -- `Audio::playSound()` - SFX playback -- `jail_audio` library - Low-level audio operations - -### For Game Logic -- `Game::run()` - Main game loop -- `Room` class - Collision and level logic -- `Player::update()` - Physics and movement - -### For Asset Management -- `config/assets.yaml` - Asset configuration file (text-based, no recompilation needed) -- `Resource::List::loadFromFile()` - Loads asset registry from config file -- `Resource::List::get()` - Retrieves asset path (O(1) lookup with unordered_map) -- `Resource::Cache` - Asset loading and caching -- `Director::setFileList()` - Calls `Resource::List::loadFromFile()` with PREFIX and system_folder - ---- - -## 13. Future Enhancement Points - -### Identified Areas for Expansion - -1. **More Scenes:** Additional game modes -3. **Custom Rooms:** Level editor integration -4. **Audio Streaming:** Background music without loading entire file -5. **Particle System:** Visual effects for pickups/collisions -6. **Controller Feedback:** Haptic feedback for game events -7. **Accessibility:** Font scaling, color-blind modes, key remapping UI - ---- - -## Development Notes - -- **Language:** All code comments and some variable names are in Spanish (maintaining original author style) -- **Compilation:** Use CMake - automatically handles platform differences -- **Performance Profiling:** Use debug overlay (F12) for basic metrics; consider external profilers for deeper analysis -- **Common Warnings:** The codebase has been cleaned of the `struct`/`class` forward declaration inconsistency warnings that previously appeared - -### Important Code Consistency Rules +## Important Code Consistency Rules 1. **Forward Declarations:** Always use `class` for forward declarations of classes defined with `class` (not `struct`). The `Surface` class is defined as `class Surface` in `surface.hpp:57`, so all forward declarations must use `class Surface;` diff --git a/data/locale/ca.yaml b/data/locale/ca.yaml index e06ebc0..2d8f1e3 100644 --- a/data/locale/ca.yaml +++ b/data/locale/ca.yaml @@ -7,7 +7,6 @@ title: play: "1. JUGAR" keyboard: "2. REDEFINIR TECLES" joystick: "3. REDEFINIR MANDO" - projects: "4. PROJECTES" keys: prompt0: "PREM UNA TECLA PER A ESQUERRA" prompt1: "PREM UNA TECLA PER A DRETA" @@ -24,7 +23,6 @@ title: prompt2: "PREM UN BOTÓ PER A SALTAR" defined: "BOTONS DEFINITS" already_used: "BOTÓ JA USAT! PROVA'N UN ALTRE" - projects: "PROJECTES" game_over: title: "G A M E O V E R" @@ -74,30 +72,6 @@ credits: achievements: header: "ASSOLIMENT DESBLOQUEJAT!" - c1: "COSES BRILLANTS" - d1: "Aconseguiu el 25% dels objectes" - c2: "A MITJAN CAMÍ" - d2: "Aconseguiu el 50% dels objectes" - c3: "QUASI HI SOM" - d3: "Aconseguiu el 75% dels objectes" - c4: "EL COL·LECCIONISTA" - d4: "Aconseguiu el 100% dels objectes" - c5: "PASSEJANT PER ACÍ" - d5: "Visiteu 20 sales" - c6: "M'HE PERDUT" - d6: "Visiteu 40 sales" - c7: "M'AGRADA EXPLORAR" - d7: "Visiteu totes les sales" - c8: "JA ESTÀ?" - d8: "Completeu el joc" - c9: "UN FORAT EM VA ENGOLIR" - d9: "Completeu el joc sense entrar a la presó" - c10: "ELS MEUS PROJECTES" - d10: "Completeu el joc amb tots els objectes" - c11: "M'AGRADEN ELS MEUS AMICS DE COLORS" - d11: "Completeu el joc sense morir" - c12: "PROJECTES A CORRE-CUITA" - d12: "Completeu el joc en menys de 30 minuts" ui: press_again_menu: "PREM DE NOU PER TORNAR AL MENÚ" diff --git a/data/locale/en.yaml b/data/locale/en.yaml index 66286ed..ba10b4c 100644 --- a/data/locale/en.yaml +++ b/data/locale/en.yaml @@ -7,7 +7,6 @@ title: play: "1. PLAY" keyboard: "2. REDEFINE KEYBOARD" joystick: "3. REDEFINE JOYSTICK" - projects: "4. PROJECTS" keys: prompt0: "PRESS KEY FOR LEFT" prompt1: "PRESS KEY FOR RIGHT" @@ -24,7 +23,6 @@ title: prompt2: "PRESS BUTTON FOR JUMP" defined: "BUTTONS DEFINED" already_used: "BUTTON ALREADY USED! TRY ANOTHER" - projects: "PROJECTS" game_over: title: "G A M E O V E R" @@ -74,30 +72,6 @@ credits: achievements: header: "ACHIEVEMENT UNLOCKED!" - c1: "SHINY THINGS" - d1: "Get 25% of the items" - c2: "HALF THE WORK" - d2: "Get 50% of the items" - c3: "GETTING THERE" - d3: "Get 75% of the items" - c4: "THE COLLECTOR" - d4: "Get 100% of the items" - c5: "WANDERING AROUND" - d5: "Visit 20 rooms" - c6: "I GOT LOST" - d6: "Visit 40 rooms" - c7: "I LIKE TO EXPLORE" - d7: "Visit all rooms" - c8: "FINISH THE GAME" - d8: "Complete the game" - c9: "I WAS SUCKED BY A HOLE" - d9: "Complete the game without entering the jail" - c10: "MY LITTLE PROJECTS" - d10: "Complete the game with all items" - c11: "I LIKE MY MULTICOLOURED FRIENDS" - d11: "Complete the game without dying" - c12: "SHIT PROJECTS DONE FAST" - d12: "Complete the game in under 30 minutes" ui: press_again_menu: "PRESS AGAIN TO RETURN TO MENU" diff --git a/source/game/defaults.hpp b/source/game/defaults.hpp index c412c00..0ee202f 100644 --- a/source/game/defaults.hpp +++ b/source/game/defaults.hpp @@ -60,7 +60,6 @@ namespace Defaults::Sound { namespace Defaults::Cheat { constexpr bool INFINITE_LIVES = false; // Vidas infinitas desactivadas por defecto constexpr bool INVINCIBLE = false; // Invencibilidad desactivada por defecto - constexpr bool JAIL_IS_OPEN = false; // Jail abierta desactivada por defecto } // namespace Defaults::Cheat namespace Defaults::Stats { @@ -88,13 +87,8 @@ namespace Defaults::Localization { constexpr const char* LANGUAGE = "ca"; // Idioma por defecto (en = inglés, ca = catalán) } // namespace Defaults::Localization -namespace Defaults::Game::Items { - constexpr const float PERCENT_TO_OPEN_THE_JAIL = 0.9F; // Porcentaje de items necesarios para abrir la jail -} // namespace Defaults::Game::Items - namespace Defaults::Game::Room { constexpr const char* INITIAL = "03.yaml"; // Habitación de inicio - constexpr const char* END_ROOM = "01"; // Habitación final (jail) } // namespace Defaults::Game::Room namespace Defaults::Game::Player { diff --git a/source/game/gameplay/cheevos.cpp b/source/game/gameplay/cheevos.cpp index cf36a6a..85ca9f4 100644 --- a/source/game/gameplay/cheevos.cpp +++ b/source/game/gameplay/cheevos.cpp @@ -45,19 +45,6 @@ Cheevos::~Cheevos() { // Inicializa los logros void Cheevos::init() { // NOLINT(readability-convert-member-functions-to-static) cheevos_list_.clear(); - auto* loc = Locale::get(); - cheevos_list_.emplace_back(Achievement{.id = 1, .caption = loc->get("achievements.c1"), .description = loc->get("achievements.d1"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 2, .caption = loc->get("achievements.c2"), .description = loc->get("achievements.d2"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 3, .caption = loc->get("achievements.c3"), .description = loc->get("achievements.d3"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 4, .caption = loc->get("achievements.c4"), .description = loc->get("achievements.d4"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 5, .caption = loc->get("achievements.c5"), .description = loc->get("achievements.d5"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 6, .caption = loc->get("achievements.c6"), .description = loc->get("achievements.d6"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 7, .caption = loc->get("achievements.c7"), .description = loc->get("achievements.d7"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 8, .caption = loc->get("achievements.c8"), .description = loc->get("achievements.d8"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 9, .caption = loc->get("achievements.c9"), .description = loc->get("achievements.d9"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 10, .caption = loc->get("achievements.c10"), .description = loc->get("achievements.d10"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 11, .caption = loc->get("achievements.c11"), .description = loc->get("achievements.d11"), .icon = 2}); - cheevos_list_.emplace_back(Achievement{.id = 12, .caption = loc->get("achievements.c12"), .description = loc->get("achievements.d12"), .icon = 2}); } // Busca un logro por id y devuelve el indice diff --git a/source/game/gameplay/scoreboard.cpp b/source/game/gameplay/scoreboard.cpp index 3947295..23d6b26 100644 --- a/source/game/gameplay/scoreboard.cpp +++ b/source/game/gameplay/scoreboard.cpp @@ -31,7 +31,6 @@ void Scoreboard::render() { // Actualiza las variables del objeto void Scoreboard::update(float delta_time) { - updateItemsColor(delta_time); fillTexture(); if (!is_paused_) { @@ -64,17 +63,6 @@ void Scoreboard::setPaused(bool value) { } } -// Actualiza el color de la cantidad de items recogidos -void Scoreboard::updateItemsColor(float delta_time) { - if (!data_->jail_is_open) { return; } - - items_color_timer_ += delta_time; - if (items_color_timer_ >= ITEMS_COLOR_BLINK_DURATION * 2.0F) { - items_color_timer_ = 0.0F; - } - items_color_ = (items_color_timer_ < ITEMS_COLOR_BLINK_DURATION) ? VALUE_COLOR : 6; -} - // Devuelve la cantidad de minutos de juego transcurridos auto Scoreboard::getMinutes() -> int { return getTime().minutes; @@ -114,7 +102,7 @@ void Scoreboard::fillTexture() { x += text->length(SEP); text->writeColored(x, LINE1_Y, ITEMS_LABEL, LABEL_COLOR); x += text->length(ITEMS_LABEL); - text->writeColoredMono(x, LINE1_Y, ITEMS_STR, items_color_, MONO_W); + text->writeColoredMono(x, LINE1_Y, ITEMS_STR, VALUE_COLOR, MONO_W); x += text->lengthMono(ITEMS_STR, MONO_W); text->writeColored(x, LINE1_Y, SEP, LABEL_COLOR); x += text->length(SEP); diff --git a/source/game/gameplay/scoreboard.hpp b/source/game/gameplay/scoreboard.hpp index 35946b0..321eca2 100644 --- a/source/game/gameplay/scoreboard.hpp +++ b/source/game/gameplay/scoreboard.hpp @@ -18,7 +18,6 @@ class Scoreboard { bool music{true}; // Indica si ha de sonar la música durante el juego Uint8 color{0}; // Color para escribir el texto del marcador Uint32 ini_clock{0}; // Tiempo inicial para calcular el tiempo transcurrido - bool jail_is_open{false}; // Indica si se puede entrar a la Jail }; // Métodos públicos @@ -39,8 +38,6 @@ class Scoreboard { }; // Constantes de tiempo - static constexpr float ITEMS_COLOR_BLINK_DURATION = 0.333F; - // Posición de los elementos (2 líneas centradas verticalmente en surface de 24px) static constexpr int LINE1_Y = 5; static constexpr int LINE2_Y = 13; @@ -51,7 +48,6 @@ class Scoreboard { // Métodos privados auto getTime() -> ClockData; - void updateItemsColor(float delta_time); void fillTexture(); // Objetos y punteros @@ -63,7 +59,5 @@ class Scoreboard { Uint32 paused_time_{0}; Uint32 paused_time_elapsed_{0}; ClockData clock_{}; - Uint8 items_color_{VALUE_COLOR}; SDL_FRect surface_dest_{}; - float items_color_timer_{0.0F}; }; diff --git a/source/game/options.hpp b/source/game/options.hpp index bb4be55..9a33361 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -39,11 +39,10 @@ namespace Options { State infinite_lives{Defaults::Cheat::INFINITE_LIVES ? State::ENABLED : State::DISABLED}; // Indica si el jugador dispone de vidas infinitas State invincible{Defaults::Cheat::INVINCIBLE ? State::ENABLED : State::DISABLED}; // Indica si el jugador puede morir - State jail_is_open{Defaults::Cheat::JAIL_IS_OPEN ? State::ENABLED : State::DISABLED}; // Indica si la Jail está abierta - // Método para comprobar si alguno de los tres primeros trucos está activo + // Método para comprobar si algún truco está activo [[nodiscard]] auto enabled() const -> bool { - return infinite_lives == State::ENABLED || invincible == State::ENABLED || jail_is_open == State::ENABLED; + return infinite_lives == State::ENABLED || invincible == State::ENABLED; } }; diff --git a/source/game/scenes/game.cpp b/source/game/scenes/game.cpp index 568e784..c3dce27 100644 --- a/source/game/scenes/game.cpp +++ b/source/game/scenes/game.cpp @@ -19,7 +19,6 @@ #include "core/system/global_events.hpp" // Para check #include "game/defaults.hpp" // Para Defaults::Game #include "game/game_control.hpp" // Para GameControl -#include "game/gameplay/cheevos.hpp" // Para Cheevos #include "game/gameplay/item_tracker.hpp" // Para ItemTracker #include "game/gameplay/room.hpp" // Para Room, RoomData #include "game/gameplay/room_tracker.hpp" // Para RoomTracker @@ -39,7 +38,7 @@ // Constructor Game::Game(Mode mode) - : scoreboard_data_(std::make_shared(0, 9, 0, true, 0, SDL_GetTicks(), Options::cheats.jail_is_open == Options::Cheat::State::ENABLED)), + : scoreboard_data_(std::make_shared(0, 9, 0, true, 0, SDL_GetTicks())), scoreboard_(std::make_shared(scoreboard_data_)), room_tracker_(std::make_shared()), mode_(mode), @@ -69,13 +68,9 @@ Game::Game(Mode mode) demoInit(); room_ = std::make_shared(current_room_, scoreboard_data_); initPlayer(spawn_data_, room_); - total_items_ = getTotalItems(); - game_backbuffer_surface_ = std::make_shared(Options::game.width, Options::game.height); changeRoom(current_room_); - Cheevos::get()->enable(!Options::cheats.enabled()); // Deshabilita los logros si hay trucos activados - Cheevos::get()->clearUnobtainableState(); #ifdef _DEBUG Console::get()->setScope("debug"); @@ -335,8 +330,7 @@ void Game::updatePlaying(float delta_time) { checkPlayerAndItems(); checkPlayerAndEnemies(); checkIfPlayerIsAlive(); - checkEndGame(); - checkSomeCheevos(); + // Avanzar transición if (transitioning_) { @@ -884,9 +878,6 @@ void Game::killPlayer() { --scoreboard_data_->lives; } - // Invalida el logro de pasarse el juego sin morir - Cheevos::get()->setUnobtainable(11); - // Sonido Audio::get()->playSound("death.wav", Audio::Group::GAME); @@ -906,41 +897,6 @@ void Game::setScoreBoardColor() { // NOLINT(readability-convert-member-function scoreboard_data_->color = IS_BLACK || IS_BRIGHT_BLACK ? 14 : BORDER_COLOR; } -// Comprueba si ha finalizado el juego -auto Game::checkEndGame() -> bool { - const bool IS_ON_THE_ROOM = room_->getNumber() == Defaults::Game::Room::END_ROOM; // Estar en la habitación que toca - const bool HAVE_THE_ITEMS = - scoreboard_data_->items >= int(total_items_ * Defaults::Game::Items::PERCENT_TO_OPEN_THE_JAIL) || - Options::cheats.jail_is_open == Options::Cheat::State::ENABLED; // Con mas del 90% de los items recogidos - const bool IS_ON_THE_DOOR = player_->getRect().x <= 128; // Y en la ubicación que toca (En la puerta) - - scoreboard_data_->jail_is_open = HAVE_THE_ITEMS; - - if (HAVE_THE_ITEMS && IS_ON_THE_ROOM && IS_ON_THE_DOOR) { - // Comprueba los logros de completar el juego - checkEndGameCheevos(); - - // Iniciar transición de fade en vez de cambio inmediato de escena - transitionToState(State::FADE_TO_ENDING); - Audio::get()->fadeOutMusic(1000); // Fade out de música en 1 segundo - return true; - } - - return false; -} - -// Obtiene la cantidad total de items que hay en el mapeado del juego -auto Game::getTotalItems() -> int { - int items = 0; - auto rooms = Resource::Cache::get()->getRooms(); - - for (const auto& room : rooms) { - items += room.room->items.size(); - } - - return items; -} - // Pone el juego en pausa void Game::togglePause() { paused_ = !paused_; @@ -950,63 +906,6 @@ void Game::togglePause() { scoreboard_->setPaused(paused_); } -// Comprueba algunos logros -void Game::checkSomeCheevos() { // NOLINT(readability-convert-member-functions-to-static) - auto* cheevos = Cheevos::get(); - - // Logros sobre la cantidad de items - if (scoreboard_data_->items == total_items_) { - cheevos->unlock(4); - cheevos->unlock(3); - cheevos->unlock(2); - cheevos->unlock(1); - } else if (scoreboard_data_->items >= total_items_ * 0.75F) { - cheevos->unlock(3); - cheevos->unlock(2); - cheevos->unlock(1); - } else if (scoreboard_data_->items >= total_items_ * 0.5F) { - cheevos->unlock(2); - cheevos->unlock(1); - } else if (scoreboard_data_->items >= total_items_ * 0.25F) { - cheevos->unlock(1); - } - - // Logros sobre las habitaciones visitadas - if (scoreboard_data_->rooms >= 60) { - cheevos->unlock(7); - cheevos->unlock(6); - cheevos->unlock(5); - } else if (scoreboard_data_->rooms >= 40) { - cheevos->unlock(6); - cheevos->unlock(5); - } else if (scoreboard_data_->rooms >= 20) { - cheevos->unlock(5); - } -} - -// Comprueba los logros de completar el juego -void Game::checkEndGameCheevos() { // NOLINT(readability-convert-member-functions-to-static) - auto* cheevos = Cheevos::get(); - - // "Complete the game" - cheevos->unlock(8); - - // "Complete the game without entering the jail" - cheevos->unlock(9); - - // "Complete the game with all items" - if (scoreboard_data_->items == total_items_) { - cheevos->unlock(10); - } - - // "Complete the game without dying" - cheevos->unlock(11); - - // "Complete the game in under 30 minutes" - if (scoreboard_->getMinutes() < 30) { - cheevos->unlock(12); - } -} // Inicializa al jugador void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr room) { // NOLINT(readability-convert-member-functions-to-static) diff --git a/source/game/scenes/game.hpp b/source/game/scenes/game.hpp index 098b13f..a825b9c 100644 --- a/source/game/scenes/game.hpp +++ b/source/game/scenes/game.hpp @@ -75,11 +75,7 @@ class Game { void checkIfPlayerIsAlive(); // Comprueba si el jugador esta vivo void killPlayer(); // Mata al jugador void setScoreBoardColor(); // Pone el color del marcador en función del color del borde de la habitación - auto checkEndGame() -> bool; // Comprueba si ha finalizado el juego - static auto getTotalItems() -> int; // Obtiene la cantidad total de items que hay en el mapeado del juego void togglePause(); // Pone el juego en pausa - void checkSomeCheevos(); // Comprueba algunos logros - void checkEndGameCheevos(); // Comprueba los logros de completar el juego void initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr room); // Inicializa al jugador void endTransition(); // Finaliza la transición entre pantallas void keepMusicPlaying(); // Hace sonar la música @@ -106,7 +102,6 @@ class Game { DeltaTimer delta_timer_; // Timer para calcular delta time std::string current_room_; // Fichero de la habitación actual Player::SpawnData spawn_data_; // Lugar de la habitación donde aparece el jugador - int total_items_; // Cantidad total de items que hay en el mapeado del juego bool paused_{false}; // Indica si el juego se encuentra en pausa float state_time_{0.0F}; // Tiempo acumulado en el estado actual float fade_accumulator_{0.0F}; // Acumulador de tiempo para el fade diff --git a/source/game/scenes/title.cpp b/source/game/scenes/title.cpp index 1794323..c9468b1 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -16,7 +16,6 @@ #include "core/resources/resource_list.hpp" // Para Asset #include "core/system/event_buffer.hpp" // Para EventBuffer #include "core/system/global_events.hpp" // Para check -#include "game/gameplay/cheevos.hpp" // Para Cheevos, Achievement #include "game/options.hpp" // Para Options, options, SectionState, Section #include "game/scene_manager.hpp" // Para SceneManager #include "game/ui/console.hpp" // Para Console @@ -42,7 +41,6 @@ Title::Title() SceneManager::options = SceneManager::Options::NONE; // Acciones iniciales - createCheevosTexture(); // Crea y rellena la textura para mostrar los logros Screen::get()->setBorderColor(0); // Cambia el color del borde Audio::get()->playMusic("574071_EA_DTV.ogg"); // Inicia la musica } @@ -111,11 +109,6 @@ void Title::handleMainMenuKeyPress(SDL_Keycode key) { // Si no hay gamepad, simplemente no hacer nada break; - case SDLK_4: - // PROJECTS - transitionToState(State::CHEEVOS_MENU); - break; - default: break; } @@ -139,19 +132,6 @@ void Title::handleInput(float delta_time) { return; } - switch (state_) { - case State::CHEEVOS_MENU: - if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT) || - Input::get()->checkAction(InputAction::CANCEL, Input::DO_NOT_ALLOW_REPEAT)) { - resetCheevosScroll(); - transitionToState(State::MAIN_MENU); - } - break; - - default: - break; - } - GlobalInputs::handle(); } @@ -175,10 +155,6 @@ void Title::updateState(float delta_time) { updateMainMenu(delta_time); break; - case State::CHEEVOS_MENU: - updateCheevosMenu(delta_time); - break; - case State::FADE_MENU: updateFadeMenu(delta_time); break; @@ -231,49 +207,6 @@ void Title::updateMainMenu(float delta_time) { } } -// Actualiza el estado CHEEVOS_MENU -void Title::updateCheevosMenu(float delta_time) { - // Determina la velocidad objetivo basada en el input - float target_velocity = 0.0F; - if (Input::get()->checkAction(InputAction::RIGHT, Input::ALLOW_REPEAT)) { - target_velocity = CHEEVOS_SCROLL_MAX_SPEED; // Scroll hacia abajo - } else if (Input::get()->checkAction(InputAction::LEFT, Input::ALLOW_REPEAT)) { - target_velocity = -CHEEVOS_SCROLL_MAX_SPEED; // Scroll hacia arriba - } - - // Interpola suavemente la velocidad actual hacia la velocidad objetivo - if (target_velocity != 0.0F) { - // Acelerando hacia la velocidad objetivo - const float ACCELERATION_STEP = CHEEVOS_SCROLL_ACCELERATION * delta_time; - if (cheevos_scroll_velocity_ < target_velocity) { - cheevos_scroll_velocity_ = std::min(cheevos_scroll_velocity_ + ACCELERATION_STEP, target_velocity); - } else if (cheevos_scroll_velocity_ > target_velocity) { - cheevos_scroll_velocity_ = std::max(cheevos_scroll_velocity_ - ACCELERATION_STEP, target_velocity); - } - } else { - // Desacelerando hacia 0 - const float DECELERATION_STEP = CHEEVOS_SCROLL_DECELERATION * delta_time; - if (cheevos_scroll_velocity_ > 0.0F) { - cheevos_scroll_velocity_ = std::max(cheevos_scroll_velocity_ - DECELERATION_STEP, 0.0F); - } else if (cheevos_scroll_velocity_ < 0.0F) { - cheevos_scroll_velocity_ = std::min(cheevos_scroll_velocity_ + DECELERATION_STEP, 0.0F); - } - } - - // Aplica la velocidad actual al scroll position - if (cheevos_scroll_velocity_ != 0.0F) { - cheevos_surface_view_.y += cheevos_scroll_velocity_ * delta_time; - - // Ajusta los límites - const float BOTTOM = cheevos_surface_->getHeight() - cheevos_surface_view_.h; - cheevos_surface_view_.y = std::clamp(cheevos_surface_view_.y, 0.0F, BOTTOM); - - cheevos_sprite_->setClip(cheevos_surface_view_); - } - - // No incrementar state_time_ (no timeout en este estado) -} - // Actualiza el estado FADE_MENU void Title::updateFadeMenu(float delta_time) { fade_accumulator_ += delta_time; @@ -310,68 +243,6 @@ void Title::render() { Screen::get()->render(); } -// Crea y rellena la textura para mostrar los logros -void Title::createCheevosTexture() { // NOLINT(readability-convert-member-functions-to-static) - // Define la zona central del menu (entre el logo y la marquesina) - constexpr int MENU_ZONE_Y = 73; // Top of menu zone - constexpr int MENU_ZONE_HEIGHT = 102; // Height of menu zone - - // Crea la textura con el listado de logros - const auto CHEEVOS_LIST = Cheevos::get()->list(); - const auto TEXT = Resource::Cache::get()->getText("subatomic"); - constexpr int CHEEVOS_TEXTURE_WIDTH = 200; - constexpr int CHEEVOS_TEXTURE_VIEW_HEIGHT = MENU_ZONE_HEIGHT; - constexpr int CHEEVOS_PADDING = 10; - const int CHEEVO_HEIGHT = CHEEVOS_PADDING + (TEXT->getCharacterSize() * 2) + 1; - const int CHEEVOS_TEXTURE_HEIGHT = (CHEEVO_HEIGHT * CHEEVOS_LIST.size()) + 2 + TEXT->getCharacterSize() + 8; - cheevos_surface_ = std::make_shared(CHEEVOS_TEXTURE_WIDTH, CHEEVOS_TEXTURE_HEIGHT); - - // Prepara para dibujar sobre la textura - auto previuos_renderer = Screen::get()->getRendererSurface(); - Screen::get()->setRendererSurface(cheevos_surface_); - - // Rellena la textura con color sólido - const auto CHEEVOS_BG_COLOR = 0; - cheevos_surface_->clear(CHEEVOS_BG_COLOR); - - // Escribe la lista de logros en la textura - const std::string CHEEVOS_OWNER = Locale::get()->get("title.projects"); // NOLINT(readability-static-accessed-through-instance) - const std::string CHEEVOS_LIST_CAPTION = CHEEVOS_OWNER + " (" + std::to_string(Cheevos::get()->getTotalUnlockedAchievements()) + " / " + std::to_string(Cheevos::get()->size()) + ")"; - int pos = 2; - TEXT->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, cheevos_surface_->getWidth() / 2, pos, CHEEVOS_LIST_CAPTION, 1, 9); - pos += TEXT->getCharacterSize(); - const Uint8 CHEEVO_LOCKED_COLOR = 14; - const Uint8 CHEEVO_UNLOCKED_COLOR = 9; - constexpr int LINE_X1 = (CHEEVOS_TEXTURE_WIDTH / 7) * 3; - constexpr int LINE_X2 = LINE_X1 + ((CHEEVOS_TEXTURE_WIDTH / 7) * 1); - - for (const auto& cheevo : CHEEVOS_LIST) { - const Uint8 CHEEVO_COLOR = cheevo.completed ? CHEEVO_UNLOCKED_COLOR : CHEEVO_LOCKED_COLOR; - pos += CHEEVOS_PADDING; - constexpr int HALF = CHEEVOS_PADDING / 2; - cheevos_surface_->drawLine(LINE_X1, pos - HALF - 1, LINE_X2, pos - HALF - 1, CHEEVO_COLOR); - TEXT->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, CHEEVOS_TEXTURE_WIDTH / 2, pos, cheevo.caption, 1, CHEEVO_COLOR); - pos += TEXT->getCharacterSize() + 1; - TEXT->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, CHEEVOS_TEXTURE_WIDTH / 2, pos, cheevo.description, 1, CHEEVO_COLOR); - pos += TEXT->getCharacterSize(); - } - - // Restablece el RenderSurface - Screen::get()->setRendererSurface(previuos_renderer); - - // Crea el sprite para el listado de logros (usa la zona del menu) - cheevos_sprite_ = std::make_unique(cheevos_surface_, (GameCanvas::WIDTH - cheevos_surface_->getWidth()) / 2, MENU_ZONE_Y, cheevos_surface_->getWidth(), cheevos_surface_->getHeight()); - cheevos_surface_view_ = {.x = 0, .y = 0, .w = cheevos_surface_->getWidth(), .h = CHEEVOS_TEXTURE_VIEW_HEIGHT}; - cheevos_sprite_->setClip(cheevos_surface_view_); -} - -// Resetea el scroll de la lista de logros -void Title::resetCheevosScroll() { - cheevos_surface_view_.y = 0; - cheevos_scroll_velocity_ = 0.0F; - cheevos_sprite_->setClip(cheevos_surface_view_); -} - // Dibuja el logo con el titulo del juego void Title::renderGameLogo() { game_logo_sprite_->render(); @@ -389,30 +260,24 @@ void Title::renderMainMenu() { return; } - // Zona central del menu (debe coincidir con la textura de cheevos) + // Zona central del menu constexpr int MENU_ZONE_Y = 73; constexpr int MENU_ZONE_HEIGHT = 102; - // Menú principal normal con 4 opciones centradas verticalmente en la zona + // Menú principal normal con 3 opciones centradas verticalmente en la zona const Uint8 COLOR = 8; const int TEXT_SIZE = menu_text_->getCharacterSize(); const int MENU_CENTER_Y = MENU_ZONE_Y + (MENU_ZONE_HEIGHT / 2); const int SPACING = 2 * TEXT_SIZE; // Espaciado entre opciones - // Calcula posiciones centradas verticalmente (4 items con espaciado) - const int TOTAL_HEIGHT = 3 * SPACING; // 3 espacios entre 4 items + // Calcula posiciones centradas verticalmente (3 items con espaciado) + const int TOTAL_HEIGHT = 2 * SPACING; // 2 espacios entre 3 items const int START_Y = MENU_CENTER_Y - (TOTAL_HEIGHT / 2); auto* loc = Locale::get(); menu_text_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, PlayArea::CENTER_X, START_Y, loc->get("title.menu.play"), 1, COLOR); menu_text_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, PlayArea::CENTER_X, START_Y + SPACING, loc->get("title.menu.keyboard"), 1, COLOR); menu_text_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, PlayArea::CENTER_X, START_Y + (2 * SPACING), loc->get("title.menu.joystick"), 1, COLOR); - menu_text_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, PlayArea::CENTER_X, START_Y + (3 * SPACING), loc->get("title.menu.projects"), 1, COLOR); -} - -// Dibuja el menu de logros -void Title::renderCheevosMenu() { - cheevos_sprite_->render(); } // Dibuja los elementos en la surface @@ -432,12 +297,6 @@ void Title::fillTitleSurface() { break; - case State::CHEEVOS_MENU: - renderGameLogo(); - renderCheevosMenu(); - - break; - default: break; } @@ -534,7 +393,7 @@ void Title::applyKeyboardRemap() { // NOLINT(readability-convert-member-functio // Dibuja la pantalla de redefinir teclado void Title::renderKeyboardRemap() const { - // Zona central del menu (debe coincidir con la textura de cheevos) + // Zona central del menu constexpr int MENU_ZONE_Y = 73; constexpr int MENU_ZONE_HEIGHT = 102; @@ -582,7 +441,7 @@ void Title::renderKeyboardRemap() const { // Dibuja la pantalla de redefinir joystick void Title::renderJoystickRemap() const { - // Zona central del menu (debe coincidir con la textura de cheevos) + // Zona central del menu constexpr int MENU_ZONE_Y = 73; constexpr int MENU_ZONE_HEIGHT = 102; diff --git a/source/game/scenes/title.hpp b/source/game/scenes/title.hpp index ed8745e..2308d9d 100644 --- a/source/game/scenes/title.hpp +++ b/source/game/scenes/title.hpp @@ -26,7 +26,6 @@ class Title { // --- Estructuras y enumeraciones --- enum class State { MAIN_MENU, - CHEEVOS_MENU, FADE_MENU, POST_FADE_MENU, }; @@ -35,10 +34,6 @@ class Title { static constexpr float FADE_STEP_INTERVAL = 0.05F; // Intervalo entre pasos de fade (antes cada 4 frames) static constexpr float POST_FADE_DELAY = 1.0F; // Delay después del fade (pantalla en negro) static constexpr float KEYBOARD_REMAP_DISPLAY_DELAY = 2.0F; // Tiempo mostrando teclas definidas antes de guardar - static constexpr float CHEEVOS_SCROLL_MAX_SPEED = 180.0F; // Velocidad máxima de scroll de logros (pixels/segundo) - static constexpr float CHEEVOS_SCROLL_ACCELERATION = 600.0F; // Aceleración del scroll (pixels/segundo²) - static constexpr float CHEEVOS_SCROLL_DECELERATION = 800.0F; // Desaceleración del scroll (pixels/segundo²) - // --- Métodos --- void handleEvents(); // Comprueba el manejador de eventos void handleMainMenuKeyPress(SDL_Keycode key); // Maneja las teclas del menu principal @@ -46,12 +41,10 @@ class Title { void updateState(float delta_time); // Actualiza el estado actual void transitionToState(State new_state); // Transiciona a un nuevo estado void updateMainMenu(float delta_time); // Actualiza MAIN_MENU - void updateCheevosMenu(float delta_time); // Actualiza CHEEVOS_MENU void updateFadeMenu(float delta_time); // Actualiza FADE_MENU void updatePostFadeMenu(float delta_time); // Actualiza POST_FADE_MENU void renderGameLogo(); // Dibuja el logo con el titulo del juego void renderMainMenu(); // Dibuja el menu principal - void renderCheevosMenu(); // Dibuja el menu de logros void renderKeyboardRemap() const; // Dibuja la pantalla de redefinir teclado void renderJoystickRemap() const; // Dibuja la pantalla de redefinir joystick void handleKeyboardRemap(const SDL_Event& event); // Maneja la captura de teclas @@ -63,24 +56,16 @@ class Title { void applyJoystickRemap(); // Aplica y guarda los botones del gamepad redefinidos static auto getActionName(int step) -> std::string; // Retorna el nombre de la accion (LEFT/RIGHT/JUMP) static auto getButtonName(int button) -> std::string; // Retorna el nombre amigable del boton del gamepad - void createCheevosTexture(); // Crea y rellena la surface para mostrar los logros - void resetCheevosScroll(); // Resetea el scroll de la lista de logros void fillTitleSurface(); // Dibuja los elementos en la surface // --- Variables miembro --- // Objetos y punteros std::shared_ptr game_logo_surface_; // Textura con los graficos std::unique_ptr game_logo_sprite_; // SSprite para manejar la surface - std::shared_ptr cheevos_surface_; // Textura con la lista de logros - std::unique_ptr cheevos_sprite_; // SSprite para manejar la surface con la lista de logros std::shared_ptr title_surface_; // Surface donde se dibuja toda la clase std::unique_ptr delta_timer_; // Timer para delta time std::shared_ptr menu_text_; // Texto para los menus - // Variables de estado del menú de logros - SDL_FRect cheevos_surface_view_; // Zona visible de la surface con el listado de logros - float cheevos_scroll_velocity_{0.0F}; // Velocidad actual del scroll de logros (pixels/segundo) - // Variables de estado general State state_; // Estado en el que se encuentra el bucle principal float state_time_{0.0F}; // Tiempo acumulado en el estado actual diff --git a/source/game/ui/console_commands.cpp b/source/game/ui/console_commands.cpp index 4e9ed3f..04f5242 100644 --- a/source/game/ui/console_commands.cpp +++ b/source/game/ui/console_commands.cpp @@ -794,11 +794,7 @@ static auto cmdShow(const std::vector& args) -> std::string { Notifier::get()->show({"NOTIFICATION"}); return "Notification shown"; } - if (!args.empty() && args[0] == "CHEEVO") { - Notifier::get()->show({Locale::get()->get("achievements.header"), Locale::get()->get("achievements.c1")}, Notifier::Style::CHEEVO, -1, false); // NOLINT(readability-static-accessed-through-instance) - return "Cheevo notification shown"; - } - if (args.empty() || args[0] != "INFO") { return "usage: show [info|notification|cheevo]"; } + if (args.empty() || args[0] != "INFO") { return "usage: show [info|notification]"; } #else if (args.empty() || args[0] != "INFO") { return "usage: show [info]"; } #endif @@ -818,7 +814,7 @@ static auto cmdHide(const std::vector& args) -> std::string { // CHEAT [subcomando] static auto cmdCheat(const std::vector& args) -> std::string { // NOLINT(readability-function-cognitive-complexity) if (SceneManager::current != SceneManager::Scene::GAME) { return "Only available in GAME scene"; } - if (args.empty()) { return "usage: cheat [infinite lives|invincibility|open the jail|close the jail]"; } + if (args.empty()) { return "usage: cheat [infinite lives|invincibility]"; } // CHEAT INFINITE LIVES [ON|OFF] if (args[0] == "INFINITE") { @@ -858,23 +854,7 @@ static auto cmdCheat(const std::vector& args) -> std::string { // return std::string("Invincibility ") + (cheat == State::ENABLED ? "ON" : "OFF"); } - // CHEAT OPEN THE JAIL - if (args[0] == "OPEN") { - if (args.size() < 3 || args[1] != "THE" || args[2] != "JAIL") { return "usage: cheat open the jail"; } - if (Options::cheats.jail_is_open == Options::Cheat::State::ENABLED) { return "Jail already open"; } - Options::cheats.jail_is_open = Options::Cheat::State::ENABLED; - return "Jail opened"; - } - - // CHEAT CLOSE THE JAIL - if (args[0] == "CLOSE") { - if (args.size() < 3 || args[1] != "THE" || args[2] != "JAIL") { return "usage: cheat close the jail"; } - if (Options::cheats.jail_is_open == Options::Cheat::State::DISABLED) { return "Jail already closed"; } - Options::cheats.jail_is_open = Options::Cheat::State::DISABLED; - return "Jail closed"; - } - - return "usage: cheat [infinite lives|invincibility|open the jail|close the jail]"; + return "usage: cheat [infinite lives|invincibility]"; } // PLAYER SKIN / PLAYER COLOR