merge docs/arquitectura: guia d'arquitectura del projecte
This commit is contained in:
@@ -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` (F1–F10 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 / F1–F12 | `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.*
|
||||
Reference in New Issue
Block a user