193 lines
8.3 KiB
GDScript
193 lines
8.3 KiB
GDScript
extends SceneTree
|
|
|
|
const WARRIOR_TEXTURE := "res://assets/art/characters/warrior_man_sheet.png"
|
|
const WARRIOR_WOMAN_TEXTURE := "res://assets/art/characters/warrior_woman_sheet.png"
|
|
const CHARGE_EFFECT_TEXTURE := "res://assets/art/effects/effect_hp_mp_sheet.png"
|
|
const EFFECT_TEXTURE := "res://assets/art/effects/effect_sheet.png"
|
|
const WARRIOR_COLUMNS := 16
|
|
const WARRIOR_ROWS := 25
|
|
|
|
var failures: Array[String] = []
|
|
|
|
|
|
func _init() -> void:
|
|
_run.call_deferred()
|
|
|
|
|
|
func _run() -> void:
|
|
var scene: PackedScene = load("res://scenes/characters/player.tscn")
|
|
if scene == null:
|
|
push_error("Could not load player.tscn")
|
|
quit(1)
|
|
return
|
|
|
|
var player: Node = scene.instantiate()
|
|
get_root().add_child(player)
|
|
await process_frame
|
|
var animation_player: AnimationPlayer = player.get_node("AnimationPlayer") as AnimationPlayer
|
|
|
|
_expect_action_has_key("combo_w", KEY_W)
|
|
_expect_action_has_key("combo_a", KEY_A)
|
|
_expect_action_has_key("combo_d", KEY_D)
|
|
_expect_action_has_key("combo_s", KEY_S)
|
|
_expect_action_has_key("combo_space", KEY_SPACE)
|
|
|
|
_expect_warrior_animation(animation_player, "warrior_idle", 1, 8)
|
|
_expect_warrior_animation(animation_player, "warrior_w", 6, 6)
|
|
_expect_warrior_animation(animation_player, "warrior_wa", 7, 5)
|
|
_expect_warrior_animation(animation_player, "warrior_s", 9, 3)
|
|
_expect_warrior_animation(animation_player, "warrior_a", 10, 7)
|
|
_expect_warrior_animation(animation_player, "warrior_aa", 11, 5)
|
|
_expect_warrior_animation(animation_player, "warrior_aaa", 12, 8)
|
|
_expect_warrior_animation(animation_player, "warrior_s_projectile", 14, 13)
|
|
_expect_warrior_animation(animation_player, "warrior_charge_intro", 13, 8, WARRIOR_WOMAN_TEXTURE)
|
|
_expect_warrior_animation(animation_player, "warrior_charge_loop", 13, 4, WARRIOR_WOMAN_TEXTURE, 4)
|
|
_expect_animation_loops(animation_player, "warrior_charge_loop")
|
|
_expect_warrior_animation(animation_player, "warrior_charge_release", 13, 8, WARRIOR_WOMAN_TEXTURE, 8)
|
|
_expect_warrior_animation(animation_player, "warrior_a_space_space", 15, 12)
|
|
_expect_warrior_animation(animation_player, "warrior_a_space", 17, 10)
|
|
_expect_charge_effect(player)
|
|
|
|
if animation_player.has_animation("player_punch"):
|
|
failures.append("Old player_punch animation should be removed")
|
|
if animation_player.has_animation("挥砍"):
|
|
failures.append("Old slash animation should be removed")
|
|
|
|
player.call("submit_combo_input", "W", "perfect")
|
|
_expect_string(str(player.get("last_requested_skill_id")), "skill_w", "W alone should request row 6 skill")
|
|
_expect_string(str(player.get("current_skill_animation")), "warrior_w", "W alone should play warrior_w")
|
|
player.call("submit_combo_input", "A", "perfect")
|
|
await create_timer(0.55).timeout
|
|
await physics_frame
|
|
_expect_string(str(player.get("last_requested_skill_id")), "skill_wa", "W+A should request row 7 skill")
|
|
_expect_string(str(player.get("current_skill_animation")), "warrior_wa", "W+A should play warrior_wa")
|
|
|
|
var projectile := PlayerProjectile.new()
|
|
get_root().add_child(projectile)
|
|
_expect_projectile_animation(projectile)
|
|
projectile.queue_free()
|
|
|
|
player.queue_free()
|
|
_finish()
|
|
|
|
|
|
func _expect_action_has_key(action_name: String, key: Key) -> void:
|
|
if not InputMap.has_action(action_name):
|
|
failures.append("Missing input action: %s" % action_name)
|
|
return
|
|
for event: InputEvent in InputMap.action_get_events(action_name):
|
|
var key_event := event as InputEventKey
|
|
if key_event != null and (key_event.keycode == key or key_event.physical_keycode == key):
|
|
return
|
|
failures.append("Input action %s should be bound to key %s" % [action_name, OS.get_keycode_string(key)])
|
|
|
|
|
|
func _expect_warrior_animation(animation_player: AnimationPlayer, animation_name: String, row: int, expected_frames: int, texture_path := WARRIOR_TEXTURE, start_column := 0) -> void:
|
|
if not animation_player.has_animation(animation_name):
|
|
failures.append("Missing animation: %s" % animation_name)
|
|
return
|
|
var animation: Animation = animation_player.get_animation(animation_name)
|
|
var hframes_found := false
|
|
var vframes_found := false
|
|
var texture_found := false
|
|
var frame_values: Array[int] = []
|
|
for track_index: int in range(animation.get_track_count()):
|
|
var track_path := animation.track_get_path(track_index)
|
|
if track_path == NodePath("CharacterSprite:texture"):
|
|
var texture: Texture2D = animation.track_get_key_value(track_index, 0)
|
|
texture_found = texture != null and texture.resource_path == texture_path
|
|
elif track_path == NodePath("CharacterSprite:hframes"):
|
|
hframes_found = true
|
|
var hframes: int = animation.track_get_key_value(track_index, 0)
|
|
if hframes != WARRIOR_COLUMNS:
|
|
failures.append("%s hframes expected %d, got %d" % [animation_name, WARRIOR_COLUMNS, hframes])
|
|
elif track_path == NodePath("CharacterSprite:vframes"):
|
|
vframes_found = true
|
|
var vframes: int = animation.track_get_key_value(track_index, 0)
|
|
if vframes != WARRIOR_ROWS:
|
|
failures.append("%s vframes expected %d, got %d" % [animation_name, WARRIOR_ROWS, vframes])
|
|
elif track_path == NodePath("CharacterSprite:frame"):
|
|
for key_index: int in range(animation.track_get_key_count(track_index)):
|
|
frame_values.append(animation.track_get_key_value(track_index, key_index))
|
|
if not texture_found:
|
|
failures.append("%s should use %s" % [animation_name, texture_path])
|
|
if not hframes_found:
|
|
failures.append("Missing hframes track: %s" % animation_name)
|
|
if not vframes_found:
|
|
failures.append("Missing vframes track: %s" % animation_name)
|
|
if frame_values.size() != expected_frames:
|
|
failures.append("%s should key %d frames, got %d" % [animation_name, expected_frames, frame_values.size()])
|
|
var first_frame := (row - 1) * WARRIOR_COLUMNS + start_column
|
|
for index: int in range(frame_values.size()):
|
|
var expected := first_frame + index
|
|
if frame_values[index] != expected:
|
|
failures.append("%s frame %d expected sheet frame %d, got %d" % [
|
|
animation_name,
|
|
index,
|
|
expected,
|
|
frame_values[index],
|
|
])
|
|
|
|
|
|
func _expect_string(actual: String, expected: String, label: String) -> void:
|
|
if actual != expected:
|
|
failures.append("%s: expected %s, got %s" % [label, expected, actual])
|
|
|
|
|
|
func _expect_animation_loops(animation_player: AnimationPlayer, animation_name: String) -> void:
|
|
if not animation_player.has_animation(animation_name):
|
|
failures.append("Missing animation for loop check: %s" % animation_name)
|
|
return
|
|
var animation: Animation = animation_player.get_animation(animation_name)
|
|
if int(animation.loop_mode) != 1:
|
|
failures.append("%s should loop, got loop_mode %d" % [animation_name, int(animation.loop_mode)])
|
|
|
|
|
|
func _expect_projectile_animation(projectile: Node) -> void:
|
|
if projectile.get_child_count() == 0:
|
|
failures.append("Projectile should create a Sprite2D child")
|
|
return
|
|
var sprite := projectile.get_child(0) as Sprite2D
|
|
if sprite == null:
|
|
failures.append("Projectile child should be Sprite2D")
|
|
return
|
|
if sprite.texture == null or sprite.texture.resource_path != EFFECT_TEXTURE:
|
|
failures.append("Projectile should use %s" % EFFECT_TEXTURE)
|
|
if sprite.hframes != 6:
|
|
failures.append("Projectile hframes expected 6, got %d" % sprite.hframes)
|
|
if sprite.vframes != 2:
|
|
failures.append("Projectile vframes expected 2, got %d" % sprite.vframes)
|
|
projectile.call("_process", 0.0)
|
|
if sprite.frame != 0:
|
|
failures.append("Projectile first frame expected 0, got %d" % sprite.frame)
|
|
projectile.call("_process", 0.18)
|
|
if sprite.frame != 3:
|
|
failures.append("Projectile should use first row frame 3 after 0.18s, got %d" % sprite.frame)
|
|
|
|
|
|
func _expect_charge_effect(player: Node) -> void:
|
|
var sprite := player.get_node_or_null("ChargeEffectSprite") as Sprite2D
|
|
if sprite == null:
|
|
failures.append("Player should include ChargeEffectSprite")
|
|
return
|
|
if sprite.texture == null or sprite.texture.resource_path != CHARGE_EFFECT_TEXTURE:
|
|
failures.append("Charge effect should use %s" % CHARGE_EFFECT_TEXTURE)
|
|
if sprite.hframes != 5:
|
|
failures.append("Charge effect hframes expected 5, got %d" % sprite.hframes)
|
|
if sprite.vframes != 2:
|
|
failures.append("Charge effect vframes expected 2, got %d" % sprite.vframes)
|
|
if sprite.z_index < 1:
|
|
failures.append("Charge effect should draw above the player feet, got z_index %d" % sprite.z_index)
|
|
if sprite.visible:
|
|
failures.append("Charge effect should start hidden")
|
|
|
|
|
|
func _finish() -> void:
|
|
if failures.is_empty():
|
|
print("PASS player warrior actions")
|
|
quit(0)
|
|
else:
|
|
for failure: String in failures:
|
|
push_error(failure)
|
|
quit(1)
|