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

107 lines
4.4 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends SceneTree
const PAST_STRONG := &"effect_tp_past_enemy_strong"
const PAST_WEAK := &"effect_tp_past_enemy_weak"
var failures: Array[String] = []
func _init() -> void:
_run.call_deferred()
func _run() -> void:
await process_frame
# 伤害基线按 easy 难度取值;显式钉住,不依赖残留的 settings.cfg。
var settings := root.get_node_or_null("GameSettings")
if settings != null:
settings.call("set_difficulty", &"easy")
var bus: Node = load("res://autoload/event_bus.gd").new()
bus.name = "EventBus"
root.add_child(bus)
var manager: Node = load("res://autoload/time_phase_manager.gd").new()
manager.name = "TimePhaseManager"
root.add_child(manager)
var actor := Node.new()
actor.name = "PhaseActor"
var container: Node = load("res://scenes/components/effect_container.gd").new()
container.name = "EffectContainer"
actor.add_child(container)
var adapter: Node = load("res://scenes/components/time_phase_adapter.gd").new()
adapter.name = "TimePhaseAdapter"
adapter.set("profile", load("res://resources/time_phase/profile_past_strong_enemy.tres"))
actor.add_child(adapter)
root.add_child(actor)
await process_frame
# --- Idempotent init applies the current (past) phase effects. ---
var ids: Array = container.call("active_effect_ids")
_expect_bool(ids.has(PAST_STRONG), true, "past phase should mount the strong effect")
_expect_bool(ids.has(PAST_WEAK), false, "past phase should not mount the weak effect")
_expect_int(int(container.call("active_count")), 1, "exactly one time phase effect expected after init")
# --- Switching phases swaps the effect set. ---
manager.call("toggle_time_phase", &"time_anchor_broken")
ids = container.call("active_effect_ids")
_expect_bool(ids.has(PAST_WEAK), true, "future phase should mount the weak effect")
_expect_bool(ids.has(PAST_STRONG), false, "future phase should unmount the strong effect")
_expect_int(int(container.call("active_count")), 1, "effect balance: exactly one phase effect after a switch")
# --- Switching back restores the original set with no residue. ---
manager.call("toggle_time_phase", &"time_anchor_broken")
ids = container.call("active_effect_ids")
_expect_bool(ids.has(PAST_STRONG), true, "back in past the strong effect should return")
_expect_int(int(container.call("active_count")), 1, "effect balance holds across repeated switches")
# --- Damage numbers actually flip with the phase. ---
# 强势 ×1.4 / 弱势 ×0.7 以 resources/effects/time_phase/ 四个资源现值为准
# 2026-07-04 校准批次;旧口径 ×1.2 已废弃)。
var stat_resolver: Script = load("res://scripts/resolvers/stat_resolver.gd")
var past_damage := float(stat_resolver.call("resolve_damage", 100.0, null, {"label": "perfect"}, container, null))
_expect_float(past_damage, 140.0, "past-strong enemy should deal x1.4 damage in past")
manager.call("toggle_time_phase", &"time_anchor_broken")
var future_damage := float(stat_resolver.call("resolve_damage", 100.0, null, {"label": "perfect"}, container, null))
_expect_float(future_damage, 70.0, "past-strong enemy should deal x0.7 damage in future")
# --- Actors without a profile are untouched by phase switches. ---
var plain_actor := Node.new()
plain_actor.name = "PlainActor"
var plain_container: Node = load("res://scenes/components/effect_container.gd").new()
plain_container.name = "EffectContainer"
plain_actor.add_child(plain_container)
var plain_adapter: Node = load("res://scenes/components/time_phase_adapter.gd").new()
plain_adapter.name = "TimePhaseAdapter"
plain_actor.add_child(plain_adapter)
root.add_child(plain_actor)
await process_frame
manager.call("toggle_time_phase", &"time_anchor_broken")
_expect_int(int(plain_container.call("active_count")), 0, "actors without a profile must be unaffected")
_finish()
func _expect_int(actual: int, expected: int, label: String) -> void:
if actual != expected:
failures.append("%s: expected %d, got %d" % [label, expected, actual])
func _expect_float(actual: float, expected: float, label: String) -> void:
if not is_equal_approx(actual, expected):
failures.append("%s: expected %.3f, got %.3f" % [label, expected, 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 _finish() -> void:
if failures.is_empty():
print("PASS time phase adapter")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)