Files
gplan-2/game/tests/unit/presentation/standee_fx_sweep_test.gd
T
DKChan 9f21236f80 工程(注释标记词换代·oracle→判据出处): 用户 2026-11-07 令——判据出处注记的标记词改用项目已有中文名,避免 Oracle 被读成数据库。注释格式句、机检正则、标识符、卡片与登记同步换代;零行为改动。
改动面 112 文件 572+/572-:game/tests/** 与 game/probe/** 共 106 件 545 行 `# oracle:`→`# 判据出处:`;tools/capability_audit.py 正则字面量换中文+ORACLE_*→CRITERION_*/check_oracle_markers→check_criterion_markers/oracle_marked(flagged)→criterion_* 共 11 行;test-conventions.md:119 格式句+:155 措辞;待办清单与需求卡片-QA覆盖余量收口批各 1 处字面量;coverage_enum.py:21 与 camp_scene_layout_test.gd:101 旁支措辞;ui_click_probe.gd 对拍局部变量 oracle→expected 7 处;auto_player.gd 三处 safe_set 真值措辞。不动:历史审计报告两份、test-oracle-anchor 分支名、git 史、生成日志;指针格式/扫描面/判红条件/验收义务全不变。

读数(区内实跑):改前 capability_audit --strict「417 注记函数·红项 0」→改后「417 判据出处注记函数·红项 0」exit=0;新标记 545 行/106 文件,现行义务面 oracle 残留 0(在册沿革除外);diff 自检 game/ 非注释新增行仅 6 行且全在 ui_click_probe.gd 的 expected 变量段;112 改动文件 CRLF=0;py_compile tools/capability_audit.py OK;--docs exit=0【验收通过】无新增红;--gates exit=0(静态扫描绿、闸壳 bash -n ×13 失败 0)。
2026-11-07 07:11:15 +08:00

