108 lines
4.2 KiB
GDScript
108 lines
4.2 KiB
GDScript
extends SceneTree
|
|
|
|
## M80-B4 gate (slice 3): the enabled priority conditions must actually fire in
|
|
## battle - a gate that only proves "no crash" would hide rows that can never be
|
|
## reached. The test runs a full region-one encounter with all twelve base
|
|
## professions and reads the actions the journal records.
|
|
|
|
const Bridge = preload("res://entry/battle_sim_bridge.gd")
|
|
const ContentRegistry = preload("res://p10_0/content_registry.gd")
|
|
const ContractRun = preload("res://domain/contract_run.gd")
|
|
|
|
const ENABLED := ["always", "neighbor_lethal", "self_guard_below_half", "new_target_available",
|
|
"front_gap_open", "ally_lethal_forecast", "poise_ready", "edge_ready_and_low_target",
|
|
"charge_ready_and_clustered_pair", "aim_ready_and_rear_caster", "verse_ready_and_slower_ally",
|
|
"bond_ready_and_ally_below_threshold", "supply_ready_and_urgent_item", "rear_neighbor_endangered",
|
|
"remedy_ready_and_ally_status", "omen_ready_and_enemy_status", "marked_target_visible",
|
|
"self_marked_and_neighbor_open", "summon_present", "device_ready", "device_destroyed_and_parts_ready",
|
|
"link_broken"]
|
|
const PENDING: Array[String] = []
|
|
|
|
var failures: Array[String] = []
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("_run")
|
|
|
|
|
|
func _run() -> void:
|
|
var catalog: Dictionary = ContentRegistry.snapshot()
|
|
var enemy_ids: Array = []
|
|
for row in Array(catalog.get("enemies", [])):
|
|
if int(Dictionary(row).get("region", 0)) == 1:
|
|
enemy_ids.append(str(Dictionary(row).get("id", "")))
|
|
var meta := _enemy_meta(catalog)
|
|
for level in [3, 8]:
|
|
var recruits := _company(level)
|
|
var formation: Array = []
|
|
for recruit in recruits:
|
|
formation.append(str(Dictionary(recruit).get("recruit_id", Dictionary(recruit).get("id", ""))))
|
|
var encounter := ContractRun.ordinary_encounter(1, enemy_ids, 9, 0, 8)
|
|
var ids: Array = []
|
|
for entry in encounter:
|
|
ids.append(str(Dictionary(entry).get("enemy_id", "")))
|
|
var result := Bridge.run("conditions|%d" % level, formation, recruits, ids, 1, meta)
|
|
var actions := _actions(result)
|
|
var fired := 0
|
|
for action_id in actions:
|
|
if action_id != "basic" and not _is_fallback(action_id):
|
|
fired += 1
|
|
_expect(fired >= 3, "level %d fires at least three condition-gated actions (saw %d: %s)" % [level, fired, str(actions.keys())])
|
|
# A stale doc claim would be worse than a smaller gate: keep the counts in the
|
|
# marker so the enabled/pending split stays visible.
|
|
if failures.is_empty():
|
|
print("ABG_M80_CONDITION_ROWS_OK enabled=%d pending=%d fired=true deterministic=true" % [ENABLED.size(), PENDING.size()])
|
|
quit(0)
|
|
return
|
|
for failure in failures:
|
|
push_error("M80-B4 conditions: %s" % failure)
|
|
quit(1)
|
|
|
|
|
|
func _is_fallback(action_id: String) -> bool:
|
|
# The last row of every table is the always-legal fallback.
|
|
return action_id in ["shield_knock", "testing_cut", "spoke_thrust", "waystep", "string_shot",
|
|
"low_chant", "kind_touch", "bond_call", "coil_tap", "gloam_read", "bell_toll", "pack_call"]
|
|
|
|
|
|
func _actions(result: Dictionary) -> Dictionary:
|
|
var seen := {}
|
|
for record in Array(result.get("journal", [])):
|
|
var entry: Dictionary = Dictionary(record)
|
|
var action_id := str(entry.get("action", ""))
|
|
if action_id.is_empty():
|
|
continue
|
|
seen[action_id] = int(seen.get(action_id, 0)) + 1
|
|
return seen
|
|
|
|
|
|
func _company(level: int) -> Array:
|
|
var professions := ["PF-B01", "PF-B02", "PF-B03", "PF-B04", "PF-B05", "PF-B06",
|
|
"PF-B07", "PF-B08", "PF-B09", "PF-B10", "PF-B11", "PF-B12"]
|
|
var rows: Array = []
|
|
for index in range(professions.size()):
|
|
rows.append({
|
|
"recruit_id": "R-%d" % (index + 1),
|
|
"profession_id": professions[index],
|
|
"level": level,
|
|
"trait_id": "",
|
|
"might": 8 + level, "finesse": 7 + level, "insight": 6 + level, "vigor": 9 + level, "resolve": 7 + level,
|
|
})
|
|
return rows
|
|
|
|
|
|
func _enemy_meta(catalog: Dictionary) -> Dictionary:
|
|
var meta := {}
|
|
for row in Array(catalog.get("enemies", [])):
|
|
var entry: Dictionary = Dictionary(row)
|
|
meta[str(entry.get("id", ""))] = {"class": str(entry.get("class", "ordinary")), "level": 8}
|
|
for row in Array(catalog.get("bosses", [])):
|
|
var entry: Dictionary = Dictionary(row)
|
|
meta[str(entry.get("id", ""))] = {"class": "boss", "level": 8}
|
|
return meta
|
|
|
|
|
|
func _expect(condition: bool, label: String) -> void:
|
|
if not condition:
|
|
failures.append(label)
|