Close RTINIT movement provider semantics

This commit is contained in:
gamer147
2026-07-23 17:11:14 -04:00
parent 8574673d53
commit 64f9cebd3b
10 changed files with 210 additions and 69 deletions

View File

@@ -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 = (

View File

@@ -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"]
== {

View File

@@ -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",