# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. --- # JailDoctor's Dilemma - Codebase Architecture Guide ## Overview **JailDoctor's Dilemma** 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 ./jaildoctors_dilemma ``` **Important:** The build directory is `/Users/sergio/Gitea/jaildoctors_dilemma/build` 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 the wrapper script (RECOMMENDED)** ```bash ./run_headless.sh ``` **Option 2: Using xvfb-run directly** ```bash xvfb-run -a ./jaildoctors_dilemma ``` **Option 3: Custom display configuration** ```bash xvfb-run -a -s "-screen 0 1280x720x24" ./jaildoctors_dilemma ``` #### 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 ``` **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 #### 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` **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 | 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 | #### 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 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. --- ## 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) │ ├── input/ # Input handling │ │ ├── input.hpp/cpp # Input manager (keyboard, gamepad) │ │ ├── global_inputs.hpp # Global input state │ │ └── mouse.hpp # Mouse input │ ├── rendering/ # Graphics rendering │ │ ├── screen.hpp/cpp # Screen/window singleton, SDL renderer │ │ ├── surface.hpp/cpp # 8-bit indexed color surface abstraction │ │ ├── surface_sprite.hpp # Static sprite rendering │ │ ├── surface_animated_sprite.hpp # Animated sprite with frame data │ │ ├── surface_moving_sprite.hpp # Moving sprite with velocity │ │ ├── texture.hpp/cpp # SDL texture wrapper │ │ ├── text.hpp/cpp # Text rendering system │ │ ├── gif.hpp/cpp # GIF image loader │ │ ├── opengl/ # OpenGL shader backend │ │ │ └── opengl_shader.hpp/cpp # CRT shader effects │ │ └── shader_backend.hpp # Abstract shader interface │ ├── resources/ # Asset & Resource management │ │ ├── asset.hpp/cpp # Asset registry (file path mapping) │ │ └── resource.hpp/cpp # Resource singleton (loads/caches assets) │ └── 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, tilemap, collision │ │ ├── room_tracker.hpp/cpp # Tracks visited rooms │ │ ├── scoreboard.hpp/cpp # Score display & data │ │ ├── item_tracker.hpp/cpp # Tracks collected items │ │ ├── stats.hpp/cpp # Game statistics │ │ └── 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 │ ├── options.hpp/cpp # Game configuration/options │ ├── scene_manager.hpp # Scene flow state machine │ ├── defaults.hpp # Game defaults constants │ └── gameplay.hpp # Gameplay constants ├── external/ # Third-party libraries │ ├── jail_audio.hpp/cpp # Custom audio library │ ├── jail_audio.h # C interface for jail_audio │ ├── stb_image.h # Image loading library │ └── stb_vorbis.h # OGG Vorbis audio decoding ├── utils/ # Utility code │ ├── delta_timer.hpp/cpp # Frame-rate independent timing │ ├── 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, 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 - `SurfaceSprite` - Renders a fixed region of a surface - `SurfaceAnimatedSprite` - Frame-based animation on top of sprite - `SurfaceMovingSprite` - Adds velocity/position to animated 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 .ani files (list of animation names) // Rendered with SurfaceAnimatedSprite ``` --- ## 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 configuration (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() └─ Asset::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: `SurfaceSprite`, `SurfaceAnimatedSprite` **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 - `Surface::setPalette()` changes rendering colors - 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 inline Stats stats{}; // Game statistics } 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** | OpenGL | 3.2+ | Shader effects (CRT) | | **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 | | `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, tilemap rendering | | `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 | | `SurfaceSprite` | Renders a sprite region | | `SurfaceAnimatedSprite` | Frame-based animation rendering | | `SurfaceMovingSprite` | Sprite with velocity/position | | `Text` | Text rendering system | | `OpenGLShader` | Shader compilation and effects | ### Utility Classes | Class | Purpose | |-------|---------| | `DeltaTimer` | Frame-rate independent timing | --- ## 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 # JailDoctor's Dilemma - Asset Configuration # Variables: ${PREFIX}, ${SYSTEM_FOLDER} assets: # FONTS fonts: - type: BITMAP path: ${PREFIX}/data/font/smb2.gif - type: FONT path: ${PREFIX}/data/font/smb2.txt # 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 (.ani) List of animation names, one per line: ``` default jump run fall ``` ### Room Data Files (.room) Key-value pairs defining room properties: ``` number=01 name=Starting Room bg_color=0x000000 border_color=0xFF00FF ... ``` ### 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::setPalete()` - Palette application - `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) - `Asset::loadFromFile()` - Loads assets from config file - `Resource::List::get()` - Retrieves asset path (O(1) lookup with unordered_map) - `Resource::load()` - Asset loading - `Director::setFileList()` - Calls `Asset::loadFromFile()` with PREFIX and system_folder --- ## 13. Future Enhancement Points ### Identified Areas for Expansion 1. **Network Play:** Stats upload to online service 2. **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 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 --- **Last Updated:** November 2022 (per README) **Original Author:** JailDesigner **Repository:** Gitea (internal)