# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. --- # Projecte 2026 - Nuevo juego (derivado de JailDoctor's Dilemma) **IMPORTANTE:** Este repositorio parte del código de *JailDoctor's Dilemma* como base, pero es un **juego nuevo**. `projecte_2026` es un nombre placeholder hasta tener el diseño final. Gran parte de la arquitectura documentada más abajo describe el código heredado; varios subsistemas se van a reescribir. ## Cambios de diseño previstos respecto al juego original 1. **Habitaciones más grandes** — aprovechar el espacio del marcador (scoreboard) para ampliar el área jugable. Esto implica revisar la resolución de canvas, el layout de la HUD y el tamaño de los tilemaps. 2. ~~**Nueva física del jugador**~~ ✅ **HECHO** — Player reescrito con pipeline de 6 fases, colisiones tile-based, ~20 métodos eliminados. 3. ~~**Motor de colisiones por tiles**~~ ✅ **HECHO** — `TileCollider` con queries directas al grid. Collision tilemap editado desde el editor (tecla 8). Sistema antiguo de superficies preservado pero no usado. Pendiente: tiles kill (5) y conveyor (6). 4. ~~**Transición de pantalla animada**~~ ✅ **HECHO** — Scroll con easing `cubicInOut` (0.5s), ambas rooms visibles, enemigos activos, jugador puede moverse durante la transición. 5. **Paleta Amstrad CPC** — subir de la paleta actual (8-bit indexada limitada) a la paleta del Amstrad CPC (27 colores / más colores que la actual). Afecta a `PaletteManager` y a todos los assets de color. ## Estado del renombrado Se han renombrado las referencias de `JailDoctor's Dilemma` → `Projecte 2026` y `jaildoctors_dilemma` → `projecte_2026` en código, configs, Makefile, CMake, LICENSE, Info.plist, scripts, locales, etc. Copyright actualizado a 2026. Se han mantenido como placeholders: - La clave de locale `jaildoctor:` en `data/locale/*.yaml` y su uso en `source/game/scenes/ending2.cpp` (es contenido de juego, pendiente de rediseño). - 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). ## Pendiente - **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 **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. **Language:** C++20 **Graphics:** SDL3, OpenGL **Audio:** SDL3 + custom jail_audio library **Build:** CMake 3.10+ **Game Canvas:** 256x192 pixels (retro resolution) --- ## Build Commands ### Initial Setup & Build ```bash # From project root mkdir -p build cd build cmake .. cmake --build . ``` ### Rebuild After Changes ```bash # From build directory cmake --build . # Or from project root cmake --build build ``` ### Clean Build ```bash # From build directory cmake --build . --clean-first # Or from project root cmake --build build --clean-first ``` ### Run the Game ```bash # Executable is placed in project root ./projecte_2026 ``` **Important:** The build directory is `build/` relative to the project root and the output executable is placed in the project root directory. ### Testing in Headless Environment (SSH/Remote Server) **IMPORTANT:** When working on a remote server via SSH without a physical display, the game MUST be run using Xvfb (X Virtual Framebuffer) to avoid SDL3 display initialization errors. #### Required Setup (One-time) ```bash # Install Xvfb sudo apt-get install xvfb ``` #### Running the Game in Headless Mode **Option 1: Using xvfb-run directly (RECOMMENDED)** ```bash xvfb-run -a ./projecte_2026 ``` **Option 2: Custom display configuration** ```bash xvfb-run -a -s "-screen 0 1280x720x24" ./projecte_2026 ``` #### Why This Is Critical - **SDL3 requires a display:** The game uses SDL3 which requires X11/Wayland display - **No code changes needed:** Xvfb simulates a virtual display without modifying the codebase - **Full logging:** Console output and logs work normally, essential for debugging resource loading - **Testing resource loading:** When modifying asset loading code, running with xvfb-run allows seeing all initialization logs **ALWAYS use xvfb-run when testing on the remote server, especially when:** - Modifying resource loading code - Testing asset initialization - Debugging startup issues - Verifying configuration changes --- ## Static Analysis Tools (Linters) This project uses two complementary static analysis tools for code quality: ### clang-tidy (Modernization & Best Practices) **Purpose:** Detects style issues, modernization opportunities, and potential bugs. Best for refactoring and applying C++20 best practices. **IMPORTANT:** Always run on specific files, NOT on the entire project, to avoid long execution times and errors in unrelated files. ```bash # Analyze a specific file (RECOMMENDED) tools/linter/run_clang-tidy.sh source/game/entities/player.cpp # Analyze multiple specific files tools/linter/run_clang-tidy.sh source/game/entities/player.cpp source/game/entities/enemy.cpp # Apply fixes automatically to a specific file tools/linter/run_clang-tidy.sh --fix source/game/entities/player.cpp # Analyze entire project (SLOW, may have errors in defaults.hpp) tools/linter/run_clang-tidy.sh ``` **Known False Positives:** - `defaults.hpp`: May report errors in constant definitions - `readability-magic-numbers` / `cppcoreguidelines-avoid-magic-numbers`: Acceptable for game constants (block sizes, speeds, etc.) ### cppcheck (Bug Detection & Memory Safety) **Purpose:** Detects bugs, memory leaks, undefined behavior, and style issues. Complementary to clang-tidy. ```bash # Warning, style, and performance analysis (RECOMMENDED for daily use) tools/linter/run_cppcheck.sh -w --path source/game/entities/player.cpp # Exhaustive analysis (slower, more thorough) tools/linter/run_cppcheck.sh -a --path source/game/entities/ # Detect unused functions (whole project analysis) tools/linter/run_cppcheck.sh -u # Analyze entire project with warning level tools/linter/run_cppcheck.sh -w ``` **Output:** Results are saved in `tools/linter/cppcheck-result-*.txt` **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 | Scenario | Tool | Reason | |----------|------|--------| | **Daily refactoring** | clang-tidy | Fast, auto-fixable issues | | **Before committing** | Both | Comprehensive quality check | | **After major changes** | cppcheck -a | Deep bug analysis | | **Hunting memory leaks** | cppcheck | Specialized detection | | **Code modernization** | clang-tidy --fix | Automatic C++20 upgrades | ### Integration with Development Workflow When refactoring code (especially with `/refactor-class` command): 1. Make structural changes 2. **Compile** to verify syntax 3. **Run clang-tidy** (without --fix) to identify issues 4. **Run cppcheck -w** to catch bugs 5. Review and fix legitimate issues 6. Apply automatic fixes if appropriate 7. Recompile and test **Note:** The `/refactor-class` command automatically runs both linters after compilation and provides intelligent analysis of results. --- ## 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;` 2. **Singleton Pattern:** When creating new singletons, follow the existing pattern: - Private static instance pointer - Private constructor/destructor - Public `init()`, `destroy()`, and `get()` methods 3. **Delta Time:** Always use `DeltaTimer` for frame-rate independent physics calculations 4. **Memory Management:** Prefer `std::shared_ptr` for shared resources (Surfaces, Sprites) and `std::unique_ptr` for sole ownership 5. **Room file format — single source of truth:** Cualquier cambio al formato `data/room/*.yaml` (añadir/quitar/renombrar campos) se hace **exclusivamente** en `source/game/gameplay/room_format.cpp`. Esa clase es la única autoridad: combina parser (`loadYAML`), serializer (`saveYAML`, debug-only) y `createDefault` para rooms nuevas. Cuando añadas un campo nuevo: - Añade el field a `Room::Data` en `source/game/gameplay/room.hpp`. - Actualiza `parseRoomConfig`/`buildContent`/`createDefault` en `room_format.cpp` (los tres en el mismo módulo). - **Nunca** escribas yaml a pelo con `std::ofstream` desde otro sitio (especialmente desde `MapEditor::createNewRoom`, que ya delega en `RoomFormat::createDefault` + `RoomFormat::saveYAML`). El editor solo manipula `Room::Data`; el formato yaml es invisible para él. Saltarse esta regla causa bugs como el del crash de `06.yaml` (formato hardcoded en `createNewRoom` que se desincroniza del parser real). 6. **Nuevas entidades de room — soporte completo en editor y consola:** Cuando añadas un tipo nuevo de entidad a las rooms (al estilo de `enemies`, `items`, `platforms`, `keys`, `doors`), no basta con el parser/serializer y el manager runtime. Debes implementar también su contrapartida en el editor y en la consola, en paridad con los tipos existentes: - **Renderizado dentro del editor**: añadir la llamada al `room_->renderXxx()` correspondiente en `MapEditor::render()`. Sin esto la entidad no se ve cuando el editor está activo (aunque sí se vea en juego), porque el editor renderiza entidades por separado del flujo normal del juego. - **Selección visual** en `MapEditor` (click sobre la entidad → `selection_` con su tipo y índice). Extender el loop de hit test en `MapEditor::handleMouseDown` con el nuevo `EntityType`. - **Drag & drop** para mover la entidad por el grid (con autosave al soltar). Extender `moveEntityVisual` y `commitEntityDrag`. - **Entry en la statusbar** del editor cuando la entidad está seleccionada (mostrar id, animación, etc). Switch en `updateStatusBarInfo`. - **Comandos de consola**: `cmd` para `add/delete/duplicate` y routing en `cmdSet` para `setXxxProperty`. Ver `cmdEnemy`/`cmdItem`/`cmdPlatform`/`cmdKey`/`cmdDoor` en `console_commands.cpp`. Registrar en `data/console/commands.yaml` también. - **Helpers genéricos**: `entityCount`, `entityRect`, `entityPosition`, `entityDataCount`, `entityLabel` deben cubrir el nuevo tipo (switch sobre `EntityType`). - **Manager debug API**: el manager de la entidad necesita `getCount()` y `getXxx(int)` bajo `#ifdef _DEBUG` para que el editor pueda iterar. - **Setter de posición**: la entidad necesita `setPosition(float, float)` bajo `#ifdef _DEBUG` para el drag visual. - **`EntityType enum`** en `map_editor.hpp` extendido con el nuevo tipo. - **Si la entidad afecta a colisiones** (como `Door` que escribe `WALL` en el `CollisionMap`), el manager debe exponer `move(idx, x, y)` y `remove(idx)` que encapsulen el bookkeeping. **El editor no debe tocar nunca el `CollisionMap` directamente.** Cualquier entidad nueva debe nacer con soporte completo, no diferirlo "para después". --- **Last Updated:** April 2026 **Original Author:** JailDesigner **Repository:** Gitea (internal)