Document numeric HUD opcode contracts
This commit is contained in:
@@ -2467,6 +2467,38 @@ Focused tests cover stability, overflow, and zero count. A real-script regressio
|
|||||||
SYSTEM4-to-SC0000 state into CHMENU and stops after `0x1db8`, proving selected slot 2 survives the first
|
SYSTEM4-to-SC0000 state into CHMENU and stops after `0x1db8`, proving selected slot 2 survives the first
|
||||||
release roster sort without a fallback. No startup seed or menu-specific roster injection is involved.
|
release roster sort without a fallback. No startup seed or menu-specific roster injection is involved.
|
||||||
|
|
||||||
|
### Numeric glyph styles/draws and half-byte string length — `0x13a` / `0x23b` / `0x1a6` (2026-07-21)
|
||||||
|
|
||||||
|
The missing values in the first working `DEBUGMAP` field HUD are not missing globals or a failed texture
|
||||||
|
load. They are generated by a dedicated decimal-glyph subsystem whose two opcodes were still skipped by
|
||||||
|
the port:
|
||||||
|
|
||||||
|
- `op_0x13a_register_numeric_glyph_style@0x421ab0` takes
|
||||||
|
`(style_index, surface_slot, atlas_x, atlas_y, digit_width, digit_height)`. It accepts style indices
|
||||||
|
`0..10` and stores the remaining five operands in the 20-byte record at
|
||||||
|
`EngineCtx+0x55180+style_index*0x14`; an invalid index raises the standard script error. The corpus has
|
||||||
|
74 registrations in 24 scripts, including eight in `DRAWCHP.BIN`.
|
||||||
|
- `op_0x23b_draw_decimal_glyphs@0x424190` takes
|
||||||
|
`(base_handle, style_index, value, x, y, digit_capacity, flags)`. It first erases the destination handle
|
||||||
|
range, splits the signed integer through division/remainder by ten, and binds one retained object per
|
||||||
|
displayed digit using horizontally adjacent cells from the selected style record. Flag bit `0x1`
|
||||||
|
includes leading zeroes, bit `0x2` centers the used digits, and bit `0x4` left-aligns them; without an
|
||||||
|
alignment flag the value is right-aligned in the requested capacity. An invalid or unregistered style
|
||||||
|
raises the script error. The corpus has 147 draws in the same 24 scripts; `DRAWCHP.BIN` has 22 and uses
|
||||||
|
them for the field HUD's turn/control/mana/level/HP/SP/FS values.
|
||||||
|
|
||||||
|
This path creates ordinary retained graphics objects, so the existing atlas decode and compositor are
|
||||||
|
already the correct backend. The missing engine model is the 11 style records plus the two VM dispatches;
|
||||||
|
it is not an immediate `GodotAdvHost.DrawTexture` raster operation.
|
||||||
|
|
||||||
|
The absent unit and weapon names are a separate layout-compute gap. `DRAWCHP.BIN` does populate both
|
||||||
|
strings and calls `draw-string` at `0x9c6`/`0x9f5`, but first centers each one with opcode `0x1a6`.
|
||||||
|
`op_0x1a6_half_byte_strlen@0x427020` resolves the NUL-terminated engine byte string and writes
|
||||||
|
`strlen(bytes) >> 1`. The script multiplies that result by 21 and subtracts it from x=257 on a 263-pixel
|
||||||
|
scratch surface. With the opcode skipped, x remains 257 and Godot correctly clips nearly all of the text.
|
||||||
|
An implementation must preserve the original encoded byte count (or reproduce it with CP932 encoding),
|
||||||
|
not use the .NET UTF-16 character count.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Native walls backlog (targets for this loop)
|
## Native walls backlog (targets for this loop)
|
||||||
|
|||||||
@@ -237,6 +237,13 @@ Implemented with domain-preserving addressed-array access, native signed 32-bit
|
|||||||
- **grounding:** source=investigation, confidence=high
|
- **grounding:** source=investigation, confidence=high
|
||||||
- **evidence:** Ghidra /v2 op_0x194_string_equals@0x426e20 fetches operands 2 and 3 through the string resolver, compares their byte ranges through FUN_004017a0, and writes compare_result==0 to integer operand 1. INIT2 and GAMESTART use it as a branch predicate for INPUTNAME/default-name handling; the natural Game Start diagnostic reached one GAMESTART call at 0x134c. The C# VM implements ordinal equality through the shared string resolver, covering literal, global, local, global-string-pointer, and local-string-pointer operands; the traced natural-boot regression proves the reached GAMESTART call no longer falls back.
|
- **evidence:** Ghidra /v2 op_0x194_string_equals@0x426e20 fetches operands 2 and 3 through the string resolver, compares their byte ranges through FUN_004017a0, and writes compare_result==0 to integer operand 1. INIT2 and GAMESTART use it as a branch predicate for INPUTNAME/default-name handling; the natural Game Start diagnostic reached one GAMESTART call at 0x134c. The C# VM implements ordinal equality through the shared string resolver, covering literal, global, local, global-string-pointer, and local-string-pointer operands; the traced natural-boot regression proves the reached GAMESTART call no longer falls back.
|
||||||
|
|
||||||
|
### 0x1a6 `half-byte-string-length` (halve-strlen, argc 2)
|
||||||
|
- **summary:** Write half the resolved string's byte length, using integer truncation.
|
||||||
|
- **grounding:** source=investigation, confidence=high
|
||||||
|
- **evidence:** Ghidra /v2: op_0x1a6_half_byte_strlen@0x427020 resolves operand 2, scans to NUL, and vm_operand_write(1, strlen_bytes >> 1). DRAWCHP sites 0x9b3/0x9e2 multiply the result by 21 and subtract it from x=257 before draw-string.
|
||||||
|
|
||||||
|
Native applies strlen to the NUL-terminated engine byte string and shifts the byte count right by one. DRAWCHP uses this Shift-JIS-oriented width proxy to center unit and weapon names before rasterizing them into a scratch surface.
|
||||||
|
|
||||||
### 0x1b0 `copy-dwords` (copy-dwords, argc 3)
|
### 0x1b0 `copy-dwords` (copy-dwords, argc 3)
|
||||||
- **summary:** (source)(destination)(count) - copy count consecutive 32-bit cells from source to destination.
|
- **summary:** (source)(destination)(count) - copy count consecutive 32-bit cells from source to destination.
|
||||||
- **grounding:** source=investigation, confidence=high
|
- **grounding:** source=investigation, confidence=high
|
||||||
@@ -412,6 +419,14 @@ The handler uses an alpha step of 1 and timer interval=argument when argument <=
|
|||||||
- **grounding:** source=investigation, confidence=high
|
- **grounding:** source=investigation, confidence=high
|
||||||
- **evidence:** Ghidra /v2: op_0x131_handler@0x4295e0 calls the settings getter with `message:MesWinAlpha` and writes the result. HISTORY.BIN and the shared ADV redraw path compute (16-value)<<4 for the control-strip alpha.
|
- **evidence:** Ghidra /v2: op_0x131_handler@0x4295e0 calls the settings getter with `message:MesWinAlpha` and writes the result. HISTORY.BIN and the shared ADV redraw path compute (16-value)<<4 for the control-strip alpha.
|
||||||
|
|
||||||
|
### 0x13a `register-numeric-glyph-style` (u0041F3A0, argc 6)
|
||||||
|
- **summary:** Register one of 11 decimal-glyph atlas styles as (surface slot, source x/y, digit width/height).
|
||||||
|
- **grounding:** source=investigation, confidence=high
|
||||||
|
- **depended on by:** 0x23b
|
||||||
|
- **evidence:** Ghidra /v2: op_0x13a_register_numeric_glyph_style@0x421ab0 writes operands 2..6 to the selected five-dword record at EngineCtx+0x55180 after enforcing style_index<11. Corpus: 74 sites in 24 scripts; DRAWCHP has eight registrations immediately before its stylized HUD-number draws.
|
||||||
|
|
||||||
|
The five-dword definition is stored at EngineCtx+0x55180+style_index*0x14. Opcode 0x23b consumes it to turn an integer into retained draw objects, one atlas cell per decimal digit. An index outside [0,10] raises the engine's script error.
|
||||||
|
|
||||||
### 0x1f6 `clear-retained-gfx-objects` (clear-retained-gfx-objects, argc 0)
|
### 0x1f6 `clear-retained-gfx-objects` (clear-retained-gfx-objects, argc 0)
|
||||||
- **summary:** Clear the complete retained gfx-object registry while preserving allocated surface resources. Subsequent object queries return absent until draw/geometry operations recreate records.
|
- **summary:** Clear the complete retained gfx-object registry while preserving allocated surface resources. Subsequent object queries return absent until draw/geometry operations recreate records.
|
||||||
- **grounding:** source=investigation, confidence=high
|
- **grounding:** source=investigation, confidence=high
|
||||||
@@ -650,6 +665,14 @@ The handler requires an existing destination texture, allocates/reuses a 0x478-b
|
|||||||
- **grounding:** source=investigation, confidence=high
|
- **grounding:** source=investigation, confidence=high
|
||||||
- **evidence:** Native /v2 worker and gfx_object_apply_transform_channels decompile. The consumer advances target_frame cells over duration after delay, preserves the existing source-rect dimensions, and commits the endpoint.
|
- **evidence:** Native /v2 worker and gfx_object_apply_transform_channels decompile. The consumer advances target_frame cells over duration after delay, preserves the existing source-rect dimensions, and commits the endpoint.
|
||||||
|
|
||||||
|
### 0x23b `draw-decimal-glyphs` (u00422460, argc 7)
|
||||||
|
- **summary:** Draw an integer as decimal glyph objects from a style registered by opcode 0x13a.
|
||||||
|
- **grounding:** source=investigation, confidence=high
|
||||||
|
- **depends on:** 0x13a
|
||||||
|
- **evidence:** Ghidra /v2: op_0x23b_draw_decimal_glyphs@0x424190 reads the five-dword style record at EngineCtx+0x55180, erases the destination handle range, and calls gfx_object_bind_draw once per displayed digit. Corpus: 147 sites in 24 scripts; DRAWCHP contains 22 calls for the field HUD, including turn/control/mana/level/HP/SP/FS values visible as blank in the DEBUGMAP discrepancy.
|
||||||
|
|
||||||
|
First erase digit_capacity objects beginning at base_handle. Then split value by signed division/modulo 10 and bind at most digit_capacity retained objects using adjacent digit-width cells from the registered atlas. Flags bit 0 zero-pads, bit 1 centers the used digits, and bit 2 left-aligns them; with no alignment bit the value is right-aligned in the capacity. Invalid or unregistered style indices raise the engine's script error.
|
||||||
|
|
||||||
### 0x23d `release-transient-surfaces` (release-transient-surfaces, argc 0)
|
### 0x23d `release-transient-surfaces` (release-transient-surfaces, argc 0)
|
||||||
- **summary:** Stop movie bindings and release transient gfx surface slots 42 through 999 inclusive, preserving system-owned slots 0 through 41.
|
- **summary:** Stop movie bindings and release transient gfx surface slots 42 through 999 inclusive, preserving system-owned slots 0 through 41.
|
||||||
- **grounding:** source=investigation, confidence=high
|
- **grounding:** source=investigation, confidence=high
|
||||||
@@ -1075,10 +1098,6 @@ op 0x90 (u0041BEB0, argc 7): `0x90 x y w h tgt_a tgt_b tgt_c`. Kelebek left it "
|
|||||||
- **summary:** —
|
- **summary:** —
|
||||||
- **grounding:** source=kelebek, confidence=low
|
- **grounding:** source=kelebek, confidence=low
|
||||||
|
|
||||||
### 0x13a `u0041F3A0` (u0041F3A0, argc 6)
|
|
||||||
- **summary:** —
|
|
||||||
- **grounding:** source=kelebek, confidence=low
|
|
||||||
|
|
||||||
### 0x13f `check-bit` (check-bit, argc 3)
|
### 0x13f `check-bit` (check-bit, argc 3)
|
||||||
- **summary:** —
|
- **summary:** —
|
||||||
- **grounding:** source=kelebek, confidence=med
|
- **grounding:** source=kelebek, confidence=med
|
||||||
@@ -1143,10 +1162,6 @@ op 0x90 (u0041BEB0, argc 7): `0x90 x y w h tgt_a tgt_b tgt_c`. Kelebek left it "
|
|||||||
- **summary:** —
|
- **summary:** —
|
||||||
- **grounding:** source=kelebek, confidence=med
|
- **grounding:** source=kelebek, confidence=med
|
||||||
|
|
||||||
### 0x1a6 `halve-strlen` (halve-strlen, argc 2)
|
|
||||||
- **summary:** —
|
|
||||||
- **grounding:** source=kelebek, confidence=med
|
|
||||||
|
|
||||||
### 0x1a7 `comment` (comment, argc 1)
|
### 0x1a7 `comment` (comment, argc 1)
|
||||||
- **summary:** —
|
- **summary:** —
|
||||||
- **grounding:** source=kelebek, confidence=med
|
- **grounding:** source=kelebek, confidence=med
|
||||||
@@ -1219,10 +1234,6 @@ op 0x90 (u0041BEB0, argc 7): `0x90 x y w h tgt_a tgt_b tgt_c`. Kelebek left it "
|
|||||||
- **summary:** —
|
- **summary:** —
|
||||||
- **grounding:** source=kelebek, confidence=low
|
- **grounding:** source=kelebek, confidence=low
|
||||||
|
|
||||||
### 0x23b `u00422460` (u00422460, argc 7)
|
|
||||||
- **summary:** —
|
|
||||||
- **grounding:** source=kelebek, confidence=low
|
|
||||||
|
|
||||||
### 0x23c `u004162B0` (u004162B0, argc 0)
|
### 0x23c `u004162B0` (u004162B0, argc 0)
|
||||||
- **summary:** —
|
- **summary:** —
|
||||||
- **grounding:** source=kelebek, confidence=low
|
- **grounding:** source=kelebek, confidence=low
|
||||||
|
|||||||
@@ -434,6 +434,23 @@ that value during synchronous movie-graph initialization and retains it per movi
|
|||||||
slots return -1; unavailable timing metadata warns and returns -1 rather than exposing native's undefined
|
slots return -1; unavailable timing metadata warns and returns -1 rather than exposing native's undefined
|
||||||
failure output.
|
failure output.
|
||||||
|
|
||||||
|
The next visual comparison found all field-HUD numbers absent while their labels, bars, and source artwork
|
||||||
|
were present, plus apparently blank unit/weapon text. Native and script-side tracing resolves this into two
|
||||||
|
bounded opcode gaps rather than missing game state:
|
||||||
|
|
||||||
|
- `0x13a` registers one of 11 `(surface, atlas x/y, digit width/height)` styles, and `0x23b` expands a
|
||||||
|
decimal value into retained per-digit objects with zero-pad/center/left/right layout flags. `DRAWCHP.BIN`
|
||||||
|
contains eight style registrations and 22 numeric draws covering the visible turn/control/mana/level and
|
||||||
|
HP/SP/FS fields. Both opcodes are currently unimplemented, which precisely explains the blank values.
|
||||||
|
- `DRAWCHP.BIN` already reads and submits the unit and weapon strings to `0x204`, but its two preceding
|
||||||
|
`0x1a6` centering calls are unimplemented. Native `0x1a6` returns `strlen(CP932_bytes) >> 1`; skipping it
|
||||||
|
places the strings at x=257 on a 263-pixel scratch surface, so the existing compositor clips them.
|
||||||
|
|
||||||
|
The exact native contracts and addresses live in `docs/engine-re.md`; opcode-source metadata is in
|
||||||
|
`vm-map/opcodes.toml`. No runtime implementation was made in this investigation. The next field slice is
|
||||||
|
therefore to implement the shared 11-style numeric renderer and the encoded-byte-length calculation, then
|
||||||
|
recheck the same `DEBUGMAP` HUD before pursuing any state seeding.
|
||||||
|
|
||||||
## Later Phase B breadth
|
## Later Phase B breadth
|
||||||
|
|
||||||
Once the natural spine and first gameplay loop are trustworthy, broaden in independent tracks:
|
Once the natural spine and first gameplay loop are trustworthy, broaden in independent tracks:
|
||||||
|
|||||||
@@ -41,11 +41,13 @@ INFERRED: dict[int, dict] = {
|
|||||||
0x10b: dict(name='map-mouse-button', category='input', noop=False, confidence='high', source='investigation', summary='(button_slot)(physical_button) - map a physical mouse button to a logical button slot; polling emits the slot as logical action slot+4.'),
|
0x10b: dict(name='map-mouse-button', category='input', noop=False, confidence='high', source='investigation', summary='(button_slot)(physical_button) - map a physical mouse button to a logical button slot; polling emits the slot as logical action slot+4.'),
|
||||||
0x10c: dict(name='map-keyboard-scancode', category='input', noop=False, confidence='high', source='investigation', summary='(action)(dik_scan_code) - map a DirectInput keyboard scan code to a logical input action.'),
|
0x10c: dict(name='map-keyboard-scancode', category='input', noop=False, confidence='high', source='investigation', summary='(action)(dik_scan_code) - map a DirectInput keyboard scan code to a logical input action.'),
|
||||||
0x10d: dict(name='consume-mouse-wheel-delta', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return the accumulated signed mouse-wheel delta and clear it.'),
|
0x10d: dict(name='consume-mouse-wheel-delta', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return the accumulated signed mouse-wheel delta and clear it.'),
|
||||||
|
0x13a: dict(name='register-numeric-glyph-style', category='draw', noop=False, confidence='high', source='investigation', summary='Register one of 11 decimal-glyph atlas styles as (surface slot, source x/y, digit width/height).'),
|
||||||
0x140: dict(name='coroutine-label-yield', category='control', noop=False, confidence='med', source='investigation', summary="(out)(name_str)(sub_str)(in) — scene-coroutine LOOP ITERATOR / labeled yield. Handler copies name/sub strings + the int operand and calls the NATIVE video/transition service (*DAT_005c6018)(8, ctx[0x54fe8], &{name,sub,in}); writes the returned PC-like value to operand 1. In SC0000 label_462 'ループ開始' (@0x46d): `out=G[0x6be]=LABEL('J',G[0x6be])`; loop runs the intro-setup body (incl. call label_125bd = slot-table fill G[0x3239..0x324e]=4..11) and jmps back until out==G[0x6c3] (a per-scene exit-PC immediate) → mov aba5c 0 → content. The gate G[0xaba5c]==1 that opens this loop is NATIVE scene-entry state (no script sets it to 1). DAT_005c6018 is runtime-resolved (all xrefs READ) = SAME class as the DirectDraw workers we don't model. PORT = HOST-MODEL IMPLEMENTED: synthesize the ADV scene-entry gate, run the LABEL/J setup body once, then return the structurally discovered per-scene terminal; do not emulate the video service. See engine-re.md §Scene-coroutine framework."),
|
0x140: dict(name='coroutine-label-yield', category='control', noop=False, confidence='med', source='investigation', summary="(out)(name_str)(sub_str)(in) — scene-coroutine LOOP ITERATOR / labeled yield. Handler copies name/sub strings + the int operand and calls the NATIVE video/transition service (*DAT_005c6018)(8, ctx[0x54fe8], &{name,sub,in}); writes the returned PC-like value to operand 1. In SC0000 label_462 'ループ開始' (@0x46d): `out=G[0x6be]=LABEL('J',G[0x6be])`; loop runs the intro-setup body (incl. call label_125bd = slot-table fill G[0x3239..0x324e]=4..11) and jmps back until out==G[0x6c3] (a per-scene exit-PC immediate) → mov aba5c 0 → content. The gate G[0xaba5c]==1 that opens this loop is NATIVE scene-entry state (no script sets it to 1). DAT_005c6018 is runtime-resolved (all xrefs READ) = SAME class as the DirectDraw workers we don't model. PORT = HOST-MODEL IMPLEMENTED: synthesize the ADV scene-entry gate, run the LABEL/J setup body once, then return the structurally discovered per-scene terminal; do not emulate the video service. See engine-re.md §Scene-coroutine framework."),
|
||||||
0x199: dict(name='yield-adv-coroutine', category='control', noop=False, confidence='high', source='investigation', summary='Yield/re-enter the registered ADV coroutine handler. The fifth standard chrome button uses this transition to enter the HIDEWIN/window-hidden flow.'),
|
0x199: dict(name='yield-adv-coroutine', category='control', noop=False, confidence='high', source='investigation', summary='Yield/re-enter the registered ADV coroutine handler. The fifth standard chrome button uses this transition to enter the HIDEWIN/window-hidden flow.'),
|
||||||
0x19a: dict(name='get-message-skip', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return the current all-message skip state set by op 0x88.'),
|
0x19a: dict(name='get-message-skip', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return the current all-message skip state set by op 0x88.'),
|
||||||
0x19b: dict(name='suspend-adv-skip-service', category='input', noop=False, confidence='high', source='investigation', summary="() - suspend active ADV fast-forward while preserving the user's persistent all-message Skip toggle."),
|
0x19b: dict(name='suspend-adv-skip-service', category='input', noop=False, confidence='high', source='investigation', summary="() - suspend active ADV fast-forward while preserving the user's persistent all-message Skip toggle."),
|
||||||
0x19c: dict(name='resume-adv-skip-service', category='input', noop=False, confidence='high', source='investigation', summary='() - enable the ADV skip service and recompute active fast-forward from persistent all-message Skip or the live read-skip channel.'),
|
0x19c: dict(name='resume-adv-skip-service', category='input', noop=False, confidence='high', source='investigation', summary='() - enable the ADV skip service and recompute active fast-forward from persistent all-message Skip or the live read-skip channel.'),
|
||||||
|
0x1a6: dict(name='half-byte-string-length', category='compute', noop=False, confidence='high', source='investigation', summary="Write half the resolved string's byte length, using integer truncation."),
|
||||||
0x1a8: dict(name='instruction-marker-noop', category='marker', noop=True, confidence='high', source='investigation', summary="Zero-operand structural marker. The native shared 0xaf/0x1a8 handler only records this instruction's one-dword length and returns."),
|
0x1a8: dict(name='instruction-marker-noop', category='marker', noop=True, confidence='high', source='investigation', summary="Zero-operand structural marker. The native shared 0xaf/0x1a8 handler only records this instruction's one-dword length and returns."),
|
||||||
0x1b6: dict(name='get-auto-message', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return whether automatic message advance is enabled.'),
|
0x1b6: dict(name='get-auto-message', category='input', noop=False, confidence='high', source='investigation', summary='(out) - return whether automatic message advance is enabled.'),
|
||||||
0x1b7: dict(name='set-auto-message', category='input', noop=False, confidence='high', source='investigation', summary='(enabled) - enable or disable automatic message advance.'),
|
0x1b7: dict(name='set-auto-message', category='input', noop=False, confidence='high', source='investigation', summary='(enabled) - enable or disable automatic message advance.'),
|
||||||
@@ -71,6 +73,7 @@ INFERRED: dict[int, dict] = {
|
|||||||
0x231: dict(name='animate-gfx-srcrect-loop', category='draw', noop=False, confidence='high', source='investigation', summary="(handle)(frame_period_ms)(frame_count)(column_count) — loop row-major through the spritesheet. Every frame preserves draw-texture's source-rectangle width/height; frame=floor(elapsed/frame_period)%frame_count, src offset=(frame%columns*width, frame/columns*height). Worker gfx_worker_anim_srcrect @0x47eec0; consumer gfx_object_anim_interpolate @0x473ed0."),
|
0x231: dict(name='animate-gfx-srcrect-loop', category='draw', noop=False, confidence='high', source='investigation', summary="(handle)(frame_period_ms)(frame_count)(column_count) — loop row-major through the spritesheet. Every frame preserves draw-texture's source-rectangle width/height; frame=floor(elapsed/frame_period)%frame_count, src offset=(frame%columns*width, frame/columns*height). Worker gfx_worker_anim_srcrect @0x47eec0; consumer gfx_object_anim_interpolate @0x473ed0."),
|
||||||
0x232: dict(name='animate-gfx-color-loop', category='draw', noop=False, confidence='high', source='investigation', summary='0x232 anim-color (handle)(period)(alpha)(color): ping-pong the temporary packed ARGB passed to the normal object blit. Handler resolves negative alpha/RGB from static color obj+0x60 and clamps alpha above 255. Blend selector obj+0x30 is unchanged: mode 0 keeps default blending (animated alpha is inert; RGB is vertex modulation), while mode 1 uses sampled ARGB alpha as the SRCALPHA scale for additive composition. Fresh static color is 0xffffffff. The C# VM resolves sentinels and consumes sampled ARGB through the unchanged mode-specific path. See docs/engine-re.md §SC0000 anim cluster.'),
|
0x232: dict(name='animate-gfx-color-loop', category='draw', noop=False, confidence='high', source='investigation', summary='0x232 anim-color (handle)(period)(alpha)(color): ping-pong the temporary packed ARGB passed to the normal object blit. Handler resolves negative alpha/RGB from static color obj+0x60 and clamps alpha above 255. Blend selector obj+0x30 is unchanged: mode 0 keeps default blending (animated alpha is inert; RGB is vertex modulation), while mode 1 uses sampled ARGB alpha as the SRCALPHA scale for additive composition. Fresh static color is 0xffffffff. The C# VM resolves sentinels and consumes sampled ARGB through the unchanged mode-specific path. See docs/engine-re.md §SC0000 anim cluster.'),
|
||||||
0x239: dict(name='animate-gfx-srcrect-target', category='draw', noop=False, confidence='high', source='investigation', summary='(handle)(delay_ms)(duration_ms)(frame_count)(column_count)(target_frame) — one-shot row-major source-rectangle cell channel. Worker gfx_worker_set_srcrect_cell @0x47ed90 stores timing at obj+0x48/+0x5c, layout at +0x238/+0x23c, and target at +0x234. C# currently retains the endpoint cell immediately.'),
|
0x239: dict(name='animate-gfx-srcrect-target', category='draw', noop=False, confidence='high', source='investigation', summary='(handle)(delay_ms)(duration_ms)(frame_count)(column_count)(target_frame) — one-shot row-major source-rectangle cell channel. Worker gfx_worker_set_srcrect_cell @0x47ed90 stores timing at obj+0x48/+0x5c, layout at +0x238/+0x23c, and target at +0x234. C# currently retains the endpoint cell immediately.'),
|
||||||
|
0x23b: dict(name='draw-decimal-glyphs', category='draw', noop=False, confidence='high', source='investigation', summary='Draw an integer as decimal glyph objects from a style registered by opcode 0x13a.'),
|
||||||
0x23f: dict(name='query-surface-stop-time-ms', category='draw', noop=False, confidence='high', source='investigation', summary='(out_stop_time_ms)(surface_slot) — query the DirectShow stop position retained by a loaded movie surface, convert seconds to integer milliseconds by truncating toward zero, and write -1 when the movie slot is empty. The port retains this metadata during 0x236 graph initialization; unavailable metadata emits a warning and also returns -1.'),
|
0x23f: dict(name='query-surface-stop-time-ms', category='draw', noop=False, confidence='high', source='investigation', summary='(out_stop_time_ms)(surface_slot) — query the DirectShow stop position retained by a loaded movie surface, convert seconds to integer milliseconds by truncating toward zero, and write -1 when the movie slot is empty. The port retains this metadata during 0x236 graph initialization; unavailable metadata emits a warning and also returns -1.'),
|
||||||
0x258: dict(name='decl?', category='marker', noop=True, confidence='low', source='harness', summary='2 imm; runs in a chain right after script-entry 0x259, enumerating ids — prologue declaration/registration?'),
|
0x258: dict(name='decl?', category='marker', noop=True, confidence='low', source='harness', summary='2 imm; runs in a chain right after script-entry 0x259, enumerating ids — prologue declaration/registration?'),
|
||||||
0x259: dict(name='script-entry', category='marker', noop=True, confidence='low', source='harness', summary='zero-arg; the first instruction of a script (offset 0), opens the decl chain that 0x258 continues — script/prologue entry marker, structural'),
|
0x259: dict(name='script-entry', category='marker', noop=True, confidence='low', source='harness', summary='zero-arg; the first instruction of a script (offset 0), opens the decl chain that 0x258 continues — script/prologue entry marker, structural'),
|
||||||
|
|||||||
@@ -2814,43 +2814,44 @@ argc = 6
|
|||||||
abi_source = "kelebek+decode-validated"
|
abi_source = "kelebek+decode-validated"
|
||||||
|
|
||||||
[opcode.semantics]
|
[opcode.semantics]
|
||||||
name = "u0041F3A0"
|
name = "register-numeric-glyph-style"
|
||||||
category = "unknown"
|
category = "draw"
|
||||||
summary = ""
|
summary = "Register one of 11 decimal-glyph atlas styles as (surface slot, source x/y, digit width/height)."
|
||||||
|
details = "The five-dword definition is stored at EngineCtx+0x55180+style_index*0x14. Opcode 0x23b consumes it to turn an integer into retained draw objects, one atlas cell per decimal digit. An index outside [0,10] raises the engine's script error."
|
||||||
noop_headless = false
|
noop_headless = false
|
||||||
source = "kelebek"
|
source = "investigation"
|
||||||
confidence = "low"
|
confidence = "high"
|
||||||
depends_on = []
|
depends_on = []
|
||||||
evidence = ""
|
evidence = "Ghidra /v2: op_0x13a_register_numeric_glyph_style@0x421ab0 writes operands 2..6 to the selected five-dword record at EngineCtx+0x55180 after enforcing style_index<11. Corpus: 74 sites in 24 scripts; DRAWCHP has eight registrations immediately before its stylized HUD-number draws."
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 1
|
i = 1
|
||||||
role = ""
|
role = "style_index"
|
||||||
observed_types = ["imm"]
|
observed_types = ["imm"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 2
|
i = 2
|
||||||
role = ""
|
role = "surface_slot"
|
||||||
observed_types = ["imm", "l-int"]
|
observed_types = ["imm", "l-int"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 3
|
i = 3
|
||||||
role = ""
|
role = "atlas_x"
|
||||||
observed_types = ["imm"]
|
observed_types = ["imm"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 4
|
i = 4
|
||||||
role = ""
|
role = "atlas_y"
|
||||||
observed_types = ["imm"]
|
observed_types = ["imm"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 5
|
i = 5
|
||||||
role = ""
|
role = "digit_width"
|
||||||
observed_types = ["imm"]
|
observed_types = ["imm"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 6
|
i = 6
|
||||||
role = ""
|
role = "digit_height"
|
||||||
observed_types = ["imm"]
|
observed_types = ["imm"]
|
||||||
|
|
||||||
[[opcode]]
|
[[opcode]]
|
||||||
@@ -3559,23 +3560,24 @@ argc = 2
|
|||||||
abi_source = "kelebek+decode-validated"
|
abi_source = "kelebek+decode-validated"
|
||||||
|
|
||||||
[opcode.semantics]
|
[opcode.semantics]
|
||||||
name = "halve-strlen"
|
name = "half-byte-string-length"
|
||||||
category = "unknown"
|
category = "compute"
|
||||||
summary = ""
|
summary = "Write half the resolved string's byte length, using integer truncation."
|
||||||
|
details = "Native applies strlen to the NUL-terminated engine byte string and shifts the byte count right by one. DRAWCHP uses this Shift-JIS-oriented width proxy to center unit and weapon names before rasterizing them into a scratch surface."
|
||||||
noop_headless = false
|
noop_headless = false
|
||||||
source = "kelebek"
|
source = "investigation"
|
||||||
confidence = "med"
|
confidence = "high"
|
||||||
depends_on = []
|
depends_on = []
|
||||||
evidence = ""
|
evidence = "Ghidra /v2: op_0x1a6_half_byte_strlen@0x427020 resolves operand 2, scans to NUL, and vm_operand_write(1, strlen_bytes >> 1). DRAWCHP sites 0x9b3/0x9e2 multiply the result by 21 and subtract it from x=257 before draw-string."
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 1
|
i = 1
|
||||||
role = ""
|
role = "destination"
|
||||||
observed_types = ["l-int"]
|
observed_types = ["l-int"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 2
|
i = 2
|
||||||
role = ""
|
role = "string"
|
||||||
observed_types = ["l-str", "l-str-ptr"]
|
observed_types = ["l-str", "l-str-ptr"]
|
||||||
|
|
||||||
[[opcode]]
|
[[opcode]]
|
||||||
@@ -6299,48 +6301,49 @@ argc = 7
|
|||||||
abi_source = "kelebek+decode-validated"
|
abi_source = "kelebek+decode-validated"
|
||||||
|
|
||||||
[opcode.semantics]
|
[opcode.semantics]
|
||||||
name = "u00422460"
|
name = "draw-decimal-glyphs"
|
||||||
category = "unknown"
|
category = "draw"
|
||||||
summary = ""
|
summary = "Draw an integer as decimal glyph objects from a style registered by opcode 0x13a."
|
||||||
|
details = "First erase digit_capacity objects beginning at base_handle. Then split value by signed division/modulo 10 and bind at most digit_capacity retained objects using adjacent digit-width cells from the registered atlas. Flags bit 0 zero-pads, bit 1 centers the used digits, and bit 2 left-aligns them; with no alignment bit the value is right-aligned in the capacity. Invalid or unregistered style indices raise the engine's script error."
|
||||||
noop_headless = false
|
noop_headless = false
|
||||||
source = "kelebek"
|
source = "investigation"
|
||||||
confidence = "low"
|
confidence = "high"
|
||||||
depends_on = []
|
depends_on = [0x13a]
|
||||||
evidence = ""
|
evidence = "Ghidra /v2: op_0x23b_draw_decimal_glyphs@0x424190 reads the five-dword style record at EngineCtx+0x55180, erases the destination handle range, and calls gfx_object_bind_draw once per displayed digit. Corpus: 147 sites in 24 scripts; DRAWCHP contains 22 calls for the field HUD, including turn/control/mana/level/HP/SP/FS values visible as blank in the DEBUGMAP discrepancy."
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 1
|
i = 1
|
||||||
role = ""
|
role = "base_handle"
|
||||||
observed_types = ["imm", "l-int"]
|
observed_types = ["imm", "l-int"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 2
|
i = 2
|
||||||
role = ""
|
role = "style_index"
|
||||||
observed_types = ["imm", "l-int"]
|
observed_types = ["imm", "l-int"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 3
|
i = 3
|
||||||
role = ""
|
role = "value"
|
||||||
observed_types = ["imm", "g-int", "l-int", "l-ptr"]
|
observed_types = ["imm", "g-int", "l-int", "l-ptr"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 4
|
i = 4
|
||||||
role = ""
|
role = "destination_x"
|
||||||
observed_types = ["imm", "l-int"]
|
observed_types = ["imm", "l-int"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 5
|
i = 5
|
||||||
role = ""
|
role = "destination_y"
|
||||||
observed_types = ["imm", "l-int"]
|
observed_types = ["imm", "l-int"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 6
|
i = 6
|
||||||
role = ""
|
role = "digit_capacity"
|
||||||
observed_types = ["imm"]
|
observed_types = ["imm"]
|
||||||
|
|
||||||
[[opcode.semantics.args]]
|
[[opcode.semantics.args]]
|
||||||
i = 7
|
i = 7
|
||||||
role = ""
|
role = "flags"
|
||||||
observed_types = ["imm"]
|
observed_types = ["imm"]
|
||||||
|
|
||||||
[[opcode]]
|
[[opcode]]
|
||||||
|
|||||||
Reference in New Issue
Block a user