|
|
|
|
@@ -54,12 +54,17 @@ func _init() -> void:
|
|
|
|
|
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_no_skill_requested("W alone should not request a skill")
|
|
|
|
|
_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")
|
|
|
|
|
@@ -74,7 +79,7 @@ func _init() -> void:
|
|
|
|
|
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_idle", "holding A charge should keep idle animation")
|
|
|
|
|
_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:
|
|
|
|
|
@@ -82,9 +87,6 @@ func _init() -> void:
|
|
|
|
|
else:
|
|
|
|
|
_expect_bool(charge_effect.visible, true, "holding A should show charge effect")
|
|
|
|
|
requested_skills.clear()
|
|
|
|
|
var a_release_event := InputEventKey.new()
|
|
|
|
|
a_release_event.pressed = false
|
|
|
|
|
a_release_event.physical_keycode = KEY_A
|
|
|
|
|
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")
|
|
|
|
|
@@ -97,6 +99,7 @@ func _init() -> void:
|
|
|
|
|
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")
|
|
|
|
|
@@ -115,10 +118,17 @@ func _init() -> void:
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
@@ -140,6 +150,7 @@ func _init() -> void:
|
|
|
|
|
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
|
|
|
|
|
@@ -150,6 +161,74 @@ func _init() -> void:
|
|
|
|
|
_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)
|
|
|
|
|
@@ -186,20 +265,39 @@ func _init() -> void:
|
|
|
|
|
if supports_energy:
|
|
|
|
|
player.set("current_energy", 0)
|
|
|
|
|
player.call("submit_combo_input", "W", "perfect")
|
|
|
|
|
_expect_int(player.call("get_energy"), 2, "perfect input should add two energy segments")
|
|
|
|
|
_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"), 3, "good input should add one energy segment")
|
|
|
|
|
_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"), 3, "bad input should not add energy")
|
|
|
|
|
_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"), 3, "miss input should not add energy")
|
|
|
|
|
_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"), 10, "energy should cap at ten segments")
|
|
|
|
|
_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()
|
|
|
|
|
@@ -349,34 +447,58 @@ func _init() -> void:
|
|
|
|
|
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")
|
|
|
|
|
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")
|
|
|
|
|
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", 0)
|
|
|
|
|
player.set("current_energy", 3)
|
|
|
|
|
player.call("submit_combo_input", "S", "perfect")
|
|
|
|
|
player.call("submit_combo_input", "SP", "perfect")
|
|
|
|
|
_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"), 1, "S+Space should spend three energy after two perfect inputs")
|
|
|
|
|
_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"), 1, "S+Space+Space should spend two energy after the next perfect input")
|
|
|
|
|
_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"), 2, "S+Space+Space+Space should spend one energy after the next perfect input")
|
|
|
|
|
_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")
|
|
|
|
|
|