151 lines
6.8 KiB
GDScript
Raw 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.
# VERTICAL SLICE - NOT FOR PRODUCTION
# 呈现域缺陷扫掠断言(行为缺陷定点修批卡① T2 五族):
# ① 意图蓄力档可达(d2——_intent_charge 分档,旧 GOLD_DEEP 判据恒不可达);
# ② 庆祝 tween 句柄纪律(d4——重开不叠加、close 必杀);
# ③ 互斥四口(d5 调试钮同判据 / d8 控制器运行态可查);
# ⑤ 站桩按敌 id 解析(d12 两口:on_step_row_fx 闪白落点 + enemy_standee_center 弹道落点)。
# d6/d7 两守卫断言宿主 = system_test;d3/d17/d18 属非行为面(实现报告等价申报)。
# 运行:godot --headless --path game --script res://tests/unit/presentation/standee_fx_sweep_test.gd(expect 0)
extends SceneTree
const Kit := preload("res://tests/unit/test_kit.gd")
const StandeeBodyScript := preload("res://presentation/views/standee_body.gd")
const BattleEndScript := preload("res://presentation/views/battle_end_overlay.gd")
const DebugOverlayScript := preload("res://presentation/views/debug_overlay.gd")
const TuneSimScript := preload("res://presentation/tune_sim_controller.gd")
const StageScript := preload("res://presentation/views/battle_stage_view.gd")
# 假调试面板(TuneSimController 所需 setter 面 + 树内节点供给 get_tree)
class FakePanel extends Node:
var running := false
var progress := ""
var report := ""
var atk := 0
var hp := 0
func atk_pct() -> int:
return atk
func hp_pct() -> int:
return hp
func set_sim_running(r: bool) -> void:
running = r
func set_sim_progress(t: String) -> void:
progress = t
func set_sim_report(t: String) -> void:
report = t
# 假自动策略(run_level 签名同 level_autoplay——回调内读控制器运行态)
class FakeDriver extends RefCounted:
var ctrl
var seen: Array[bool] = []
var calls := 0
func run_level(_db: Variant, _seed: int, _level: int, _atk: int, _hp: int, _other: bool, _logger: Variant) -> Dictionary:
calls += 1
seen.append(ctrl.is_running())
if calls == 1:
return {"hero_dmg": 12.0, "rounds": 4, "result": "victory", "hp_left": 3.0, "hp_at_boss": 5.0}
return {"hero_dmg": 6.0, "rounds": 2, "result": "defeat",
"defeat_node_index": 3, "defeat_node_type": "battle", "hp_left": 0.0, "hp_at_boss": 0.0}
# 假配置库(TuneSimController 只读 db.run.action_economy.ap_per_round——最小域对象图)
class FakeActionEconomy:
var ap_per_round := 2
class FakeRun:
var action_economy := FakeActionEconomy.new()
class FakeDB:
var run := FakeRun.new()
func _init() -> void:
# 判据出处: design/ux/battle.md:154 (站桩呈现域缺陷扫掠组)
UiKit.motion_scale = 1.0
# ---- ⑤ 站桩按 id 解析(两口共用同名字敌载体)----
var stage = StageScript.new(null, load("res://data/tables/battle_layout.tres"))
root.add_child(stage)
var s1 = StandeeBodyScript.new("enemy")
var s2 = StandeeBodyScript.new("enemy")
stage.world.add_child(s1)
stage.world.add_child(s2)
s1.set_data({"display_name": "地精", "enemy_id": "goblin_a", "hp": 3, "max_hp": 3, "order": 1})
s2.set_data({"display_name": "地精", "enemy_id": "goblin_b", "hp": 3, "max_hp": 3, "order": 2})
s1.position = Vector2(10, 20)
s2.position = Vector2(200, 20)
stage._cards.clear()
stage._cards.append(s1)
stage._cards.append(s2)
Kit.check("站桩 enemy_id 访问器读装载值〔wd12〕", s1.enemy_id() == "goblin_a" and s2.enemy_id() == "goblin_b")
Kit.check("同名敌按 id 精确解析(不做名子串撞车)〔wd12〕",
stage._card_by_id("goblin_b") == s2 and stage._card_by_id("goblin_a") == s1)
Kit.check("空 id / 未登记 id 恒不命中(名兜底归调用点)〔wd12〕",
stage._card_by_id("") == null and stage._card_by_id("no_such") == null)
# 口一:on_step_row_fx —— 伤害行携 target_id,闪白落点须在 id 指向的站桩
stage.on_step_row_fx({"type": "damage", "target": "地精", "target_id": "goblin_b"})
await create_timer(0.6).timeout # 弹道到达拍 0.33s + 余量
Kit.check("伤害行按 target_id 命中正确站桩(闪白落点)〔wd12〕",
s2.fx_probe().flash_count == 1 and s1.fx_probe().flash_count == 0)
# 口二:enemy_standee_center —— id 先、display_name 兜底
var c_b = stage.enemy_standee_center("goblin_b", "地精")
var c_b_expect: Vector2 = stage.world_to_shell(s2.position + s2.box * 0.5)
Kit.check("弹道落点按 target_id 取站桩中心〔wd12〕", c_b != null and c_b == c_b_expect)
var c_fallback = stage.enemy_standee_center("", "地精")
var c_fallback_expect: Vector2 = stage.world_to_shell(s1.position + s1.box * 0.5)
Kit.check("无 target_id 时按名兜底同旧行为(首命中)〔wd12〕", c_fallback != null and c_fallback == c_fallback_expect)
# ---- ① 意图蓄力档可达(d2)----
# 蓄力判据表:[kind, skill_id, 期望 _intent_charge, 个案标签]
var charge_cases := [
["damage", "heavy", true, "蓄力技能(heavy)置 _intent_charge=true"],
["damage", "goblin_slash", false, "非蓄力攻击技(goblin_slash)零置位"],
["buff", "goblin_rage", false, "增益系零置位"],
["damage", "basic", false, "普攻零表示路径复位 _intent_charge"],
]
for c in charge_cases:
s1.set_pending(c[0], c[1])
Kit.check("%s〔wd2〕" % c[3], s1._intent_charge == c[2])
# ---- ② 庆祝 tween 句柄纪律(d4)----
var ov = BattleEndScript.new()
root.add_child(ov)
ov.open_victory("判定行", "继续", Rect2(0, 0, 100, 100))
var first: Tween = ov.get_meta(&"celebrate_tw", null)
Kit.check("首开胜利画面创建庆祝句柄〔wd4〕", first != null and first.is_valid())
ov.open_victory("判定行", "继续", Rect2(0, 0, 100, 100))
var second: Tween = ov.get_meta(&"celebrate_tw", null)
Kit.check("重开胜利画面:旧句柄已 kill、新句柄在位(至多一个活跃)〔wd4〕",
first != null and not first.is_valid() and second != null and second.is_valid())
ov.close()
Kit.check("close 必杀庆祝句柄(句柄清空)〔wd4〕", ov.get_meta(&"celebrate_tw", null) == null)
# ---- ③ 互斥四口(d5/d8)----
var dbg = DebugOverlayScript.new(null, 0, 0)
dbg.set_sim_running(true)
Kit.check("模拟运行期调试入口钮同置灰〔wd5〕", dbg._dbg_btn.disabled)
dbg.set_sim_running(false)
Kit.check("模拟收尾调试入口钮恢复(未锁定)〔wd5〕", not dbg._dbg_btn.disabled)
dbg.free()
var panel := FakePanel.new()
root.add_child(panel)
var drv := FakeDriver.new()
var ctrl = TuneSimScript.new(FakeDB.new(), panel, 100, drv)
drv.ctrl = ctrl
await ctrl.run(2) # 假 driver 回调内读 is_running()(两局各一读)
Kit.check("控制器运行中 is_running()=true(驱动回调内读数)〔wd8〕", drv.seen == [true, true])
Kit.check("控制器收尾 is_running()=false〔wd8〕", not ctrl.is_running() and not panel.running)
Kit.check("两局报告全文注入面板(run 收尾链路完整)〔wd8〕", String(panel.report) != "")
quit(Kit.finish("standee_fx_sweep"))