extends SceneTree var failures: Array[String] = [] func _init() -> void: _run.call_deferred() func _run() -> void: var ui_scene := load("res://scenes/ui/main_ui.tscn") as PackedScene _expect(ui_scene != null, "Main UI scene should load") if ui_scene == null: _finish() return var ui := ui_scene.instantiate() root.add_child(ui) await process_frame _expect(ui.get_node_or_null("StatusBars/HealthBar") is ProgressBar, "UI should keep Player HealthBar") _expect(ui.get_node_or_null("BossStatus/BossHealthBar") is ProgressBar, "UI should include BossHealthBar") _expect(ui.get_node_or_null("BossStatus/BossPortrait") is TextureRect, "BossStatus should include the Boss portrait art") _expect(ui.has_method("bind_boss_actor"), "MainUI should expose bind_boss_actor") var boss_status := ui.get_node_or_null("BossStatus") as Control var player_health_bar := ui.get_node_or_null("StatusBars/HealthBar") as ProgressBar var boss_health_bar := ui.get_node_or_null("BossStatus/BossHealthBar") as ProgressBar var boss_portrait := ui.get_node_or_null("BossStatus/BossPortrait") as TextureRect if boss_status == null or player_health_bar == null or boss_health_bar == null or boss_portrait == null: ui.free() _finish() return _expect_equal(boss_portrait.texture.resource_path if boss_portrait.texture != null else "", "res://assets/ui/panels/boss_portrait.png", "Boss portrait should use the supplied boss art") _expect_float(boss_portrait.size.x, 57.0, "Boss portrait should keep the supplied art width") _expect_float(boss_portrait.size.y, 58.0, "Boss portrait should keep the supplied art height") _expect_bool(boss_status.visible, false, "BossStatus should stay hidden before boss-room entry") var player := _actor_with_health("Player", 1000, 1000) var boss := _actor_with_health("Boss", 28000, 28000) root.add_child(player) root.add_child(boss) await process_frame if ui.has_method("bind_boss_actor"): ui.call("bind_boss_actor", boss) await process_frame _expect_bool(boss_status.visible, false, "Binding a Boss actor should not show BossStatus before boss-room entry") var bus := root.get_node_or_null("EventBus") _expect(bus != null and bus.has_signal("flow_state_changed"), "EventBus should expose flow_state_changed") if bus != null and bus.has_signal("flow_state_changed"): bus.emit_signal("flow_state_changed", &"Title", &"Gameplay_FrontArea") await process_frame _expect_bool(boss_status.visible, false, "BossStatus should remain hidden in the front area") bus.emit_signal("flow_state_changed", &"Gameplay_FrontArea", &"Gameplay_BossRoom") await process_frame _expect_bool(boss_status.visible, true, "BossStatus should show after boss-room entry") bus.emit_signal("flow_state_changed", &"Gameplay_BossRoom", &"Title") await process_frame _expect_bool(boss_status.visible, false, "BossStatus should hide outside boss-room gameplay") _expect_float(float(player_health_bar.max_value), 1000.0, "Player HealthBar should initialize from Player HealthComponent") _expect_float(float(boss_health_bar.max_value), 28000.0, "BossHealthBar max should follow Boss HealthComponent") _expect_float(float(boss_health_bar.value), 28000.0, "BossHealthBar value should follow Boss HealthComponent") boss.get_node("HealthComponent").call("apply_damage", 1200) await process_frame _expect_float(float(boss_health_bar.value), 26800.0, "BossHealthBar should follow Boss damage") _expect_float(float(player_health_bar.value), 1000.0, "Boss damage should not change Player HealthBar") player.get_node("HealthComponent").call("set_values", 640, 1000) await process_frame _expect_float(float(player_health_bar.max_value), 1000.0, "Player HealthBar should follow Player HealthComponent when bound by event") _expect_float(float(player_health_bar.value), 640.0, "Player HealthBar should follow Player damage") _expect_float(float(boss_health_bar.value), 26800.0, "Player damage should not change BossHealthBar") ui.free() player.free() boss.free() _finish() func _actor_with_health(actor_name: String, current: int, maximum: int) -> Node: var actor := Node2D.new() actor.name = actor_name var health_script: Script = load("res://scenes/components/health_component.gd") var health: Node = health_script.new() health.name = "HealthComponent" actor.add_child(health) health.set("maximum", maximum) health.set("current", current) return actor func _expect(condition: bool, label: String) -> void: if not condition: failures.append(label) func _expect_float(actual: float, expected: float, label: String) -> void: if absf(actual - expected) > 0.001: failures.append("%s: expected %.3f, got %.3f" % [label, expected, actual]) func _expect_equal(actual: Variant, expected: Variant, label: String) -> void: if actual != expected: failures.append("%s: expected %s, got %s" % [label, str(expected), str(actual)]) func _expect_bool(actual: bool, expected: bool, label: String) -> void: if actual != expected: failures.append("%s: expected %s, got %s" % [label, expected, actual]) func _finish() -> void: if failures.is_empty(): print("PASS phase9 boss health ui") quit(0) else: for failure: String in failures: push_error(failure) quit(1)