Decode battle passive activation state
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<!-- DO NOT EDIT -- generated from vm-map/globals.toml by tools/globals_build.py --build -->
|
||||
# Global Variable Reference (generated)
|
||||
|
||||
4276 globals (428 curated, 3848 auto shape-inferred). Source of truth: `vm-map/globals.toml`.
|
||||
4277 globals (430 curated, 3847 auto shape-inferred). Source of truth: `vm-map/globals.toml`.
|
||||
|
||||
## choice-output
|
||||
|
||||
@@ -288,6 +288,7 @@
|
||||
| `0x152421` | card_definition_visual_asset_ids | high | investigation | Card-result visual selected by FIELD before applying and presenting the effect. All 81 authored rows resolve to MVS*.AGF assets, with related card families sharing artwork. |
|
||||
| `0x152486` | card_generation_weight_schedules | high | investigation | CDINIT's selector-specific candidate weights, parallel to card_generation_card_ids. FIELD computes base_weight + floor(current_stage_turn / growth_interval_turns) * growth_weight, with a zero interval selecting the fixed base path. The shipped lists populate 11..75 one-based slots. Columns: 0=base_weight, 1=growth_interval_turns, 2=growth_weight. |
|
||||
| `0x1525b2` | card_generation_card_ids | high | investigation | Card ids parallel to card_generation_weight_schedules. FIELD scans slots 0..99, filters each nonzero id through the CDINIT2 story-flag rows, and performs cumulative weighted random selection. CDINIT clears only the first 50 slots even though its largest authored list reaches slot 75. |
|
||||
| `0x15261f` | battle_triggered_passive_skill_flags | high | investigation | Per-exchange passive-skill activation matrix. CALCDMG clears both 300-cell side rows, considers the four equipped skills on each battle entity, retains category-4 passives allowed for that actor/target role, rolls skill_proc_chance_percent, and applies species, boss, movement-skill, action-category, and mutual-exclusion filters. BTL consumes the surviving flags to draw triggered-passive icons, play each passive's battle animation, and execute Roar, Counter, Reflect, Absorb, Pierce, Shield, Parry, and Revive behavior. |
|
||||
| `0x152877` | battle_entity_indices | high | investigation | The two runtime entity rows participating in BTL. battle_actor_side_index and battle_target_side_index select these cells before BTL and CALCDMG access HP, unit definitions, skills, animation state, and voice banks. Columns: 0=side_0, 1=side_1. |
|
||||
| `0x152879` | battle_selected_skill_ids | high | investigation | Selected skill for each battle side. BTL displays a positive entry through the skill-name table and selects skill-use voice columns; CALCDMG uses the same id for skill parameters. A zero entry follows the equipped/default ordinary-attack path. Columns: 0=side_0, 1=side_1. |
|
||||
| `0x15288e` | battle_animation_effect_ids | high | investigation | BTANINIT2's sparse battle-animation composition table. BTANINIT expands the selected row into six runtime effect work slots. BTL anchors requested effects in slots 0 and 1 to the actor and slots 2 through 5 to the target; shipped data never populates slot 4. Columns: 0=effect_slot_0, 1=effect_slot_1, 2=effect_slot_2, 3=effect_slot_3, 4=reserved_effect_slot_4, 5=effect_slot_5. |
|
||||
@@ -3747,6 +3748,7 @@
|
||||
| `0xab8fb` | class_change_state_work | high | investigation | Ten-cell working copy of the current unit's unit_class_change_state row. CCINIT sets the slot belonging to an awarded rule; CALCCC manages the block copy between this buffer and persistent per-unit state. Columns: 0=promotion_slot_1, 1=promotion_slot_2, 2=promotion_slot_3, 3=promotion_slot_4, 4=promotion_slot_5, 5=promotion_slot_6, 6=promotion_slot_7, 7=promotion_slot_8, 8=promotion_slot_9, 9=promotion_slot_10. |
|
||||
| `0x15261c` | battle_hit_result | high | investigation | CALCDMG initializes this to miss, changes it to hit after the accuracy gate, and then to critical after the critical-chance gate. BTL uses the same result to choose presentation, cut-ins, and critical voice columns; -1 is written only by a synthetic pre-battle path. |
|
||||
| `0x15261d` | battle_hp_delta | high | investigation | CALCDMG's signed HP result. BTL subtracts it from the target's current HP, so positive values deal damage and negative values heal; zero and result state gate damage reactions and defeat handling. |
|
||||
| `0x15261e` | battle_actor_hp_recovery | high | investigation | CALCDMG's actor-side HP recovery output. Absorb (SKINIT skill 40) contributes half of positive battle_hp_delta with a minimum of one, and the target's HP-absorption condition can add its level-scaled amount capped at the damage dealt. BTL adds the result to the actor's current HP, renders the green recovery number, and clamps the resource through the ordinary post-battle path. |
|
||||
| `0x84a` | — | high | auto-shape | unit-name-table |
|
||||
| `0xc32` | — | high | auto-shape | unit-desc-table |
|
||||
| `0x101a` | — | high | auto-shape | unit-desc1-table |
|
||||
@@ -3919,7 +3921,6 @@
|
||||
| `0x15235a` | — | low | auto-shape | cdinit2-field? |
|
||||
| `0x1523be` | — | low | auto-shape | cdinit2-field? |
|
||||
| `0x152422` | — | med | auto-shape | cdinit2-field |
|
||||
| `0x15261f` | — | med | auto-shape | record-table[stride 300] |
|
||||
| `0x152878` | — | low | auto-shape | index/counter? |
|
||||
| `0x15288b` | — | low | auto-shape | index/counter? |
|
||||
| `0x152894` | — | low | auto-shape | btaninit2-field? |
|
||||
|
||||
@@ -709,8 +709,10 @@ The v1 map labels *shapes and tables*; the next increments add *meaning*, cheape
|
||||
story gates, map/minimap geometry, rewards, and 174 resolved entry/clear/failure transitions. With
|
||||
RTINIT's used-provider surface closed, ITMES/SKMES/VIMES/EIMES/CIMES/MAMES joined, INFOMES/MES
|
||||
classified, STINIT2's engine-dead authoring tier retained at medium confidence, and the
|
||||
309-script ADV primary/alternate/transition surface-slot registry named, continue with
|
||||
consumer-led tables that still have shipped readers;
|
||||
309-script ADV primary/alternate/transition surface-slot registry named, the selected
|
||||
movement-route grid reconstructed, and CALCDMG/BTL's two-side-by-300 triggered-passive
|
||||
matrix plus actor HP-recovery output closed, continue with consumer-led tables that still
|
||||
have shipped readers;
|
||||
never assign one universal meaning to a parameter bank whose meaning varies by provider selector.
|
||||
2. **Label remaining 2D record tables by their readers** — cross-reference which scripts read each
|
||||
`rec[sN]` table and infer purpose from context, preserving reserved rows and sparse cells. RECOVER's
|
||||
|
||||
@@ -3267,3 +3267,34 @@ Evidence regressions protect the exact corpus xrefs and clear geometry, all seve
|
||||
readers, both SETROUTE flood-score copies, the INIT2 cardinal vectors, and every canonical name.
|
||||
|
||||
**Next:** investigate the remaining unnamed stride-300 table at `G[0x15261f]`.
|
||||
|
||||
## Data-semantics sidebar: battle triggered-passive matrix (2026-07-24)
|
||||
|
||||
The former stride-300 auto table at `G[0x15261f]` is the reserved `2 × 300`
|
||||
`battle_triggered_passive_skill_flags` work matrix. Its first dimension is BTL's two battle sides,
|
||||
and its second dimension is the SKINIT skill id. The complete corpus surface is compact and exact:
|
||||
BTL and CALCDMG are its only readers/writers, with 37 two-dimensional lookups and three full
|
||||
600-cell clears.
|
||||
|
||||
CALCDMG rebuilds the matrix for each exchange. A local eligibility surface first assigns the
|
||||
actor/target roles of shipped passive ids 28..50 (with Seal/id 44 absent from this activation path).
|
||||
The script then scans the four equipped skills on both battle entities, accepts category-4 passives,
|
||||
applies the configured `skill_proc_chance_percent`, and filters surviving cells through the concrete
|
||||
combat contract: species and boss slayers, anti-air/anti-sub movement skills, ordinary-versus-special
|
||||
attack categories, role-specific defensive/offensive passives, and mutually exclusive reactions.
|
||||
The result is an activation record for this exchange rather than the entity's persistent skill
|
||||
ownership; `entity_skill_flags` remains the latter source.
|
||||
|
||||
BTL proves the output side. It indexes each participant's four equipped skills through the matrix
|
||||
to draw the triggered-passive icons, and repeats the dynamic join for actor- and target-side passive
|
||||
battle animations. Direct column tests then implement Roar, Counter, Reflect, Absorb, Pierce, Shield,
|
||||
Parry, and Revive behavior. The adjacent `G[0x15261e]` is now
|
||||
`battle_actor_hp_recovery`: CALCDMG adds Absorb's half-damage return and any level-scaled HP-absorption
|
||||
condition amount, while BTL adds the result to the actor's HP and renders the green recovery number.
|
||||
|
||||
Evidence regressions protect the exact two-script/40-reference surface, all three `2 × 300` clears,
|
||||
the passive-id eligibility range, category gate and dynamic filters, BTL's three skill-indexed
|
||||
presentation consumers, and the actor-recovery producer/consumer pair.
|
||||
|
||||
**Next:** investigate the highest-use remaining auto-shaped row table, the stride-14 table at
|
||||
`G[0x6f70]` (27 references across ADDEXP, EVOLVE, GAMECLEAR, GAMESTART, TRAIN, and UNITECH).
|
||||
|
||||
@@ -71,8 +71,9 @@
|
||||
- [x] **2.3n — Extract `STINIT2`'s stage-definition registry.** Name/string-matrix specialization corrects the generic 321-record view to 74 sparse stages plus 296 strings in six pre/post-clear description slots, classifying all 1,634 instructions. FORT, FIELD, SELSTAGE, and STAGECLEAR prove main/EX flags, seven-column story gates, unlock groups, numbered/event presentation, map/minimap geometry, base point and three-coin rewards, and the loader contract. All 174 entry/clear/failure decisions resolve through SCINIT and all 74 loader ids resolve to STINIT. The remaining `0xedc4d` array has no shipped reader and is retained at medium confidence as the authoring-only stage difficulty tier: values 1..8 correlate with challenge/reward progression but have no runtime effect.
|
||||
- [x] **2.3o — Name the ADV layer surface-slot registry.** `G[0x3239]` is an eight-by-three primary/alternate/transition surface bank initialized by 143 scripts and read across 309. The common CG loader proves double-buffer selection and transition staging; INIT2 supplies the paired retained-object handles, and the companion resource, layer-index, live-slot, and handle globals are curated.
|
||||
- [x] **2.3p — Name the selected movement-route grid.** `G[0xc6077]` is a reserved 1000-by-27 work grid carrying the one-cell-wide route copied from MVSEEK's remaining-step scores. SETROUTE proves the cardinal backtrace, FIELD proves route rendering and execution, SELACT proves move-before-action use, and RTN_M002..018 prove candidate-endpoint testing. The shared map target coordinates and INIT2 cardinal vectors are curated with it.
|
||||
- [x] **2.3q — Name the triggered passive-skill matrix.** `G[0x15261f]` is a two-side-by-300 SKINIT-indexed activation matrix rebuilt for each CALCDMG exchange. CALCDMG gates owned category-4 passives by actor/target role, proc chance, species/boss/movement/action conditions, and pairwise exclusions; BTL uses the surviving flags for passive icons, reaction animations, and passive combat behavior. The adjacent actor HP-recovery output is curated with it.
|
||||
- [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: RTINIT is closed at 1,043/1,043 movement steps; the RECOVER/ILINIT condition ABI, ALINIT recipes, AFINIT affinity/progression tables, CTINIT name palette, CVINIT character-voice registry, LAINIT terrain definitions, MPINIT stage-terrain atlas, SPINIT H-scene gallery, TRINIT training actions, CDINIT/CDINIT2 card selection/effects, BTANINIT/BTANINIT2 battle animations, STINIT2's complete stage surface, the 309-script ADV layer surface-slot registry, and the selected movement-route grid are closed; ITMES/SKMES/VIMES/EIMES/CIMES/MAMES are joined to their definitions; and the non-table INFOMES/MES ABIs are classified. Next, continue remaining consumer-led 2D table naming. Full detail: `docs/name-resolution.md` → "Future step — growing the map". Packed `call-script` ids, SCJUMP decision-to-scene dispatch, the shipped RTINIT movement-provider join, and the six completed message joins are resolved.
|
||||
- [ ] **2.5 — Grow the global-var map (future, incremental).** Static first: RTINIT is closed at 1,043/1,043 movement steps; the RECOVER/ILINIT condition ABI, ALINIT recipes, AFINIT affinity/progression tables, CTINIT name palette, CVINIT character-voice registry, LAINIT terrain definitions, MPINIT stage-terrain atlas, SPINIT H-scene gallery, TRINIT training actions, CDINIT/CDINIT2 card selection/effects, BTANINIT/BTANINIT2 battle animations, STINIT2's complete stage surface, the 309-script ADV layer surface-slot registry, the selected movement-route grid, and the battle triggered-passive matrix are closed; ITMES/SKMES/VIMES/EIMES/CIMES/MAMES are joined to their definitions; and the non-table INFOMES/MES ABIs are classified. Next, continue remaining consumer-led 2D table naming. Full detail: `docs/name-resolution.md` → "Future step — growing the map". Packed `call-script` ids, SCJUMP decision-to-scene dispatch, the shipped RTINIT movement-provider join, and the six completed message joins are resolved.
|
||||
|
||||
## Phase 3 — Name the unnamed opcodes *(top ~20 BEFORE Phase 4; the rest on demand)*
|
||||
|
||||
|
||||
@@ -170,6 +170,11 @@ def test_load_and_lint():
|
||||
and entries[0xccc0a]["name"] == "map_target_tile_x"
|
||||
and entries[0xccc0b]["name"] == "map_target_tile_y",
|
||||
"selected movement route grid and coordinate helpers are curated")
|
||||
check(entries[0x15261e]["name"] == "battle_actor_hp_recovery"
|
||||
and entries[0x15261f]["name"]
|
||||
== "battle_triggered_passive_skill_flags"
|
||||
and entries[0x15261f]["type"] == "int[2][300]",
|
||||
"battle recovery output and triggered-passive matrix are curated")
|
||||
# lint clean against a permissive address universe (curated addrs are self-consistent)
|
||||
errors, warnings = G.lint(entries, set(entries))
|
||||
check(errors == [], f"globals.toml lints clean (errors={errors})")
|
||||
@@ -308,6 +313,110 @@ def test_selected_movement_route_grid_evidence():
|
||||
0xccbd4: [0, 1, 0, -1, 0],
|
||||
}, "INIT2 defines the no-move plus four-cardinal-neighbor vectors")
|
||||
|
||||
def test_battle_triggered_passive_skill_flags_evidence():
|
||||
target = 0x15261f
|
||||
recovery = 0x15261e
|
||||
refs = []
|
||||
recovery_refs = []
|
||||
loaded = {}
|
||||
for name, path in paths.scripts().items():
|
||||
if path.read_bytes()[:8] != b"SYS4422 ":
|
||||
continue
|
||||
script = sys4load.load(path)
|
||||
loaded[name] = script
|
||||
for index, instruction in enumerate(script.instructions):
|
||||
if (3, target) in instruction.args:
|
||||
refs.append((name, script, index, instruction))
|
||||
if (3, recovery) in instruction.args:
|
||||
recovery_refs.append((name, instruction))
|
||||
|
||||
check({name for name, _, _, _ in refs}
|
||||
== {"BTL.BIN", "CALCDMG.BIN"}
|
||||
and len(refs) == 40
|
||||
and sum(instruction.opcode == 0x12c
|
||||
for _, _, _, instruction in refs) == 37
|
||||
and sum(instruction.opcode == 0x6c
|
||||
for _, _, _, instruction in refs) == 3,
|
||||
"triggered-passive matrix has exactly 37 lookups and three clears in BTL/CALCDMG")
|
||||
|
||||
clears_cover_both_rows = True
|
||||
for _, script, index, instruction in refs:
|
||||
if instruction.opcode != 0x6c:
|
||||
continue
|
||||
previous = script.instructions[index - 1]
|
||||
clears_cover_both_rows &= (
|
||||
previous.label == "mul"
|
||||
and previous.args[1:] == [(0, 2), (0, 300)]
|
||||
and instruction.args[1] == previous.args[0]
|
||||
)
|
||||
check(clears_cover_both_rows,
|
||||
"every triggered-passive clear covers both reserved 300-skill side rows")
|
||||
|
||||
calcdmg = loaded["CALCDMG.BIN"].instructions
|
||||
eligibility_columns = {
|
||||
instruction.args[-1][1]
|
||||
for index, instruction in enumerate(calcdmg[:-1])
|
||||
if 0x1f1 <= instruction.offset <= 0x3b9
|
||||
and instruction.opcode == 0x12c
|
||||
and instruction.args[1] == (9, 0xf)
|
||||
and instruction.args[3] == (0, 300)
|
||||
and calcdmg[index + 1].label == "mov"
|
||||
and calcdmg[index + 1].args[1] == (0, 1)
|
||||
}
|
||||
check(eligibility_columns == set(range(28, 51)) - {44},
|
||||
"CALCDMG seeds the actor/target eligibility surface for shipped passive skill ids")
|
||||
|
||||
category_gate = [
|
||||
instruction for instruction in calcdmg
|
||||
if instruction.offset == 0x4d6
|
||||
]
|
||||
dynamic_writes = {
|
||||
instruction.offset
|
||||
for instruction in calcdmg
|
||||
if instruction.opcode == 0x12c
|
||||
and instruction.args[1] == (3, target)
|
||||
and instruction.args[3] == (0, 300)
|
||||
and instruction.args[-1] == (9, 8)
|
||||
}
|
||||
check(len(category_gate) == 1
|
||||
and category_gate[0].args == [
|
||||
(12, 0), (3, 0xa6f86), (9, 8)
|
||||
]
|
||||
and dynamic_writes == {
|
||||
0x52e, 0x57c, 0x5d3, 0x612, 0x62a, 0x65b,
|
||||
0x688, 0x6bd, 0x725, 0x799, 0x7b5, 0x7fb,
|
||||
0x817, 0x85d,
|
||||
},
|
||||
"CALCDMG gates category-4 skills then filters the side/skill activation cells")
|
||||
|
||||
btl_dynamic_consumers = {
|
||||
instruction.offset
|
||||
for instruction in loaded["BTL.BIN"].instructions
|
||||
if instruction.opcode == 0x12c
|
||||
and instruction.args[1] == (3, target)
|
||||
and instruction.args[3] == (0, 300)
|
||||
and instruction.args[-1] == (9, 0x12)
|
||||
}
|
||||
check(btl_dynamic_consumers == {0x1b8c, 0x2270, 0x2319},
|
||||
"BTL indexes triggered flags by equipped skill for icons and both-side animations")
|
||||
|
||||
check({name for name, _ in recovery_refs}
|
||||
== {"BTL.BIN", "CALCDMG.BIN"}
|
||||
and len(recovery_refs) == 20
|
||||
and any(instruction.offset == 0xa3f
|
||||
and instruction.label == "div"
|
||||
and instruction.args == [
|
||||
(3, recovery), (3, 0x15261d), (0, 2)
|
||||
]
|
||||
for name, instruction in recovery_refs
|
||||
if name == "CALCDMG.BIN")
|
||||
and any(instruction.offset == 0x943
|
||||
and instruction.label == "add"
|
||||
and instruction.args[-1] == (3, recovery)
|
||||
for name, instruction in recovery_refs
|
||||
if name == "BTL.BIN"),
|
||||
"CALCDMG computes actor recovery and BTL adds it to the acting entity's HP")
|
||||
|
||||
def test_merge_precedence():
|
||||
curated, _ = G.load_toml(paths.VM_MAP / "globals.toml")
|
||||
auto = G.load_auto(paths.BUILD / "global-var-map.json")
|
||||
@@ -372,6 +481,7 @@ if __name__ == "__main__":
|
||||
test_lint_catches_bad_vocab()
|
||||
test_adv_layer_surface_slot_evidence()
|
||||
test_selected_movement_route_grid_evidence()
|
||||
test_battle_triggered_passive_skill_flags_evidence()
|
||||
test_merge_precedence()
|
||||
test_sys4load_labels_from_registry()
|
||||
test_miner_finds_known_flags()
|
||||
|
||||
@@ -2036,6 +2036,28 @@ usage = "CALCDMG's signed HP result. BTL subtracts it from the target's current
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
|
||||
[[global]]
|
||||
address = "0x15261e"
|
||||
name = "battle_actor_hp_recovery"
|
||||
category = "unknown"
|
||||
type = "int"
|
||||
value_domain = "nonnegative HP restored to the acting side"
|
||||
usage = "CALCDMG's actor-side HP recovery output. Absorb (SKINIT skill 40) contributes half of positive battle_hp_delta with a minimum of one, and the target's HP-absorption condition can add its level-scaled amount capped at the damage dealt. BTL adds the result to the actor's current HP, renders the green recovery number, and clamps the resource through the ordinary post-battle path."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
depends_on = ["0x4e085", "0x52383", "0x15261d"]
|
||||
|
||||
[[global]]
|
||||
address = "0x15261f"
|
||||
name = "battle_triggered_passive_skill_flags"
|
||||
category = "data-table"
|
||||
type = "int[2][300]"
|
||||
value_domain = "{0,1}; rows are battle side, columns are SKINIT skill ids"
|
||||
usage = "Per-exchange passive-skill activation matrix. CALCDMG clears both 300-cell side rows, considers the four equipped skills on each battle entity, retains category-4 passives allowed for that actor/target role, rolls skill_proc_chance_percent, and applies species, boss, movement-skill, action-category, and mutual-exclusion filters. BTL consumes the surviving flags to draw triggered-passive icons, play each passive's battle animation, and execute Roar, Counter, Reflect, Absorb, Pierce, Shield, Parry, and Revive behavior."
|
||||
source = "investigation"
|
||||
confidence = "high"
|
||||
depends_on = ["0x4e693", "0x5212b", "0xa6f86", "0xaa8f2", "0xaaa1e", "0x15261a", "0x15261b", "0x152877"]
|
||||
|
||||
[[global]]
|
||||
address = "0x152877"
|
||||
name = "battle_entity_indices"
|
||||
|
||||
Reference in New Issue
Block a user