Decode STINIT tagged object payloads

This commit is contained in:
gamer147
2026-07-23 09:07:58 -04:00
parent 668e138507
commit 3210b907f6
9 changed files with 151 additions and 42 deletions

View File

@@ -269,7 +269,21 @@ the shared fallback. DRAWOBJ converts `0xe7325` and `0xe7357` to map-space coord
SETOBJ/DRAWOBJ/FIELD use `0xe7389` to index shared object definitions. They are object tile X, tile Y, and
type id. SETOBJ tests the `{3,4,7}` masks in `0xe7483` against GAMESTART's three-way `difficulty_index`,
then applies seven required and five forbidden one-based ids from `0xe74b5`/`0xe7613` against the shared
`story_event_flags` bank.
`story_event_flags` bank. FIELD's turn loop establishes `0xe741f` and `0xe7451` as each object's
reinforcement interval and spawn limit. Type 27 uses the same pair for a one-shot special spawn.
The intervening `0xe73bb`/`0xe73ed` pair is deliberately not assigned one global name: FIELD dispatches it
by `stage_object_type_id`, making it a tagged payload. The generated join decodes only consumer-proven
variants:
- types 1--4: `initial_faction_id` in the first cell;
- types 6 and 36: teleport `destination_tile_x` / `destination_tile_y`;
- types 7 and 8: treasure `item_id` / `item_quantity`, passed to ADDITEM;
- type 28: `card_generation_list_id`, passed to CDINIT.
This accounts for 220 initial-owner values, 229 teleport destinations, 626 treasure pairs, and 246 card
list ids. Another 185 placements across object types 11, 17--21, 25--27 retain one raw payload cell because
their type-specific meaning is not yet separable from the consumer behavior.
The enemy pass follows the separate 30-cell family through FIELD, SETEN, ADDEN, MVRTN, and BTRTN. Slot
zero is reserved for ADDEN's synthesized special-unit path; the stage table populates slots 1 through 29.
@@ -279,21 +293,22 @@ three-bit difficulty mask in `0xe77b7`, uses `0xe77f3` as a weighted-random alte
the seven required plus five forbidden story flags in `0xe793d`/`0xe7a0f`. SETEN proves `0xe782f`,
`0xe784d`, and `0xe786b` are the scenario level floor, cap, and party-level scaling divisor. Finally,
the three-value footer rows in `0xe7889` and optional `0xe78e3` become difficulty-specific movement and
battle routine-set ids selected by MVRTN/BTRTN.
battle routine-set ids selected by MVRTN/BTRTN. The final `0xe77d5` gate is also resolved:
STAGECLEAR writes `stage_clear_state[current_stage] = 1`, and FIELD suppresses a spawn when that state is
set and the spawn's cell equals 2. The joined view exposes all 485 populated cases as
`first_clear_only: true`.
Generated INIT records now retain their raw `fields`/`record_fields`/buffer keys and additionally expose a
flat `semantic_fields` projection joined through the top-level `field_semantics` map. For STINIT, the four
confirmed parallel buffers plus both prerequisite tables are also assembled into 2,312
`object_placements` across 66 stages. Each placement contains its slot, type, tile coordinates, difficulty
mask, and populated positive/negative story prerequisites. The four still-unresolved object-parameter
buffers remain attached under `unknown_fields`, so this convenience view loses no evidence or invents names.
mask, populated positive/negative story prerequisites, optional reinforcement schedule, and the decoded
type-tagged payload variants above. The remaining 185 undecoded payload cells stay attached under
`unknown_fields`, so this convenience view loses no evidence or invents names.
The same records now contain 1,378 joined `enemy_spawns` across 66 stages, with unit/faction, direct or
object-linked placement data when present, difficulty and story gates, level rules, random-selection
weight, and movement/battle routine rows. Raw footer metadata stays in `footer_arrays`, while its
`semantic_fields` value is the copied row itself. The one remaining spawn-mode cell (`0xe77d5`, always 2
when populated) stays under `unknown_fields`: FIELD ties it to already-cleared-stage state, but the precise
player-facing nuance is not yet strong enough to name. The next STINIT batch is the four type-specific
object parameters plus that isolated spawn-mode gate.
weight, movement/battle routine rows, and `first_clear_only` replay gating. Raw footer metadata stays in
`footer_arrays`, while its `semantic_fields` value is the copied row itself.
### The curated registry — `vm-map/globals.toml` (2026-07-07)
@@ -341,10 +356,10 @@ The v1 map labels *shapes and tables*; the next increments add *meaning*, cheape
1. **Continue INIT semantics by evidence density.** ITINIT/SKINIT, the confirmed EBINIT row layouts, and
STINIT's mixed stage records now have machine-readable investigation surfaces, including joined object
placements and enemy spawns. Next trace STINIT's four remaining specialized object parameters and its
isolated spawn-mode gate only where type-specific/runtime branches distinguish them. Isolate EBINIT's
remaining voice/action slots under the same rule. Preserve explicit joins and do not infer meaning from
column position alone.
placements and enemy spawns. STINIT's universal object schedule, four consumer-proven tagged payload
variants, and first-clear enemy gate are decoded; next trace the 185 remaining raw object payloads only
where their type-specific runtime branches distinguish them. Isolate EBINIT's remaining voice/action
slots under the same rule. Preserve explicit joins and do not infer meaning from column position alone.
2. **Extend message-table joins beyond the completed ITMES/SKMES pair** (`VIMES`, other id dispatchers, …)
and fold in other `set-string`/`copy-to-global` writers not covered by the `*INIT` set.
3. **Label 2D record tables by their readers** — cross-reference which scripts read each