diff --git a/docs/global-reference.md b/docs/global-reference.md index 444e02c..4e589e6 100644 --- a/docs/global-reference.md +++ b/docs/global-reference.md @@ -1,7 +1,7 @@ # Global Variable Reference (generated) -5039 globals (252 curated, 4787 auto shape-inferred). Source of truth: `vm-map/globals.toml`. +5039 globals (256 curated, 4783 auto shape-inferred). Source of truth: `vm-map/globals.toml`. ## choice-output @@ -13,6 +13,7 @@ | `0x62ccc` | scjump_decision_out2 | low | inference | Adjacent to scjump_decision_out (0x62ccf) in the 0x62ccc-0x62ccf progression decision-output cluster; same 136-scene reach, written by CAMP/CLOSE/DEBUGADV. INFERENCE from adjacency — confirm meaning before relying on it. | | `0x62ccf` | scjump_decision_out | high | investigation | SCJUMP's selected progression decision id. Its chapter/flag decision tree writes one of 847 distinct values across 1,755 sites; SYSTEM4, FIELD, SALLY, and TRAIN use it to index scjump_scene_script_resource_ids and dispatch the corresponding SCxxxx scene script. | | `0xcc9f1` | movement_search_mode | high | investigation | Transient MVSEEK mode. Zero replaces the caller-supplied origin with the current entity tile and uses movement+1 as the search allowance; nonzero modes retain the caller coordinate and use a broad allowance of 9999. Mode 2 additionally masks the doubled-coordinate terrain cells occupied by active entities of another faction before the flood fill. MVSEEK resets the mode to zero on exit. | +| `0xeff77` | routine_execution_state | high | investigation | Shared movement/battle routine result state. MVRTN and BTRTN clear it before scanning steps; a nonzero provider result stops the scan. Movement providers use state 1 for ordinary field movement/progress, state 2 for an immediate offensive battle action, and state 3 for an immediate healing/support action; MVRTN supplies state 1 when no provider produced another result. | ## counter @@ -20,8 +21,8 @@ |---|---|---|---|---| | `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. | -| `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. | +| `0xcc9f2` | usable_action_min_range | high | investigation | CALCSCOPE initializes this from the equipped/default attack's minimum range and widens it for usable offensive and healing skills. It is the lower bound shared by the offensive and healing action-scope tables. | +| `0xcc9f3` | usable_action_max_range | high | investigation | CALCSCOPE initializes this from the equipped/default attack's maximum range and widens it for usable offensive and healing skills. ATSEEK bounds its action-range flood fill with this value; RTN_M051/052 and RTN_M061 use it as their upper scan bound. | | `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. | | `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. | @@ -44,14 +45,17 @@ | `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. | | `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. | +| `0x4e693` | entity_skill_flags | high | investigation | Per-runtime-entity skill-state row. CALCREVISE and CALCSCOPE mark equipped skills, combat/field consumers test specific skill ids, and RTN_M009 requires skill 22 (Unlock) before treating an unopened type-7 chest as a treasure target. | +| `0x5212b` | entity_equipped_active_skill_ids | high | investigation | Four equipped active-skill slots per runtime entity. CALCSCOPE maps each usable offensive or healing skill into the corresponding action bit and range band; RTN_M051/052 select offensive skills and RTN_M061 selects a healing skill from these slots. | +| `0x52289` | entity_selected_action_ids | high | investigation | Per-entity selected action. RTN_M051/052 write either zero for the normal attack or an offensive equipped skill and return routine execution state 2; RTN_M061 writes a healing skill and returns state 3. 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. | | `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. | | `0x53517` | entity_movement_routine_set_ids | high | investigation | Per-runtime-entity movement routine set for easy/normal/hard. SETEN copies a stage-specific override or the EBINIT default into this row; MVRTN selects the current difficulty column and stores it in current_routine_set_id. | | `0x535ad` | entity_battle_routine_set_ids | high | investigation | Per-runtime-entity battle routine set for easy/normal/hard. SETEN copies a stage-specific override or the EBINIT default into this row; BTRTN selects the current difficulty column and stores it in current_routine_set_id. | | `0x53643` | entity_movement_routine_progress | high | investigation | Per-runtime-entity movement-routine progress counters. FIELD clears all fifty rows, movement providers increment the current step, and MVRTN compares it with movement_routine_minimum_progress_counts before enabling a step. | +| `0x53e13` | entity_carried_item_ids | high | investigation | Two carried/drop-item slots per runtime entity. SETEN initializes slot 0 from the unit's starting equipment item, FIELD fills an empty or matching slot when treasure is collected, and RTN_M009 requires an empty slot or an item-id match before approaching a chest/treasure object. Columns: 0=slot_0, 1=slot_1. | +| `0x53e77` | entity_carried_item_counts | high | investigation | Quantities for the two per-entity carried/drop-item slots. SETEN seeds a starting item with quantity one; FIELD adds treasure quantities to the matching slot and caps the result at 999. Columns: 0=slot_0, 1=slot_1. | | `0x5660b` | skill_info_revealed_flags | high | investigation | Persistent skill-information visibility flags. ADDSKILL sets the selected skill, BTL marks every equipped skill when it is observed in combat, and INFOIT suppresses a skill's icon/handler-driven details until this flag is nonzero. This is broader than skill_acquired_flags. | | `0x56738` | entity_battle_routine_random_rolls | high | investigation | Per-runtime-entity battle-step random rolls. FIELD and BTL fill every active entity's twenty cells with random-modulo-100; BTRTN executes a step when the matching roll is below battle_routine_activation_percents. | | `0x56b20` | entity_patrol_waypoint_indices | high | investigation | RTN_M011 compares each step's one-based waypoint_ordinal minus one with the current entity's value. Reaching the selected destination advances this value modulo the largest RTN_M011 waypoint ordinal in the routine set. | @@ -135,9 +139,10 @@ | `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. | | `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. | +| `0xb8d86` | action_range_distance_grid | high | investigation | ATSEEK's row-major action-range flood-fill grid. It starts from the acting entity, expands through map-valid doubled-coordinate neighbors up to usable_action_max_range, and stores 1 for the first range band, 2 for the next, and so on. RTN_M051/052 select offensive targets from it; RTN_M061 selects in-range healing targets. | | `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. | +| `0xcc9fe` | healing_action_scope_masks | high | investigation | CALCSCOPE clears ten encoded-range cells and sets the equipped-slot bit for each usable category-7 healing skill over its applicable range. RTN_M061 uses the masks to restrict ally targets and to select the range-enabled healing skill. 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. | | `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. | @@ -286,7 +291,6 @@ | `0xaba4b` | — | low | auto-shape | array | | `0xaba53` | — | low | auto-shape | array | | `0xaba5f` | — | low | auto-shape | array | -| `0xcc9fe` | — | low | auto-shape | array | | `0xcca3a` | — | low | auto-shape | array | | `0xccb66` | — | low | auto-shape | array | | `0xccbcf` | — | low | auto-shape | array | @@ -452,7 +456,6 @@ | `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']. | | `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']. | | `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']. | | `0x15a094` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 6 scripts; compared against [0]; writers=['ALCHEMY.BIN', 'EVOLVE.BIN', 'SELSTAGE.BIN', 'STUDY.BIN']. | | `0x15a095` | — | med | auto-shape | TODO: confirm. Branch-read in 0 scenes / 6 scripts; compared against [0]; writers=['INFO.BIN', 'INFOCH.BIN', 'MENU.BIN']. | @@ -3710,13 +3713,10 @@ | `0x7e54` | — | med | auto-shape | record-table[stride 50] | | `0x341ab` | — | med | auto-shape | record-table[stride 53] | | `0x4e3d7` | — | med | auto-shape | record-table[stride 14] | -| `0x4e693` | — | med | auto-shape | record-table[stride 300] | | `0x52383` | — | med | auto-shape | record-table[stride 30] | | `0x5295f` | — | med | auto-shape | record-table[stride 30] | | `0x52f3b` | — | med | auto-shape | record-table[stride 30] | | `0x53a2b` | — | med | auto-shape | record-table[stride 20] | -| `0x53e13` | — | med | auto-shape | record-table[stride 2] | -| `0x53e77` | — | med | auto-shape | record-table[stride 2] | | `0x53edd` | — | low | auto-shape | index/counter? | | `0x53ef5` | — | low | auto-shape | index/counter? | | `0x53ef7` | — | med | auto-shape | record-table[stride 8] | diff --git a/docs/name-resolution.md b/docs/name-resolution.md index a2c997e..9b706a1 100644 --- a/docs/name-resolution.md +++ b/docs/name-resolution.md @@ -445,7 +445,9 @@ empty reserved banks. Structural and consumer-proven meanings live in `vm-map/gl 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/003/004/005/006/007/008/010/011/012/013/014/015/017/051/052: 1,027 movement steps, 974 semantically +all nineteen used providers, +RTN_M001/002/003/004/005/006/007/008/009/010/011/012/013/014/015/017/051/052/061: +all 1,043 movement steps, 974 semantically 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 @@ -509,6 +511,17 @@ 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 enemy. +RTN_M002 is the parameterless randomized-roaming provider. It builds the actor's movement-limited +reachability grid, applies SETMVWORK, retains tiles with positive filtered route scores whose movement +cost fits current FS, randomizes their order, and accepts the first destination for which SETROUTE +constructs a path. Success advances progress and returns ordinary movement state 1. + +RTN_M009 is the parameterless treasure seeker. It considers active unopened OBINIT type-7 chests only +when the actor has SKINIT skill 22 (`開錠`, Unlock), while type-8 treasure has no skill gate. A target +also requires one of the actor's two carried-item slots to be empty or already hold the object's item +id. M009 selects the nearest eligible object, then uses the same filtered reachability/cost pipeline to +approach a reachable tile nearest it; success advances progress and returns movement state 1. + 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 @@ -536,6 +549,13 @@ lowest current HP and randomizes among those ties. After choosing the target, it actual ATSEEK range band, randomizes among the effective normal attack/equipped skills enabled at that band, stores the target and action, and returns immediate-battle state 2 without movement. +RTN_M061 is the parameterless immediate-healing provider. CALCSCOPE places usable category-7 healing +skills in a separate range-band mask. M061 keeps active same-faction entities inside ATSEEK whose band +enables healing, retains only allies tied at the lowest current-HP percentage, and randomizes among +those ties. It then compares the chosen ally's current HP plus each range-enabled equipped spell's +recovery against max HP, stores the selected ally and healing skill, advances progress, and returns +support-action state 3 without movement. FIELD handles that state through its dedicated healing path. + 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. Modes 1/2 retain the caller coordinate and seed it with 9999, producing a broad target-distance grid; @@ -547,17 +567,19 @@ by M006/007/015. `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 provider. All 977 populated movement-parameter cells are now accounted for: 974 semantic inputs and -three explicit residue cells. The three used providers still without schemas (M002/009/061) have no -populated parameter cells, so their remaining work is behavior decoding rather than column semantics. +three explicit residue cells. All nineteen providers used by the shipped table now have behavior +schemas; the three additionally dispatchable but unused providers remain outside the generated join. The supporting runtime joins are now curated too: `entity_runtime_flags`, `entity_faction_ids`, `entity_tile_x`/`entity_tile_y`, the fourteen-column `entity_effective_stats`, -current HP/SP/FS, `stage_object_runtime_flags`, `movement_search_mode`, +current HP/SP/FS, `entity_skill_flags`, the paired carried-item id/count slots, +`stage_object_runtime_flags`, `movement_search_mode`, `offensive_action_scope_masks`, `pathfinding_remaining_route_steps`, `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 `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, +`target_entity_index`, `action_range_distance_grid`, the shared usable-action range bounds, the +offensive and healing range masks, the offensive 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) @@ -608,10 +630,10 @@ The v1 map labels *shapes and tables*; the next increments add *meaning*, cheape machine-readable investigation surfaces and semantic joins; EBINIT's populated schema is fully named, 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 - banks are structurally decoded with every populated movement-parameter cell classified and 1,027 of - 1,043 movement steps joined to provider behavior. Next close the tiny behavior-only RTN_M002/009/061 - tail; never assign one universal meaning to a parameter bank whose meaning varies by provider - selector. + banks are structurally decoded with every populated movement-parameter cell classified and all 1,043 + shipped movement steps joined to provider behavior. With RTINIT's used-provider surface closed, + resume the remaining `*MES` writers and other reader-proven 2D tables; never assign one universal + meaning to a parameter bank whose meaning varies by provider selector. 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 diff --git a/docs/phase-b-framework.md b/docs/phase-b-framework.md index e740434..712a13f 100644 --- a/docs/phase-b-framework.md +++ b/docs/phase-b-framework.md @@ -788,15 +788,15 @@ resolved and the full overwrite history retained. RTINIT is now the seventh shap 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 history. Provider-tagged decoding now covers movement providers 1, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, -14, 15, 17, 51, and 52: progress-only steps, stage-object slots, coordinate destinations (including M012's +14, 15, 17, 51, and 52, plus providers 2, 9, and 61: progress-only steps, randomized roaming, +stage-object slots, coordinate destinations (including M012's foreign-entity route mask), enemy/ally and Magic Pillar searches, resource-gated Healing Feather -selection, cyclic waypoints, faction-traversable terrain, retreat, normal-attack routing, and immediate -element-effective target/action selection, including low-current-HP variants of both attack paths. This -covers 1,027 steps and classifies every one of the 977 +selection, collectible-treasure seeking, cyclic waypoints, faction-traversable terrain, retreat, +normal-attack routing, immediate element-effective target/action selection, and immediate allied +healing. This covers all 1,043 steps across all nineteen used providers and classifies every one of the 977 authored movement-parameter cells: 974 are semantic inputs, while the three cells attached to M001/M008 are retained as provider-unread residue; thirteen unwritten zero defaults are projected separately. The -three remaining used providers (M002/009/061) are behavior-only in the shipped table and account for -only sixteen movement steps. Close that tiny tail next. +three dispatchable providers absent from the shipped RTINIT table remain outside the generated join. Once the natural spine and first gameplay loop are trustworthy, broaden in independent tracks: diff --git a/docs/script-inventory.md b/docs/script-inventory.md index 63c4439..c57b7cc 100644 --- a/docs/script-inventory.md +++ b/docs/script-inventory.md @@ -100,15 +100,17 @@ movement banks consumed by MVRTN/RTN_M providers and ten battle banks consumed b 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 banks visible. Selector-specific schemas now cover -RTN_M001/003/004/005/006/007/008/010/011/012/013/014/015/017/051/052: progress-only steps, stage-object slots, -coordinate destinations, enemy/ally and Magic Pillar searches, resource-threshold Healing Feather -search, cyclic waypoints, faction-traversable terrain, retreat, reachable normal-attack routing, and -immediate element-effective target/action selection, including low-current-HP variants of both attack -paths. The generated join covers 1,027 steps and accounts for all 977 authored movement parameters: +all nineteen used providers, +RTN_M001/002/003/004/005/006/007/008/009/010/011/012/013/014/015/017/051/052/061: +progress-only steps, randomized roaming, stage-object slots, coordinate destinations, enemy/ally and +Magic Pillar searches, resource-threshold Healing Feather search, collectible-treasure seeking, cyclic +waypoints, faction-traversable terrain, retreat, reachable normal-attack routing, immediate +element-effective target/action selection, and immediate allied healing. The generated join covers all +1,043 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. -The remaining three used providers (M002/009/061, sixteen steps total) have no populated parameter -cells and therefore need behavior decoding, not additional column semantics. +The three additionally dispatchable providers which are absent from the shipped table have no +instantiated steps to join. ### Message/string tables (`*MES`) `ITMES` (64 KB — item text), `VIMES` (43 KB), `EIMES` (37 KB), `SKMES` (31 KB — skill diff --git a/docs/tools-reference.md b/docs/tools-reference.md index cdc59a8..466b5c0 100644 --- a/docs/tools-reference.md +++ b/docs/tools-reference.md @@ -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_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 [OUTNAME]` | `.BIN` → `build/data/.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 schemas where proven. Current schemas cover RTN_M001/003/004/005/006/007/008/010/011/012/013/014/015/017/051/052, 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, with low-current-HP variants of both attack paths. Behavior-only schemas such as M003/M017/M051/M052 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 [OUTNAME] [--mode …]` | `
.BIN` plus EBINIT/SKINIT for CCINIT, OBINIT for STINIT, `build/callscript-names.json` for RTINIT/SCINIT, `build/scjump-decisions.json` for SCINIT, matching `.BIN` when supported, and `build/globals.json` → `build/data/.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 all nineteen used providers, RTN_M001/002/003/004/005/006/007/008/009/010/011/012/013/014/015/017/051/052/061, including progress-only, randomized roaming, object-slot, coordinate, enemy/ally, treasure and Magic Pillar search, Healing Feather, waypoint, faction-terrain, retreat, reachable normal-attack routing, immediate offensive target/action selection, and immediate allied healing. Parameterless behavior schemas 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
[OUTNAME] [--mode …]` | `
.BIN` plus EBINIT/SKINIT for CCINIT, OBINIT for STINIT, `build/callscript-names.json` for RTINIT/SCINIT, `build/scjump-decisions.json` for SCINIT, matching `.BIN` when supported, and `build/globals.json` → `build/data/.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
[--build] [--limit N] [--message-query REGEX]` | `build/data/
.json` + corpus → stdout; with `--build`, `build/data/
-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 | — | | `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}` | diff --git a/docs/vm-mapping-plan.md b/docs/vm-mapping-plan.md index 3c4188d..1e70a61 100644 --- a/docs/vm-mapping-plan.md +++ b/docs/vm-mapping-plan.md @@ -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.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.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/017/051/052 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—including low-current-HP variants of both attack paths—to 1,027 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 all 1,043 steps to all 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/002/003/004/005/006/007/008/009/010/011/012/013/014/015/017/051/052/061 add selector-specific progress, randomized roaming, object-slot, coordinate, enemy/ally, treasure and object search, Healing Feather, waypoint, faction-terrain, retreat, normal-attack routing, offensive target/action selection, and immediate allied-healing semantics. 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`. -- [ ] **2.5 — Grow the global-var map (future, incremental).** Static first: with RTINIT's populated movement-parameter tail plus M003/M017/M051/M052 attack behavior now closed, decode the tiny behavior-only M002/009/061 tail (sixteen used steps total), 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 entire used-provider surface now closed at 1,043/1,043 movement steps, 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, SCJUMP decision-to-scene dispatch, and the shipped RTINIT movement-provider join 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)* diff --git a/tools/extract_init.py b/tools/extract_init.py index 004f2c9..1294413 100644 --- a/tools/extract_init.py +++ b/tools/extract_init.py @@ -109,6 +109,21 @@ MOVEMENT_PROVIDER_PARAMETER_SCHEMAS = { "produce movement result state 1 without selecting a destination" ), }, + 2: { + "behavior": "roam_to_random_reachable_tile", + "parameter_fields": {}, + "target_selection": ( + "build the acting entity's movement-limited reach grid, apply " + "SETMVWORK filtering, and retain map tiles with a positive " + "filtered route score whose movement cost is no greater than " + "current FS; randomize the candidate order and use the first tile " + "for which SETROUTE produces a route" + ), + "completion": ( + "advance the current step's progress counter and produce movement " + "result state 1 after routing to a randomized reachable tile" + ), + }, 3: { "behavior": "route_toward_reachable_normal_attack_target", "parameter_fields": {}, @@ -228,6 +243,21 @@ MOVEMENT_PROVIDER_PARAMETER_SCHEMAS = { "Magic Pillar exists" ), }, + 9: { + "behavior": "approach_collectible_treasure", + "parameter_fields": {}, + "target_selection": ( + "select the nearest active unopened OBINIT type-7 chest when the " + "acting entity has skill 22 (Unlock), or type-8 treasure without " + "that skill gate; require at least one of the entity's two carried-" + "item slots to be empty or already contain the object's item id, " + "then approach a reachable tile nearest the selected object" + ), + "completion": ( + "advance the current step's progress counter and produce movement " + "result state 1 after routing toward collectible treasure" + ), + }, 10: { "behavior": "approach_healing_feather", "parameter_fields": { @@ -432,6 +462,28 @@ MOVEMENT_PROVIDER_PARAMETER_SCHEMAS = { "movement route is produced" ), }, + 61: { + "behavior": "select_lowest_hp_ally_and_healing_skill", + "parameter_fields": {}, + "target_selection": ( + "require at least one range-enabled healing skill, scan active " + "same-faction entities inside the ATSEEK range grid, retain only " + "targets tied at the lowest current-HP percentage whose range band " + "enables a healing action, and choose randomly among those ties" + ), + "action_selection": ( + "among equipped healing skills enabled at the chosen target's " + "range, compare current HP plus each skill's HP recovery against " + "max HP, maximizing the projected result while it remains below " + "max and minimizing it after reaching or exceeding max; store the " + "chosen target entity and healing skill id" + ), + "completion": ( + "advance the current step's progress counter and produce immediate-" + "support result state 3 when a target/healing-skill pair is " + "selected; no movement route is produced" + ), + }, } UNIT_STAT_COLUMNS = ( diff --git a/tools/test_extract_init.py b/tools/test_extract_init.py index c1519a1..640bf2c 100644 --- a/tools/test_extract_init.py +++ b/tools/test_extract_init.py @@ -371,8 +371,8 @@ def test_real_routine_banks() -> None: and len(meta["used_battle_provider_selectors"]) == 4 and len(meta["record_field_columns"]) == 117, "RTINIT assembles every populated movement and battle step") - check(meta["decoded_movement_provider_count"] == 16 - and meta["decoded_movement_step_count"] == 1027 + check(meta["decoded_movement_provider_count"] == 19 + and meta["decoded_movement_step_count"] == 1043 and meta["decoded_movement_parameter_count"] == 974 and meta["decoded_movement_defaulted_parameter_count"] == 13 and meta["ignored_movement_parameter_count"] == 3, @@ -510,11 +510,29 @@ def test_real_routine_banks() -> None: == "select_lowest_hp_effective_attack_target_and_action" and "movement_parameter_1" not in provider_52, "RTINIT joins RTN_M052's low-HP attack-selection behavior") - undecoded_movement = by_id[2]["movement_steps"][1] - check(undecoded_movement["movement_provider_selector"] == 2 - and "provider_behavior" not in undecoded_movement - and "destination_tile_x" not in undecoded_movement, - "RTINIT does not leak provider-specific meanings onto undecoded selectors") + provider_2 = by_id[2]["movement_steps"][1] + check(provider_2["movement_provider_selector"] == 2 + and provider_2["provider_behavior"] + == "roam_to_random_reachable_tile" + and "movement_parameter_1" not in provider_2, + "RTINIT joins RTN_M002's randomized roaming behavior") + provider_9 = by_id[98]["movement_steps"][1] + check(provider_9["movement_provider_selector"] == 9 + and provider_9["provider_behavior"] + == "approach_collectible_treasure" + and "movement_parameter_1" not in provider_9, + "RTINIT joins RTN_M009's collectible-treasure behavior") + provider_61 = by_id[33]["movement_steps"][0] + check(provider_61["movement_provider_selector"] == 61 + and provider_61["provider_behavior"] + == "select_lowest_hp_ally_and_healing_skill" + and "movement_parameter_1" not in provider_61, + "RTINIT joins RTN_M061's immediate healing behavior") + check(all( + "provider_behavior" in step + for record in records + for step in record.get("movement_steps", []) + ), "RTINIT joins behavior semantics onto every shipped movement step") check( meta["movement_provider_parameter_schemas"]["11"]["parameter_fields"] == { diff --git a/tools/test_globals.py b/tools/test_globals.py index b6974a9..85b6ba2 100644 --- a/tools/test_globals.py +++ b/tools/test_globals.py @@ -28,6 +28,14 @@ def test_load_and_lint(): check(entries[0x4e021]["name"] == "entity_runtime_flags" and entries[0x522ed]["name"] == "entity_faction_ids", "entity activity and faction arrays are curated") + check(entries[0x4e693]["name"] == "entity_skill_flags", + "per-entity skill flags are curated") + check(entries[0x53e13]["name"] == "entity_carried_item_ids" + and entries[0x53e77]["name"] == "entity_carried_item_counts", + "per-entity carried-item slots are curated") + check(entries[0xeff77]["name"] == "routine_execution_state" + and entries[0xeff77]["value_domain"] == "0..3", + "movement routine result states are curated") check(entries[0x56b20]["name"] == "entity_patrol_waypoint_indices", "RTN_M011 waypoint state is curated") check(entries[0xaba96]["name"] == "pathfinding_remaining_route_steps" @@ -36,9 +44,10 @@ def test_load_and_lint(): check(entries[0xbf6fe]["name"] == "pathfinding_filtered_route_scores" and entries[0xcc9f4]["name"] == "offensive_action_scope_masks", "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[0xb8d86]["name"] == "action_range_distance_grid" + and entries[0xcc9f2]["name"] == "usable_action_min_range" + and entries[0xcc9f3]["name"] == "usable_action_max_range", + "action-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", @@ -47,6 +56,8 @@ def test_load_and_lint(): and entries[0xab5ba]["name"] == "attack_element_effectiveness_percent", "AI action-element eligibility state is curated") + check(entries[0xcc9fe]["name"] == "healing_action_scope_masks", + "AI healing-action eligibility state is curated") check(entries[0x20543]["name"] == "tile_faction_traversal_masks", "faction-specific tile traversal masks are curated") check(entries[0xaba64]["name"] == "stage_object_runtime_flags", diff --git a/vm-map/globals.toml b/vm-map/globals.toml index 629faaf..a817725 100644 --- a/vm-map/globals.toml +++ b/vm-map/globals.toml @@ -1147,7 +1147,7 @@ name = "routine_execution_state" category = "choice-output" type = "int" value_domain = "0..3" -usage = "Shared movement/battle routine result state. MVRTN and BTRTN clear it before scanning steps; RTN_M/RTN_B providers set a nonzero result to stop the scan, and the dispatcher supplies state 1 when no provider produced another result. Exact distinctions between provider-written states 1..3 remain unresolved." +usage = "Shared movement/battle routine result state. MVRTN and BTRTN clear it before scanning steps; a nonzero provider result stops the scan. Movement providers use state 1 for ordinary field movement/progress, state 2 for an immediate offensive battle action, and state 3 for an immediate healing/support action; MVRTN supplies state 1 when no provider produced another result." source = "investigation" confidence = "high" depends_on = ["0xeff75", "0xeff76"] @@ -1187,6 +1187,17 @@ source = "investigation" confidence = "high" depends_on = ["0x4e11b"] +[[global]] +address = "0x4e693" +name = "entity_skill_flags" +category = "data-table" +type = "int[50][300]" +value_domain = "zero absent; nonzero skill state indexed by SKINIT skill id" +usage = "Per-runtime-entity skill-state row. CALCREVISE and CALCSCOPE mark equipped skills, combat/field consumers test specific skill ids, and RTN_M009 requires skill 22 (Unlock) before treating an unopened type-7 chest as a treasure target." +source = "investigation" +confidence = "high" +depends_on = ["0x5212b", "0xa6f86"] + [[global]] address = "0x522ed" name = "entity_faction_ids" @@ -1220,6 +1231,30 @@ source = "investigation" confidence = "high" depends_on = ["0x5231f"] +[[global]] +address = "0x53e13" +name = "entity_carried_item_ids" +category = "data-table" +type = "int[50][2]" +columns = { "0" = "slot_0", "1" = "slot_1" } +value_domain = "zero for empty; otherwise ITINIT item id" +usage = "Two carried/drop-item slots per runtime entity. SETEN initializes slot 0 from the unit's starting equipment item, FIELD fills an empty or matching slot when treasure is collected, and RTN_M009 requires an empty slot or an item-id match before approaching a chest/treasure object." +source = "investigation" +confidence = "high" +depends_on = ["0x53e77", "0x78c0e"] + +[[global]] +address = "0x53e77" +name = "entity_carried_item_counts" +category = "data-table" +type = "int[50][2]" +columns = { "0" = "slot_0", "1" = "slot_1" } +value_domain = "0..999 quantity paired with entity_carried_item_ids" +usage = "Quantities for the two per-entity carried/drop-item slots. SETEN seeds a starting item with quantity one; FIELD adds treasure quantities to the matching slot and caps the result at 999." +source = "investigation" +confidence = "high" +depends_on = ["0x53e13"] + [[global]] address = "0x53517" name = "entity_movement_routine_set_ids" @@ -1288,14 +1323,14 @@ depends_on = ["0x4e085"] [[global]] address = "0xb8d86" -name = "attack_range_distance_grid" +name = "action_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." +usage = "ATSEEK's row-major action-range flood-fill grid. It starts from the acting entity, expands through map-valid doubled-coordinate neighbors up to usable_action_max_range, and stores 1 for the first range band, 2 for the next, and so on. RTN_M051/052 select offensive targets from it; RTN_M061 selects in-range healing targets." source = "investigation" confidence = "high" -depends_on = ["0x5231f", "0x52351", "0xcc9f3", "0xcc9f4"] +depends_on = ["0x5231f", "0x52351", "0xcc9f3", "0xcc9f4", "0xcc9fe"] [[global]] address = "0x20543" @@ -1347,7 +1382,7 @@ 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." +usage = "Four equipped active-skill slots per runtime entity. CALCSCOPE maps each usable offensive or healing skill into the corresponding action bit and range band; RTN_M051/052 select offensive skills and RTN_M061 selects a healing skill from these slots." source = "investigation" confidence = "high" depends_on = ["0xa6f86", "0xa71de", "0xa730a", "0xa7436"] @@ -1358,18 +1393,18 @@ 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." +usage = "Per-entity selected action. RTN_M051/052 write either zero for the normal attack or an offensive equipped skill and return routine execution state 2; RTN_M061 writes a healing skill and returns state 3. 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" +name = "usable_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." +value_domain = "encoded action-range band 0..9" +usage = "CALCSCOPE initializes this from the equipped/default attack's minimum range and widens it for usable offensive and healing skills. It is the lower bound shared by the offensive and healing action-scope tables." source = "investigation" confidence = "high" depends_on = ["0x8d431", "0xa71de"] @@ -1408,6 +1443,18 @@ source = "investigation" confidence = "high" depends_on = ["0x8d431", "0x8d819", "0xa71de", "0xa730a", "0xcc9f2", "0xcc9f3", "0xcca08"] +[[global]] +address = "0xcc9fe" +name = "healing_action_scope_masks" +category = "data-table" +type = "int[10]" +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" } +value_domain = "action-availability bitmask: bits 1..4 are equipped healing skills" +usage = "CALCSCOPE clears ten encoded-range cells and sets the equipped-slot bit for each usable category-7 healing skill over its applicable range. RTN_M061 uses the masks to restrict ally targets and to select the range-enabled healing skill." +source = "investigation" +confidence = "high" +depends_on = ["0x5212b", "0xa6f86", "0xa71de", "0xa730a", "0xcc9f2", "0xcc9f3"] + [[global]] address = "0x152616" name = "current_entity_index" @@ -2158,11 +2205,11 @@ depends_on = [] [[global]] address = "0xcc9f3" -name = "offensive_action_max_range" +name = "usable_action_max_range" category = "counter" type = "int" -value_domain = "encoded attack-range band 0..9" -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." +value_domain = "encoded action-range band 0..9" +usage = "CALCSCOPE initializes this from the equipped/default attack's maximum range and widens it for usable offensive and healing skills. ATSEEK bounds its action-range flood fill with this value; RTN_M051/052 and RTN_M061 use it as their upper scan bound." source = "investigation" confidence = "high" depends_on = ["0x8d819", "0xa730a"] @@ -2178,17 +2225,6 @@ source = "auto-shape" confidence = "med" depends_on = [] -[[global]] -address = "0xeff77" -name = "" -category = "story-flag" -type = "int" -value_domain = "one of {0, 2, 3}" -usage = "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']." -source = "auto-shape" -confidence = "med" -depends_on = [] - [[global]] address = "0x152617" name = ""