Refactor rhythm action architecture
This commit is contained in:
@@ -1,541 +1,169 @@
|
||||
extends SceneTree
|
||||
|
||||
const InputIntentScript := preload("res://scenes/components/input_intent.gd")
|
||||
|
||||
var failures: Array[String] = []
|
||||
var requested_skills: Array[String] = []
|
||||
var projectile_requests: Array[Dictionary] = []
|
||||
var judged_labels: 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)
|
||||
var animation_player: AnimationPlayer = player.get_node("AnimationPlayer") as AnimationPlayer
|
||||
var supports_energy := player.has_method("get_energy") and player.has_method("get_max_energy")
|
||||
var supports_charge := player.has_method("get_charge") and player.has_method("get_max_charge") and player.has_method("is_charge_active") and player.has_method("is_charge_ready")
|
||||
if player.has_signal("skill_requested"):
|
||||
player.connect("skill_requested", _on_skill_requested)
|
||||
else:
|
||||
failures.append("Player missing skill_requested signal")
|
||||
if not player.has_signal("charge_changed"):
|
||||
failures.append("Player should expose charge_changed signal")
|
||||
if supports_charge:
|
||||
_expect_zero(player.call("get_charge"), "charge should start empty")
|
||||
_expect_bool(player.call("is_charge_ready"), false, "charge should not start ready")
|
||||
else:
|
||||
failures.append("Player should expose charge getters")
|
||||
if not player.has_signal("energy_changed"):
|
||||
failures.append("Player should expose energy_changed signal")
|
||||
if not player.has_signal("health_changed"):
|
||||
failures.append("Player should expose health_changed signal")
|
||||
if supports_energy:
|
||||
_expect_int(player.call("get_max_energy"), 10, "energy bar should have ten segments")
|
||||
_expect_int(player.call("get_energy"), 0, "energy should start empty")
|
||||
else:
|
||||
failures.append("Player should expose get_energy and get_max_energy")
|
||||
if player.has_method("get_health") and player.has_method("get_max_health"):
|
||||
_expect_int(player.call("get_health"), player.call("get_max_health"), "health should start full")
|
||||
else:
|
||||
failures.append("Player should expose get_health and get_max_health")
|
||||
|
||||
_expect_action("player_w", KEY_W)
|
||||
_expect_action("player_a", KEY_A)
|
||||
_expect_action("player_d", KEY_D)
|
||||
_expect_action("player_s", KEY_S)
|
||||
_expect_action("player_space", KEY_SPACE)
|
||||
|
||||
var w_event := InputEventKey.new()
|
||||
w_event.pressed = true
|
||||
w_event.physical_keycode = KEY_W
|
||||
player.call("_input", w_event)
|
||||
w_event.echo = true
|
||||
player.call("_input", w_event)
|
||||
_expect_array(player.call("get_combo_slots"), ["W"], "W key press should enter once and ignore echo repeat")
|
||||
_expect_last_skill("skill_w", "W alone should request row 6 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_w", "W should play row 6 animation")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
|
||||
var a_event := InputEventKey.new()
|
||||
a_event.pressed = true
|
||||
a_event.physical_keycode = KEY_A
|
||||
var a_release_event := InputEventKey.new()
|
||||
a_release_event.pressed = false
|
||||
a_release_event.physical_keycode = KEY_A
|
||||
player.call("_input", a_event)
|
||||
_expect_array(player.call("get_combo_slots"), ["A"], "A alone should stay visible in the combo window")
|
||||
_expect_last_skill("skill_a", "A should request row 10 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a", "A should play row 10 animation")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "A should lunge left")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
root.add_child(player)
|
||||
await process_frame
|
||||
|
||||
if supports_charge:
|
||||
player.call("_input", a_event)
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("attack_time_left", 0.0)
|
||||
player.call("_process", 0.2)
|
||||
_expect_bool(player.call("is_charge_active"), true, "holding A after its animation should enter charge state")
|
||||
_expect_string(animation_player.current_animation, "warrior_charge_intro", "holding A charge should start with charge intro animation")
|
||||
_expect_positive(player.call("get_charge"), "holding A should grow charge")
|
||||
var charge_effect := player.get_node_or_null("ChargeEffectSprite") as Sprite2D
|
||||
if charge_effect == null:
|
||||
failures.append("ChargeEffectSprite missing during A charge test")
|
||||
else:
|
||||
_expect_bool(charge_effect.visible, true, "holding A should show charge effect")
|
||||
requested_skills.clear()
|
||||
player.call("_input", a_release_event)
|
||||
_expect_bool(player.call("is_charge_active"), false, "early A release should cancel charge")
|
||||
_expect_bool(player.call("is_charge_ready"), false, "early A release should not be ready")
|
||||
_expect_no_skill_requested("early A release should not request charge release skill")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
for node_name: String in ["InputComponent", "ComboWindow", "ActionResolver", "ActionExecutor", "MotionExecutor", "BurstComponent", "ChargeComponent", "EnergyComponent", "HealthComponent", "DamageReceiver", "DamageEmitter"]:
|
||||
if not player.has_node(node_name):
|
||||
failures.append("Player missing component %s" % node_name)
|
||||
for signal_name: String in ["skill_requested", "energy_changed", "health_changed", "charge_changed", "projectile_requested"]:
|
||||
if not player.has_signal(signal_name):
|
||||
failures.append("Player missing signal %s" % signal_name)
|
||||
|
||||
player.call("_input", a_event)
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("attack_time_left", 0.0)
|
||||
player.call("_process", player.call("get_max_charge") + 0.1)
|
||||
_expect_bool(player.call("is_charge_ready"), true, "held A should become ready when charge is full")
|
||||
_expect_string(animation_player.current_animation, "warrior_charge_loop", "full A hold should keep charge loop animation")
|
||||
requested_skills.clear()
|
||||
player.call("_input", a_release_event)
|
||||
_expect_last_skill("skill_a_charge_release", "full A release should request charge release skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_charge_release", "full A release should play row 13 animation")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "full A release should lunge left")
|
||||
_expect_bool(player.call("is_charge_active"), false, "full A release should leave charge state")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
player.connect("skill_requested", _on_skill_requested)
|
||||
player.connect("projectile_requested", _on_projectile_requested)
|
||||
_event_bus().connect("action_judged", _on_action_judged)
|
||||
|
||||
player.call("_input", a_event)
|
||||
player.call("_input", a_event)
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "A"], "two separate A presses should both enter the combo window")
|
||||
_expect_last_skill("skill_aa", "A+A should request row 11 skill")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
_expect_action("move_left", KEY_A)
|
||||
_expect_action("move_right", KEY_D)
|
||||
_expect_action("combo_w", KEY_W)
|
||||
_expect_action("combo_a", KEY_A)
|
||||
_expect_action("combo_d", KEY_D)
|
||||
_expect_action("combo_s", KEY_S)
|
||||
_expect_action("combo_space", KEY_SPACE)
|
||||
_expect_bool(InputMap.has_action("player_space"), false, "player_space should be removed")
|
||||
|
||||
player.call("_input", a_event)
|
||||
Input.action_press("player_a")
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("velocity", Vector2.ZERO)
|
||||
player.call("handle_input")
|
||||
Input.action_release("player_a")
|
||||
_expect_array(player.call("get_combo_slots"), ["A"], "one A key event should not be recorded again by physics polling")
|
||||
_expect_last_skill("skill_a", "single A key event should still be the last requested skill after physics polling")
|
||||
_expect_zero((player as CharacterBody2D).velocity.x, "holding consumed A key should not keep sliding after combo input")
|
||||
var a_release_after_single_hold := InputEventKey.new()
|
||||
a_release_after_single_hold.pressed = false
|
||||
a_release_after_single_hold.physical_keycode = KEY_A
|
||||
player.call("_input", a_release_after_single_hold)
|
||||
player.call("flush_pending_combo_clear")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
|
||||
var d_event := InputEventKey.new()
|
||||
d_event.pressed = true
|
||||
d_event.physical_keycode = KEY_D
|
||||
player.call("_input", d_event)
|
||||
_expect_array(player.call("get_combo_slots"), ["D"], "D key press should enter the combo window")
|
||||
_expect_last_skill("skill_d", "D should request mirrored row 10 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a", "D should reuse row 10 animation")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "D should lunge right")
|
||||
player.call("flush_pending_combo_clear")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
_expect_int(player.call("get_max_energy"), 10, "energy bar should have ten segments")
|
||||
_expect_int(player.call("get_energy"), 0, "energy should start empty")
|
||||
_expect_int(player.call("get_health"), player.call("get_max_health"), "health should start full")
|
||||
|
||||
if supports_charge:
|
||||
player.call("_input", d_event)
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("attack_time_left", 0.0)
|
||||
player.call("_process", player.call("get_max_charge") + 0.1)
|
||||
_expect_string(animation_player.current_animation, "warrior_charge_loop", "full D hold should keep charge loop animation")
|
||||
var d_release_event := InputEventKey.new()
|
||||
d_release_event.pressed = false
|
||||
d_release_event.physical_keycode = KEY_D
|
||||
requested_skills.clear()
|
||||
player.call("_input", d_release_event)
|
||||
_expect_last_skill("skill_d_charge_release", "full D release should request charge release skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_charge_release", "full D release should reuse row 13 animation")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "full D release should lunge right")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
|
||||
player.call("_input", d_event)
|
||||
player.call("_input", d_release_event)
|
||||
player.call("_input", d_event)
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("attack_time_left", 0.0)
|
||||
player.call("_process", 0.2)
|
||||
_expect_array(player.call("get_combo_slots"), ["D", "D"], "second held D should keep D+D in the combo window")
|
||||
_expect_last_skill("skill_dd", "second held D should trigger D+D skill before charging")
|
||||
_expect_bool(player.call("is_charge_active"), true, "holding second D after D+D animation should enter charge state")
|
||||
_expect_string(animation_player.current_animation, "warrior_charge_intro", "holding second D should start with charge intro animation")
|
||||
_expect_positive(player.call("get_charge"), "holding second D should grow charge after D+D")
|
||||
requested_skills.clear()
|
||||
player.call("_input", d_release_event)
|
||||
_expect_bool(player.call("is_charge_active"), false, "releasing held second D should cancel D+D charge")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
|
||||
player.call("_input", a_event)
|
||||
player.call("_input", a_release_event)
|
||||
player.call("_input", a_event)
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("attack_time_left", 0.0)
|
||||
player.call("_process", 0.2)
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "A"], "second held A should keep A+A in the combo window")
|
||||
_expect_last_skill("skill_aa", "second held A should trigger A+A skill before charging")
|
||||
_expect_bool(player.call("is_charge_active"), true, "holding second A after A+A animation should enter charge state")
|
||||
_expect_string(animation_player.current_animation, "warrior_charge_intro", "holding second A should start with charge intro animation")
|
||||
_expect_positive(player.call("get_charge"), "holding second A should grow charge after A+A")
|
||||
requested_skills.clear()
|
||||
player.call("_input", a_release_event)
|
||||
_expect_bool(player.call("is_charge_active"), false, "releasing held second A should cancel A+A charge")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
|
||||
player.call("_input", d_event)
|
||||
player.call("_input", d_event)
|
||||
Input.action_press("player_d")
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("velocity", Vector2.ZERO)
|
||||
player.call("handle_input")
|
||||
Input.action_release("player_d")
|
||||
_expect_array(player.call("get_combo_slots"), ["D", "D"], "held second D should still record D+D once")
|
||||
_expect_last_skill("skill_dd", "held second D should request D+D skill")
|
||||
_expect_zero((player as CharacterBody2D).velocity.x, "holding consumed second D should not slide in idle")
|
||||
var d_release_after_hold := InputEventKey.new()
|
||||
d_release_after_hold.pressed = false
|
||||
d_release_after_hold.physical_keycode = KEY_D
|
||||
player.call("_input", d_release_after_hold)
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
|
||||
player.call("_input", a_event)
|
||||
player.call("_input", a_event)
|
||||
Input.action_press("player_a")
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("velocity", Vector2.ZERO)
|
||||
player.call("handle_input")
|
||||
Input.action_release("player_a")
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "A"], "held second A should still record A+A once")
|
||||
_expect_last_skill("skill_aa", "held second A should request A+A skill")
|
||||
_expect_zero((player as CharacterBody2D).velocity.x, "holding consumed second A should not slide in idle")
|
||||
var a_release_after_hold := InputEventKey.new()
|
||||
a_release_after_hold.pressed = false
|
||||
a_release_after_hold.physical_keycode = KEY_A
|
||||
player.call("_input", a_release_after_hold)
|
||||
player.get("combo_window").clear("test-reset")
|
||||
requested_skills.clear()
|
||||
|
||||
Input.action_press("player_a")
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("velocity", Vector2.ZERO)
|
||||
player.call("handle_input")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "A should move the player left")
|
||||
_expect_vector(player.get("heading"), Vector2.LEFT, "A should face left")
|
||||
_expect_array(player.call("get_combo_slots"), [], "physics-only movement polling should not write combo slots")
|
||||
Input.action_release("player_a")
|
||||
player.call("flush_pending_combo_clear")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
Input.action_press("player_d")
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("velocity", Vector2.ZERO)
|
||||
player.call("handle_input")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "D should move the player right")
|
||||
_expect_vector(player.get("heading"), Vector2.RIGHT, "D should face right")
|
||||
Input.action_release("player_d")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
var unhandled_s_event := InputEventKey.new()
|
||||
unhandled_s_event.pressed = true
|
||||
unhandled_s_event.physical_keycode = KEY_S
|
||||
player.call("_unhandled_input", unhandled_s_event)
|
||||
_expect_array(player.call("get_combo_slots"), ["S"], "unhandled S should enter S")
|
||||
_expect_no_skill_requested("S alone should not request a skill")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "S", "miss")
|
||||
_expect_array(player.call("get_combo_slots"), ["Ø"], "miss should display Ø in the combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
if supports_energy:
|
||||
player.set("current_energy", 0)
|
||||
player.call("submit_combo_input", "W", "perfect")
|
||||
_expect_int(player.call("get_energy"), 0, "W should not add energy")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "A", "good")
|
||||
_expect_int(player.call("get_energy"), 1, "A skill should add one energy segment")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "D", "bad")
|
||||
_expect_int(player.call("get_energy"), 2, "D skill should add one energy segment")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "S", "miss")
|
||||
_expect_int(player.call("get_energy"), 2, "miss input should not add energy")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "A", "perfect")
|
||||
player.call("submit_combo_input", "A", "perfect")
|
||||
_expect_int(player.call("get_energy"), 4, "A+A skill should add one energy segment")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "D", "perfect")
|
||||
player.call("submit_combo_input", "D", "perfect")
|
||||
player.call("submit_combo_input", "D", "perfect")
|
||||
_expect_int(player.call("get_energy"), 7, "D, D+D, and D+D+D skills should each add one energy segment")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "A", "miss")
|
||||
_expect_int(player.call("get_energy"), 7, "missed A should not add energy")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "SP", "perfect")
|
||||
_expect_int(player.call("get_energy"), 7, "Space should not add energy")
|
||||
player.call("flush_pending_combo_clear")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.set("current_energy", 9)
|
||||
player.call("submit_combo_input", "W", "perfect")
|
||||
_expect_int(player.call("get_energy"), 9, "W should not change energy near cap")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "A", "perfect")
|
||||
_expect_int(player.call("get_energy"), 10, "A energy reward should cap at ten segments")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
requested_skills.clear()
|
||||
player.call("_play_skill_animation", "warrior_a", Vector2.LEFT)
|
||||
player.call("submit_combo_input", "A", "miss")
|
||||
_expect_array(player.call("get_combo_slots"), ["Ø"], "missed A should display Ø in the combo window")
|
||||
_expect_no_skill_requested("missed A should not request a skill")
|
||||
_expect_zero((player as CharacterBody2D).velocity.x, "missed A should stop horizontal lunge")
|
||||
_expect_int(int(player.get("state")), Character.State.IDLE, "missed A should return to idle state")
|
||||
_expect_string(animation_player.current_animation, "warrior_idle", "missed A should keep idle animation")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
requested_skills.clear()
|
||||
player.call("_play_skill_animation", "warrior_a", Vector2.RIGHT)
|
||||
player.call("submit_combo_input", "D", "miss")
|
||||
_expect_array(player.call("get_combo_slots"), ["Ø"], "missed D should display Ø in the combo window")
|
||||
_expect_no_skill_requested("missed D should not request a skill")
|
||||
_expect_zero((player as CharacterBody2D).velocity.x, "missed D should stop horizontal lunge")
|
||||
_expect_int(int(player.get("state")), Character.State.IDLE, "missed D should return to idle state")
|
||||
_expect_string(animation_player.current_animation, "warrior_idle", "missed D should keep idle animation")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "W", "perfect")
|
||||
_expect_last_judgement("perfect", "W should display Perfect judgement")
|
||||
_expect_array(player.call("get_combo_slots"), [&"W"], "W should enter the combo window")
|
||||
_expect_last_skill("skill_w", "W should request skill_w")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_w", "W should play warrior_w")
|
||||
_expect_int(player.call("get_energy"), 0, "W should not add energy")
|
||||
player.get_node("ComboWindow").clear(&"test-reset")
|
||||
requested_skills.clear()
|
||||
await _wait_for_action_settle()
|
||||
|
||||
player.call("submit_combo_input", "A", "good")
|
||||
_expect_array(player.call("get_combo_slots"), ["W", "A"], "W+A should stay visible after skill trigger")
|
||||
_expect_last_skill("skill_wa", "W+A should request row 7 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_wa", "W+A should play row 7 animation")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "W+A should lunge left")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), ["W", "A"], "W+A should not clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
_expect_last_judgement("good", "A should display Good judgement")
|
||||
player.get_node("ChargeComponent").finish_hold(&"A")
|
||||
_expect_last_skill("skill_a", "A should request skill_a")
|
||||
_expect_int(player.call("get_energy"), 0, "A should not reward during startup")
|
||||
await _wait_for_active_phase()
|
||||
_expect_int(player.call("get_energy"), 1, "A should reward one energy")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "A should lunge left")
|
||||
player.get_node("ComboWindow").clear(&"test-reset")
|
||||
await _wait_for_action_settle()
|
||||
|
||||
player.call("submit_combo_input", "W", "perfect")
|
||||
player.call("submit_combo_input", "D", "good")
|
||||
_expect_array(player.call("get_combo_slots"), ["W", "D"], "W+D should stay visible after skill trigger")
|
||||
_expect_last_skill("skill_wd", "W+D should request mirrored row 7 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_wa", "W+D should reuse row 7 animation")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "W+D should lunge right")
|
||||
_expect_vector(player.get("heading"), Vector2.RIGHT, "W+D should face right")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), ["W", "D"], "W+D should not clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "A")
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "A", "A"], "A+A+A should stay visible after skill trigger")
|
||||
_expect_last_skill("skill_aaa", "A+A+A should request row 12 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_aaa", "A+A+A should play row 12 animation")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "A+A+A should lunge left")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "A", "A"], "A+A+A should not clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "A")
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "A", "A", "A"], "fourth A should still fill the old four-slot window before clear")
|
||||
_expect_last_skill("skill_a", "fourth A after A+A+A should play normal A animation")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a", "fourth A should fall back to row 10 animation")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "fourth A should lunge left as a normal A")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "fourth A full window should clear after display")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "D")
|
||||
_expect_array(player.call("get_combo_slots"), ["D", "D", "D"], "D+D+D should stay visible after skill trigger")
|
||||
_expect_last_skill("skill_ddd", "D+D+D should request mirrored row 12 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_aaa", "D+D+D should reuse row 12 animation")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "D+D+D should lunge right")
|
||||
_expect_vector(player.get("heading"), Vector2.RIGHT, "D+D+D should face right")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), ["D", "D", "D"], "D+D+D should not clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "D")
|
||||
_expect_array(player.call("get_combo_slots"), ["D", "D", "D", "D"], "fourth D should still fill the old four-slot window before clear")
|
||||
_expect_last_skill("skill_d", "fourth D after D+D+D should play normal D animation")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a", "fourth D should fall back to row 10 animation")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "fourth D should lunge right as a normal D")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "fourth D full window should clear after display")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "SP")
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "SP"], "A+Space should be visible before skill clear")
|
||||
_expect_last_skill("skill_a_space", "A+Space should request row 17 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a_space", "A+Space should play row 17 animation")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "A+Space should lunge left")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "A+Space should clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "SP")
|
||||
_expect_array(player.call("get_combo_slots"), ["D", "SP"], "D+Space should be visible before skill clear")
|
||||
_expect_last_skill("skill_d_space", "D+Space should request mirrored row 17 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a_space", "D+Space should reuse row 17 animation")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "D+Space should lunge right")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "D+Space should clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "SP")
|
||||
player.call("submit_combo_input", "SP")
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "SP", "SP"], "A+Space+Space should cancel the pending A+Space clear and stay visible before its own clear")
|
||||
_expect_last_skill("skill_a_space_space", "A+Space+Space should request row 15 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a_space_space", "A+Space+Space should play row 15 animation")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "A+Space+Space should lunge left")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "A+Space+Space should clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "SP")
|
||||
player.call("submit_combo_input", "SP")
|
||||
_expect_array(player.call("get_combo_slots"), ["D", "SP", "SP"], "D+Space+Space should cancel the pending D+Space clear and stay visible before its own clear")
|
||||
_expect_last_skill("skill_d_space_space", "D+Space+Space should request mirrored row 15 skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a_space_space", "D+Space+Space should reuse row 15 animation")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "D+Space+Space should lunge right")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "D+Space+Space should clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "A")
|
||||
player.call("submit_combo_input", "SP")
|
||||
_expect_array(player.call("get_combo_slots"), ["A", "A", "SP"], "A+A+Space should be visible before skill clear")
|
||||
_expect_last_skill("skill_aa_space", "A+A+Space should request clear skill")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "A+A+Space should clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "D")
|
||||
player.call("submit_combo_input", "SP")
|
||||
_expect_array(player.call("get_combo_slots"), ["D", "D", "SP"], "D+D+Space should be visible before skill clear")
|
||||
_expect_last_skill("skill_dd_space", "D+D+Space should request clear skill")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "D+D+Space should clear combo window")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "D", "bad")
|
||||
_expect_last_judgement("bad", "D should display Bad judgement")
|
||||
player.get_node("ChargeComponent").finish_hold(&"D")
|
||||
_expect_last_skill("skill_d", "D should request skill_d")
|
||||
await _wait_for_active_phase()
|
||||
_expect_int(player.call("get_energy"), 2, "D should reward one energy")
|
||||
_expect_positive((player as CharacterBody2D).velocity.x, "D should lunge right")
|
||||
player.get_node("ComboWindow").clear(&"test-reset")
|
||||
requested_skills.clear()
|
||||
|
||||
player.call("submit_combo_input", "SP")
|
||||
_expect_array(player.call("get_combo_slots"), ["SP"], "Space should be visible before space clear")
|
||||
_expect_no_skill_requested("Space alone should not request a skill")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "Space should clear combo window")
|
||||
await _wait_for_action_settle()
|
||||
|
||||
_reset_player_action_state(player)
|
||||
_press_release_symbol(player, &"D")
|
||||
await _wait_for_cancel_consumption()
|
||||
_press_release_symbol(player, &"D")
|
||||
await _wait_for_cancel_consumption()
|
||||
player.call("_on_input_intent_created", _perfect_intent(&"D", &"pressed"))
|
||||
_expect_last_skill("skill_ddd", "D+D+D should request the third D skill")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_aaa", "D+D+D should start warrior_aaa")
|
||||
player.call("_on_input_intent_created", _perfect_intent(&"D", &"released"))
|
||||
await _wait_for_cancel_consumption()
|
||||
_expect_array(player.call("get_combo_slots"), [&"D", &"D", &"D"], "D+D+D should keep the three input slots")
|
||||
_expect_int(int(player.get("state")), Character.State.IDLE, "D+D+D should return player presentation to idle when the action ends")
|
||||
_expect_string(_current_animation(player), "warrior_idle", "D+D+D should not leave warrior_aaa stuck after the action ends")
|
||||
player.call("_on_input_intent_created", _perfect_intent(&"D", &"pressed"))
|
||||
_expect_array(player.call("get_combo_slots"), [&"D", &"D", &"D", &"D"], "Fourth D should fill the four-slot window before clear")
|
||||
_expect_last_skill("skill_d", "Fourth D after D+D+D should fall back to normal D")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a", "Fourth D should play normal D animation")
|
||||
_expect_string(str(player.get("heading")), str(Vector2.RIGHT), "Fourth D should face right")
|
||||
player.call("_on_input_intent_created", _perfect_intent(&"D", &"released"))
|
||||
await create_timer(0.4).timeout
|
||||
await process_frame
|
||||
_expect_array(player.call("get_combo_slots"), [], "Fourth D full window should clear after display")
|
||||
|
||||
_reset_player_action_state(player)
|
||||
player.call("_on_input_intent_created", _perfect_intent(&"A", &"pressed"))
|
||||
player.call("_on_input_intent_created", _perfect_intent(&"A", &"released"))
|
||||
player.call("_on_input_intent_created", _perfect_intent(&"D", &"pressed"))
|
||||
_expect_array(player.call("get_combo_slots"), [&"A"], "A then immediate D should keep D outside the window during A startup")
|
||||
_expect_string(str(player.get("heading")), str(Vector2.LEFT), "Pending D should not change heading before it is consumed")
|
||||
player.call("_on_input_intent_created", _perfect_intent(&"D", &"released"))
|
||||
await _wait_for_cancel_consumption()
|
||||
_expect_array(player.call("get_combo_slots"), [&"A", &"D"], "A then D should enter the window only when the phase allows it")
|
||||
_expect_last_skill("skill_d", "A then D unresolved prefix should fall back to normal D")
|
||||
_expect_string(str(player.get("current_skill_animation")), "warrior_a", "A then D fallback should play normal D animation")
|
||||
_expect_string(str(player.get("heading")), str(Vector2.RIGHT), "A then D fallback should face right")
|
||||
await _wait_for_action_settle()
|
||||
_expect_int(int(player.get("state")), Character.State.IDLE, "A then D fallback should settle back to idle")
|
||||
_expect_string(_current_animation(player), "warrior_idle", "A then D fallback should not leave the previous presentation stuck")
|
||||
_reset_player_action_state(player)
|
||||
player.get_node("EnergyComponent").set_current(2)
|
||||
|
||||
player.call("submit_combo_input", "S", "miss")
|
||||
_expect_last_judgement("miss", "S should display Miss judgement")
|
||||
_expect_array(player.call("get_combo_slots"), [&"Ø"], "miss should enter the combo window as an explicit placeholder")
|
||||
_expect_no_skill_requested("miss should not request a skill")
|
||||
_expect_int(player.call("get_energy"), 2, "miss should not change energy")
|
||||
await create_timer(0.4).timeout
|
||||
await process_frame
|
||||
_expect_array(player.call("get_combo_slots"), [&"Ø"], "miss should not clear the combo window by itself")
|
||||
player.get_node("ComboWindow").clear(&"test-reset")
|
||||
await _wait_for_action_settle()
|
||||
|
||||
player.call("submit_combo_input", "A", "perfect")
|
||||
player.get_node("ChargeComponent").finish_hold(&"A")
|
||||
player.call("submit_combo_input", "SP", "perfect")
|
||||
_expect_array(player.call("get_combo_slots"), [&"A"], "A+Space should wait for cancel window before adding Space")
|
||||
await _wait_for_cancel_consumption()
|
||||
_expect_last_skill("skill_a_space", "A+Space should request clear-window skill")
|
||||
_expect_array(player.call("get_combo_slots"), [&"A", &"SP"], "A+Space should stay visible before clear")
|
||||
await _wait_for_action_settle()
|
||||
_expect_array(player.call("get_combo_slots"), [], "A+Space should clear when the action finishes")
|
||||
player.get_node("ComboWindow").clear(&"test-reset")
|
||||
await _wait_for_action_settle()
|
||||
|
||||
player.get_node("EnergyComponent").set_current(3)
|
||||
projectile_requests.clear()
|
||||
requested_skills.clear()
|
||||
var space_event := InputEventKey.new()
|
||||
space_event.pressed = true
|
||||
space_event.physical_keycode = KEY_SPACE
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("current_skill_animation", "")
|
||||
animation_player.play("warrior_idle")
|
||||
player.call("_input", space_event)
|
||||
Input.action_press("player_space")
|
||||
Input.action_press("jump")
|
||||
player.call("handle_input")
|
||||
Input.action_release("jump")
|
||||
Input.action_release("player_space")
|
||||
_expect_int(int(player.get("state")), Character.State.IDLE, "direct Space should keep idle state")
|
||||
_expect_string(animation_player.current_animation, "warrior_idle", "direct Space should keep idle animation")
|
||||
_expect_no_skill_requested("direct Space key should not request a skill")
|
||||
player.call("flush_pending_combo_clear")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
if supports_energy:
|
||||
player.set("current_energy", 3)
|
||||
player.call("submit_combo_input", "S", "perfect")
|
||||
player.call("submit_combo_input", "SP", "perfect")
|
||||
_expect_array(player.call("get_combo_slots"), [&"S"], "S+Space should wait for cancel window before adding Space")
|
||||
await _wait_for_cancel_consumption()
|
||||
_expect_last_skill("skill_s_projectile_1", "S+Space should request projectile skill")
|
||||
_expect_projectile_count(1, "S+Space should fire one projectile")
|
||||
if supports_energy:
|
||||
_expect_int(player.call("get_energy"), 0, "S+Space should spend three energy without input rewards")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), ["S", "SP"], "S+Space should not clear combo window")
|
||||
if supports_energy:
|
||||
player.set("current_energy", 2)
|
||||
player.call("submit_combo_input", "SP", "perfect")
|
||||
_expect_last_skill("skill_s_projectile_2", "S+Space+Space should request projectile skill")
|
||||
_expect_projectile_count(2, "Second Space should fire another projectile")
|
||||
if supports_energy:
|
||||
_expect_int(player.call("get_energy"), 0, "S+Space+Space should spend two energy without Space reward")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), ["S", "SP", "SP"], "S+Space+Space should not clear combo window")
|
||||
if supports_energy:
|
||||
player.set("current_energy", 1)
|
||||
player.call("submit_combo_input", "SP", "perfect")
|
||||
_expect_last_skill("skill_s_projectile_3", "S+Space+Space+Space should request projectile skill")
|
||||
_expect_projectile_count(3, "Third Space should fire another projectile")
|
||||
if supports_energy:
|
||||
_expect_int(player.call("get_energy"), 0, "S+Space+Space+Space should spend one energy without Space reward")
|
||||
_expect_array(player.call("get_combo_slots"), ["S", "SP", "SP", "SP"], "projectile chain should fill four slots before clear")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "projectile chain should clear combo window because four slots are full")
|
||||
await _wait_for_active_phase()
|
||||
_expect_int(player.call("get_energy"), 0, "S+Space should spend three energy")
|
||||
_expect_int(projectile_requests.size(), 1, "S+Space should emit one projectile request")
|
||||
await _wait_for_action_settle()
|
||||
|
||||
if supports_energy:
|
||||
requested_skills.clear()
|
||||
player.set("current_energy", 0)
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "S", "bad")
|
||||
player.call("submit_combo_input", "SP", "bad")
|
||||
_expect_no_skill_requested("S+Space should not execute when energy is insufficient")
|
||||
_expect_projectile_count(3, "insufficient energy should not fire another projectile")
|
||||
_expect_int(player.call("get_energy"), 0, "insufficient projectile attempt should leave energy at zero")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.get_node("ChargeComponent").cancel()
|
||||
Input.action_press(&"move_left")
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("velocity", Vector2.ZERO)
|
||||
player.call("handle_input")
|
||||
Input.action_release(&"move_left")
|
||||
_expect_negative((player as CharacterBody2D).velocity.x, "move_left should move the player left")
|
||||
|
||||
requested_skills.clear()
|
||||
if supports_energy:
|
||||
player.set("current_energy", 10)
|
||||
player.get("combo_window").clear("test-reset")
|
||||
player.call("submit_combo_input", "S", "perfect")
|
||||
player.call("submit_combo_input", "A", "miss")
|
||||
player.call("submit_combo_input", "SP", "perfect")
|
||||
_expect_array(player.call("get_combo_slots"), ["S", "Ø", "SP"], "miss should remain visible between S and Space")
|
||||
_expect_no_skill_requested("S miss Space should not execute projectile skill")
|
||||
_expect_projectile_count(3, "S miss Space should not fire another projectile")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "S miss Space should clear as a normal Space input")
|
||||
player.get("combo_window").clear("test-reset")
|
||||
|
||||
player.call("submit_combo_input", "W")
|
||||
player.call("submit_combo_input", "W")
|
||||
player.call("submit_combo_input", "W")
|
||||
player.call("submit_combo_input", "W")
|
||||
_expect_array(player.call("get_combo_slots"), ["W", "W", "W", "W"], "four non-skill inputs should be visible before clear")
|
||||
player.call("flush_pending_combo_clear")
|
||||
_expect_array(player.call("get_combo_slots"), [], "four non-skill inputs should clear combo window")
|
||||
|
||||
player.queue_free()
|
||||
_finish()
|
||||
|
||||
@@ -565,6 +193,20 @@ func _expect_no_skill_requested(label: String) -> void:
|
||||
failures.append("%s: expected no skill, got %s" % [label, requested_skills[requested_skills.size() - 1]])
|
||||
|
||||
|
||||
func _expect_last_judgement(expected: String, label: String) -> void:
|
||||
if judged_labels.is_empty():
|
||||
failures.append("%s: no judgement displayed" % label)
|
||||
return
|
||||
var actual := judged_labels[judged_labels.size() - 1]
|
||||
if actual != expected:
|
||||
failures.append("%s: expected %s, got %s" % [label, expected, actual])
|
||||
|
||||
|
||||
func _expect_array(actual: Array, expected: Array, label: String) -> void:
|
||||
if actual != expected:
|
||||
failures.append("%s: expected %s, got %s" % [label, expected, actual])
|
||||
|
||||
|
||||
func _expect_string(actual: String, expected: String, label: String) -> void:
|
||||
if actual != expected:
|
||||
failures.append("%s: expected %s, got %s" % [label, expected, actual])
|
||||
@@ -575,20 +217,7 @@ func _expect_int(actual: int, expected: int, label: String) -> void:
|
||||
failures.append("%s: expected %d, got %d" % [label, expected, actual])
|
||||
|
||||
|
||||
func _expect_projectile_count(expected: int, label: String) -> void:
|
||||
var actual := _count_projectiles(get_root())
|
||||
if actual != expected:
|
||||
failures.append("%s: expected %d, got %d" % [label, expected, actual])
|
||||
|
||||
|
||||
func _count_projectiles(node: Node) -> int:
|
||||
var total := 1 if node.is_in_group("player_projectiles") else 0
|
||||
for child: Node in node.get_children():
|
||||
total += _count_projectiles(child)
|
||||
return total
|
||||
|
||||
|
||||
func _expect_array(actual: Array, expected: Array, label: String) -> void:
|
||||
func _expect_bool(actual: bool, expected: bool, label: String) -> void:
|
||||
if actual != expected:
|
||||
failures.append("%s: expected %s, got %s" % [label, expected, actual])
|
||||
|
||||
@@ -603,25 +232,80 @@ func _expect_positive(actual: float, label: String) -> void:
|
||||
failures.append("%s: expected positive x velocity, got %.3f" % [label, actual])
|
||||
|
||||
|
||||
func _expect_bool(actual: bool, expected: bool, label: String) -> void:
|
||||
if actual != expected:
|
||||
failures.append("%s: expected %s, got %s" % [label, expected, actual])
|
||||
|
||||
|
||||
func _expect_zero(actual: float, label: String) -> void:
|
||||
if not is_zero_approx(actual):
|
||||
failures.append("%s: expected zero x velocity, got %.3f" % [label, actual])
|
||||
|
||||
|
||||
func _expect_vector(actual: Vector2, expected: Vector2, label: String) -> void:
|
||||
if not actual.is_equal_approx(expected):
|
||||
failures.append("%s: expected %s, got %s" % [label, expected, actual])
|
||||
|
||||
|
||||
func _on_skill_requested(skill_id: String) -> void:
|
||||
requested_skills.append(skill_id)
|
||||
|
||||
|
||||
func _on_projectile_requested(projectile_scene: PackedScene, spawn_position: Vector2, direction: Vector2) -> void:
|
||||
projectile_requests.append({
|
||||
"scene": projectile_scene,
|
||||
"position": spawn_position,
|
||||
"direction": direction,
|
||||
})
|
||||
|
||||
|
||||
func _on_action_judged(_action_name: StringName, rating: Dictionary) -> void:
|
||||
judged_labels.append(str(rating.get("label", "")))
|
||||
|
||||
|
||||
func _event_bus() -> Node:
|
||||
var bus := root.get_node_or_null("EventBus")
|
||||
if bus == null:
|
||||
bus = load("res://autoload/event_bus.gd").new()
|
||||
bus.name = "EventBus"
|
||||
root.add_child(bus)
|
||||
return bus
|
||||
|
||||
|
||||
func _reset_player_action_state(player: Node) -> void:
|
||||
player.get_node("ComboWindow").clear(&"test-reset")
|
||||
player.get_node("ActionController").call("_reset_to_idle")
|
||||
player.get_node("ChargeComponent").cancel()
|
||||
player.set("state", Character.State.IDLE)
|
||||
player.set("attack_time_left", 0.0)
|
||||
player.set("velocity", Vector2.ZERO)
|
||||
player.set("heading", Vector2.RIGHT)
|
||||
player.set("current_skill_animation", "warrior_idle")
|
||||
var animation_player := player.get_node("AnimationPlayer") as AnimationPlayer
|
||||
if animation_player != null and animation_player.has_animation("warrior_idle"):
|
||||
animation_player.play("warrior_idle")
|
||||
requested_skills.clear()
|
||||
|
||||
|
||||
func _press_release_symbol(player: Node, symbol: StringName) -> void:
|
||||
player.call("_on_input_intent_created", _perfect_intent(symbol, &"pressed"))
|
||||
player.call("_on_input_intent_created", _perfect_intent(symbol, &"released"))
|
||||
|
||||
|
||||
func _perfect_intent(symbol: StringName, event_type: StringName) -> RefCounted:
|
||||
var rhythm_action: StringName = symbol.to_lower()
|
||||
if symbol == &"SP":
|
||||
rhythm_action = &"space"
|
||||
var intent: RefCounted = InputIntentScript.create(symbol, rhythm_action, event_type, float(Time.get_ticks_msec()))
|
||||
intent.judgement = {"label": "perfect", "diff": 0.0}
|
||||
return intent
|
||||
|
||||
|
||||
func _current_animation(player: Node) -> String:
|
||||
var animation_player := player.get_node("AnimationPlayer") as AnimationPlayer
|
||||
return animation_player.current_animation if animation_player != null else ""
|
||||
|
||||
|
||||
func _wait_for_active_phase() -> void:
|
||||
await create_timer(0.2).timeout
|
||||
await physics_frame
|
||||
|
||||
|
||||
func _wait_for_cancel_consumption() -> void:
|
||||
await create_timer(0.55).timeout
|
||||
await physics_frame
|
||||
|
||||
|
||||
func _wait_for_action_settle() -> void:
|
||||
await create_timer(0.7).timeout
|
||||
await physics_frame
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
if failures.is_empty():
|
||||
print("PASS player combo input")
|
||||
|
||||
Reference in New Issue
Block a user