Files
aetherbound-guild/runtime/tests/p9_0r4_second_cycle_test.gd

127 lines
4.9 KiB
GDScript

extends SceneTree
const MainScene = preload("res://main.tscn")
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
prepare_first_victory(game, "Hearthguard", "Farstring")
expect(game.page == game.AppPage.VICTORY, "first battle reaches diagnosis")
expect(game.coin == 20 and game.first_reward_committed, "first victory grants 20 Coin exactly once")
expect(find_control(game, "VictoryDiagnosis") != null, "first result renders causal diagnosis")
expect(find_control(game, "FirstReward") != null, "first result renders the reward")
game.commit_first_victory_reward()
expect(game.coin == 20, "replaying reward commit cannot duplicate Coin")
game.open_adaptation()
expect(game.page == game.AppPage.ADAPTATION, "diagnosis opens adaptation")
expect(game.adaptation_choice.is_empty(), "adaptation has no preselection")
expect(find_control(game, "Adaptation_EQ_002") != null and find_control(game, "Adaptation_EQ_061") != null, "both stable choices render")
var begin := find_control(game, "BeginSecondBattle") as BaseButton
expect(begin != null and begin.disabled, "second battle is disabled until a choice")
game.choose_adaptation("EQ-061")
game.choose_adaptation("EQ-002")
expect(game.adaptation_choice == "EQ-002", "selection is reversible before commit")
game.begin_second_battle()
expect(game.page == game.AppPage.SECOND_BATTLE and game.adaptation_committed, "departure locks the chosen loan")
game.choose_adaptation("EQ-061")
expect(game.adaptation_choice == "EQ-002", "committed loan cannot change")
var safe_time := resolve_second_battle(game)
expect(game.page == game.AppPage.SECOND_RESULT, "safe route reaches second result")
expect(game.front_hp == 90 and game.enemy_hp == 0, "Frontpin Farstring route keeps 90 front HP and wins")
expect(game.coin == 20, "second battle does not duplicate first reward")
expect(game.battle_feedback_history.size() == 4, "safe route emits four exact HP feedback events")
expect(find_control(game, "SecondResultFacts") != null, "second result renders exact facts")
game.request_restart()
game.confirm_restart()
expect(game.page == game.AppPage.MAIN_MENU, "confirmed replay returns to Main Menu")
expect(game.coin == 0 and game.adaptation_choice.is_empty() and not game.adaptation_committed, "restart clears reward and adaptation")
prepare_first_victory(game, "Hearthguard", "Farstring")
game.open_adaptation()
game.choose_adaptation("EQ-061")
game.begin_second_battle()
var fast_time := resolve_second_battle(game)
expect(game.front_hp == 70 and game.enemy_hp == 0, "Early Bell Farstring route accepts full strike and wins")
expect(game.battle_feedback_history.size() == 5, "fast route emits initiative plus four HP feedback events")
expect(fast_time < safe_time, "Early Bell route is faster than Frontpin route")
game.clear_experience()
prepare_first_victory(game, "Hearthguard", "Kindhand")
game.open_adaptation()
game.choose_adaptation("EQ-002")
game.begin_second_battle()
resolve_second_battle(game)
expect(game.front_hp == 100, "Frontpin Kindhand route caps healing at 100")
game.clear_experience()
prepare_first_victory(game, "Wayrunner", "Kindhand")
game.open_adaptation()
game.choose_adaptation("EQ-061")
game.begin_second_battle()
resolve_second_battle(game)
expect(game.front_hp == 82, "Early Bell Kindhand route heals 70 to 82")
game.go_home()
expect(game.page == game.AppPage.MAIN_MENU and game.coin == 0 and game.front_choice.is_empty(), "Home clears the complete transient loop")
game.queue_free()
await settle(80)
if failures.is_empty():
print("ABG_P9_0R4_SECOND_CYCLE_OK coin=20 once=true choices=2 unselected=true revision=true lock=true safe_hp=90,100 fast_hp=70,82 safe_time=%.2f fast_time=%.2f feedback=4,5 cleanup=true" % [safe_time, fast_time])
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func prepare_first_victory(game: Control, front: String, rear: String) -> void:
game.front_choice = front
game.rear_choice = rear
game.depart()
for phase in range(6):
game.advance_battle_phase()
func resolve_second_battle(game: Control) -> float:
var declared_time := 0.0
for phase in range(6):
var duration: float = game.phase_duration(phase)
declared_time += duration
game.second_battle_elapsed += duration
game.advance_battle_phase()
return declared_time
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.0R4 second cycle: %s" % message)