Decode RTINIT providers 3 and 51

This commit is contained in:
gamer147
2026-07-23 16:44:49 -04:00
parent 6ce98da1ab
commit cb68e9eabd
10 changed files with 216 additions and 52 deletions

View File

@@ -1,7 +1,7 @@
<!-- DO NOT EDIT -- generated from vm-map/globals.toml by tools/globals_build.py --build --> <!-- DO NOT EDIT -- generated from vm-map/globals.toml by tools/globals_build.py --build -->
# Global Variable Reference (generated) # Global Variable Reference (generated)
5038 globals (245 curated, 4793 auto shape-inferred). Source of truth: `vm-map/globals.toml`. 5039 globals (252 curated, 4787 auto shape-inferred). Source of truth: `vm-map/globals.toml`.
## choice-output ## choice-output
@@ -20,6 +20,8 @@
|---|---|---|---|---| |---|---|---|---|---|
| `0x2052e` | scjump_progress_b | med | inference | Second SCJUMP switch input (1223 comparison reads) — progression counter/position. INFERENCE from SCJUMP usage. | | `0x2052e` | scjump_progress_b | med | inference | Second SCJUMP switch input (1223 comparison reads) — progression counter/position. INFERENCE from SCJUMP usage. |
| `0x4dfbc` | scjump_progress_a | med | inference | Dominant SCJUMP switch input (1609 comparison reads) — a per-chapter story-progress counter/position the progression machine branches on. INFERENCE from SCJUMP usage; confirm exact meaning via a listing/playthrough. | | `0x4dfbc` | scjump_progress_a | med | inference | Dominant SCJUMP switch input (1609 comparison reads) — a per-chapter story-progress counter/position the progression machine branches on. INFERENCE from SCJUMP usage; confirm exact meaning via a listing/playthrough. |
| `0xcc9f2` | offensive_action_min_range | high | investigation | CALCSCOPE initializes this from the equipped/default attack's minimum range and widens it for usable offensive skills. It is the lower bound used while populating offensive_action_scope_masks. |
| `0xcc9f3` | offensive_action_max_range | high | investigation | CALCSCOPE initializes this from the equipped/default attack's maximum range and widens it for usable offensive skills. ATSEEK bounds its attack-range flood fill with this value; RTN_M051/052 use it as the upper scan bound. |
| `0xe6c5d` | scjump_progress_d | med | inference | SCJUMP switch input (168 comparison reads) — progression counter/position. INFERENCE from SCJUMP usage. | | `0xe6c5d` | scjump_progress_d | med | inference | SCJUMP switch input (168 comparison reads) — progression counter/position. INFERENCE from SCJUMP usage. |
| `0x152618` | scjump_progress_c | med | inference | Third SCJUMP switch input (530 comparison reads) — progression counter/position. INFERENCE from SCJUMP usage. | | `0x152618` | scjump_progress_c | med | inference | Third SCJUMP switch input (530 comparison reads) — progression counter/position. INFERENCE from SCJUMP usage. |
| `0x152619` | battle_exchange_step | high | investigation | BTL's six-step alternating exchange counter. Dividing it by two selects the first, second, or third ordinary-attack/skill voice variant and related animation slots. | | `0x152619` | battle_exchange_step | high | investigation | BTL's six-step alternating exchange counter. Dividing it by two selects the first, second, or third ordinary-attack/skill voice variant and related animation slots. |
@@ -42,6 +44,8 @@
| `0x4e021` | entity_runtime_flags | high | investigation | Per-runtime-entity state flags. RTN_M007 requires bit 0 when selecting an injured ally, and MVSEEK mode 2 requires it before masking a foreign entity's occupied terrain cell. | | `0x4e021` | entity_runtime_flags | high | investigation | Per-runtime-entity state flags. RTN_M007 requires bit 0 when selecting an injured ally, and MVSEEK mode 2 requires it before masking a foreign entity's occupied terrain cell. |
| `0x4e085` | entity_current_resources | high | investigation | Per-runtime-entity current resources. DRAWCHP/DRAWENP render columns 0..2 against max-stat columns 11..13, skill/item resource deltas modify the same three columns, and movement search compares path cost with current_fs. Columns: 0=current_hp, 1=current_sp, 2=current_fs. | | `0x4e085` | entity_current_resources | high | investigation | Per-runtime-entity current resources. DRAWCHP/DRAWENP render columns 0..2 against max-stat columns 11..13, skill/item resource deltas modify the same three columns, and movement search compares path cost with current_fs. Columns: 0=current_hp, 1=current_sp, 2=current_fs. |
| `0x4e11b` | entity_effective_stats | high | investigation | Per-runtime-entity effective fourteen-stat row after CALCREVISE applies base data, equipment, skills, and conditions. Combat/UI consumers use columns 0..10 directly; columns 11..13 are the maxima paired with entity_current_resources HP/SP/FS. Columns: 0=accuracy, 1=evasion, 2=physical_attack, 3=physical_defense, 4=magic_attack, 5=magic_defense, 6=speed, 7=luck, 8=critical_chance, 9=capture_power, 10=movement, 11=max_hp, 12=max_sp, 13=max_fs. | | `0x4e11b` | entity_effective_stats | high | investigation | Per-runtime-entity effective fourteen-stat row after CALCREVISE applies base data, equipment, skills, and conditions. Combat/UI consumers use columns 0..10 directly; columns 11..13 are the maxima paired with entity_current_resources HP/SP/FS. Columns: 0=accuracy, 1=evasion, 2=physical_attack, 3=physical_defense, 4=magic_attack, 5=magic_defense, 6=speed, 7=luck, 8=critical_chance, 9=capture_power, 10=movement, 11=max_hp, 12=max_sp, 13=max_fs. |
| `0x5212b` | entity_equipped_active_skill_ids | high | investigation | Four equipped active-skill slots per runtime entity. CALCSCOPE maps each usable offensive skill into an action bit and range band; RTN_M051 turns the selected nonzero action bit back into its skill id. |
| `0x52289` | entity_selected_action_ids | high | investigation | Per-entity selected battle action. RTN_M051/052 write either zero for the normal attack or an id from entity_equipped_active_skill_ids, then return routine execution state 2 so FIELD enters battle. BTRTN may replace the value through a battle-provider decision. |
| `0x522ed` | entity_faction_ids | high | investigation | Per-runtime-entity faction id. RTN_M007 restricts its injured-unit target to the acting entity's faction; MVSEEK mode 2 compares this value while masking active foreign-entity cells, and ordinary movement checks the acting faction's bit in tile passability masks. | | `0x522ed` | entity_faction_ids | high | investigation | Per-runtime-entity faction id. RTN_M007 restricts its injured-unit target to the acting entity's faction; MVSEEK mode 2 compares this value while masking active foreign-entity cells, and ordinary movement checks the acting faction's bit in tile passability masks. |
| `0x5231f` | entity_tile_x | high | investigation | Per-runtime-entity map X coordinate. FIELD movement and occupancy logic maintain it; movement providers pair it with entity_tile_y and compare or route from the current tile. | | `0x5231f` | entity_tile_x | high | investigation | Per-runtime-entity map X coordinate. FIELD movement and occupancy logic maintain it; movement providers pair it with entity_tile_y and compare or route from the current tile. |
| `0x52351` | entity_tile_y | high | investigation | Per-runtime-entity map Y coordinate paired with entity_tile_x. Values use the same stage map-space cell keys as STINIT object and enemy coordinates. | | `0x52351` | entity_tile_y | high | investigation | Per-runtime-entity map Y coordinate paired with entity_tile_x. Values use the same stage map-space cell keys as STINIT object and enemy coordinates. |
@@ -126,12 +130,15 @@
| `0xaa8f2` | skill_proc_chance_percent | high | investigation | Probability for 14 passive skills. CALCDMG compares random-modulo 100 against this value; examples include Re-action 20, Double Action 100, Counter 10, and Resurrection 50. | | `0xaa8f2` | skill_proc_chance_percent | high | investigation | Probability for 14 passive skills. CALCDMG compares random-modulo 100 against this value; examples include Re-action 20, Double Action 100, Counter 10, and Resurrection 50. |
| `0xaaa1e` | skill_battle_animation_id | high | investigation | Populated for 101 combat skills. BTL and CALCDMG place this value in the battle-animation selector before calling BTANINIT; most skills reuse their own id, while related skills deliberately share an animation and passive reactions use ids 801..808. | | `0xaaa1e` | skill_battle_animation_id | high | investigation | Populated for 101 combat skills. BTL and CALCDMG place this value in the battle-animation selector before calling BTANINIT; most skills reuse their own id, while related skills deliberately share an animation and passive reactions use ids 801..808. |
| `0xaab4a` | skill_handler_script_id | high | investigation | SKINIT field for all 131 skills. CHMENU and INFOIT look it up and pass it directly to call-script; packed id 0x31ca resolves to SKMES.BIN, the shared per-skill text/behavior dispatcher. | | `0xaab4a` | skill_handler_script_id | high | investigation | SKINIT field for all 131 skills. CHMENU and INFOIT look it up and pass it directly to call-script; packed id 0x31ca resolves to SKMES.BIN, the shared per-skill text/behavior dispatcher. |
| `0xab5ba` | attack_element_effectiveness_percent | high | investigation | AFINIT-authored element matchup table. Positive values make an action eligible in SETMVWORK and RTN_M051/052; CALCBTPARAM multiplies battle parameters by the selected percentage and handles negative values as special/immunity cases. |
| `0xab8c7` | class_change_rule_script_ids | high | investigation | CALCCC iterates these 32 cells and call-scripts every positive entry to evaluate class-change providers. CCINIT is the shipped rule program decoded into build/data/CCINIT.json. | | `0xab8c7` | class_change_rule_script_ids | high | investigation | CALCCC iterates these 32 cells and call-scripts every positive entry to evaluate class-change providers. CCINIT is the shipped rule program decoded into build/data/CCINIT.json. |
| `0xaba64` | stage_object_runtime_flags | high | investigation | Per-current-stage object flags. RTN_M010 and RTN_M015 require bit 1 before considering Healing Feathers or Magic Pillars as movement targets; FIELD and object rendering maintain the broader type-dependent bitfield. | | `0xaba64` | stage_object_runtime_flags | high | investigation | Per-current-stage object flags. RTN_M010 and RTN_M015 require bit 1 before considering Healing Feathers or Magic Pillars as movement targets; FIELD and object rendering maintain the broader type-dependent bitfield. |
| `0xaba96` | pathfinding_remaining_route_steps | high | investigation | MVSEEK's row-major reachability grid. Mode 0 searches from the current entity with movement+1 at the origin; modes 1/2 search from the caller-supplied coordinate with 9999 at the origin. Each traversed edge decrements the value, so a larger positive value is nearer to the origin. RTN_M006/007/015 use origin-minus-target values as route-step radii; RTN_M010 ranks Healing Feathers by the negated value. | | `0xaba96` | pathfinding_remaining_route_steps | high | investigation | MVSEEK's row-major reachability grid. Mode 0 searches from the current entity with movement+1 at the origin; modes 1/2 search from the caller-supplied coordinate with 9999 at the origin. Each traversed edge decrements the value, so a larger positive value is nearer to the origin. RTN_M006/007/015 use origin-minus-target values as route-step radii; RTN_M010 ranks Healing Feathers by the negated value. |
| `0xb240e` | pathfinding_movement_costs | high | investigation | MVSEEK's row-major movement-cost work grid, indexed as [tile_y][tile_x] with stride 27. FIELD and RTN_M providers accept candidate destinations only when this cost is within the acting entity's current FS or a provider-specific override. | | `0xb240e` | pathfinding_movement_costs | high | investigation | MVSEEK's row-major movement-cost work grid, indexed as [tile_y][tile_x] with stride 27. FIELD and RTN_M providers accept candidate destinations only when this cost is within the acting entity's current FS or a provider-specific override. |
| `0xb8d86` | attack_range_distance_grid | high | investigation | ATSEEK's row-major attack-range flood-fill grid. It starts from the acting entity, expands through map-valid doubled-coordinate neighbors up to offensive_action_max_range, and stores 1 for the first range band, 2 for the next, and so on. RTN_M051/052 use the value at an enemy tile to select an offensive_action_scope_masks band. |
| `0xbf6fe` | pathfinding_filtered_route_scores | high | investigation | SETMVWORK begins by copying pathfinding_remaining_route_steps, then filters occupied entity cells according to faction and the acting entity's usable offensive-action mask/effectiveness. RTN_M providers combine this target-proximity score with a movement-limited MVSEEK grid to select a reachable tile nearest an entity or stage object. | | `0xbf6fe` | pathfinding_filtered_route_scores | high | investigation | SETMVWORK begins by copying pathfinding_remaining_route_steps, then filters occupied entity cells according to faction and the acting entity's usable offensive-action mask/effectiveness. RTN_M providers combine this target-proximity score with a movement-limited MVSEEK grid to select a reachable tile nearest an entity or stage object. |
| `0xcc9f4` | offensive_action_scope_masks | high | investigation | CALCSCOPE clears ten encoded-range cells, sets bit 0 over the equipped/default attack's range, and sets bits 1..4 over each usable offensive skill's range. SETMVWORK uses the range-0 mask and paired attack elements when filtering target cells; RTN_M003/006/016/017/018 require its normal-attack bit. Columns: 0=range_0, 1=range_1, 2=range_2, 3=range_3, 4=range_4, 5=range_5, 6=range_6, 7=range_7, 8=range_8, 9=range_9. | | `0xcc9f4` | offensive_action_scope_masks | high | investigation | CALCSCOPE clears ten encoded-range cells, sets bit 0 over the equipped/default attack's range, and sets bits 1..4 over each usable offensive skill's range. SETMVWORK uses the range-0 mask and paired attack elements when filtering target cells; RTN_M003/006/016/017/018 require its normal-attack bit. Columns: 0=range_0, 1=range_1, 2=range_2, 3=range_3, 4=range_4, 5=range_5, 6=range_6, 7=range_7, 8=range_8, 9=range_9. |
| `0xcca08` | offensive_action_attack_elements | high | investigation | CALCSCOPE stores the normal attack element in action column 0 and each usable equipped skill's attack element in columns 1..4 for every applicable range band. SETMVWORK and RTN_M051/052 test these elements against attack_element_effectiveness_percent. |
| `0xe6dee` | object_sprite_state_row_mode | high | investigation | OBINIT metadata indexed by object type. FIELD copies the type-tagged initial payload into stage_object_runtime_state only for mode 1; DRAWOBJ likewise multiplies that runtime state by the object sprite height to select source Y only for mode 1. | | `0xe6dee` | object_sprite_state_row_mode | high | investigation | OBINIT metadata indexed by object type. FIELD copies the type-tagged initial payload into stage_object_runtime_state only for mode 1; DRAWOBJ likewise multiplies that runtime state by the object sprite height to select source Y only for mode 1. |
| `0xe7302` | stage_bgm_id | high | investigation | STINIT's per-stage scalar loaded for all 74 records. FIELD passes the value directly to play-bgm when starting the stage. | | `0xe7302` | stage_bgm_id | high | investigation | STINIT's per-stage scalar loaded for all 74 records. FIELD passes the value directly to play-bgm when starting the stage. |
| `0xe7303` | stage_target_clear_turns | high | investigation | STINIT's target/par turn count. STAGECLEAR divides elapsed turns by this value to derive a performance multiplier; when replaying an already-cleared ordinary stage, FIELD also uses it as the forced-retreat turn limit. | | `0xe7303` | stage_target_clear_turns | high | investigation | STINIT's target/par turn count. STAGECLEAR divides elapsed turns by this value to derive a performance multiplier; when replaying an already-cleared ordinary stage, FIELD also uses it as the forced-retreat turn limit. |
@@ -231,7 +238,6 @@
| `0x521f3` | — | low | auto-shape | array | | `0x521f3` | — | low | auto-shape | array |
| `0x52225` | — | low | auto-shape | array | | `0x52225` | — | low | auto-shape | array |
| `0x52257` | — | low | auto-shape | array | | `0x52257` | — | low | auto-shape | array |
| `0x52289` | — | low | auto-shape | array |
| `0x522bb` | — | low | auto-shape | array | | `0x522bb` | — | low | auto-shape | array |
| `0x53ede` | — | low | auto-shape | array | | `0x53ede` | — | low | auto-shape | array |
| `0x55e3b` | — | low | auto-shape | array | | `0x55e3b` | — | low | auto-shape | array |
@@ -394,6 +400,8 @@
|---|---|---|---|---| |---|---|---|---|---|
| `0x32f1` | difficulty_index | high | investigation | GAMESTART's three-way difficulty selection. SETEN uses the zero-based index to select difficulty stat adjustments; FIELD indexes three-column stage-enemy arrays with it, and SETOBJ tests it against each object's difficulty mask. | | `0x32f1` | difficulty_index | high | investigation | GAMESTART's three-way difficulty selection. SETEN uses the zero-based index to select difficulty stat adjustments; FIELD indexes three-column stage-enemy arrays with it, and SETOBJ tests it against each object's difficulty mask. |
| `0x6718` | selected_party_slot | high | investigation | Current/selected slot in the 100-entry party-unit arrays. UNITECH chooses a free slot here before populating it; CHMENU replaces it with the selected sorted roster slot, then uses it to index party_slot_flags, party_slot_character_id, and companion per-slot tables. A natural New Game enters SC0000 with slot 2 selected. | | `0x6718` | selected_party_slot | high | investigation | Current/selected slot in the 100-entry party-unit arrays. UNITECH chooses a free slot here before populating it; CHMENU replaces it with the selected sorted roster slot, then uses it to index party_slot_flags, party_slot_character_id, and companion per-slot tables. A natural New Game enters SC0000 with slot 2 selected. |
| `0x66713` | acting_entity_index | high | investigation | Entity whose movement or battle turn is being resolved. FIELD sets it before MVRTN; RTN_M providers use it for faction, position, resources, selected action, and routine progress. Together with target_entity_index it forms the attacker/target pair passed into battle. |
| `0x66714` | target_entity_index | high | investigation | Selected target/opponent entity. RTN_M051/052 choose and write an active foreign-faction target; FIELD pairs it with acting_entity_index for movement presentation and battle setup. |
| `0x66715` | current_unit_id | high | investigation | Shared current-unit selector used by character growth and setup scripts. CCINIT keys every class-change rule on this value; CALCCC, ADDEXP, SETEN, SALLY, and related scripts use it to index unit definitions and persistent per-unit state. | | `0x66715` | current_unit_id | high | investigation | Shared current-unit selector used by character growth and setup scripts. CCINIT keys every class-change rule on this value; CALCCC, ADDEXP, SETEN, SALLY, and related scripts use it to index unit definitions and persistent per-unit state. |
| `0x8c877` | current_item_id | high | investigation | Shared item-id argument/selection slot. Item menus and gameplay scripts write a chosen item id, use it to index ITINIT arrays, and dispatch through item_handler_script_id; ITMES compares it against all 287 item ids to select the matching player-facing title and description. | | `0x8c877` | current_item_id | high | investigation | Shared item-id argument/selection slot. Item menus and gameplay scripts write a chosen item id, use it to index ITINIT arrays, and dispatch through item_handler_script_id; ITMES compares it against all 287 item ids to select the matching player-facing title and description. |
| `0xa6e59` | current_skill_id | high | investigation | Shared skill-id argument/selection slot. Skill menus and combat scripts write the chosen skill id and use it to index SKINIT arrays; SKMES compares it against all 131 skill ids to select the matching player-facing title and description. | | `0xa6e59` | current_skill_id | high | investigation | Shared skill-id argument/selection slot. Skill menus and combat scripts write the chosen skill id and use it to index SKINIT arrays; SKMES compares it against all 131 skill ids to select the matching player-facing title and description. |
@@ -441,10 +449,8 @@
| `0x665d3` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 4 scripts; compared against [1, 2, 4, 8, 32, 64, 128, 65536]; writers=['ALCHEMY.BIN', 'BUNKI.BIN', 'DEBUGADV.BIN', 'EVOLVE.BIN']. | | `0x665d3` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 4 scripts; compared against [1, 2, 4, 8, 32, 64, 128, 65536]; writers=['ALCHEMY.BIN', 'BUNKI.BIN', 'DEBUGADV.BIN', 'EVOLVE.BIN']. |
| `0x665d6` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 3 scripts; compared against []; writers=['MES.BIN', 'SBUNKI.BIN']. | | `0x665d6` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 3 scripts; compared against []; writers=['MES.BIN', 'SBUNKI.BIN']. |
| `0x665d7` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 5 scripts; compared against [1, 3]; writers=['ADDSKILL.BIN', 'SBUNKI.BIN']. | | `0x665d7` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 5 scripts; compared against [1, 3]; writers=['ADDSKILL.BIN', 'SBUNKI.BIN']. |
| `0x66714` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 3 scripts; compared against []; writers=['DEBUGBTL.BIN', 'FIELD.BIN', 'RTN_M051.BIN', 'RTN_M052.BIN']. |
| `0xaba5c` | — | med | auto-shape | TODO: confirm. Branch-read in 136 scenes / 149 scripts; compared against [0, 1]; writers=['DEBUGADV.BIN', 'DEBUGADV2.BIN', 'SC0000.BIN', 'SC0010.BIN']. | | `0xaba5c` | — | med | auto-shape | TODO: confirm. Branch-read in 136 scenes / 149 scripts; compared against [0, 1]; writers=['DEBUGADV.BIN', 'DEBUGADV2.BIN', 'SC0000.BIN', 'SC0010.BIN']. |
| `0xaba5e` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 5 scripts; compared against [2]; writers=['DEBUGMAP.BIN', 'DEBUGMAP2.BIN', 'DEBUGMAP3.BIN']. | | `0xaba5e` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 5 scripts; compared against [2]; writers=['DEBUGMAP.BIN', 'DEBUGMAP2.BIN', 'DEBUGMAP3.BIN']. |
| `0xcc9f3` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 6 scripts; compared against []; writers=['CALCSCOPE.BIN']. |
| `0xccc21` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 4 scripts; compared against [0]; writers=['CHMENU.BIN']. | | `0xccc21` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 4 scripts; compared against [0]; writers=['CHMENU.BIN']. |
| `0xeff77` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 3 scripts; compared against [0, 2, 3]; writers=['BTRTN.BIN', 'MVRTN.BIN', 'RTN_B001.BIN', 'RTN_B002.BIN']. | | `0xeff77` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 3 scripts; compared against [0, 2, 3]; writers=['BTRTN.BIN', 'MVRTN.BIN', 'RTN_B001.BIN', 'RTN_B002.BIN']. |
| `0x1560e7` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 4 scripts; compared against [0, 1, 2, 3, 4, 5, 6, 7]; writers=['MAGIC.BIN', 'SELACT.BIN', 'SUMMON.BIN']. | | `0x1560e7` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 4 scripts; compared against [0, 1, 2, 3, 4, 5, 6, 7]; writers=['MAGIC.BIN', 'SELACT.BIN', 'SUMMON.BIN']. |
@@ -3705,7 +3711,6 @@
| `0x341ab` | — | med | auto-shape | record-table[stride 53] | | `0x341ab` | — | med | auto-shape | record-table[stride 53] |
| `0x4e3d7` | — | med | auto-shape | record-table[stride 14] | | `0x4e3d7` | — | med | auto-shape | record-table[stride 14] |
| `0x4e693` | — | med | auto-shape | record-table[stride 300] | | `0x4e693` | — | med | auto-shape | record-table[stride 300] |
| `0x5212b` | — | med | auto-shape | record-table[stride 4] |
| `0x52383` | — | med | auto-shape | record-table[stride 30] | | `0x52383` | — | med | auto-shape | record-table[stride 30] |
| `0x5295f` | — | med | auto-shape | record-table[stride 30] | | `0x5295f` | — | med | auto-shape | record-table[stride 30] |
| `0x52f3b` | — | med | auto-shape | record-table[stride 30] | | `0x52f3b` | — | med | auto-shape | record-table[stride 30] |
@@ -5025,21 +5030,17 @@
| `0x64cdd` | — | low | auto-shape | cg-gallery-field? | | `0x64cdd` | — | low | auto-shape | cg-gallery-field? |
| `0x64cde` | — | med | auto-shape | cg-gallery-field | | `0x64cde` | — | med | auto-shape | cg-gallery-field |
| `0x6638b` | — | med | auto-shape | record-table[stride 15] | | `0x6638b` | — | med | auto-shape | record-table[stride 15] |
| `0x66713` | — | low | auto-shape | index/counter? |
| `0x81c96` | — | med | auto-shape | record-table[stride 3] | | `0x81c96` | — | med | auto-shape | record-table[stride 3] |
| `0x8284e` | — | med | auto-shape | record-table[stride 3] | | `0x8284e` | — | med | auto-shape | record-table[stride 3] |
| `0xaac76` | — | low | auto-shape | index/counter? | | `0xaac76` | — | low | auto-shape | index/counter? |
| `0xaacf0` | — | med | auto-shape | record-table[stride 5] | | `0xaacf0` | — | med | auto-shape | record-table[stride 5] |
| `0xaad86` | — | med | auto-shape | record-table[stride 55] | | `0xaad86` | — | med | auto-shape | record-table[stride 55] |
| `0xab3f8` | — | med | auto-shape | record-table[stride 15] | | `0xab3f8` | — | med | auto-shape | record-table[stride 15] |
| `0xab5ba` | — | med | auto-shape | record-table[stride 20] |
| `0xab6fa` | — | med | auto-shape | record-table[stride 11] | | `0xab6fa` | — | med | auto-shape | record-table[stride 11] |
| `0xab7d6` | — | med | auto-shape | record-table[stride 11] | | `0xab7d6` | — | med | auto-shape | record-table[stride 11] |
| `0xab8b2` | — | med | auto-shape | record-table[stride 7] | | `0xab8b2` | — | med | auto-shape | record-table[stride 7] |
| `0xb8d86` | — | med | auto-shape | record-table[stride 27] |
| `0xc6077` | — | med | auto-shape | record-table[stride 27] | | `0xc6077` | — | med | auto-shape | record-table[stride 27] |
| `0xcc9f0` | — | low | auto-shape | index/counter? | | `0xcc9f0` | — | low | auto-shape | index/counter? |
| `0xcca08` | — | med | auto-shape | record-table[stride 5] |
| `0xccbdc` | — | med | auto-shape | record-table[stride 14] | | `0xccbdc` | — | med | auto-shape | record-table[stride 14] |
| `0xccc0b` | — | low | auto-shape | index/counter? | | `0xccc0b` | — | low | auto-shape | index/counter? |
| `0xccc33` | — | med | auto-shape | record-table[stride 3] | | `0xccc33` | — | med | auto-shape | record-table[stride 3] |

