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

150 lines
4.5 KiB
GDScript

extends SceneTree
const MainScene = preload("res://main.tscn")
const STATES := [
"guard_damage",
"evade_damage",
"ranged_damage",
"healing",
"combo_damage",
"final_damage",
]
var failures: Array[String] = []
var output_root := ""
var viewport_size := Vector2i(1280, 720)
var locale := "zh_CN"
var text_scale := 1.0
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
output_root = read_string("ABG_P9_0R3_CAPTURE_ROOT", "/tmp/abg-p9-0r3-feedback-captures")
viewport_size = Vector2i(read_int("ABG_P9_0R3_VIEWPORT_WIDTH", 1280), read_int("ABG_P9_0R3_VIEWPORT_HEIGHT", 720))
locale = read_string("ABG_P9_0R3_LOCALE", "zh_CN")
text_scale = read_float("ABG_P9_0R3_TEXT_SCALE", 1.0)
DirAccess.make_dir_recursive_absolute(output_root)
var viewport := SubViewport.new()
viewport.size = viewport_size
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
root.add_child(viewport)
var game := MainScene.instantiate()
game.auto_boot = false
game.audio_enabled = false
viewport.add_child(game)
await settle(12)
game.locale = locale
game.text_scale = text_scale
game.reduced_motion = false
game.muted = true
game.boot_verified = true
for index in range(STATES.size()):
await capture_feedback(viewport, game, index + 1, STATES[index])
game.queue_free()
viewport.queue_free()
await settle(120)
if failures.is_empty():
print("ABG_P9_0R3_FEEDBACK_CAPTURE_OK frames=6 viewport=%sx%s locale=%s text_scale=%.1f renderer=normal root=%s" % [viewport_size.x, viewport_size.y, locale, text_scale, output_root])
call_deferred("finish", 0)
else:
for failure in failures:
push_error(failure)
call_deferred("finish", 1)
func capture_feedback(viewport: SubViewport, game: Control, index: int, state_name: String) -> void:
game.clear_experience()
apply_feedback_state(game, state_name)
game.battle_feedback_clock = 0.16
game.render()
game.update_battle_feedback_visual()
await settle(4)
await RenderingServer.frame_post_draw
var label := find_control(game, "BattleFeedbackLabel")
if label == null:
failures.append("capture %s has no feedback label" % state_name)
else:
var label_rect := Rect2(label.position, label.size * label.scale)
var health_band := Rect2(0, 0, viewport_size.x, 116)
var event_band := Rect2(viewport_size.x * 0.27, 116, viewport_size.x * 0.46, 48)
if label_rect.intersects(health_band) or label_rect.intersects(event_band):
failures.append("capture %s feedback overlaps HUD or event ribbon" % state_name)
var image := viewport.get_texture().get_image()
var path := output_root.path_join("%02d-%s.png" % [index, state_name])
var error := image.save_png(path)
if error != OK:
failures.append("capture %s failed with %s" % [state_name, error])
func apply_feedback_state(game: Control, state_name: String) -> void:
game.page = game.AppPage.BATTLE
game.battle_playing = false
game.front_choice = "Hearthguard"
game.rear_choice = "Farstring"
game.front_hp = 100
game.enemy_hp = 100
game.phase_impact_committed.clear()
match state_name:
"guard_damage":
game.battle_phase = 2
game.commit_phase_impact(2, false)
"evade_damage":
game.front_choice = "Wayrunner"
game.battle_phase = 2
game.commit_phase_impact(2, false)
"ranged_damage":
game.battle_phase = 3
game.commit_phase_impact(3, false)
"healing":
game.front_choice = "Wayrunner"
game.rear_choice = "Kindhand"
game.front_hp = 88
game.battle_phase = 3
game.commit_phase_impact(3, false)
"combo_damage":
game.enemy_hp = 64
game.battle_phase = 4
game.commit_phase_impact(4, false)
"final_damage":
game.enemy_hp = 34
game.battle_phase = 5
game.commit_phase_impact(5, false)
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 read_string(key: String, fallback: String) -> String:
var value := OS.get_environment(key)
return value if not value.is_empty() else fallback
func read_int(key: String, fallback: int) -> int:
var value := OS.get_environment(key)
return int(value) if not value.is_empty() else fallback
func read_float(key: String, fallback: float) -> float:
var value := OS.get_environment(key)
return float(value) if not value.is_empty() else fallback
func finish(exit_code: int) -> void:
quit(exit_code)
func settle(frames: int) -> void:
for frame in range(frames):
await process_frame