afig guia d'arquitectura del projecte

This commit is contained in:
2026-05-29 13:46:12 +02:00
parent d89141e014
commit 29a919be3a
+474
View File
@@ -0,0 +1,474 @@
# Arquitectura de **Aventures en Egipte (AEE)**
> Guía de orientación para un desarrollador nuevo en el proyecto.
>
> Cada afirmación está anclada a código real: se cita el fichero (y, cuando
> ayuda, la función o el número de línea) que la respalda. Donde no he
> encontrado algo, lo digo explícitamente en lugar de inventarlo.
>
> **Aventures en Egipte** es un juego de aventura/plataformas retro (el
> protagonista "Sam" explora pirámides esquivando momias y recogiendo
> tesoros), escrito en C++ + SDL3. Resolución de juego **320×200**. El rasgo
> que más condiciona el código es que está **en plena migración** desde un
> motor legacy propio ("Jail") hacia C++ moderno (ver
> [§3](#3-el-motor-legacy-jail)). Los comentarios del código están en
> valenciano/español; este documento está en castellano.
>
> Existe además un `docs/scenes-migration-plan.md` (histórico) sobre la
> migración del sistema de escenas; aquí se documenta el **estado actual** del
> código, no el plan.
---
## Índice
1. [Visión general](#1-visión-general)
2. [Punto de entrada y bucle principal](#2-punto-de-entrada-y-bucle-principal)
3. [El motor legacy "Jail"](#3-el-motor-legacy-jail)
4. [Escenas y máquina de estados](#4-escenas-y-máquina-de-estados)
5. [Renderizado: de la lógica al píxel](#5-renderizado-de-la-lógica-al-píxel)
6. [Entrada](#6-entrada)
7. [Gameplay: `ModuleGame` y entidades](#7-gameplay-modulegame-y-entidades)
8. [Sistema de escenas cinemáticas](#8-sistema-de-escenas-cinemáticas)
9. [Recursos](#9-recursos)
10. [Audio y localización](#10-audio-y-localización)
11. [Configuración y persistencia](#11-configuración-y-persistencia)
12. [Modo demo / IA](#12-modo-demo--ia)
13. [Convenciones y patrones recurrentes](#13-convenciones-y-patrones-recurrentes)
14. [Guía de navegación: "si quieres tocar X, mira Y"](#14-guía-de-navegación-si-quieres-tocar-x-mira-y)
---
## 1. Visión general
El árbol `source/` separa **motor** y **juego**, pero con una particularidad:
el motor tiene **dos generaciones** conviviendo (legacy "Jail" + capas nuevas).
- **`source/core/jail/`** — el **motor legacy "Jail"** (APIs C planas): `Jg`
(jgame), `Jd8` (jdraw8), `Ji` (jinput), `Jf` (jfile). En modernización (§3).
- **`source/core/`** (resto) — capas **nuevas**: `rendering` (`Screen`,
`Overlay`, `Text`, `Menu`, `sdl3gpu`), `input`, `system` (`Director`),
`resources`, `audio`, `locale`.
- **`source/game/`** — el juego: gameplay legacy en la raíz (`modulegame`,
`prota`, `momia`, `engendro`, `bola`, `mapa`, `marcador`, `info`, `sprite`) y
el sistema de **escenas** nuevo en `scenes/`.
- **`source/utils/`** — `easing`, `utils`.
- **`source/external/`** — vendorizado (stb, fkyaml).
~117 ficheros C++, ~40.000 líneas.
**El `CLAUDE.md` define una frontera explícita "Original vs New Code"** (§79):
`core/jail/` y `game/*.cpp` son *legacy en modernización* (modificar con
cuidado, preservando comportamiento); `core/rendering`, `core/input`,
`utils/`, `options/defines/defaults` son *código nuevo*. Interiorizar esa
frontera es lo primero para no romper invariantes del juego original.
**Ideas-fuerza:**
1. Un solo hilo, **tick-based**, vía callbacks de SDL3 (§2).
2. El render es **software paletizado 8-bit** (`Jd8`, 320×200) que al final se
convierte a ARGB y pasa por shaders GPU (§5).
3. El flujo de pantallas es una **máquina de estados** apoyada en
`Info::ctx.num_piramide`, con un `SceneRegistry` que va sustituyendo
cinemáticas legacy por escenas nuevas (§4).
```mermaid
graph TD
SDL[SDL3 callbacks · main.cpp] --> DIR[Director]
DIR -->|game_state_ + Info::ctx| DISP{createNextScene}
DISP -->|==0| MG["ModuleGame (gameplay)"]
DISP -->|==1| REG["SceneRegistry::tryCreate(num_piramide)"]
REG --> CINE["intro / banner / slides / mort / secreta / credits…"]
MG --> MAPA[Mapa] & PROTA[Prota] & MOMIA[Momia] & BOLA[Bola] & MARC[Marcador]
DIR --> INP["KeyConfig / GlobalInputs / Gamepad / KeyRemap / Mouse"]
MG -->|dibuja índices| JD8["Jd8 (8-bit 320×200)"]
CINE --> JD8
JD8 -->|JD8_Flip → ARGB| SCREEN[Screen]
OVL[Overlay] --> SCREEN
SCREEN --> GPU["sdl3gpu PostFX / CrtPi / upscale"] --> WIN[Ventana]
RES["Resource::Cache / List"] -.-> MG & CINE
```
---
## 2. Punto de entrada y bucle principal
### 2.1. SDL conduce el bucle (callbacks)
`source/main.cpp` define `SDL_MAIN_USE_CALLBACKS`. No hay `while` propio (clave
para el port a Emscripten). `SDL_AppInit` monta todo y `SDL_AppIterate` llama a
`Director::iterate()`.
El arranque en `SDL_AppInit` inicializa, en orden: carpeta de config (`Jf`),
sistema de recursos (`resources.pack` + fallback en Debug/WASM), `Options`,
`KeyConfig`, `Locale`, presets de shaders, y luego el **motor**: `Jg::init`,
`Screen::init`, `Jd8::init`, `Audio::init`, `Overlay::init`, `Menu::init`,
`Resource::List`/`Cache` (con `beginLoad()`), y `Director::init` + `setup()`.
### 2.2. El `Director`
`source/core/system/director.{hpp,cpp}`. Es el **orquestador singleton, único
hilo del runtime** (sin fibers, mutex ni condition variables; el comentario de
`director.hpp:11` lo subraya). Posee el estado de escena como miembros:
`current_scene_` (`std::unique_ptr<Scenes::Scene>`), `game_state_`,
`last_tick_ms_`, y dos buffers de frame `[320*200]` (`game_frame_`,
`presentation_buffer_`).
Cada `iterate()` (modelo documentado en `CLAUDE.md:161`):
```
Gamepad/KeyRemap/GlobalInputs/Mouse::update
JA_Update() ← bombeo de audio
if (!paused_) {
if (scene && (scene->done() || JG_Quitting())) game_state_ = scene->nextState(); scene.reset();
if (!scene) scene = createNextScene(); scene->onEnter(); ← ModuleGame o SceneRegistry
JI_Update()
scene->tick(now - last_tick_ms_)
JD8_Flip() ← índices → ARGB
memcpy → game_frame
}
memcpy game_frame → presentation_buffer
Overlay::render(presentation_buffer)
Screen::present(presentation_buffer)
SDL_Delay(frame_target - elapsed) ← cap de FPS
```
### 2.3. Tiempo, pausa y salida
Las escenas reciben `delta_ms` real (time-based). El gameplay (`ModuleGame`)
gatea su `Update()` a 10 ms fijos vía `Jg::shouldUpdate()` (ticker del motor
legacy, ya sin *yield*). La **pausa** (F11) simplemente salta el bloque de
`tick()`: el overlay y el present siguen, re-presentando el último frame
congelado. La **salida** se solicita con `requestQuit()` (doble ESC o
`SDL_QUIT`) y `requestRestart()` hace un reinicio suave (para audio, resetea
`Info::ctx`, vuelve a la intro).
---
## 3. El motor legacy "Jail"
`source/core/jail/` es el sustrato heredado, **APIs C planas con prefijo por
subsistema** (sin clases), que se está convirtiendo progresivamente a C++
idiomático manteniendo los nombres externos estables para no romper los
*call sites* (`CLAUDE.md:92`). Es el rasgo más distintivo del proyecto.
| Subsistema | Fichero | Qué hace |
|---|---|---|
| **`Jg`** (jgame) | `jail/jgame.*` | *Timing*: init/finalize, fixed-timestep (`Jg::shouldUpdate()` a 10 ms), flag de salida (`JG_Quitting`). |
| **`Jd8`** (jdraw8) | `jail/jdraw8.*` | **Renderer software 8-bit paletizado**, buffer de pantalla 320×200 (`Jd8::Surface = Uint8*`), blits con *color key*, fades no bloqueantes (máquina de estados), `flip()` (paleta→ARGB) → `Screen::present`. |
| **`Ji`** (jinput) | `jail/jinput.*` | Sondeo de teclado, *debounce*, códigos *cheat*. Filtra las teclas de GUI del juego y llama a `GlobalInputs`/`Mouse` cada update. |
| **`Jf`** (jfile) | `jail/jfile.*` | I/O de ficheros: carpeta `data/` o pack; carpeta de config en `~/.config/jailgames/aee/`. |
### `Jd8` en detalle (el corazón del render)
`jail/jdraw8.hpp`. API representativa:
- `using Surface = Uint8*` (búfer de índices de paleta), `using Palette = Color*`.
- `loadSurface`/`newSurface`/`freeSurface`, `loadPalette`/`setScreenPalette`.
- Blits: `blit`, `blitCK` (con *color key*/transparencia), `blitCKCut`,
`blitCKScroll`, `blitToSurface`/`blitCKToSurface` (blit entre surfaces).
- `fillRect`/`fillSquare`/`putPixel`/`getPixel`.
- **Fade no bloqueante** (`fadeStart*` + `fadeTickStep` que devuelve `true` al
acabar): sustituye los `JD8_FadeOut` bloqueantes del código original.
- `flip()` convierte el buffer indexado + paleta a ARGB y delega en
`Screen::present`; `getFramebuffer()` devuelve el `Uint32*` resultante.
> Mentalidad clave: **todo el dibujo del juego ocurre sobre índices de 8 bits**
> en un buffer 320×200; el color real y los shaders entran solo al final.
---
## 4. Escenas y máquina de estados
### 4.1. La base `Scene`
`source/game/scenes/scene.hpp` (`namespace Scenes`):
```cpp
class Scene {
public:
virtual void onEnter() {} // una vez, antes del primer tick
virtual void tick(int delta_ms) = 0; // no bloquea, NO llama a Jd8::flip
virtual auto done() const -> bool = 0;
virtual auto nextState() const -> int { return 1; } // 1=siguiente, 0=gameplay, -1=salir
};
```
El `Director` hace avanzar la escena hasta que `done()` es cierto, consulta
`nextState()` y construye la siguiente.
### 4.2. El despachador: `game_state_` + `Info::ctx`
`Director::createNextScene()` decide la siguiente escena:
- `game_state_ == 0``new ModuleGame` (gameplay puro, §7).
- `game_state_ == 1``SceneRegistry::tryCreate(Info::ctx.num_piramide)`
(`game/scenes/scene_registry.hpp`): un mapa `int → factory` que devuelve la
escena registrada para ese estado, o `nullptr` para caer al **path legacy**.
Replica el viejo `ModuleSequence::Go`, incluido el *redirect* heredado
`num_piramide == 6 && diners < 200 → 7` (`CLAUDE.md:104`).
- `game_state_ == -1` → salir.
### 4.3. `Info::ctx`: el estado del juego
`source/game/info.hpp``Info::GameContext ctx` (singleton inline) es la fuente
de verdad del estado:
```cpp
struct GameContext {
int num_piramide, num_habitacio, diners, diamants, vida, momies, engendros;
bool nou_personatge, pepe_activat;
void reset();
};
```
`num_piramide` es la pieza central: hace de **selector tanto de cinemáticas como
de nivel jugable**. El `SceneRegistry` va migrando cada estado de cinemática a
una `Scene` nueva; lo que no esté registrado cae a legacy. Por eso el registro
"crece" a medida que avanza la modernización.
```mermaid
graph LR
SC[Scene activa] -->|done()| NS{nextState}
NS -->|0| MG[ModuleGame]
NS -->|1| REG["SceneRegistry(num_piramide)"]
NS -->|-1| QUIT[salir]
MG -->|muta Info::ctx| REG
REG --> SC
```
---
## 5. Renderizado: de la lógica al píxel
El pipeline tiene dos mitades: **software paletizado** (`Jd8`) y **GPU**
(`Screen` + shaders).
### 5.1. Software: dibujar índices
Escenas y `ModuleGame` dibujan sobre el buffer `screen` de `Jd8` (índices 8-bit,
320×200) con blits y *color key*. `JD8_Flip()` aplica la paleta y produce un
buffer ARGB (formato **ABGR8888**: `0xFF000000 + R + (G<<8) + (B<<16)`;
`CLAUDE.md:220`).
### 5.2. `Overlay`: sobre el buffer ARGB
`source/core/rendering/overlay.*` pinta **directamente sobre el buffer ARGB**
antes de presentar: notificaciones (slide-in), info de render animada (4
segmentos), indicador de **PAUSA** y la lógica de **doble-ESC para salir**.
### 5.3. `Screen`: a la ventana (GPU o fallback)
`source/core/rendering/screen.*` (singleton). Doble camino
(`Screen::present`, `CLAUDE.md:204`):
- **GPU con shaders** (primario, `sdl3gpu/`): sube los píxeles a una textura
de escena 320×200; opcionalmente *upscale*/**supersampling** (3×/6×/9× con
*downscale* Lanczos) y **estiramiento 4:3** fusionado en el *upscale*; luego
el shader **PostFX** o **CRT-Pi** (con presets) a la *swapchain* con
*letterboxing*.
- **GPU sin shaders**: subida limpia a la *swapchain*.
- **Fallback**: `SDL_UpdateTexture` + `SDL_RenderPresent` (`SDL_Renderer`).
`Screen` gestiona ventana, fullscreen, zoom, 4:3, *integer scaling*, VSync, FPS.
Apoyos de UI: `Text` (fuentes bitmap `.fnt`+`.gif` sobre el buffer ARGB, con
*clipping* 2D) y `Menu` (menú flotante de opciones con navegación por páginas,
animaciones y captura de teclas para *remapping*).
---
## 6. Entrada
Toda la entrada de UI/sistema converge en **`KeyConfig`** como fuente única de
verdad de las teclas (`source/core/input/key_config.*`): carga
`data/input/keys.yaml` (F1F10 GlobalInputs + F11 pausa + F12 menú) y aplica
*overrides* del usuario; expone `scancode("id")`, `isGuiKey(sc)` (para que el
`Director` no propague teclas de UI al juego), y persiste solo lo que difiere
del default.
- **`GlobalInputs`** (`global_inputs.*`) — mapea las F-keys a acciones de
presentación (zoom, fullscreen, shaders, 4:3, supersampling, filtro, render
info, pausa, menú). Tabla completa en `CLAUDE.md:139`.
- **`Gamepad`** (`gamepad.*`) — primer mando con *hot-plug* y notificación;
D-pad/stick → flechas virtuales; botones frontales → Enter sintético;
SELECT → menú, START → pausa. Carga `gamecontrollerdb.txt`.
- **`KeyRemap`** (`key_remap.*`) — cada frame copia `Options::keys_game.*` al
estado virtual de scancodes estándar (UP/DOWN/LEFT/RIGHT). Permite remapear el
movimiento **sin tocar el código legacy** de `prota.cpp`/`mapa.cpp`.
- **`Mouse`** (`mouse.*`) — auto-oculta el cursor tras 3 s de inactividad.
> Reparto deliberado: las teclas de **UI/sistema** viven en `KeyConfig`
> (`keys.yaml`); las de **movimiento del jugador** en `Options::keys_game`
> (`config.yaml`, sección `controls:`).
---
## 7. Gameplay: `ModuleGame` y entidades
`source/game/modulegame.{hpp,cpp}` es la **escena de gameplay puro**
(`game_state_ == 0`). Hereda de `Scenes::Scene` y sustituye el viejo `Go()`
bloqueante por un `tick()`. Tres fases internas (`Phase`):
`FADING_IN → PLAYING → FADING_OUT → DONE` (`modulegame.hpp:46`), con un
`PaletteFade` para los fundidos no bloqueantes.
Coordina las entidades del nivel, todas con una `Jd8::Surface gfx_` compartida:
- **`Mapa`** (`game/mapa.*`) — la sala/pirámide: tiles con contenido
(`CONTE_RES`/`CONTE_TRESOR`/`CONTE_FARAO`…), colisión y dibujo del escenario.
- **`Prota`** (`game/prota.*`) — el protagonista "Sam" (hereda de `Sprite`),
movimiento y colisión.
- **`Momia`** (`game/momia.*`) — enemigo que persigue al `Prota` (recibe
`Prota*`); variante `dimoni` (demonio).
- **`Bola`** (`game/bola.*`) — bola/roca que interactúa con el `Prota`.
- **`Engendro`** (`game/engendro.*`) — entidad generada (su `update()` devuelve
`bool`); `Info::ctx.engendros` lleva la cuenta.
- **`Marcador`** (`game/marcador.*`) — el marcador (vidas, dinero, diamantes),
lee del `Prota`/`Info::ctx`.
`ModuleGame::tick()` hace `draw()` (a `screen`, sin `flip` — lo hace el
`Director`) y `update()` (gateado por `Jg::shouldUpdate`). Cuando la partida
acaba (`final_ != 0`: muerte o cambio de sala), `applyFinalTransitions()` muta
`Info::ctx` y `nextState()` devuelve el estado siguiente.
Todas las entidades de gameplay derivan de **`Sprite`** (`game/sprite.*`),
clase base con `draw()`/`update()` sobre `Jd8`.
---
## 8. Sistema de escenas cinemáticas
Las pantallas no jugables (`game_state_ == 1`) son `Scene`s registradas en el
`SceneRegistry`. Las concretas viven en `source/game/scenes/`: `boot_loader`
(carga incremental, §9), `banner`, `intro`, `intro_new_logo`, `intro_sprites`,
`slides`, `menu` (`menu_scene`), `mort` (secuencia de muerte), `secreta`
(pantalla secreta) y `credits`.
Sobre ellas hay un **conjunto de utilidades de animación** reutilizables —el
andamiaje "cinematográfico" del juego—:
- **`Timeline`** (`scenes/timeline.*`) — secuenciación temporal de eventos.
- **`FrameAnimator`** (`scenes/frame_animator.*`) — animación por fotogramas.
- **`SpriteMover`** (`scenes/sprite_mover.*`) — movimiento interpolado de
sprites (con `easing`).
- **`PaletteFade`** (`scenes/palette_fade.*`) — fundidos por paleta no
bloqueantes (también usado por `ModuleGame`).
- **`SurfaceHandle`** (`scenes/surface_handle.*`) — propiedad RAII de una
`Jd8::Surface` (las escenas poseen sus assets y los liberan en el destructor).
- **`scene_utils`** — helpers compartidos.
---
## 9. Recursos
- **`Resource::List`** (`core/resources/resource_list.*`) — registro de rutas de
asset desde **`data/config/assets.yaml`**, con consulta O(1).
- **`Resource::Cache`** (`core/resources/resource_cache.*`) — caché de assets con
**carga incremental**: `beginLoad()` (en `SDL_AppInit`) + la escena
`BootLoaderScene` que el `Director` arranca automáticamente mientras
`Resource::Cache::isLoadDone()` sea falso (una barra de progreso con la
ventana viva).
- **Pack y fallback**: `resource_pack.*` + `resource_helper.*` sirven desde
**`resources.pack`** (formato propio "AEE1", `CLAUDE.md:237`); en release
nativo es estricto (solo pack), en Debug/WASM hay *fallback* a `data/`.
- **Formatos**: GIF/paletas para gráficos (vía `Jd8`), fuentes `.fnt`+`.gif`,
OGG/WAV para audio, GLSL para shaders.
---
## 10. Audio y localización
- **Audio**: `core/audio/audio.*` (singleton, aplica `Options::audio`) sobre
**`jail_audio`** (`Ja`, `jail/jail_audio.hpp` / `core/audio/jail_audio.hpp`),
mezcla propia con streams SDL3 (OGG vía `stb_vorbis`, WAV). `JA_Update()` se
bombea cada frame desde el `Director`; pausa/resume con F11.
- **Localización**: `core/locale/locale.*` — mapa plano clave→cadena cargado de
YAML (`data/locale/ca.yaml`, valenciano por defecto). Claves con notación de
puntos (`menu.items.zoom`); si falta una clave, devuelve la propia clave
(fallback visible para depurar).
---
## 11. Configuración y persistencia
- **`Options`** (`source/game/options.*`) — namespace con globals `inline` y
carga/guardado YAML. Structs: `KeysGame` (movimiento), `Video`, `RenderInfo`,
`Audio`, `Window`, `Game`, `PostFXPreset`, `CrtPiPreset`.
- **`defines.hpp`** — constantes del juego: `Texts::WINDOW_TITLE`/`VERSION`,
`GameScreen::WIDTH=320`/`HEIGHT=200`/`BUFFER_SIZE=64000`.
- **`defaults.hpp`** — valores por defecto (`Defaults::KeysGame`, `Video`,
`Audio`, `Window`, `Game`).
- **`KeyConfig`** — teclas de UI (§6).
Ficheros persistentes en `~/.config/jailgames/aee/` (`CLAUDE.md:224`):
`config.yaml` (vídeo/audio/ventana/render_info/controles), `keys.yaml`
(overrides de UI), `postfx.yaml` (6 presets), `crtpi.yaml` (4 presets), y en
Debug `debug.yaml` (estado inicial de gameplay para pruebas).
**Builds condicionales**: `NDEBUG` (release: pack estricto, sin `debug.yaml`),
`__EMSCRIPTEN__` (WASM: fuerza ventana/zoom/4:3, mantiene fallback de assets,
sin persistencia MEMFS).
---
## 12. Modo demo / IA
**No he encontrado un modo demo, *attract mode* ni IA de demostración en este
proyecto.** Lo he buscado explícitamente: la única aparición de "replay" es un
comentario en `jail_audio.hpp` sobre re-reproducción de pistas de audio, sin
relación con un modo demo.
A diferencia de los proyectos hermanos `coffee_crisis` (playback de input
grabado) o `jaildoctors_dilemma` (tour de habitaciones), aquí el flujo de
atracción —si lo hubiera— se construiría sobre el `SceneRegistry` y las escenas
cinemáticas (§8), pero **hoy no existe** tal cosa implementada.
---
## 13. Convenciones y patrones recurrentes
- **Frontera legacy/nuevo** (`CLAUDE.md:79`): lo más importante. `core/jail/` y
`game/*.cpp` son legacy en modernización (preservar comportamiento); el resto
es código nuevo. Los assets de `data/gfx`/`data/music` son **intocables**.
- **Namespaces legacy abreviados** `Jg`/`Jd8`/`Ji`/`Jf`/`Ja` (APIs C planas),
con nombres externos estables durante la transición.
- **Single-thread, tick-based**: sin fibers/mutex; las escenas no bloquean ni
llaman a `Jd8::flip` (lo hace el `Director`).
- **Render paletizado 8-bit** sobre buffer 320×200; color y shaders solo al
final (`JD8_Flip``Screen`).
- **Singletons con `init()`/`destroy()`/`get()`** (`Screen`, `Audio`,
`Director`, `Menu`, `Overlay`, `Resource::*`, `Jd8`/`Jg` como módulos),
creados/destruidos en orden explícito en `SDL_AppInit`/`SDL_AppQuit`.
- **Máquina de estados por `Info::ctx.num_piramide`** + `SceneRegistry` que
migra cinemáticas legacy a `Scene`s nuevas de forma incremental.
- **Fades y timing no bloqueantes**: lo que antes eran bucles bloqueantes
(`JD8_FadeOut`) ahora son máquinas de estados que avanzan un paso por tick.
- **Comentarios** en valenciano/español; muchos `#include` con comentario de
justificación (estilo IWYU).
---
## 14. Guía de navegación: "si quieres tocar X, mira Y"
| Quiero… | Empieza por… |
|---|---|
| Entender el arranque | `source/main.cpp` (`SDL_AppInit`) + `core/system/director.cpp` |
| El bucle / orden del frame | `Director::iterate()` (`director.cpp`) |
| Tocar el motor de dibujo | `core/jail/jdraw8.*` (`Jd8`) |
| Timing / fixed-timestep | `core/jail/jgame.*` (`Jg::shouldUpdate`) |
| Añadir/editar una pantalla | `game/scenes/` (hereda de `Scenes::Scene`) + `SceneRegistry::registerScene` |
| Cómo se decide la siguiente pantalla | `Director::createNextScene` + `Info::ctx.num_piramide` + `scene_registry.*` |
| El estado del juego | `game/info.hpp` (`Info::ctx`) |
| **Gameplay** | `game/modulegame.*` (fases) + entidades `prota/momia/bola/engendro/mapa/marcador` |
| Animaciones de cinemáticas | `game/scenes/{timeline,frame_animator,sprite_mover,palette_fade,surface_handle}.*` |
| Composición final / shaders | `core/rendering/screen.*` + `sdl3gpu/` + presets `postfx.yaml`/`crtpi.yaml` |
| Overlays (notificaciones/PAUSA/info) | `core/rendering/overlay.*` |
| Texto / menú | `core/rendering/text.*`, `core/rendering/menu.*` |
| Teclas de UI / F1F12 | `core/input/key_config.*` + `global_inputs.*` + `data/input/keys.yaml` |
| Remapear movimiento | `core/input/key_remap.*` + `Options::keys_game` |
| Mando | `core/input/gamepad.*` |
| Cargar recursos / barra de carga | `core/resources/resource_cache.*` + `resource_list.*` + `scenes/boot_loader_scene.*` |
| Audio | `core/audio/audio.*` + `jail_audio.hpp` (`Ja`) |
| Idiomas | `core/locale/locale.*` + `data/locale/` |
| Opciones / constantes | `game/options.*`, `game/defines.hpp`, `game/defaults.hpp` |
| Carpetas y pack | `core/jail/jfile.*` (`Jf`) + `core/resources/resource_pack.*` |
---
*Documento generado a partir de la lectura directa del código en el commit
actual de la rama `main`. Si algo aquí no cuadra con el código, el código
manda: actualiza este documento.*