152 lines
6.1 KiB
GDScript
152 lines
6.1 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_second_cycle_result(game, "EQ-002", "Farstring", "")
|
|
expect(game.member_slots() == ["front", "rear"], "two-person Company exposes front/rear only")
|
|
game.open_training()
|
|
expect(game.page == game.AppPage.TRAINING and game.training_choice.is_empty(), "training opens unselected")
|
|
expect(find_control(game, "Training_Added") == null, "absent added member never renders")
|
|
game.choose_training("added")
|
|
expect(game.training_choice.is_empty(), "absent added member is rejected")
|
|
game.choose_training("front")
|
|
game.choose_training("rear")
|
|
expect(game.training_choice == "rear", "selection is reversible without committing")
|
|
game.open_training_review()
|
|
game.cancel_training_review()
|
|
expect(game.page == game.AppPage.TRAINING and game.training_choice == "rear", "review cancel preserves choice")
|
|
|
|
prepare_second_cycle_result(game, "", "Farstring", "Kindhand")
|
|
expect(game.member_slots() == ["front", "rear", "added"], "three-person Company exposes actual added member")
|
|
for slot in ["front", "rear", "added"]:
|
|
expect(game.member_level(slot) == 1, "%s starts at Lv.1" % slot)
|
|
game.open_training()
|
|
game.choose_training("added")
|
|
game.open_training_review()
|
|
var coin_before: int = game.coin
|
|
game.commit_training()
|
|
expect(game.training_committed and game.trained_member == "added", "commit binds one actual member")
|
|
expect(game.member_level("added") == 2 and game.member_level("front") == 1 and game.member_level("rear") == 1, "exactly one member reaches Lv.2")
|
|
game.commit_training()
|
|
expect(game.coin == coin_before and game.trained_member == "added", "duplicate training commit is inert")
|
|
resolve_fifth_battle(game)
|
|
expect(game.page == game.AppPage.THIRD_CYCLE_RESULT and game.enemy_hp == 0, "fifth battle reaches causal result")
|
|
expect(game.rear_hp == 85 and game.rear_events == 2, "trained added Kindhand heals +25 and both rears act once")
|
|
expect(game.coin == coin_before + 8 and game.fifth_reward_committed, "fifth reward commits once")
|
|
game.commit_fifth_reward()
|
|
expect(game.coin == coin_before + 8, "duplicate fifth reward is inert")
|
|
|
|
for item in ["EQ-002", ""]:
|
|
for training_slot in ["front", "rear", "added"]:
|
|
prepare_second_cycle_result(game, item, "Farstring", "Kindhand")
|
|
commit_training_choice(game, training_slot)
|
|
var duration := resolve_fifth_battle(game)
|
|
var expected_front := 90 if item == "EQ-002" else 75
|
|
if training_slot != "front":
|
|
expected_front = 70 if item == "EQ-002" else 55
|
|
var expected_rear := 85 if training_slot == "added" else 72
|
|
var expected_time := 6.40 if training_slot == "rear" else 7.40
|
|
expect(game.front_hp == expected_front, "%s/%s front counterfactual" % [item, training_slot])
|
|
expect(game.rear_hp == expected_rear, "%s/%s rear counterfactual" % [item, training_slot])
|
|
expect(is_equal_approx(duration, expected_time), "%s/%s timing counterfactual" % [item, training_slot])
|
|
expect(game.rear_events == 2, "%s/%s rear actions remain exactly two" % [item, training_slot])
|
|
|
|
prepare_second_cycle_result(game, "", "Kindhand", "Farstring")
|
|
commit_training_choice(game, "rear")
|
|
resolve_fifth_battle(game)
|
|
expect(game.rear_hp == 85 and game.rear_events == 2, "trained original Kindhand heals +25")
|
|
|
|
prepare_second_cycle_result(game, "EQ-002", "Farstring", "")
|
|
commit_training_choice(game, "rear")
|
|
var two_person_time := resolve_fifth_battle(game)
|
|
expect(game.rear_hp == 60 and game.rear_events == 1, "two-person Farstring acts once and cannot heal")
|
|
expect(is_equal_approx(two_person_time, 6.40), "two-person trained Farstring preserves fast timing")
|
|
|
|
game.request_restart()
|
|
game.confirm_restart()
|
|
expect(game.page == game.AppPage.MAIN_MENU, "Restart returns to Main Menu")
|
|
expect(game.training_choice.is_empty() and not game.training_committed and game.trained_member.is_empty() and not game.fifth_reward_committed, "Restart clears growth transaction")
|
|
game.queue_free()
|
|
await settle(90)
|
|
if failures.is_empty():
|
|
print("ABG_P9_0R7_INDIVIDUAL_GROWTH_OK slots=2,3 revise=true review_cancel=true commit_once=true level2=1 outcomes=8 front_hp=90,75,70,55 rear_hp=85,72,60 times=7.40,6.40 reward=8 cleanup=true")
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func prepare_second_cycle_result(game: Control, item: String, original_rear: String, extra_rear: String) -> void:
|
|
game.clear_experience()
|
|
game.front_choice = "Hearthguard"
|
|
game.rear_choice = original_rear
|
|
game.adaptation_choice = item if not item.is_empty() else "EQ-061"
|
|
game.adaptation_committed = true
|
|
game.guild_choice = "retain_item" if extra_rear.is_empty() else "recruit_rear"
|
|
game.guild_committed = true
|
|
game.retained_item = item
|
|
game.added_rear = extra_rear
|
|
game.coin = 12
|
|
game.route_choice = "R6-01"
|
|
game.route_committed = true
|
|
game.route_reward_committed = true
|
|
game.front_hp = 90
|
|
game.rear_hp = 100
|
|
game.enemy_hp = 0
|
|
game.fourth_result_time = 7.40
|
|
game.page = game.AppPage.SECOND_CYCLE_RESULT
|
|
game.render()
|
|
|
|
|
|
func commit_training_choice(game: Control, slot: String) -> void:
|
|
game.open_training()
|
|
game.choose_training(slot)
|
|
game.open_training_review()
|
|
game.commit_training()
|
|
|
|
|
|
func resolve_fifth_battle(game: Control) -> float:
|
|
var declared_time := 0.0
|
|
for phase in range(7):
|
|
var duration: float = game.phase_duration(phase)
|
|
declared_time += duration
|
|
game.fifth_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.0R7 growth: %s" % message)
|