OPENU5 Portada EN

Estas páginas se generan a partir de la documentación interna del proyecto. Las referencias a ficheros de código y a offsets del binario se conservan como procedencia —para que se vea de dónde sale cada afirmación—, pero todavía no se pueden seguir: el motor aún no está publicado. Cuando lo esté, pasarán a ser enlaces.

4 · El panel de depuración

El drawer de QA completo, sección a sección.

Cómo abrirlo: tecla ` ` (backquote) o F4, o ?debug=1 en la URL. Y desde ⚙ → «Debug (QA)» → «Abrir menú debug». Expone window.__u5debug` para consola y e2e.

Sólo DEV. La fila del menú SISTEMA y el atajo se anuncian únicamente cuando la dependencia openDebug existe: en las pieles fiel/shader de producción no se le dice a nadie que este panel está ahí.

Capturas nuevas generadas para este documento el 04-08-2026 contra dev server propio (:5271), sobre . Viven en docs/verdicts/debug-drawer/.


El panel entero

Drawer debug

Un drawer lateral derecho de 360 px, en DOM puro, con buscador de campos arriba y un acordeón de secciones debajo.

Censo, medido en vivo el 04-08-2026

#SecciónCampos
0Atajos3
1Teletransporte7
2Party23
3Recursos9
4Mundo / Reloj15
5Trama / Quest45
6Transportes7
7NPCs (dead / met)65
8Mazmorra · salas despejadas17
9Moonstones32
10Inventario · Reactivos8
11Inventario · Equipo (stock)48
12Inventario · Hechizos48
13Inventario · Pociones / Pergaminos16
Total14 secciones · 343 campos

Las cuatro reglas de arquitectura

Antes del recorrido, porque explican casi todo lo que se ve.

1 · Cero-rand, por construcción

Toda escritura pasa por una única fachada (debug/debugApi.ts) que escribe directo en el estado vivo —la misma struct que se persiste al save nativo— y nunca por Intents ni por nada que consuma el stream del RNG. Cada método es un puñado de escrituras planas más un refresh().

Por qué importa: si el panel consumiera tiradas, usarlo cambiaría la partida de forma invisible, y cualquier careo contra el DOS quedaría contaminado. La invariante está aseverada por un test (debug-api.test.ts) que comprueba que liveSeed() no se mueve tras ninguna operación.

Incluso el teletransporte respeta la regla: replica la receta del deep-link fijando position y, en mapas pequeños, enterMap + hydrateInteriorObjects — los dos deterministas.

2 · El registro es declarativo; el panel no sabe de nada

registry.ts declara qué se puede editar ({label, get, set, widget}); panel.ts lo pinta. Añadir un campo nuevo es una entrada más en el registro, sin tocar el panel.

3 · No estorba al juego

El canvas sigue jugable con el drawer abierto, y el panel no captura las teclas del juego salvo cuando uno de sus inputs tiene el foco (stopPropagation sólo para eventos originados en el panel). El refresco es por campo: se re-lee get() y se actualiza el control sin reconstruir el DOM, de modo que el mapa de teletransporte y el foco se preservan.

4 · Ningún tope está inventado

Regla explícita del encargo original. Cada límite se deriva del tipo de campo del SAVED.GAM y del cap que el juego aplica, o de una fórmula ya derivada del binario, y se cita en la constante:

TopeValorDe dónde sale
Oro / comida / experiencia9999campos u16, pero el juego los satura a CAP_WORD (add_word_capped, kernel 0x9C84)
Llaves, gemas, antorchas…99campos u8, pero el modelo trata las cantidades como valor de 2 dígitos
Karma99u8 en 0x2e2, 2 dígitos en Ztats
FUE / DES / INT30, no 99⬅️ ver abajo

El 30 es el detalle bonito. El planificador de turnos y los umbrales del binario operan como CONST − stat en byte sin signo: un atributo por encima de 0x23 (35) wrapea. Con DES 99 el grupo queda inmóvil e intocable — el juego «funciona», y está roto. Así que el tope del panel es 30: rápido de verdad y dentro del régimen. La etiqueta del campo lo lleva escrito, y la derivación está en audit-byte-wrap.

Es el ejemplo perfecto de por qué un editor de estado necesita conocer el binario: un control con max=99 habría sido «correcto» según el tipo de dato y habría producido un bug irreproducible.


Sección 0 · Atajos

Atajos

Tres botones de un clic, arriba del todo porque son lo que más se usa:

BotónQué hace
Maximizar todoParty (HP/MP/stats/nivel/estado) + recursos + inventario a sus topes + todos los ítems especiales (garfio, regalía de LB, esquirlas, catalejo, sextante, reloj, insignia, caja, HMS Cape)
Mejor equipo para todosEquipa a cada miembro con el mejor ítem por ranura, derivado de las tablas de ataque/defensa de los datos — no de una lista escrita a mano — respetando la regla de dos manos
Party completo al máximoLlena el grupo con miembros reales del roster (hasta 6) y aplica los dos anteriores

Los tres son lógica pura en debug/shortcuts.ts (sin mutar el Game, sin DOM), y la fachada los aplica. Todos cero-rand.

Verificación existente: docs/verdicts/debug-maxall/.

Esquirlas y regalíaInsignia y especiales
maxall shardsmaxall badge

Sección 1 · Teletransporte

Teletransporte

Dos vías: los desplegables (localización + planta, o mazmorra) y —la buena— el selector de mapa.

El selector de mapa

Selector de mapa de teletransporte

Modal grande y centrado, porque embutir un mapa en un drawer de 360 px no es usable. Tres pestañas:

Un clic teletransporta a esa celda exacta. También hay entrada numérica x,y + Enter. Al pasar el ratón se ve (x,y) y el nombre del tile, y en mazmorra el subtipo (p. ej. «Room #8»). Recuerda el último destino.

El detalle que decide su fiabilidad

Cada mapa se renderiza del dato VIVO del core, nunca de JSONs rancios. La retícula de ciudad sale de getActiveMap(world, loc, floor).tileAt — la misma fuente que usa el juego para decidir dónde puedes pisar. Un selector alimentado por un JSON exportado sería un mapa de otra versión del mundo, y sus errores parecerían bugs del juego.

Dos decisiones de UX

Y la única acción marcada como peligrosa

La sección tiene un botón «Entrar mazmorra (flujo real)» con badge rojo:

«Entrada REAL de la mazmorra — puede consumir RNG del stream (no cero-rand).»

Es la excepción declarada a la regla 1, y el panel la marca visualmente en vez de esconderla. Un editor de estado que no distingue «escribir un byte» de «ejecutar el flujo del juego» es un editor en el que no se puede confiar para preparar un careo.

Capturas del teletransporte a los cinco tipos de destino: docs/verdicts/debug-teleport/ (01-overworld, 02-overworld-zoom, 03-underworld, 04-town, 05-dungeon) y del tileado y el arreglo de la gema en docs/verdicts/debug-picker-tiling/ y docs/verdicts/debug-picker-gemfix/.

Antes del fix de la gemaDespués
picker gema, antespicker gema, después

Sección 2 · Party (23 campos)

Party

Selector de personaje y, por miembro: nombre, género (0x0B/0x0C), clase (las nueve letras de "AMBFDTPRS"), estado (G/P/C/S/D), HP, HP máx, MP, nivel, experiencia, FUE/DES/INT, partyStatus, meses en la posada y todas las ranuras de equipo.

Las etiquetas llevan la advertencia pegada: «Fuerza (máx 30 — >35 wrapea el scheduler, audit-byte-wrap)». La derivación viaja con el control, no en un documento aparte que nadie abrirá.

También: tamaño de grupo (1..6) y personaje activo.


Sección 3 · Recursos (9 campos)

Recursos

Oro, comida, llaves, gemas, antorchas, llaves de calavera, alfombras mágicas, karma y los demás contadores globales. Cada uno con su tope derivado (§«Ningún tope está inventado»).


Sección 4 · Mundo / Reloj (15 campos)

Mundo / Reloj

Año, mes (con los seis nombres reales: Deep Winter, Awakening, Time of Sowing, Season of Sun, Time of Harvest, Fruitful Winter), día, hora, minuto, viento (Calm/N/S/E/O), transporte, y los campos de runtime que el save persiste:

Que las dos fases lunares latcheadas sean editables no es un capricho: son las que determinan a dónde lleva una moongate, y sin ellas no se puede montar el escenario de un careo de viaje lunar.


Sección 5 · Trama / Quest (45 campos)

Palabras de poder pronunciadas (×8), shadowlords muertos (×3), in-doom, game-won, Blackthorn… y toda clave viva de questFlags, en crudo, incluidas las que no se saben derivar (marcadas «sin derivar»).

Enumeración total, no curada — mandato explícito del usuario. La diferencia importa: una lista curada sólo enseña las banderas que alguien ya entendía, que son justo las que menos falta hace inspeccionar.

Contrapartida: se puede escribir una bandera que nadie entiende

El precio de enumerarlo todo es que el panel ofrece controles editables sobre claves sin derivar. Se pueden ver —que es el objetivo— pero también se pueden escribir, y escribir un bit cuyo significado no se conoce produce un estado que el juego quizá no sepa leer, sin ningún aviso.

La sección las marca «sin derivar», y esa etiqueta es toda la protección que hay. Es consistente con el resto del panel (es una herramienta de QA, no una interfaz a prueba de tontos), pero conviene saber que el ruido no está sólo en la lectura.


Sección 6 · Transportes (7 campos)

Transportes

transportTile en byte crudo, más el estado de la fragata y el viento: casco, esquifes, dirección de vela, contador de deriva por viento, toggle del HMS Cape. Y un botón de QA para vaciar el pool de enemigos.

Verificación existente: docs/verdicts/debug-save-editor/01-transportes.png.


Sección 7 · NPCs (dead / met) — 65 campos

La sección más grande: por (localización, índice de NPC), un desplegable de localización y 32 + 32 casillas (muerto / conocido).

⚠️ Ojo: el índice no es la posición en un array — es un índice propio del NPC. Confundirlos hace que se marque al vecino de al lado.

Verificación existente: docs/verdicts/debug-save-editor/03-npcs-dead.png.


Sección 8 · Mazmorra · salas despejadas (17 campos)

Salas despejadas

El bitmap de salas ya despejadas: 7 ranuras × 16 salas.

Y una rareza del binario que el panel refleja en vez de disimular: Deceit y Despise colapsan en la ranura 0. Las ocho mazmorras comparten siete ranuras. La etiqueta lo dice —«Deceit / Despise»— y la derivación vive en dungeonClearedBitIndex.

Un editor que hubiera «arreglado» eso dando ocho ranuras habría escrito bits que el juego no lee.

Verificación existente: docs/verdicts/debug-save-editor/02-mazmorra-salas.png.


Sección 9 · Moonstones (32 campos)

Moonstones

Posición y estado de las ocho piedras lunares.


Secciones 10-13 · Inventario (120 campos)

SecciónCamposCaptura
Reactivos8reactivos
Equipo (stock)48equipo
Hechizos48hechizos
Pociones / Pergaminos16pociones

Cada celda es un campo numérico etiquetado con el nombre real del ítem, leído de InventoryDetails.json. No hay índices desnudos que obliguen a consultar una tabla aparte.


La guarda que impide que esto se quede atrás

El editor de save mantiene un manifiesto de cobertura —COVERED_STATE_KEYS y EXCLUDED_STATE_KEYS— que es la fuente de un test de completitud: si alguien añade un campo nuevo al GameState y no lo pone en ninguna de las dos listas, el guard se pone rojo.

Es la diferencia entre un panel de depuración que envejece bien y uno que a los seis meses edita el 70% del estado sin que nadie sepa cuál 70%. La decisión que se fuerza no es «añade el campo al panel», sino la más barata y más útil: decide y declara si viaja o si está excluido.


Lo que este panel no es