View File

@@ -444,9 +444,10 @@ keeps its raw `base/20/slot` fields and complete offset-tagged assignment histor
empty reserved banks. Structural and consumer-proven meanings live in `vm-map/globals.toml`; the generic empty reserved banks. Structural and consumer-proven meanings live in `vm-map/globals.toml`; the generic
parameter names remain as raw provenance while each RTN_M/RTN_B consumer proves its tagged schema. parameter names remain as raw provenance while each RTN_M/RTN_B consumer proves its tagged schema.
The provider-specific join now covers RTN_M001/004/005/006/007/008/010/011/012/013/014/015: 632 The provider-specific join now covers
movement steps, 974 semantically consumed populated parameters, thirteen explicit zero defaults, and RTN_M001/003/004/005/006/007/008/010/011/012/013/014/015/051: 858 movement steps, 974 semantically
three authored-but-unread parameter cells. RTN_M005/011/012 read banks 2/3 as consumed populated parameters, thirteen explicit zero defaults, and three authored-but-unread
parameter cells. RTN_M005/011/012 read banks 2/3 as
`destination_tile_x` / `destination_tile_y` and approach that exact map tile, incrementing the current `destination_tile_x` / `destination_tile_y` and approach that exact map tile, incrementing the current
step's progress counter after arrival. Their alternate completion test recognizes a type-6 stage object step's progress counter after arrival. Their alternate completion test recognizes a type-6 stage object
at the authored destination and also accepts the object's linked exit tile. RTN_M012 is byte-for-byte at the authored destination and also accepts the object's linked exit tile. RTN_M012 is byte-for-byte
@@ -508,6 +509,22 @@ movement-unreachable tiles, and randomly chooses among the lowest-positive-score
destination the reachable tile farthest from the nearby threat set rather than merely farthest from one destination the reachable tile farthest from the nearby threat set rather than merely farthest from one
enemy. enemy.
RTN_M003 is a parameterless normal-attack routing provider. It requires the normal-attack bit, builds
the actor's movement-limited MVSEEK grid, and runs SETMVWORK so active foreign-faction entity tiles
remain eligible only when the normal attack's element has positive effectiveness. It then requires the
target tile's movement cost to fit current FS, ranks candidates by descending remaining-route score
with randomized ties, and accepts the first candidate for which SETROUTE constructs a path. Success
advances progress and returns state 1, so FIELD performs movement rather than battle.
RTN_M051 is a parameterless immediate-attack selector. ATSEEK supplies a one-based range band for each
enemy tile; CALCSCOPE supplies the normal-attack/equipped-skill bits and their attack elements at each
band. M051 keeps active foreign targets for which at least one allowed action has positive effectiveness
against the target's equipped or unit defense element. Encountering a closer band clears the accumulated
candidate list, after which a target is randomized from the retained entries. It then randomizes among
the effective actions in the tracked closest band, writing zero for a normal attack or an equipped skill
id. Success stores `target_entity_index` and `entity_selected_action_ids[acting_entity_index]`, advances
progress, and returns state 2 so FIELD enters battle without producing a movement route.
MVSEEK's mode contract is also now explicit. Mode 0 replaces the input coordinate with the current MVSEEK's mode contract is also now explicit. Mode 0 replaces the input coordinate with the current
entity tile and seeds the origin with movement+1, producing the movement-limited reachability grid. entity tile and seeds the origin with movement+1, producing the movement-limited reachability grid.
Modes 1/2 retain the caller coordinate and seed it with 9999, producing a broad target-distance grid; Modes 1/2 retain the caller coordinate and seed it with 9999, producing a broad target-distance grid;
@@ -519,8 +536,8 @@ by M006/007/015.
`movement_parameter_1..4`, and top-level `movement_provider_parameter_schemas` records the reusable `movement_parameter_1..4`, and top-level `movement_provider_parameter_schemas` records the reusable
mapping, target-selection rules, zero/unwritten behavior, and authored fields proven unread by their mapping, target-selection rules, zero/unwritten behavior, and authored fields proven unread by their
provider. All 977 populated movement-parameter cells are now accounted for: 974 semantic inputs and provider. All 977 populated movement-parameter cells are now accounted for: 974 semantic inputs and
three explicit residue cells. The seven used providers still without schemas three explicit residue cells. The five used providers still without schemas
(M002/003/009/017/051/052/061) have no populated parameter cells, so their remaining work is behavior (M002/009/017/052/061) have no populated parameter cells, so their remaining work is behavior
decoding rather than column semantics. The supporting runtime joins are now curated too: decoding rather than column semantics. The supporting runtime joins are now curated too:
`entity_runtime_flags`, `entity_runtime_flags`,
`entity_faction_ids`, `entity_tile_x`/`entity_tile_y`, the fourteen-column `entity_effective_stats`, `entity_faction_ids`, `entity_tile_x`/`entity_tile_y`, the fourteen-column `entity_effective_stats`,
@@ -528,7 +545,9 @@ current HP/SP/FS, `stage_object_runtime_flags`, `movement_search_mode`,
`offensive_action_scope_masks`, `pathfinding_remaining_route_steps`, `offensive_action_scope_masks`, `pathfinding_remaining_route_steps`,
`pathfinding_filtered_route_scores`, `pathfinding_movement_costs`, and the per-entity patrol waypoint `pathfinding_filtered_route_scores`, `pathfinding_movement_costs`, and the per-entity patrol waypoint
index. The faction-specific terrain masks used by M013 are curated as index. The faction-specific terrain masks used by M013 are curated as
`tile_faction_traversal_masks`. `tile_faction_traversal_masks`. M051's shared action-selection ABI also names `acting_entity_index`,
`target_entity_index`, `attack_range_distance_grid`, the offensive range/mask/element tables,
`attack_element_effectiveness_percent`, equipped active-skill slots, and the per-entity selected action.
### The curated registry — `vm-map/globals.toml` (2026-07-07) ### The curated registry — `vm-map/globals.toml` (2026-07-07)
@@ -579,8 +598,8 @@ The v1 map labels *shapes and tables*; the next increments add *meaning*, cheape
STINIT's joined object/enemy payloads are decoded, and CCINIT's 71 class-change rules expose predicates STINIT's joined object/enemy payloads are decoded, and CCINIT's 71 class-change rules expose predicates
and effects. SCINIT closes the progression decision-to-scene join, and RTINIT's twenty movement/battle and effects. SCINIT closes the progression decision-to-scene join, and RTINIT's twenty movement/battle
banks are structurally decoded with every populated movement-parameter cell classified. Next decode banks are structurally decoded with every populated movement-parameter cell classified. Next decode
the seven behavior-only RTN_M providers by evidence density, beginning with M003, M051, M017, and the five remaining behavior-only RTN_M providers by evidence density, beginning with the closely
M052; never assign one universal meaning to a parameter bank whose related M017 and M052; never assign one universal meaning to a parameter bank whose
meaning varies by provider selector. meaning varies by provider selector.
2. **Extend message-table joins beyond the completed ITMES/SKMES pair** (`VIMES`, other id dispatchers, …) 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. and fold in other `set-string`/`copy-to-global` writers not covered by the `*INIT` set.

