Implement system menu guard opcode
This commit is contained in:
@@ -123,3 +123,4 @@ Struct `EngineCtx`, size `0xa1000`. Applied to the Ghidra `/v2` image (dispatch-
|
||||
| `0xa0cc8` | `screen_bpp` | `int` | screen bpp (8) |
|
||||
| `0xa0ce4` | `run_state_flags` | `uint` | interpreter run-state flags (bit1 sleeping; 0x8000000 skip/fast-forward) |
|
||||
| `0xa0ce8` | `timed_callback_abort_signal` | `int` | scheduler-polled abort/input signal cleared when op 0xd5 starts; redirects to abort PC when configured |
|
||||
| `0xa0d10` | `system_menu_actions_enabled` | `int` | op 0x142 replaces this AGERC/IAGEService reentrancy guard; scene reset defaults it to 1, while CONFIG brackets its scripted settings UI with 0 then 1 |
|
||||
|
||||
@@ -903,6 +903,36 @@ backing's earlier one-shot-color provenance, so classifying only animated or loo
|
||||
rebuilt message window opaque. Post-bind static alpha now controls this fresh backing as well; repeated
|
||||
CONFIG changes therefore take effect immediately while the enclosing ADV wait remains active.
|
||||
|
||||
### Native system-menu reentrancy guard — opcode `0x142` (2026-07-29)
|
||||
|
||||
`op_0x142_set_system_menu_actions_enabled@0x421fe0` is a direct one-operand setter for
|
||||
`EngineCtx.system_menu_actions_enabled` (`ctx+0xa0d10`). `scene_context_init_reset@0x40b3b0` initializes
|
||||
the field to one. CONFIG.BIN contains both shipped calls: `0x142(0)` is its first instruction, before any
|
||||
settings data or UI is built, and `0x142(1)` runs after its last optional callback and immediately before
|
||||
retained-object/surface/SFX teardown and exit.
|
||||
|
||||
The field is not consumed by the interpreter, renderer, gameplay logic, or persistence. AGE exposes it
|
||||
through `AGE:IAGEService` virtual method `iage_service_query_system_menu_enabled@0x45f7c0` (vtable offset
|
||||
`+0xb4`), which returns whether the field is nonzero. The shipped AGERC.DLL obtains that interface through
|
||||
`GetClassObject("AGE:IAGEService")`. Its `agerc_refresh_system_menu_state@0x10002e10` calls the virtual
|
||||
getter after refreshing the native menu's settings. A zero result applies `MF_GRAYED` through
|
||||
`EnableMenuItem` to command ids `0x9c63`, `0x9c64`, `0x9c65`, `0x9c68`, `0x9c6c`, `0x9c6e`, and
|
||||
`0x9c6f`; those entries launch settings/save-related callbacks and modal services that could otherwise
|
||||
reenter configuration while CONFIG already owns the scripted settings UI.
|
||||
|
||||
The opcode is therefore a host-menu availability guard, not a configuration-persistence switch or input
|
||||
lock for the game itself. A portable frontend without AGE's native AGERC menu can retain the flag for
|
||||
lifetime/state parity and gate any future equivalent menu, with no immediate visual or headless effect.
|
||||
It is an isolated implementation slice and has no dependency on the remaining opcode gaps. The handler,
|
||||
IAGEService getter, AGERC menu refresher, and typed EngineCtx field are annotated in the saved Ghidra
|
||||
programs.
|
||||
|
||||
The port retains the complete signed dword on `VirtualMachine`, initializes it to one, replaces it on each
|
||||
`0x142` call, and restores one during opcode-`0x9` root scene-context reset. It deliberately does not call
|
||||
an `IHost` service: the Godot frontend has no AGERC/native application menu to gray, and treating the flag
|
||||
as a game-input or persistence switch would broaden its native effect. `SystemMenuActionsEnabled` exposes
|
||||
the retained value for a future equivalent frontend menu.
|
||||
|
||||
The same route exposed an independent publication-atomicity requirement. Each tile step reaches
|
||||
`FIELD@0x4eb2 -> 0x9225`, which calls `DRAWMAP`, `DRAWOBJ`, and `DRAWMINIMAP`. `DRAWMAP` first erases its
|
||||
old terrain handle ranges and then rebuilds them; `DRAWMINIMAP` recreates mutable surfaces `0x42..0x44`
|
||||
|
||||
@@ -1258,6 +1258,13 @@ 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_0x12e_find_hit_rectangle@0x428ff0 resolves the reference rectangle and three array operands as VM pointers, decodes rectangle/offset values with anti_tamper_a, and starts at incoming_index+1. Each candidate is [left,right,top,bottom]; the worker subtracts its per-entry x/y offsets from the pointer, inclusively intersects it with the reference rectangle, and writes the matched array index or -1 to operand 1. HISTORY.BIN uses decoded local arrays for scrollbar/control regions, close region 8, and visible text rows 9..13.
|
||||
|
||||
### 0x142 `set-system-menu-enabled` (set-system-menu-enabled, argc 1)
|
||||
- **summary:** (enabled) - replace the EngineCtx flag exposed through IAGEService to gate reentrant native AGERC system-menu actions. Scene reset defaults it to 1; CONFIG writes 0 on entry and 1 immediately before teardown and exit.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x142_set_system_menu_actions_enabled@0x421fe0 directly stores operand 1 at EngineCtx+0xa0d10. scene_context_init_reset initializes the field to 1. iage_service_query_system_menu_enabled@0x45f7c0 exposes it as a boolean through the AGE:IAGEService vtable at +0xb4. Shipped /support/AGERC.DLL's agerc_refresh_system_menu_state@0x10002e10 calls that method; zero invokes EnableMenuItem(...,MF_GRAYED) for command ids 0x9c63/64/65/68/6c/6e/6f. CONFIG.BIN's only sites bracket its complete scripted settings UI with 0 then 1.
|
||||
|
||||
Port status (2026-07-29): implemented as an EngineCtx-lifetime signed-dword field on VirtualMachine. Root scene reload restores one. The current Godot frontend has no AGERC native system menu, so the value is retained for exact state parity and a future equivalent menu consumer without affecting game input or persisted settings.
|
||||
|
||||
### 0x144 `edit-fullwidth-string-dialog` (edit-fullwidth-string-dialog, argc 2)
|
||||
- **summary:** (result_inout)(initial_text) - synchronously open AGERC's modal full-width text editor. Accept writes at most eight valid CP932 double-byte characters to operand 1; cancel leaves operand 1 unchanged. Operand 2 supplies the initial edit text and is preserved.
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
@@ -1976,10 +1983,6 @@ Port status (2026-07-24): implemented through the same profile-lifetime setting
|
||||
- **summary:** —
|
||||
- **grounding:** source=kelebek, confidence=med
|
||||
|
||||
### 0x142 `u0041FB10` (u0041FB10, argc 1)
|
||||
- **summary:** —
|
||||
- **grounding:** source=kelebek, confidence=low
|
||||
|
||||
### 0x145 `u00416040` (u00416040, argc 1)
|
||||
- **summary:** Broader AGE-catalog compatibility stub; the port currently traces and skips it.
|
||||
- **grounding:** source=kelebek, confidence=low
|
||||
|
||||
@@ -982,6 +982,35 @@ build, clean diff checking, and the Himegari-targeted threaded `SELFTEST OK`.
|
||||
**NEXT:** investigate CONFIG's two-site `0x142`; keep developer-only `0x24d` for a later dedicated
|
||||
movie-mask compositor slice.
|
||||
|
||||
**SYSTEM-MENU GUARD `0x142` INVESTIGATION COMPLETE (2026-07-29):** the opcode directly replaces
|
||||
`EngineCtx.system_menu_actions_enabled`. Scene reset defaults it to one. CONFIG's first instruction writes
|
||||
zero; its second and final call restores one immediately before UI/surface/SFX teardown and exit.
|
||||
|
||||
AGE exposes the field through `AGE:IAGEService` virtual offset `+0xb4`. The shipped AGERC menu refresher
|
||||
calls it and, when false, grays seven settings/save-related native menu actions so they cannot reenter
|
||||
configuration while CONFIG owns the scripted settings screen. No interpreter, renderer, gameplay, or save
|
||||
consumer reads the field. The port has no AGERC native menu, so the exact implementation is a small
|
||||
EngineCtx-lifetime boolean retained for parity and available to gate any future host equivalent; it should
|
||||
not block game input or change persisted options. The remaining inventory stays 5 opcodes / 7 instructions
|
||||
until implementation.
|
||||
|
||||
**NEXT:** implement `0x142` as the isolated system-menu availability guard. Afterwards rerank the four
|
||||
remaining opcodes, with SYSTEM4 singleton `0x149` the likely next native investigation.
|
||||
|
||||
**SYSTEM-MENU GUARD `0x142` IMPLEMENTED (2026-07-29):** the VM now retains AGE's complete signed-dword
|
||||
field, starts it at one, replaces it on every call, and restores one on root scene-context reload.
|
||||
CONFIG's exact `0 -> 1` bracket is handled without routing the flag into game input, options persistence,
|
||||
or a synthetic host service. The public retained value is available if a future frontend grows an
|
||||
equivalent application menu.
|
||||
|
||||
Three focused regressions cover the native default and signed replacement, CONFIG's exact pair, and
|
||||
root-reload lifetime. Both shipped sites are closed, reducing the remaining effectful inventory to
|
||||
4 opcodes / 5 instructions. Validation passes 498/498 engine tests, opcode and EngineCtx build/lint, a
|
||||
zero-warning Godot build, clean diff checking, and the Himegari-targeted threaded `SELFTEST OK`.
|
||||
|
||||
**NEXT:** rerank the final four gaps and investigate SYSTEM4's singleton `0x149`; keep developer-only
|
||||
`0x24d` for its dedicated movie-mask compositor slice.
|
||||
|
||||
## Later Phase B breadth
|
||||
|
||||
**INIT data-semantics side track started (2026-07-22).** Before naming more gameplay state, the static
|
||||
|
||||
Reference in New Issue
Block a user