Files
rthythm_archor_game/tests/test_level1_melee_contact.gd
T
2026-07-06 22:59:47 -07:00

133 lines
3.9 KiB
GDScript

extends SceneTree
## Regression for the first Level 1 contact: body blocking must not leave the
## opening melee minion outside the player's basic attack hit window.
var failures: Array[String] = []
func _init() -> void:
_run.call_deferred()
func _run() -> void:
await process_frame
var rhythm := root.get_node_or_null("RhythmManager")
if rhythm != null and rhythm.has_method("stop_manager"):
rhythm.call("stop_manager")
await _check_inactive_boss_is_not_front_area_body_wall()
await _check_body_blocked_contact_hits()
await _check_opening_sequence_can_reach_minion()
_finish()
func _check_inactive_boss_is_not_front_area_body_wall() -> void:
var stage := await _make_stage()
if stage == null:
return
var boss := stage.get_node("ActorsContainer/Boss") as CharacterBody2D
var receiver := boss.get_node("DamageReceiver") as Area2D
_expect(
(int(boss.collision_layer) & (1 << 6)) == 0,
"Inactive Level 1 Boss should not occupy the enemy_body layer before boss-room entry"
)
_expect(
not receiver.monitorable,
"Inactive Level 1 Boss should not expose a damage receiver before boss-room entry"
)
boss.set("combat_enabled", true)
await physics_frame
_expect(
(int(boss.collision_layer) & (1 << 6)) != 0,
"Boss should restore enemy_body collision when boss combat unlocks"
)
_expect(receiver.monitorable, "Boss damage receiver should restore when boss combat unlocks")
stage.free()
func _check_body_blocked_contact_hits() -> void:
var stage := await _make_stage()
if stage == null:
return
var container := stage.get_node("ActorsContainer")
var player := container.get_node("Player") as Node2D
var minion := container.get_node("JinZhanMinion") as Node2D
var behavior := minion.get_node_or_null("MinionBehavior")
if behavior != null:
behavior.set("enabled", false)
var health := minion.get_node("HealthComponent")
player.global_position = Vector2(minion.global_position.x - 20.0, minion.global_position.y)
player.set("heading", Vector2.RIGHT)
await physics_frame
var start_health := int(health.get("current"))
player.call("submit_combo_input", "D", "perfect")
await create_timer(0.8).timeout
await physics_frame
_expect(
int(health.get("current")) < start_health,
"Body-blocked Level 1 melee contact should still be hit by D basic attack"
)
stage.free()
func _check_opening_sequence_can_reach_minion() -> void:
var stage := await _make_stage()
if stage == null:
return
var container := stage.get_node("ActorsContainer")
var player := container.get_node("Player") as Node2D
var minion := container.get_node("JinZhanMinion") as Node2D
var health := minion.get_node("HealthComponent")
var start_health := int(health.get("current"))
# new2 出生点改到地图最左侧后,玩家需要先推进一段路才遇敌;这里直接把
# 玩家放到近战怪的追击停步距离(120px)上,验证接敌后的连招能够命中。
player.global_position = Vector2(minion.global_position.x - 120.0, minion.global_position.y)
player.set("heading", Vector2.RIGHT)
await physics_frame
for _index: int in range(5):
player.call("submit_combo_input", "D", "perfect")
await create_timer(0.65).timeout
await physics_frame
_expect(
int(health.get("current")) < start_health,
"Approach-range Level 1 sequence should be able to damage the first minion"
)
stage.free()
func _make_stage() -> Node:
var stage_scene: PackedScene = load("res://scenes/stage/stage.tscn")
_expect(stage_scene != null, "stage.tscn should load")
if stage_scene == null:
return null
var stage: Node = stage_scene.instantiate()
root.add_child(stage)
await process_frame
await physics_frame
return stage
func _expect(condition: bool, label: String) -> void:
if not condition:
failures.append(label)
func _finish() -> void:
if failures.is_empty():
print("PASS level1 melee contact")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)