View File

@@ -787,15 +787,15 @@ the shared `semantic_fields` join. SCINIT is now the sixth shape: 2,179 paired a
resolved and the full overwrite history retained. RTINIT is now the seventh shape: its twenty parallel resolved and the full overwrite history retained. RTINIT is now the seventh shape: its twenty parallel
1000-by-20 banks produce 172 routine sets, 1,043 movement steps, and fourteen battle steps with RTN_M/RTN_B 1000-by-20 banks produce 172 routine sets, 1,043 movement steps, and fourteen battle steps with RTN_M/RTN_B
provider joins, activation/progress/story gates, six explicit reserved banks, and complete overwrite provider joins, activation/progress/story gates, six explicit reserved banks, and complete overwrite
history. Provider-tagged decoding now covers movement providers 1, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, history. Provider-tagged decoding now covers movement providers 1, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13,
and 15: progress-only steps, stage-object slots, coordinate destinations (including M012's 14, 15, and 51: progress-only steps, stage-object slots, coordinate destinations (including M012's
foreign-entity route mask), enemy/ally and Magic Pillar searches, resource-gated Healing Feather foreign-entity route mask), enemy/ally and Magic Pillar searches, resource-gated Healing Feather
selection, cyclic waypoints, faction-traversable terrain, and retreat from nearby enemies. This selection, cyclic waypoints, faction-traversable terrain, retreat, normal-attack routing, and immediate
classifies every one of the 977 authored movement-parameter cells: 974 are semantic inputs across 632 element-effective target/action selection. This covers 858 steps and classifies every one of the 977
steps, while the three cells attached to M001/M008 are retained as provider-unread residue; thirteen authored movement-parameter cells: 974 are semantic inputs, while the three cells attached to M001/M008
unwritten zero defaults are projected separately. The seven remaining used providers are retained as provider-unread residue; thirteen unwritten zero defaults are projected separately. The
(M002/003/009/017/051/052/061) are behavior-only in the shipped table. Decode those next by use density, five remaining used providers (M002/009/017/052/061) are behavior-only in the shipped table. Decode the
starting with M003 and M051. closely related M017/M052 pair next.
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:

