Close RTINIT movement provider semantics
This commit is contained in:
@@ -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 = (
|
||||
|
||||
@@ -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"]
|
||||
== {
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user