Implement History mouse wheel navigation

This commit is contained in:
gamer147
2026-07-19 21:38:34 -04:00
parent 5ba16505d6
commit b8928ec7b8
10 changed files with 169 additions and 12 deletions

View File

@@ -11,6 +11,7 @@ Struct `EngineCtx`, size `0xa1000`. Applied to the Ghidra `/v2` image (dispatch-
| `0x410` | `archive_name_table` | `void*` | archive-name table base (arc_id*0x100 indexes it) |
| `0x414` | `sys4ini_records` | `void*` | SYS4INI 80-byte record base {name[64],arc_id,file_number,offset,size}; record = base + id*0x50 |
| `0x13dc` | `message_skip_enabled` | `int` | persistent all-message Skip flag; op 0x88 writes it and adv_interpreter_tick injects input bit 0x40 while nonzero |
| `0x1c34` | `mouse_wheel_delta` | `int` | signed WM_MOUSEWHEEL delta accumulated by age_main_window_proc; op 0x10d returns and clears it |
| `0x3028` | `alt_pack_table` | `int` | call-script high-byte alternate pack table (unused by corpus) |
| `0xb558` | `gfx_dirty_a` | `int` | gfx dirty flag (anim set raises) |
| `0xb560` | `gfx_dirty_b` | `int` | gfx dirty flag |

View File

@@ -1445,7 +1445,31 @@ script frame, blocks only at these scheduler service boundaries using the host c
after each local callback returns. Focused tests cover exact relative deadlines and the late catch-up choice.
Smooth-scroll scheduling is now implemented without changing History backlog ownership or choosing a
save/profile backend. HISTORY's remaining static gaps are five supporting opcodes across seven instructions.
save/profile backend.
#### Mouse-wheel accumulation and History navigation (2026-07-19)
Opcode `0x10d` is the read half of AGE's generic Win32 mouse-wheel service. The newly recovered
`age_main_window_proc@0x486320` handles `WM_MOUSEWHEEL` (`0x20a`), sign-extends the high word of `wParam`,
and normally adds that value to `ctx+0x1c34`. In special run modes it instead maps the sign through the
configurable `set:WheelKeyUp`/`set:WheelKeyDown` actions, so the accumulator is specifically the ordinary
raw-wheel channel used by scripts such as HISTORY.
`op_0x10d_consume_mouse_wheel_delta@0x428cf0` writes the accumulated signed value to operand 1 and clears
the field immediately. HISTORY polls it twice: once while establishing the callback loop to discard stale
input, then once per timed mouse callback. The script only tests zero and sign, converting a positive or
negative native delta into one call of its existing smooth-scroll path.
The port follows that ownership directly: Godot converts wheel-up/down events to signed 120-unit native
deltas, the VM atomically accumulates them, and `0x10d` atomically reads and clears the total. This state is
runtime input only; it is neither a script seed nor profile/save data. A real SC0000-to-HISTORY regression
opens after eight retained messages and proves wheel-up selects older retained rows without releasing or
re-entering the enclosing ADV wait.
HISTORY is now 74/78 distinct opcodes and 849/854 instructions handled or safe-noop. Its remaining static
gaps are four supporting opcodes across five instructions: text-style setter `0x8b` occurs twice,
`0x1ce`/`0x20a` form a sprite-animation service pair, and `0x1cb` reads the deliberately deferred
Read-message Skip profile setting.
The original dependency order was **Hide Window first** to establish reusable callback/coroutine input, then
Read-message Skip, then History after both the input layer and message-completion seam exist. Hide Window is

View File

@@ -594,6 +594,11 @@ op 0x90 (u0041BEB0, argc 7): `0x90 x y w h tgt_a tgt_b tgt_c`. Kelebek left it "
- **grounding:** source=investigation, confidence=high
- **evidence:** Ghidra /v2: op_0x10a_set_cursor_virtual@0x421590 maps virtual coordinates through the active VirtualFullScreen geometry and calls SetCursorPos. SC0000 alternates the cursor by one vertical pixel after state-changing ADV button clicks so the hover state re-enters cleanly.
### 0x10d `consume-mouse-wheel-delta` (u00415F10, argc 1)
- **summary:** (out) - return the accumulated signed mouse-wheel delta and clear it.
- **grounding:** source=investigation, confidence=high
- **evidence:** Ghidra /v2: op_0x10d_consume_mouse_wheel_delta@0x428cf0 copies ctx+0x1c34 to operand 1 and immediately clears the field. AGE's window procedure at 0x486925 handles WM_MOUSEWHEEL by sign-extending the high word of wParam and accumulating it at ctx+0x1c34; HISTORY.BIN polls this value and branches on its sign to select one scroll direction.
### 0x12e `find-hit-rectangle` (find-hit-rectangle, argc 8)
- **summary:** (index_inout)(reference_rect)(pointer_x)(pointer_y)(rect_array)(x_offsets)(y_offsets)(count) - scan after the incoming index for the next inclusive rectangle intersection, or return -1.
- **grounding:** source=investigation, confidence=high
@@ -878,10 +883,6 @@ op 0x90 (u0041BEB0, argc 7): `0x90 x y w h tgt_a tgt_b tgt_c`. Kelebek left it "
- **summary:** —
- **grounding:** source=kelebek, confidence=low
### 0x10d `u00415F10` (u00415F10, argc 1)
- **summary:** —
- **grounding:** source=kelebek, confidence=low
### 0x12c `lookup-array-2d` (lookup-array-2d, argc 5)
- **summary:** —
- **grounding:** source=kelebek, confidence=med

View File

@@ -1874,3 +1874,28 @@ implementation slice from their actual responsibilities rather than treating the
Validation: all 203 engine tests pass, opcode and EngineCtx tests/lints are clean, vm0 RECOVER passes, the
Godot build has zero warnings, and threaded `SELFTEST OK`.
### ADV History mouse-wheel navigation implemented (2026-07-19)
The five-gap investigation separated independent responsibilities instead of grouping them by proximity.
Native `age_main_window_proc@0x486320` handles `WM_MOUSEWHEEL` by sign-extending its high-word delta and
accumulating it at `EngineCtx+0x1c34`; op `0x10d` returns that signed total and clears it. HISTORY first
uses the opcode to discard stale motion, then polls it from its timed mouse callback and feeds the sign into
the already implemented smooth-scroll route.
Godot now translates wheel-up/down into signed 120-unit deltas, and the VM atomically accumulates and
consumes them. This extends the existing generic raw-input callback seam and introduces no script-specific
offsets, seeded state, or persistence choice. A focused regression proves accumulation/read-clear behavior;
a real SC0000-to-HISTORY regression opens after eight messages and proves wheel-up changes the retained row
selection without releasing the enclosing ADV wait.
The canonical opcode and EngineCtx sources are regenerated, and `/v2` now names/comments the recovered main
window procedure and the specific `0x10d` handler. HISTORY is 74/78 distinct opcodes and 849/854 instructions
handled or safe-noop. Remaining: `0x8b` twice, paired sprite-animation service ops `0x1ce`/`0x20a`, and the
deferred Read-message Skip setting getter `0x1cb`.
**Next:** reverse the common text-style block around `0x8b`; it is the smallest remaining non-persistence
gap. Keep `0x1cb` deferred, and treat `0x1ce`/`0x20a` together as their own sprite-animation slice.
Validation: all 205 engine tests pass, opcode and EngineCtx tests/lints are clean, vm0 RECOVER passes, the
Godot build has zero warnings, and threaded `SELFTEST OK`.