View File

@@ -99,13 +99,15 @@ RTINIT is a seventh banked shape. Its 3,336 writes populate twenty parallel `100
movement banks consumed by MVRTN/RTN_M providers and ten battle banks consumed by BTRTN/RTN_B providers. movement banks consumed by MVRTN/RTN_M providers and ten battle banks consumed by BTRTN/RTN_B providers.
The generated 172 routine-set records assemble 1,043 movement steps and fourteen battle steps, join The generated 172 routine-set records assemble 1,043 movement steps and fourteen battle steps, join
provider selectors to script names, retain all 29 overwritten cells, and keep the six reserved empty provider selectors to script names, retain all 29 overwritten cells, and keep the six reserved empty
banks visible. Selector-specific schemas now cover RTN_M001/004/005/006/007/008/010/011/012/013/014/015: banks visible. Selector-specific schemas now cover
progress-only steps, stage-object slots, coordinate destinations, enemy/ally and Magic Pillar searches, RTN_M001/003/004/005/006/007/008/010/011/012/013/014/015/051: progress-only steps, stage-object slots,
resource-threshold Healing Feather search, cyclic waypoints, faction-traversable terrain, and retreat coordinate destinations, enemy/ally and Magic Pillar searches, resource-threshold Healing Feather
from nearby enemies. The generated join covers 632 steps and accounts for all 977 authored movement search, cyclic waypoints, faction-traversable terrain, retreat, reachable normal-attack routing, and
parameters: 974 semantic inputs plus three M001/M008 cells proven unread by their providers. Thirteen immediate element-effective target/action selection. The generated join covers 858 steps and accounts
for all 977 authored movement parameters: 974 semantic inputs plus three M001/M008 cells proven unread
by their providers. Thirteen
unwritten zero defaults are projected separately while the structurally named raw banks remain intact. unwritten zero defaults are projected separately while the structurally named raw banks remain intact.
The remaining seven used providers have no populated parameter cells and therefore need behavior The remaining five used providers have no populated parameter cells and therefore need behavior
decoding, not additional column semantics. decoding, not additional column semantics.
### Message/string tables (`*MES`) ### Message/string tables (`*MES`)

View File

@@ -55,7 +55,7 @@ All opcode knowledge (ABI, semantics, provenance, `depends_on`) is hand-edited *
|---|---|---|---| |---|---|---|---|
| `extract_phase2.py` | Batch: disassembly + text corpora for every script. | `extract_phase2.py` | corpus → `build/disasm/*.asm`, `build/text/{dialogue.jsonl,strings.jsonl,*.strings.txt}`, `build/manifest.json` | | `extract_phase2.py` | Batch: disassembly + text corpora for every script. | `extract_phase2.py` | corpus → `build/disasm/*.asm`, `build/text/{dialogue.jsonl,strings.jsonl,*.strings.txt}`, `build/manifest.json` |
| `extract_message_table.py` | Discover a repeated global-id dispatch chain such as ITMES/SKMES, reconstruct player-facing title/description lines (including furigana surface text and readings), and emit an ID-keyed message table with bytecode provenance. | `extract_message_table.py <MES> [OUTNAME]` | `<MES>.BIN``build/data/<OUTNAME>.json` | | `extract_message_table.py` | Discover a repeated global-id dispatch chain such as ITMES/SKMES, reconstruct player-facing title/description lines (including furigana surface text and readings), and emit an ID-keyed message table with bytecode provenance. | `extract_message_table.py <MES> [OUTNAME]` | `<MES>.BIN``build/data/<OUTNAME>.json` |
| `extract_init.py` | Parse a `*INIT` data source (auto-detects name / numeric / footer / mixed / rules / dispatch / banked shape). Name tables infer their reserved record span, preserve sparse one-based runtime ids, distinguish lookup bases from first written cells, statically evaluate direct and negative-value writes, and separate parallel `fields` from linked row-major `record_fields`; when flat global ranges overlap, a parallel base established by other records wins over a coincidental row-table cell calculation. Mixed tables recover selector-dispatched records, condition strings, scalars, preallocated buffer cells, consumer-confirmed strides, and length-prefixed footer arrays; STINIT additionally assembles confirmed buffers into `object_placements` and `enemy_spawns`, joins object type names and available descriptions from OBINIT, and exposes consumer-proven tagged payloads (teleport, treasure, card, initial faction, non-triggering hazard/barrier faction, and OBINIT-gated initial object state), preserves engine-dead type-27 writes under `ignored_payload_fields`, and exposes reinforcement schedules and first-clear-only enemy gates. Rules mode decodes CCINIT's source-ordered class-change predicates and output accumulators, joining EBINIT unit names, SKINIT skill names, titles, named stat bonuses, cost deltas, and applied-state slots. Dispatch mode decodes SCINIT's paired decision-to-packed-scene and authored-chapter arrays, preserving source-order overwrites, resolving SYS4INI script names, and cross-checking chapter tags against decoded SCJUMP paths. Banked mode decodes RTINIT's twenty parallel 1000-by-20 movement/battle routine banks, retains all assignments and overwrites, assembles final per-slot steps, resolves provider selectors to RTN_M/RTN_B scripts, and applies selector-scoped parameter schemas where proven. Current schemas cover RTN_M001/004/005/006/007/008/010/011/012/013/014/015, including progress-only, object-slot, coordinate, enemy/ally and Magic Pillar search, Healing Feather, waypoint, faction-terrain, and retreat behavior. Provider defaults such as M004's unwritten slot 0, M010's zero/HP resource index, and M013's any-foreign-faction filter are projected explicitly and counted separately from populated source cells. Authored cells proven unread by M001/M008 remain under per-step `ignored_movement_parameters` and contribute to top-level `ignored_movement_parameter_count`; they are not silently discarded or assigned invented meanings. Raw provider banks remain intact, and top-level `movement_provider_parameter_schemas` documents the projection. ITINIT and SKINIT join ITMES/SKMES messages. Top-level `field_semantics` maps raw keys to canonical global/column names, while each record's `semantic_fields` is the generated name-keyed join; complete footer copies map to a row and expose its values without the raw provenance wrapper. Raw keys and unresolved tagged payload cells remain provenance. OUTNAME accepts a stem or one `.json` suffix and rejects paths. Refreshes the generated data index. | `extract_init.py <TABLE> [OUTNAME] [--mode …]` | `<TABLE>.BIN` plus EBINIT/SKINIT for CCINIT, OBINIT for STINIT, `build/callscript-names.json` for RTINIT/SCINIT, `build/scjump-decisions.json` for SCINIT, matching `<MES>.BIN` when supported, and `build/globals.json``build/data/<OUTNAME>.json`, `build/data/README.md` | | `extract_init.py` | Parse a `*INIT` data source (auto-detects name / numeric / footer / mixed / rules / dispatch / banked shape). Name tables infer their reserved record span, preserve sparse one-based runtime ids, distinguish lookup bases from first written cells, statically evaluate direct and negative-value writes, and separate parallel `fields` from linked row-major `record_fields`; when flat global ranges overlap, a parallel base established by other records wins over a coincidental row-table cell calculation. Mixed tables recover selector-dispatched records, condition strings, scalars, preallocated buffer cells, consumer-confirmed strides, and length-prefixed footer arrays; STINIT additionally assembles confirmed buffers into `object_placements` and `enemy_spawns`, joins object type names and available descriptions from OBINIT, and exposes consumer-proven tagged payloads (teleport, treasure, card, initial faction, non-triggering hazard/barrier faction, and OBINIT-gated initial object state), preserves engine-dead type-27 writes under `ignored_payload_fields`, and exposes reinforcement schedules and first-clear-only enemy gates. Rules mode decodes CCINIT's source-ordered class-change predicates and output accumulators, joining EBINIT unit names, SKINIT skill names, titles, named stat bonuses, cost deltas, and applied-state slots. Dispatch mode decodes SCINIT's paired decision-to-packed-scene and authored-chapter arrays, preserving source-order overwrites, resolving SYS4INI script names, and cross-checking chapter tags against decoded SCJUMP paths. Banked mode decodes RTINIT's twenty parallel 1000-by-20 movement/battle routine banks, retains all assignments and overwrites, assembles final per-slot steps, resolves provider selectors to RTN_M/RTN_B scripts, and applies selector-scoped schemas where proven. Current schemas cover RTN_M001/003/004/005/006/007/008/010/011/012/013/014/015/051, including progress-only, object-slot, coordinate, enemy/ally and Magic Pillar search, Healing Feather, waypoint, faction-terrain, retreat, reachable normal-attack routing, and immediate target/action-selection behavior. Behavior-only schemas such as M003/M051 publish an empty `parameter_fields` mapping while still joining `provider_behavior`, target selection, action selection, and completion rules. Provider defaults such as M004's unwritten slot 0, M010's zero/HP resource index, and M013's any-foreign-faction filter are projected explicitly and counted separately from populated source cells. Authored cells proven unread by M001/M008 remain under per-step `ignored_movement_parameters` and contribute to top-level `ignored_movement_parameter_count`; they are not silently discarded or assigned invented meanings. Raw provider banks remain intact, and top-level `movement_provider_parameter_schemas` documents the projection. ITINIT and SKINIT join ITMES/SKMES messages. Top-level `field_semantics` maps raw keys to canonical global/column names, while each record's `semantic_fields` is the generated name-keyed join; complete footer copies map to a row and expose its values without the raw provenance wrapper. Raw keys and unresolved tagged payload cells remain provenance. OUTNAME accepts a stem or one `.json` suffix and rejects paths. Refreshes the generated data index. | `extract_init.py <TABLE> [OUTNAME] [--mode …]` | `<TABLE>.BIN` plus EBINIT/SKINIT for CCINIT, OBINIT for STINIT, `build/callscript-names.json` for RTINIT/SCINIT, `build/scjump-decisions.json` for SCINIT, matching `<MES>.BIN` when supported, and `build/globals.json``build/data/<OUTNAME>.json`, `build/data/README.md` |
| `init_table_profile.py` | Build the static investigation surface for an extracted name/numeric/mixed/rules/dispatch/banked table: per-scalar/string/array-cell/footer-array population and value distributions, representative records, and direct opcode/script consumers. Name tables also report message coverage; rule tables summarize covered units, titled and level-independent rules, threshold/slot distributions, and skill awards; dispatch tables summarize assignments, overwrites, script-name resolution, and SCJUMP chapter agreement; banked tables summarize populated/reserved banks, movement/battle steps and providers, selector-specific semantic coverage, and overwrite conflicts. `--message-query REGEX` shows every matching name/message beside all populated fields for semantic correlation. Findings are evidence only; confirmed meanings go in `vm-map/globals.toml`. | `init_table_profile.py <TABLE> [--build] [--limit N] [--message-query REGEX]` | `build/data/<TABLE>.json` + corpus → stdout; with `--build`, `build/data/<TABLE>-field-profile.{json,md}` | | `init_table_profile.py` | Build the static investigation surface for an extracted name/numeric/mixed/rules/dispatch/banked table: per-scalar/string/array-cell/footer-array population and value distributions, representative records, and direct opcode/script consumers. Name tables also report message coverage; rule tables summarize covered units, titled and level-independent rules, threshold/slot distributions, and skill awards; dispatch tables summarize assignments, overwrites, script-name resolution, and SCJUMP chapter agreement; banked tables summarize populated/reserved banks, movement/battle steps and providers, selector-specific semantic coverage, and overwrite conflicts. `--message-query REGEX` shows every matching name/message beside all populated fields for semantic correlation. Findings are evidence only; confirmed meanings go in `vm-map/globals.toml`. | `init_table_profile.py <TABLE> [--build] [--limit N] [--message-query REGEX]` | `build/data/<TABLE>.json` + corpus → stdout; with `--build`, `build/data/<TABLE>-field-profile.{json,md}` |
| `test_extract_init.py`, `test_init_table_profile.py` | Regression checks for sparse one-based, mixed selector-dispatched, CCINIT rule, SCINIT dispatch, and RTINIT banked extraction; MES reconstruction/joins; footer-array accounting and semantic projection; EBINIT/SKINIT/OBINIT definition joins; STINIT object/enemy joins and tagged-payload behavior; overwrite/provider joins; and field/message/rule/dispatch/banked profiling. | run each directly | — | | `test_extract_init.py`, `test_init_table_profile.py` | Regression checks for sparse one-based, mixed selector-dispatched, CCINIT rule, SCINIT dispatch, and RTINIT banked extraction; MES reconstruction/joins; footer-array accounting and semantic projection; EBINIT/SKINIT/OBINIT definition joins; STINIT object/enemy joins and tagged-payload behavior; overwrite/provider joins; and field/message/rule/dispatch/banked profiling. | run each directly | — |
| `global_map.py` | Build the partial global-variable name map from static evidence. | `global_map.py` | corpus + `build/data/``build/global-var-map.{json,md}` | | `global_map.py` | Build the partial global-variable name map from static evidence. | `global_map.py` | corpus + `build/data/``build/global-var-map.{json,md}` |

View File

@@ -57,9 +57,9 @@
- [x] **2.3 — Extract `STINIT`'s 74 sparse stage records.** The mixed mode identifies the dominant `scjump_progress_a` dispatch, recovers 29 preallocated buffer layouts (including six consumer-confirmed row strides), and keeps four condition strings, six scalars, fixed-buffer writes, and all 1,396 footer-array copies separated by stage id. Profiles supply population/value and direct-consumer evidence. Header/map semantics cover conditions, BGM, turn/replay/clear-reward settings, and map texture overrides. The object join assembles 2,312 placements with type/position/gates, OBINIT names and available descriptions, 604 reinforcement schedules, and typed initial-faction, teleport, treasure, card-list, non-triggering-faction, and initial-object-state payloads; FIELD's dedicated special-spawn path proves the final three populated type-27 tagged writes are engine-dead, so they remain visible as ignored provenance rather than unresolved semantics. The 30-cell enemy family contributes 1,378 joined spawns with unit/faction, placement, difficulty/story gates, level scaling, weighted selection, difficulty-specific movement/battle routine sets, and 485 first-clear-only gates. Raw address views remain alongside generated `semantic_fields`. - [x] **2.3 — Extract `STINIT`'s 74 sparse stage records.** The mixed mode identifies the dominant `scjump_progress_a` dispatch, recovers 29 preallocated buffer layouts (including six consumer-confirmed row strides), and keeps four condition strings, six scalars, fixed-buffer writes, and all 1,396 footer-array copies separated by stage id. Profiles supply population/value and direct-consumer evidence. Header/map semantics cover conditions, BGM, turn/replay/clear-reward settings, and map texture overrides. The object join assembles 2,312 placements with type/position/gates, OBINIT names and available descriptions, 604 reinforcement schedules, and typed initial-faction, teleport, treasure, card-list, non-triggering-faction, and initial-object-state payloads; FIELD's dedicated special-spawn path proves the final three populated type-27 tagged writes are engine-dead, so they remain visible as ignored provenance rather than unresolved semantics. The 30-cell enemy family contributes 1,378 joined spawns with unit/faction, placement, difficulty/story gates, level scaling, weighted selection, difficulty-specific movement/battle routine sets, and 485 first-clear-only gates. Raw address views remain alongside generated `semantic_fields`.
- [x] **2.3a — Extract `CCINIT`'s 71 class-change rules.** Rules mode preserves source-order guards and detects the unit id, minimum level, clear applied-state slot, selected title/level, deployment-cost delta, named fourteen-stat bonuses, awarded SKINIT skills, and state slot set by each rule. EBINIT/SKINIT definition joins and the common global semantic projection coexist with raw addresses. CALCCC/ADDEXP establish the apply/report ABI; EVOLVE explains the two level-independent empty-title Lily rules. The generated profile covers 33 units, 69 titled rules, 30 skill awards, three used promotion slots, and 19 populated output fields. - [x] **2.3a — Extract `CCINIT`'s 71 class-change rules.** Rules mode preserves source-order guards and detects the unit id, minimum level, clear applied-state slot, selected title/level, deployment-cost delta, named fourteen-stat bonuses, awarded SKINIT skills, and state slot set by each rule. EBINIT/SKINIT definition joins and the common global semantic projection coexist with raw addresses. CALCCC/ADDEXP establish the apply/report ABI; EVOLVE explains the two level-independent empty-title Lily rules. The generated profile covers 33 units, 69 titled rules, 30 skill awards, three used promotion slots, and 19 populated output fields.
- [x] **2.3b — Extract `SCINIT`'s scene-dispatch registry.** Dispatch mode recognizes 2,179 alternating writes to two 10,000-cell arrays, preserves all 710 overwritten decision ids, and emits 1,209 final rows. The primary column maps decisions to 135 packed SYS4INI ids, all resolved to numbered SC scripts; the parallel column is authored chapter metadata. All 847 live SCJUMP decisions join to rows and 844 final chapter tags agree with the independently decoded paths; three legacy/stale mismatches remain explicit. - [x] **2.3b — Extract `SCINIT`'s scene-dispatch registry.** Dispatch mode recognizes 2,179 alternating writes to two 10,000-cell arrays, preserves all 710 overwritten decision ids, and emits 1,209 final rows. The primary column maps decisions to 135 packed SYS4INI ids, all resolved to numbered SC scripts; the parallel column is authored chapter metadata. All 847 live SCJUMP decisions join to rows and 844 final chapter tags agree with the independently decoded paths; three legacy/stale mismatches remain explicit.
- [x] **2.3c — Extract `RTINIT`'s routine-step banks.** Banked mode recognizes twenty parallel 1000-by-20 tables and emits 172 sparse routine-set rows with all 3,336 source assignments and 3,307 final cells. Movement banks join 1,043 steps to 19 used RTN_M providers (22 dispatchable); battle banks join fourteen steps to all four RTN_B providers. Activation percentages, progress gates, and required/forbidden story flags are consumer-proven; six empty banks remain explicit. RTN_M001/004/005/006/007/008/010/011/012/013/014/015 add selector-specific progress, object-slot, coordinate, enemy/ally and object search, Healing Feather, waypoint, faction-terrain, and retreat semantics to 632 steps. All 977 populated movement-parameter cells are classified: 974 semantic inputs and three M001/M008 cells proven unread; thirteen unwritten defaults are projected separately while the generic raw banks remain intact. - [x] **2.3c — Extract `RTINIT`'s routine-step banks.** Banked mode recognizes twenty parallel 1000-by-20 tables and emits 172 sparse routine-set rows with all 3,336 source assignments and 3,307 final cells. Movement banks join 1,043 steps to 19 used RTN_M providers (22 dispatchable); battle banks join fourteen steps to all four RTN_B providers. Activation percentages, progress gates, and required/forbidden story flags are consumer-proven; six empty banks remain explicit. RTN_M001/003/004/005/006/007/008/010/011/012/013/014/015/051 add selector-specific progress, object-slot, coordinate, enemy/ally and object search, Healing Feather, waypoint, faction-terrain, retreat, normal-attack routing, and target/action selection semantics to 858 steps. All 977 populated movement-parameter cells are classified: 974 semantic inputs and three M001/M008 cells proven unread; thirteen unwritten defaults are projected separately while the generic raw banks remain intact.
- [x] **2.4 — Partial global-var map BUILT + wired into the disassembler.** `tools/global_map.py``build/global-var-map.{json,md}` (16,354/49,435 globals labelled: string tables, `*INIT` field arrays, 122 record tables w/ strides, current-entity index pointers). `sys4load` renders the labels inline (`=rec[s30]`, `=current-entity-index?`). See `docs/name-resolution.md`. - [x] **2.4 — Partial global-var map BUILT + wired into the disassembler.** `tools/global_map.py``build/global-var-map.{json,md}` (16,354/49,435 globals labelled: string tables, `*INIT` field arrays, 122 record tables w/ strides, current-entity index pointers). `sys4load` renders the labels inline (`=rec[s30]`, `=current-entity-index?`). See `docs/name-resolution.md`.
- [ ] **2.5 — Grow the global-var map (future, incremental).** Static first: with RTINIT's populated movement-parameter tail now closed, decode the behavior-only M002/003/009/017/051/052/061 providers (starting with high-use M003/M051), fold in remaining `*MES` writers, and label other 2D record tables by their reader scripts. Then Frida to name *which stat* each unresolved field is. Full detail: `docs/name-resolution.md` → "Future step — growing the map". Packed `call-script` ids and SCJUMP decision-to-scene dispatch are resolved; see `docs/name-resolution.md` #1 and `docs/scjump-progression.md`. - [ ] **2.5 — Grow the global-var map (future, incremental).** Static first: with RTINIT's populated movement-parameter tail and high-use M003/M051 behavior now closed, decode behavior-only M002/009/017/052/061 (starting with the related M017/M052 pair), fold in remaining `*MES` writers, and label other 2D record tables by their reader scripts. Then Frida to name *which stat* each unresolved field is. Full detail: `docs/name-resolution.md` → "Future step — growing the map". Packed `call-script` ids and SCJUMP decision-to-scene dispatch are resolved; see `docs/name-resolution.md` #1 and `docs/scjump-progression.md`.
## Phase 3 — Name the unnamed opcodes *(top ~20 BEFORE Phase 4; the rest on demand)* ## Phase 3 — Name the unnamed opcodes *(top ~20 BEFORE Phase 4; the rest on demand)*

View File

@@ -109,6 +109,24 @@ MOVEMENT_PROVIDER_PARAMETER_SCHEMAS = {
"produce movement result state 1 without selecting a destination" "produce movement result state 1 without selecting a destination"
), ),
}, },
3: {
"behavior": "route_toward_reachable_normal_attack_target",
"parameter_fields": {},
"target_selection": (
"require a usable normal attack, build the acting entity's "
"movement-limited reach grid, and retain active foreign-faction "
"entities whose occupied tile remains element-effective after "
"SETMVWORK filtering and costs no more than current FS; rank "
"candidates by descending remaining-route score with randomized "
"ties, then use the first candidate for which SETROUTE produces "
"a route"
),
"completion": (
"advance the current step's progress counter and produce movement "
"result state 1 after routing toward a reachable normal-attack "
"target"
),
},
4: { 4: {
"behavior": "approach_stage_object_slot", "behavior": "approach_stage_object_slot",
"parameter_fields": { "parameter_fields": {
@@ -349,6 +367,30 @@ MOVEMENT_PROVIDER_PARAMETER_SCHEMAS = {
"Pillar exists within the configured route-step radius" "Pillar exists within the configured route-step radius"
), ),
}, },
51: {
"behavior": "select_effective_attack_target_and_action",
"parameter_fields": {},
"target_selection": (
"require a usable nonzero attack-range band, scan active foreign-"
"faction entities inside the ATSEEK range grid, and retain targets "
"for which at least one allowed normal-attack/equipped-skill "
"element has positive effectiveness against the target's defense "
"element; encountering a lower range band clears earlier "
"candidates, and the final target is randomized from the retained "
"list"
),
"action_selection": (
"after choosing the target, collect the effective actions enabled "
"in the tracked closest range band (0 means normal attack; nonzero "
"values are equipped skill ids), choose randomly, and store both "
"the target entity and selected action"
),
"completion": (
"advance the current step's progress counter and produce immediate-"
"battle result state 2 when a target/action pair is selected; no "
"movement route is produced"
),
},
} }
UNIT_STAT_COLUMNS = ( UNIT_STAT_COLUMNS = (

View File

@@ -371,8 +371,8 @@ def test_real_routine_banks() -> None:
and len(meta["used_battle_provider_selectors"]) == 4 and len(meta["used_battle_provider_selectors"]) == 4
and len(meta["record_field_columns"]) == 117, and len(meta["record_field_columns"]) == 117,
"RTINIT assembles every populated movement and battle step") "RTINIT assembles every populated movement and battle step")
check(meta["decoded_movement_provider_count"] == 12 check(meta["decoded_movement_provider_count"] == 14
and meta["decoded_movement_step_count"] == 632 and meta["decoded_movement_step_count"] == 858
and meta["decoded_movement_parameter_count"] == 974 and meta["decoded_movement_parameter_count"] == 974
and meta["decoded_movement_defaulted_parameter_count"] == 13 and meta["decoded_movement_defaulted_parameter_count"] == 13
and meta["ignored_movement_parameter_count"] == 3, and meta["ignored_movement_parameter_count"] == 3,
@@ -486,6 +486,18 @@ def test_real_routine_banks() -> None:
and provider_14["provider_behavior"] == "retreat_from_nearby_enemies" and provider_14["provider_behavior"] == "retreat_from_nearby_enemies"
and provider_14["maximum_threat_route_steps"] == 6, and provider_14["maximum_threat_route_steps"] == 6,
"RTINIT joins RTN_M014's threat-detection radius") "RTINIT joins RTN_M014's threat-detection radius")
provider_3 = by_id[3]["movement_steps"][3]
check(provider_3["movement_provider_selector"] == 3
and provider_3["provider_behavior"]
== "route_toward_reachable_normal_attack_target"
and "movement_parameter_1" not in provider_3,
"RTINIT joins RTN_M003's parameterless attack-route behavior")
provider_51 = by_id[3]["movement_steps"][1]
check(provider_51["movement_provider_selector"] == 51
and provider_51["provider_behavior"]
== "select_effective_attack_target_and_action"
and "movement_parameter_1" not in provider_51,
"RTINIT joins RTN_M051's parameterless attack-selection behavior")
undecoded_movement = by_id[2]["movement_steps"][1] undecoded_movement = by_id[2]["movement_steps"][1]
check(undecoded_movement["movement_provider_selector"] == 2 check(undecoded_movement["movement_provider_selector"] == 2
and "provider_behavior" not in undecoded_movement and "provider_behavior" not in undecoded_movement

View File

@@ -36,6 +36,17 @@ def test_load_and_lint():
check(entries[0xbf6fe]["name"] == "pathfinding_filtered_route_scores" check(entries[0xbf6fe]["name"] == "pathfinding_filtered_route_scores"
and entries[0xcc9f4]["name"] == "offensive_action_scope_masks", and entries[0xcc9f4]["name"] == "offensive_action_scope_masks",
"movement target filtering and offensive scope are curated") "movement target filtering and offensive scope are curated")
check(entries[0xb8d86]["name"] == "attack_range_distance_grid"
and entries[0xcc9f3]["name"] == "offensive_action_max_range",
"attack-range search state is curated")
check(entries[0x66713]["name"] == "acting_entity_index"
and entries[0x66714]["name"] == "target_entity_index"
and entries[0x52289]["name"] == "entity_selected_action_ids",
"AI actor, target, and selected action state are curated")
check(entries[0xcca08]["name"] == "offensive_action_attack_elements"
and entries[0xab5ba]["name"]
== "attack_element_effectiveness_percent",
"AI action-element eligibility state is curated")
check(entries[0x20543]["name"] == "tile_faction_traversal_masks", check(entries[0x20543]["name"] == "tile_faction_traversal_masks",
"faction-specific tile traversal masks are curated") "faction-specific tile traversal masks are curated")
check(entries[0xaba64]["name"] == "stage_object_runtime_flags", check(entries[0xaba64]["name"] == "stage_object_runtime_flags",

View File

@@ -1286,6 +1286,17 @@ source = "investigation"
confidence = "high" confidence = "high"
depends_on = ["0x4e085"] depends_on = ["0x4e085"]
[[global]]
address = "0xb8d86"
name = "attack_range_distance_grid"
category = "data-table"
type = "int[][27]"
value_domain = "0 outside attack range; otherwise one-based encoded range band"
usage = "ATSEEK's row-major attack-range flood-fill grid. It starts from the acting entity, expands through map-valid doubled-coordinate neighbors up to offensive_action_max_range, and stores 1 for the first range band, 2 for the next, and so on. RTN_M051/052 use the value at an enemy tile to select an offensive_action_scope_masks band."
source = "investigation"
confidence = "high"
depends_on = ["0x5231f", "0x52351", "0xcc9f3", "0xcc9f4"]
[[global]] [[global]]
address = "0x20543" address = "0x20543"
name = "tile_faction_traversal_masks" name = "tile_faction_traversal_masks"
@@ -1330,6 +1341,61 @@ source = "investigation"
confidence = "high" confidence = "high"
depends_on = ["0x4e021", "0x4e11b", "0x522ed", "0x5231f", "0x52351"] depends_on = ["0x4e021", "0x4e11b", "0x522ed", "0x5231f", "0x52351"]
[[global]]
address = "0x5212b"
name = "entity_equipped_active_skill_ids"
category = "data-table"
type = "int[50][4]"
value_domain = "0 for an empty slot; otherwise SKINIT skill id"
usage = "Four equipped active-skill slots per runtime entity. CALCSCOPE maps each usable offensive skill into an action bit and range band; RTN_M051 turns the selected nonzero action bit back into its skill id."
source = "investigation"
confidence = "high"
depends_on = ["0xa6f86", "0xa71de", "0xa730a", "0xa7436"]
[[global]]
address = "0x52289"
name = "entity_selected_action_ids"
category = "data-table"
type = "int[50]"
value_domain = "0 for normal attack; otherwise selected skill id"
usage = "Per-entity selected battle action. RTN_M051/052 write either zero for the normal attack or an id from entity_equipped_active_skill_ids, then return routine execution state 2 so FIELD enters battle. BTRTN may replace the value through a battle-provider decision."
source = "investigation"
confidence = "high"
depends_on = ["0x5212b", "0x66713", "0x66714", "0xeff77"]
[[global]]
address = "0xcc9f2"
name = "offensive_action_min_range"
category = "counter"
type = "int"
value_domain = "encoded attack-range band 0..9"
usage = "CALCSCOPE initializes this from the equipped/default attack's minimum range and widens it for usable offensive skills. It is the lower bound used while populating offensive_action_scope_masks."
source = "investigation"
confidence = "high"
depends_on = ["0x8d431", "0xa71de"]
[[global]]
address = "0xcca08"
name = "offensive_action_attack_elements"
category = "data-table"
type = "int[10][5]"
value_domain = "attack element id indexed by encoded range and action bit"
usage = "CALCSCOPE stores the normal attack element in action column 0 and each usable equipped skill's attack element in columns 1..4 for every applicable range band. SETMVWORK and RTN_M051/052 test these elements against attack_element_effectiveness_percent."
source = "investigation"
confidence = "high"
depends_on = ["0x8dfe9", "0xa7436", "0xcc9f4"]
[[global]]
address = "0xab5ba"
name = "attack_element_effectiveness_percent"
category = "data-table"
type = "int[20][20]"
value_domain = "signed effectiveness percentage indexed by defense element then attack element"
usage = "AFINIT-authored element matchup table. Positive values make an action eligible in SETMVWORK and RTN_M051/052; CALCBTPARAM multiplies battle parameters by the selected percentage and handles negative values as special/immunity cases."
source = "investigation"
confidence = "high"
depends_on = ["0x77c6e", "0x8e3d1", "0x8dfe9", "0xa7436"]
[[global]] [[global]]
address = "0xcc9f4" address = "0xcc9f4"
name = "offensive_action_scope_masks" name = "offensive_action_scope_masks"
@@ -1340,7 +1406,7 @@ value_domain = "action-availability bitmask: bit 0 normal attack, bits 1..4 equi
usage = "CALCSCOPE clears ten encoded-range cells, sets bit 0 over the equipped/default attack's range, and sets bits 1..4 over each usable offensive skill's range. SETMVWORK uses the range-0 mask and paired attack elements when filtering target cells; RTN_M003/006/016/017/018 require its normal-attack bit." usage = "CALCSCOPE clears ten encoded-range cells, sets bit 0 over the equipped/default attack's range, and sets bits 1..4 over each usable offensive skill's range. SETMVWORK uses the range-0 mask and paired attack elements when filtering target cells; RTN_M003/006/016/017/018 require its normal-attack bit."
source = "investigation" source = "investigation"
confidence = "high" confidence = "high"
depends_on = ["0x8d431", "0x8d819", "0xa71de", "0xa730a"] depends_on = ["0x8d431", "0x8d819", "0xa71de", "0xa730a", "0xcc9f2", "0xcc9f3", "0xcca08"]
[[global]] [[global]]
address = "0x152616" address = "0x152616"
@@ -1994,15 +2060,26 @@ confidence = "med"
depends_on = [] depends_on = []
[[global]] [[global]]
address = "0x66714" address = "0x66713"
name = "" name = "acting_entity_index"
category = "story-flag" category = "index-pointer"
type = "int" type = "int"
value_domain = "?" value_domain = "runtime entity row index 0..49"
usage = "TODO: confirm. Branch-read in 0 scenes / 3 scripts; compared against []; writers=['DEBUGBTL.BIN', 'FIELD.BIN', 'RTN_M051.BIN', 'RTN_M052.BIN']." usage = "Entity whose movement or battle turn is being resolved. FIELD sets it before MVRTN; RTN_M providers use it for faction, position, resources, selected action, and routine progress. Together with target_entity_index it forms the attacker/target pair passed into battle."
source = "auto-shape" source = "investigation"
confidence = "med" confidence = "high"
depends_on = [] depends_on = ["0x4e021", "0x522ed", "0x5231f", "0x52351"]
[[global]]
address = "0x66714"
name = "target_entity_index"
category = "index-pointer"
type = "int"
value_domain = "runtime entity row index 0..49"
usage = "Selected target/opponent entity. RTN_M051/052 choose and write an active foreign-faction target; FIELD pairs it with acting_entity_index for movement presentation and battle setup."
source = "investigation"
confidence = "high"
depends_on = ["0x4e021", "0x522ed", "0x5231f", "0x52351", "0xb8d86"]
[[global]] [[global]]
address = "0xab8e7" address = "0xab8e7"
@@ -2081,14 +2158,14 @@ depends_on = []
[[global]] [[global]]
address = "0xcc9f3" address = "0xcc9f3"
name = "" name = "offensive_action_max_range"
category = "story-flag" category = "counter"
type = "int" type = "int"
value_domain = "?" value_domain = "encoded attack-range band 0..9"
usage = "TODO: confirm. Branch-read in 0 scenes / 6 scripts; compared against []; writers=['CALCSCOPE.BIN']." usage = "CALCSCOPE initializes this from the equipped/default attack's maximum range and widens it for usable offensive skills. ATSEEK bounds its attack-range flood fill with this value; RTN_M051/052 use it as the upper scan bound."
source = "auto-shape" source = "investigation"
confidence = "med" confidence = "high"
depends_on = [] depends_on = ["0x8d819", "0xa730a"]
[[global]] [[global]]
address = "0xccc21" address = "0xccc21"