Implement DEBUGMAP combat frontier

This commit is contained in:
gamer147
2026-07-21 19:30:56 -04:00
parent f6e48907d9
commit 7a957a318d
15 changed files with 1318 additions and 207 deletions

View File

@@ -474,8 +474,107 @@ fixed-width signed decimal field, applies zero-pad/alignment/half-width flags, a
suppressed leading cells, and rasterizes the result into the same temporary surface using current text
style. The shared VM implementation now covers that path; focused tests use DRAWENP's exact level call and
the observed half-width, zero-padded, and full-width variants. DRAWENP is now 611/611 instructions handled;
all 284 engine tests, the zero-warning Godot build, and threaded frontend selftest pass. A manual
deployment-card visual recheck remains.
all 284 engine tests, the zero-warning Godot build, and threaded frontend selftest pass. The manual
deployment-card comparison now passes.
### Post-DEBUGMAP script audit and next slice (2026-07-21)
The next slice should prove one complete **player attack and battle presentation** from the working
DEBUGMAP field: deploy a unit, enter its action flow, choose a reachable target, resolve one `BTL` exchange,
observe the HP/damage presentation settle, and return to an interactive `FIELD`. This is a stronger next
gate than expanding save/configuration or polishing isolated menus because the underlying gameplay scripts
are already much closer to complete than their presentation suggests:
- `CALCSCOPE`, `CALCARR`, `CALCBTPARAM`, `CALCREVISE`, `CALCOCC`, and `CALCDMG` are fully handled; so are
`BTANINIT`, `SETEN`, `REMOVECH`, and the ordinary map renderers.
- `BTL` has 2,194 of 2,215 static instructions handled (including one safe no-op) and 78 of 85 distinct
opcodes handled. Its remaining cluster is presentation-oriented: elapsed-time sampling (`0xd0`),
frame-time sampling (`0x23c`), movie
completion polling (`0x23a`), animation-service flags (`0x24e`), result-string construction (`0x193`),
profile bookkeeping (`0x1a2`), and delayed combat voice playback (`0x2c0`).
- `SELACT` has only five calls to missing `0x191`, now proven to be signed absolute value. `ADDEXP` is
similarly blocked mainly on string concatenation/decimal conversion plus two frame-time samples.
- FIELD itself has only 31 unhandled instructions out of 7,933. Save/load/profile and read-skip services
account for several of those and need not block the first attack loop.
The implementation order inside that slice should be evidence-driven and checkpointed: first `0x191` plus
the battle clock/frame cluster (`0xd0`, `0x23c`, `0x23a`, `0x24e`), then `0x193`/`0x1c8` for battle and EXP
messages. The sole `0x2c0` site is now proven audio-only, so delayed combat voice can follow the visible
exchange rather than block it.
The existing Godot `FrameClock` is already the correct millisecond timebase, so this does not require a new
scheduler. Defer `0x1a2` profile persistence unless the attack trace proves its value affects same-session
combat state.
One independent low-risk cleanup is now precisely scoped but should not displace the attack gate: opcode
`0x207` is a clipped surface-to-surface rectangle copy. Its 15 corpus calls restore eight minimap marker
copies plus STATUS/READICON/DRAWTIP composition. It is a good first commit or visual checkpoint within the
next work period, but it does not unlock combat state. After the first player attack returns cleanly to
FIELD, the next decision gate is enemy-turn/end-turn behavior, then stage-clear/win-loss transition—not
save/profile breadth.
The subsequent manual movement check found and closed a prerequisite earlier in that path. `MVSEEK`'s three
effectful gaps (`0x132`-`0x134`) are native reset/enqueue/try-dequeue operations on one of 11 engine integer
FIFOs. With the trio stubbed, queue 0's packed-coordinate flood fill wrote only the origin and exited because
the dequeue-success local stayed zero. That produced the exact observed state: Wait remained available on
the current tile, but no blue range overlay or other clickable movement target existed. The VM now owns the
11 FIFO slots and implements all three operations. Focused service tests plus seeded executions of the real
`MVSEEK.BIN` and `ATSEEK.BIN` prove movement costs and attack distances expand to neighboring tiles; both
scripts are now 100% handled. All 298 engine tests, the zero-warning Godot build, threaded selftest, opcode
validation, and full-corpus decode validation pass. The manual movement/overlay recheck is the next acceptance
gate, followed by the pending one-attack return to FIELD.
That first recheck remained broken because the direct worker tests bypassed SYSTEM4's persistent service
frames. SYSTEM4 uses missing `0x06` to preload ATSEEK, SETROUTE, and MVSEEK into frame slots `0x1d`-`0x1f`;
FIELD uses missing `0x08` to invoke them. Native RE proves that `0x06` allocates a script in a selected slot
without running it, while `0x08` restarts that slot at codebase and returns to the caller without discarding
its local bank. Both are now implemented as reusable VM frames and cleared on root reload. A focused test
proves restart/local persistence, and a bridge regression drives the real MVSEEK through the exact
`0x06(0x3381,0x1f)` / `0x08(0x1f)` ABI. All 300 engine tests, opcode validation, the zero-warning Godot
build, and threaded selftest pass. Manual DEBUGMAP acceptance now confirms that the complete live path shows
reachable-tile overlays, accepts movement, and reaches working player combat. The next bounded work is to
investigate the concrete combat discrepancies found during that acceptance run.
### Player-attack runtime frontier implemented (2026-07-21; manual attack pending)
The selected attack-path opcode cluster is now implemented. `0x191` preserves native signed-32-bit absolute
value behavior (including `INT_MIN`); `0xd0` and `0x23c` sample the shared monotonic/frame clock; `0x23a`
queries live movie-surface completion; and `0x24e` retains animation-service flags, including bit 1's
suppression of `0x243`. `0x193` and `0x1c8` now build aliased battle/progression strings, while `0x2c0`
replaces and services one delayed combat-voice request on the Godot frame clock.
The independent `0x207` checkpoint also landed as a real mutable-surface path. Created textures own RGBA
buffers, static sources apply their load-time color key before copying, paired source/destination clipping
is platform-neutral, overlapping self-copies use stable source pixels, and the compositor resolves generated
surfaces by slot even though they have no asset resource id. This covers minimap markers and the shared
STATUS/READICON/DRAWTIP background composition family.
Static coverage after implementation is: SELACT 59/59 opcodes and 1,099/1,099 instructions; ADDEXP 45/45
opcodes handled (including its two proven safe markers) and 310/310 instructions; DRAWMINIMAP, STATUS,
READICON, and DRAWTIP are all 100%; BTL is 84/85 opcodes handled and 2,213/2,215 instructions handled when
its safe marker is included. BTL's only remaining gap is two `0x1a2` shared-profile bookkeeping writes.
Those remain intentionally deferred until save/profile ownership is implemented because neither write feeds
the current exchange.
Focused regressions cover exact dispatch, signed edge cases, string aliasing, clock rollover truncation,
movie polling, animation reset suppression, delayed voice operands, paired clipping, overlap, and colorkey
transparency. The next gate is manual: execute one player attack from DEBUGMAP, confirm HP/damage and combat
voice presentation settle, and verify control returns to interactive FIELD. If that passes, proceed to an
enemy-turn/end-turn slice; if it fails, use the first concrete visual/control discrepancy rather than the
deferred profile write as the investigation entry point.
**Mutable-surface fill/blend regression corrected.** The first visual recheck exposed BUNKI's menu interior
as transparent. SYSTEM4 creates 800x600 surface 3 and fills it opaque white through `0x20b`; the metadata-only
host fill left the new pixel buffer transparent. Implementing the fill alone made the panel solid gray and
covered FIELD's paper minimap backing, exposing the second half of the contract: native created/render-target
surfaces are not loaded mode-0 textures and are not surfaceless fills. BUNKI draws created surface 3 with
alpha `0xd0`; FIELD draws it beneath the minimap with alpha `0x40`. Created-surface mode 0 now uses packed
alpha as opacity and packed RGB as multiplicative modulation, while loaded textures retain their established
opaque/alpha-inert behavior. Created surfaces also carry no-colorkey `-1` rather than key-black zero. Focused
regressions cover clipped RGBA replacement and the exact created-surface blend classification; all 295 engine
tests, the zero-warning Godot build, and threaded selftest pass. Manual recheck confirms both the translucent
BUNKI panel and minimap paper are correct. The movement/overlay recheck described above is now the next manual
gate on the one-player-attack acceptance path.
## Later Phase B breadth