# 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 & Formatting (CMake targets) Los linters y el formateador están integrados como targets de CMake. Todos excluyen `source/external/` y los headers SPIR-V generados (`*_spv.h`). ```bash # Desde el directorio build/ cmake --build . --target tidy # clang-tidy sobre todo el código (sin fixes) cmake --build . --target tidy-fix # clang-tidy aplicando fixes automáticos cmake --build . --target cppcheck # cppcheck (warning/style/performance/portability, --std=c++20) cmake --build . --target format # clang-format -i sobre todo el código cmake --build . --target format-check # clang-format en modo dry-run (CI) ``` Los targets se definen en [CMakeLists.txt](CMakeLists.txt) (sección *STATIC ANALYSIS TARGETS*) y se generan únicamente si las herramientas correspondientes (`clang-tidy`, `clang-format`, `cppcheck`) están instaladas en el sistema. **Falsos positivos conocidos de clang-tidy:** - `defaults.hpp`: puede reportar errores en definiciones de constantes. - `readability-magic-numbers` / `cppcoreguidelines-avoid-magic-numbers`: aceptables para constantes de juego (tamaños de bloque, velocidades, etc). **Notas sobre cppcheck:** - Avisos `unusedStructMember` son habituales en estructuras de datos accedidas vía serialización/yaml o por código `#ifdef _DEBUG`; revisar antes de borrar nada. - El target usa la lista explícita de fuentes (excluyendo `source/external/` y `*_spv.h`), no `--project=compile_commands.json`. Si añades flags nuevos, actualiza el target en [CMakeLists.txt](CMakeLists.txt). - Por defecto cppcheck solo evalúa 12 combinaciones de `#ifdef`. Para analizar todas, añadir `--force` (mucho más lento). **Para análisis puntual de un solo fichero**, llamar la herramienta directamente: ```bash clang-tidy -p build source/game/entities/player.cpp cppcheck --enable=warning,style --std=c++20 -I source source/game/entities/player.cpp ``` --- ## 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)