extends SceneTree const MainScene = preload("res://main.tscn") const PROFESSIONS := ["Hearthguard", "Wayrunner", "Farstring", "Kindhand"] var failures: Array[String] = [] func _initialize() -> void: call_deferred("run_test") func run_test() -> void: var game := MainScene.instantiate() game.auto_boot = false root.add_child(game) await settle(10) game.locale = "zh_CN" game.muted = true game.boot_verified = true game.page = game.AppPage.MAIN_MENU game.render() game.start_new_game() expect(game.page == game.AppPage.FIRST_MISSION, "New Game opens first mission") expect(game.selected_recruits.is_empty() and game.front_choice.is_empty() and game.rear_choice.is_empty(), "mission has no selection or assigned position") game.open_recruit_selection() expect(game.page == game.AppPage.RECRUIT_SELECTION, "mission opens unified Recruit selection") for profession in PROFESSIONS: expect(find_control(game, "Recruit_%s" % profession) != null, "unified page shows %s" % profession) expect(find_control(game, "Front_Hearthguard") == null and find_control(game, "Rear_Farstring") == null, "player-facing slot buttons are absent") var review := find_control(game, "ReviewFormationButton") as BaseButton expect(review != null and review.disabled, "review is disabled at zero selections") game.toggle_recruit("Hearthguard") game.toggle_recruit("Hearthguard") expect(game.selected_recruits.is_empty(), "tapping a selected Recruit removes only that Recruit") game.toggle_recruit("Hearthguard") game.toggle_recruit("Farstring") expect(game.selected_recruits == ["Hearthguard", "Farstring"], "two people can be selected") game.toggle_recruit("Kindhand") expect(game.selected_recruits == ["Hearthguard", "Farstring"], "third selection is rejected at capacity") game.toggle_recruit("Hearthguard") expect(game.selected_recruits == ["Farstring"], "full Company still lets the player remove one") game.toggle_recruit("Kindhand") game.review_automatic_formation() expect(game.page == game.AppPage.FORMATION_REVIEW, "two people reach review") expect(game.front_choice == "Farstring" and game.rear_choice == "Kindhand", "system orders Farstring before Kindhand") game.revise_recruit_selection() expect(game.page == game.AppPage.RECRUIT_SELECTION and game.selected_recruits == ["Farstring", "Kindhand"], "unified Revise preserves both people") var combinations := 0 for left_index in range(PROFESSIONS.size()): for right_index in range(left_index + 1, PROFESSIONS.size()): var left: String = PROFESSIONS[left_index] var right: String = PROFESSIONS[right_index] var expected: Array[String] = [left, right] for reverse in [false, true]: game.clear_experience() game.page = game.AppPage.FIRST_MISSION game.open_recruit_selection() game.toggle_recruit(right if reverse else left) game.toggle_recruit(left if reverse else right) game.review_automatic_formation() expect([game.front_choice, game.rear_choice] == expected, "%s/%s click order does not change system order" % [left, right]) game.commit_formation() expect(game.page == game.AppPage.BATTLE and game.battle_playing and game.formation_commit_count == 1, "%s/%s enters battle once" % [left, right]) resolve_first_battle(game) expect(game.page == game.AppPage.VICTORY and game.enemy_hp == 0, "%s/%s reaches Victory" % [left, right]) game.clear_experience() combinations += 1 game.page = game.AppPage.FIRST_MISSION game.open_recruit_selection() game.toggle_recruit("Wayrunner") game.toggle_recruit("Kindhand") game.go_home() expect(game.page == game.AppPage.MAIN_MENU and game.selected_recruits.is_empty() and game.formation_commit_count == 0, "Home clears selected people and assignment") game.start_new_game() game.open_recruit_selection() game.toggle_recruit("Hearthguard") game.request_restart() game.confirm_restart() expect(game.page == game.AppPage.MAIN_MENU and game.selected_recruits.is_empty(), "Restart clears incomplete selection") game.queue_free() await settle(90) if failures.is_empty(): print("ABG_P9_0R9A_AUTO_FORMATION_OK recruits=4 pairs=%d click_orders=12 no_slots=true toggle=true capacity=2 deterministic=true victory=6 commit_once=true cleanup=home,restart" % combinations) quit(0) else: for failure in failures: push_error(failure) quit(1) func resolve_first_battle(game: Control) -> void: for phase in range(6): game.advance_battle_phase() func find_control(node: Node, node_name: String) -> Control: if node.name == node_name and node is Control and not node.is_queued_for_deletion(): return node for child in node.get_children(): var found := find_control(child, node_name) if found != null: return found return null func settle(frames: int) -> void: for frame in range(frames): await process_frame func expect(condition: bool, message: String) -> void: if not condition: failures.append("P9.0R9A automatic formation: %s" % message)