Initial project sync
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user