extends SceneTree # 三选一覆盖层 UI 直验套件—— # 守 node_overlay.show_reward_items 的继任共用面;奖励节点三选一与通关三选一共用 CurioPickOverlay, # 本套件守共用面的「功能存在 ≠ 功能可达」盲区:选择外发/强制确认两段式/结果态。 # 〔无替换子面板路段——装配不可变契约 1,overlay 无 replace 态。〕 # 运行:godot --headless --path game --script res://tests/unit/presentation/reward_overlay_test.gd(expect 0) # 断言走 test_kit 计数(Kit.check)+ 失败即停早退协议(顺序状态机——坏态下后继断言无效)。 const Kit := preload("res://tests/unit/test_kit.gd") # 断言 + 失败即停(原直写 print FAIL + quit(1) + return 样板单点化——早退语义逐位保持) func _req(desc: String, ok: bool) -> bool: Kit.check(desc, ok) if not ok: quit(1) return false return true func _initialize() -> void: call_deferred("_run") func _run() -> void: var ov = load("res://presentation/views/curio_pick_overlay.gd").new() root.add_child(ov) var picked := [] var continued := [] ov.pick_confirmed.connect(func(id: String): picked.append(id)) ov.continue_pressed.connect(func(): continued.append(true)) # ① 选择态:三卡呈现、确认钮隐藏(两段式——点选前不给确认) ov.open_pick("第 1 层通过!", [ {"id": "attack", "text": "攻击力提升\n攻击 +1"}, {"id": "gp", "text": "GP 袋\nGP +20"}, {"id": "ap", "text": "行动点提升\n每战首轮 AP +1"}, ]) # bcard 形态:三选一卡为 BCard(PanelContainer) 非 Button—— # 用 `c is Button` 计数会恒 0(基线红成因,主区 3c4291d 起红在案)。本面数 _choice_box 子节点数,断言语义=三卡呈现。 var btns: int = ov._choice_box.get_child_count() if not _req("选择态应三卡呈现且确认/继续隐藏(btns=%d)" % btns, ov.visible and btns == 3 and not ov._confirm_btn.visible and not ov._continue_btn.visible): return # ①b 刷新面投喂(对齐商店 MC-1——投喂前隐藏/免费位点亮/GP 付费档禁用态/真实钮路径外发) if not _req("投喂前刷新钮应隐藏(未投喂上下文如店内专长凭证面无刷新)", not ov._refresh_btn.visible): return var refreshed := [] ov.refresh_requested.connect(func(): refreshed.append(true)) ov.set_refresh_display(0, 20, false) if not _req("GP 付费档:余量 0 价 20 余额不足=钮现形但禁用、角标 0、价签行可见", ov._refresh_btn.visible and ov._refresh_btn.disabled and ov._refresh_badge.text == "0" and ov._refresh_l.visible and ov._refresh_l.text == "刷新 20 GP"): return ov.set_refresh_display(2, 20, false) if not _req("免费位余量 2:钮点亮、角标 2、免费行——真实按钮路径外发 refresh_requested", ov._refresh_btn.visible and not ov._refresh_btn.disabled and ov._refresh_badge.text == "2" and ov._refresh_l.text == "免费 · 不消耗 AP"): return ov.set_refresh_display(0, 20, true) if not _req("付费档余额可付:免费位 0 但钮点亮(对齐商店——GP 档可刷)", ov._refresh_btn.visible and not ov._refresh_btn.disabled): return ov.press_refresh() if not _req("press_refresh 未外发 refresh_requested", refreshed.size() == 1): return # ② 点选→高亮→确认外发(真实按钮路径);确认前改选以最后点选为准 ov.press_card(0) ov.press_card(1) ov.press_confirm() if not _req("点选确认未外发 pick_confirmed(gp)(%s)" % str(picked), ov._confirm_btn.visible and picked.size() == 1 and String(picked[0]) == "gp"): return # ③ 结果态:继续钮点亮、唯一出口(刷新钮随选择态收——停点已兑付残钮零意图可点) ov.set_refresh_display(2, 20, false) ov.show_result("已选择:攻击力提升 · 攻击 +1") if not _req("结果态应点亮继续且收三卡与刷新钮", ov._continue_btn.visible and not ov._choice_box.visible and not ov._refresh_btn.visible): return ov.press_continue() if not _req("继续未外发 continue_pressed", continued.size() == 1): return ov.close_pick() if not _req("close_pick 应收屏", not ov.visible): return quit(Kit.finish("reward_verify", "PASS — 三卡两段式/确认外发/结果态/收屏 全过"))