Encounter trigger - runtime memory layout

A pre/post encounter save pair (one frame walking the map01 field scene; the next frame with battle just initiated, same map01 scene) pins the runtime memory layout of an encounter trigger. The mednafen-state diff over 0x801C0000..0x80200000 surfaces:

RangeBytes changedWhat it is
0x801CE808..0x801F3818~133 KBBattle overlay loaded into RAM (single contiguous region)
0x801C9370..0x801C9900~200–500 B8-slot battle actor pointer table; stride 0x60 per slot
0x80083000..0x80084000~600 BScene-bundle / sound-pool: encounter formation + BGM resolution

The active scene-name table at 0x80084540 is identical between the pre-encounter and post-encounter saves - the battle is layered on top of the field scene rather than swapping it out.

Battle scene-init residency window

A separate map01 save pair (one frame with the encounter armed but battle not yet entered, the next frame with battle just initiated) pins the post-load residency window of the battle scene-init pipeline. Distinct from the encounter-trigger overlay swap above; this pair brackets the loader function with concrete RAM-resident artefacts the loader writes into.

RangeBytes changedWhat it is
0x80124690..0x801503C4~168 KBBattle-bundle residency window. Pre-battle holds field-scene payload; post-battle holds battle-bundle data.
0x801CE808..0x801D3018~16 KBBattle-overlay scratch slice. Wholesale reset on entry.
0x800836C84 BPer-frame actor-tick fn-pointer slot. Pre-battle = 0x80024C50; post-battle = FUN_80021DF4.
0x801FFCA0..0x801FFFFE~600 BCD I/O state slice; rewires while the battle bundle is paged in.

The pair is post-load by design - both save frames resolve to a state where the loader function has already returned. The loader itself (which reads PROT entry 0x05C4 + sibling Seru blobs and populates the battle bundle) lives in an overlay slice not visible in either snapshot; only a mid-execution capture between the field→battle mode flip and this residency state could pin it directly.

Codified as engine_core::capture_observations::battle_init_overlay; disc-gated test battle_init_overlay_pair_pins_battle_bundle_window_and_actor_tick_wiring.

Item-use battle-event residency

A mid-battle save pair (battle just initiated; party member about to use a Healing Leaf) pins the item-use sub-mode residency:

AddressPre → PostNotes
_DAT_8007B8D00x8014BD30 → 0x800ABA4CField-pack base pointer flips. The item-use sub-mode reseats the active scene asset buffer.
0x801BA7DC..0x801BADEC~660 B shiftScript-VM context block. The menu / item / target / commit pipeline rewrites the entire ctx region.
Actor pool slots 0..4per-frame motion deltas3 party + 2 monsters (count-2 formation). Slots 5..7 stay zero across the pair.

The captured pair uses a Healing Leaf (consumable HP-restore), not a spell-learn item, so it pins the residency window of the item-use battle-event handler but says nothing about the spell-learn writer to the displayed-skills array at +0x185 - that writer needs its own capture pair.

Codified as engine_core::capture_observations::item_use_battle_event; disc-gated test item_use_pair_pins_field_pack_base_flip_and_script_vm_ctx_shift.

Captured stat-growth observations

The mednafen-state diff toolkit over a magic-rank-up + character-level-up save triplet pins the per-byte footprint for Vahn (party slot 0). The deltas inside Vahn's character record at 0x80084708 (stride 0x414):

EventOffsetBefore → AfterInterpretation
Magic-rank up (pre → post)+0x080x30 → 0x3Cflag word low byte (+12)
Magic-rank up+0x9C0x09 → 0x0Amagic-rank counter (+1)
Magic-rank up+0x10A0x1B → 0x11low byte of mp_cur (cast cost spent)
Magic-rank up+0x1610x02 → 0x03spell-level array (spell_levels[0] +1)
Level-up, 4-level jump (pre → post)+0x000x4F → 0x73unconfirmed (jump +0x24 doesn't match single-level granularity)
Level-up+0x04..+0x060x016D → 0x02DAu16 LE XP delta (+365)
Level-up+0x10E0x3A → 0x42low byte of ap_cur (AP / arts gauge refill, +8)
Level-up+0x11C..+0x12Csix per-byte +1..+4per-stat increments at byte stride 2
Level-up+0x1300x02 → 0x03displayed character level (+1 per level-up event; see level-up)

The retail per-level growth source is in SCUS_942.54: the per-stat 98-entry curves at DAT_800769CC (stride 0x62) + the parameter block at DAT_80076918 that selects each stat's curve row, read and applied by the overlay level-up function FUN_801E9504. The engine applies them: legaia_asset::level_up_tables::growth_tables_from_scus parses the tables and LevelUpTracker::with_growth_tables installs per-character StatGrowthCurve::PerLevel (all 8 stats) at boot, byte-validated against the captured Noa L2→L3 single-level deltas - see level-up.

See also