extends SceneTree ## Game-flow state machine + boss-room entry rules (AnchorV1.0 §4.5 / §19.5). var failures: Array[String] = [] func _init() -> void: _run.call_deferred() func _run() -> void: var flow: Node = load("res://autoload/game_flow_manager.gd").new() flow.set("manage_scene", false) root.add_child(flow) await process_frame # --- screens exist for every menu state --- for state_name: StringName in [&"Title", &"DifficultySelect", &"Paused", &"VolumeSettings", &"ExitGameConfirm", &"ReturnTitleConfirm", &"Defeat", &"Victory", &"Result"]: var screens: Dictionary = flow.get("_screens") _expect_bool(screens.has(state_name), true, "screen for %s exists" % state_name) var flow_ui := flow.get_node_or_null("FlowUI") _expect_bool(flow_ui != null, true, "flow UI layer exists") if flow_ui != null: _expect_bool(flow_ui.get_node_or_null("PauseButton") == null, true, "HUD should not show a top-right pause button; pause is Esc-only") # --- pause / resume drive the SceneTree pause + rhythm clock --- flow.set("state", &"Gameplay_FrontArea") var esc := InputEventAction.new() esc.action = &"ui_cancel" esc.pressed = true flow.call("_unhandled_input", esc) _expect_string(str(flow.get("state")), "Paused", "Esc enters Paused") _expect_bool(root.get_tree().paused, true, "pause stops the SceneTree") flow.call("_unhandled_input", esc) _expect_string(str(flow.get("state")), "Gameplay_FrontArea", "Esc resumes gameplay") _expect_bool(root.get_tree().paused, false, "resume releases the SceneTree") # --- boss-room entry rules on a synthetic scene (§4.5) --- var scene := _build_fake_scene() root.add_child(scene) current_scene = scene await process_frame var player := scene.get_node("Stage/ActorsContainer/Player") var streak := player.get_node("StreakCounter") streak.set("streak", 9) var combo := player.get_node("ComboWindow") combo.call("record", &"A") combo.call("record", &"A") var buff := player.get_node("AttackBuffComponent") var container := player.get_node("EffectContainer") for index: int in range(6): container.call("add_effect", buff.get("buff_definition"), &"test") _expect_int(int(buff.call("attack_buff_stacks")), 6, "test setup should reach 6 buff stacks") flow.set("state", &"Gameplay_FrontArea") flow.set("_boss_room_entered", false) flow.call("enter_boss_room") _expect_string(str(flow.get("state")), "Gameplay_BossRoom", "entering the boss room switches state") _expect_int(int(streak.get("streak")), 0, "boss entry clears the combo counter") _expect_int((combo.call("get_slots") as Array).size(), 0, "boss entry clears the four-slot window") _expect_int(int(buff.call("attack_buff_stacks")), 3, "boss entry caps the attack buff at 3 stacks") var boss := scene.get_node("Stage/ActorsContainer/Boss") _expect_bool(bool(boss.get("combat_enabled")), true, "boss combat unlocks on entry") _expect_bool(bool(boss.get("stationary")), false, "boss leaves training-dummy mode on entry") # --- re-entering is a no-op --- streak.set("streak", 5) flow.call("enter_boss_room") _expect_int(int(streak.get("streak")), 5, "boss entry rules apply only once") # --- rank appears only on victory (§19.6) --- flow.set("_victory", true) flow.set("state", &"Result") flow.call("_populate_result_screen") var labels: Dictionary = flow.get("_result_labels") _expect_bool((labels.get("rank") as Label).visible, true, "victory result shows the rank") flow.set("_victory", false) flow.call("_populate_result_screen") _expect_bool((labels.get("rank") as Label).visible, false, "defeat result hides the rank") current_scene = null scene.free() flow.free() _finish() func _build_fake_scene() -> Node: var scene := Node.new() scene.name = "Main" var stage := Node2D.new() stage.name = "Stage" scene.add_child(stage) var actors := Node2D.new() actors.name = "ActorsContainer" stage.add_child(actors) var player := CharacterBody2D.new() player.name = "Player" actors.add_child(player) var streak: Node = load("res://scenes/components/streak_counter.gd").new() streak.name = "StreakCounter" player.add_child(streak) var combo: Node = load("res://scenes/components/combo_window.gd").new() combo.name = "ComboWindow" player.add_child(combo) var container: Node = load("res://scenes/components/effect_container.gd").new() container.name = "EffectContainer" player.add_child(container) var buff: Node = load("res://scenes/components/attack_buff_component.gd").new() buff.name = "AttackBuffComponent" player.add_child(buff) var boss_script := GDScript.new() boss_script.source_code = "extends Node2D\nvar combat_enabled := false\nvar stationary := true\n" boss_script.reload() var boss := Node2D.new() boss.name = "Boss" boss.set_script(boss_script) actors.add_child(boss) return scene func _expect_bool(actual: bool, expected: bool, label: String) -> void: if actual != expected: failures.append("%s: expected %s, got %s" % [label, expected, actual]) func _expect_int(actual: int, expected: int, label: String) -> void: if actual != expected: failures.append("%s: expected %d, got %d" % [label, expected, actual]) func _expect_string(actual: String, expected: String, label: String) -> void: if actual != expected: failures.append("%s: expected %s, got %s" % [label, expected, actual]) func _finish() -> void: paused = false if failures.is_empty(): print("PASS game flow") quit(0) else: for failure: String in failures: push_error(failure) quit(1)