Files
gamedev-the-steward/tests/combat_patterns_test.gd
T
2026-08-12 10:02:45 +02:00

161 lines
4.8 KiB
GDScript

extends SceneTree
var failures: Array[String] = []
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
_test_enemy_definitions()
_test_player_downing()
_test_defend_selection()
_finish()
func _test_enemy_definitions() -> void:
var raider: EnemyDefinition = SimulationEnemies.get_enemy(&"enemy_raider")
var wolf: EnemyDefinition = SimulationEnemies.get_enemy(&"enemy_wolf")
_check(
(
raider != null
and wolf != null
and raider.kind == SimulationIds.COMBATANT_KIND_RAIDER
and wolf.kind == SimulationIds.COMBATANT_KIND_WOLF
and raider.weapon_id == SimulationIds.ITEM_SWORD
and wolf.weapon_id == SimulationIds.ITEM_CLAW
),
"Enemy definitions should describe raiders and wolves as data"
)
var manager := _create_manager(991)
var wolf_id: StringName = manager.spawn_wolf(Vector3.ZERO)
var wolf_combatant: CombatantStateRecord = manager.get_combatant(wolf_id)
_check(
(
is_equal_approx(wolf_combatant.get_health(), wolf.health)
and wolf_combatant.get_weapon_id() == wolf.weapon_id
),
"Spawned enemies should inherit their definition's health and weapon"
)
manager.free()
func _test_player_downing() -> void:
var manager := _create_manager(992)
var player_state: PlayerStateRecord = manager.get_player_state()
_check(
is_equal_approx(player_state.get_health(), 100.0) and not player_state.is_downed(),
"The player should begin healthy and standing"
)
var wolf_id: StringName = manager.spawn_wolf(Vector3.ZERO)
manager.update_player_combatant(Vector3.ZERO)
for _tick in 3:
manager.simulate_tick()
_check(
player_state.get_health() < 100.0 and not player_state.is_downed(),
"A hungry wolf should wound the player during a hunt"
)
var downed := false
for _tick in 60:
manager.simulate_tick()
if player_state.is_downed():
downed = true
break
_check(downed, "A prolonged wolf attack should eventually down the player")
if downed:
for _tick in 22:
manager.simulate_tick()
_check(not player_state.is_downed(), "The downed player should recover and stand again")
var player_combatant: CombatantStateRecord = manager.get_combatant(&"player_combatant")
_check(
(
player_state.get_health() > 0.0
and player_combatant != null
and player_combatant.is_alive()
and is_equal_approx(player_combatant.get_health(), player_state.get_health())
),
"Recovery should revive both authoritative player records at matching health"
)
manager.update_player_combatant(Vector3(100.0, 0.0, 100.0))
manager.spawn_wolf(Vector3(100.0, 0.0, 100.0))
var recovered_health := player_state.get_health()
manager.simulate_tick()
_check(
player_state.get_health() < recovered_health,
"A recovered player should become targetable and vulnerable again"
)
manager.free()
func _test_defend_selection() -> void:
var manager := _create_manager(993)
manager.clock.elapsed_ticks = 100
var tribe: FactionStateRecord = manager.get_faction(SimulationIds.FACTION_TRIBE)
tribe.set_war_plan(SimulationIds.WAR_PLAN_RAIDING, 1)
var defender: SimNPC = manager.npcs[0]
defender.strength = 9.0
defender.hunger = 20.0
defender.energy = 90.0
defender.is_starving = false
defender.mourning_ticks = 0
defender.inventory.clear()
defender.task_state = SimNPC.TASK_STATE_IDLE
defender.task_complete = true
manager.call("_select_action_if_idle", defender, SimNPC.TASK_STATE_IDLE)
_check(
(
defender.current_task == SimulationIds.ACTION_DEFEND
and manager.conflict_system.is_raiding()
),
"A strong idle villager should rally to defend during an active raid"
)
var worker: SimNPC = manager.npcs[1]
worker.strength = 1.0
worker.hunger = 20.0
worker.energy = 90.0
worker.is_starving = false
worker.mourning_ticks = 0
worker.inventory.clear()
worker.task_state = SimNPC.TASK_STATE_IDLE
worker.task_complete = true
manager.call("_select_action_if_idle", worker, SimNPC.TASK_STATE_IDLE)
_check(
worker.current_task != SimulationIds.ACTION_DEFEND,
"A weak non-guard villager should not be conscripted as a defender"
)
manager.free()
func _create_manager(seed_value: int = 991) -> Node:
var manager: Node = load("res://simulation/SimulationManager.gd").new()
manager.simulation_seed = seed_value
manager.debug_logs = false
var home_positions: Array[Vector3] = [
Vector3(0.0, 0.0, 0.0),
Vector3(2.0, 0.0, 0.0),
Vector3(10.0, 0.0, 0.0),
Vector3(12.0, 0.0, 0.0),
Vector3(30.0, 0.0, 30.0),
Vector3(40.0, 0.0, 40.0),
]
manager.home_positions = home_positions
root.add_child(manager)
manager.set_process(false)
return manager
func _finish() -> void:
if failures.is_empty():
print("[TEST] Combat patterns passed: enemy data, player downing, defend duty")
quit(0)
return
for failure in failures:
push_error("[TEST] " + failure)
quit(1)
func _check(condition: bool, message: String) -> void:
if not condition:
failures.append(message)