iter33 卡② T1+T2: 主菜单三入口化(6 钮→3 钮)+F10 位点全量迁移
钮集:build_start_overlay 六钮两组帽→三钮(进入存档 primary/设置/退出——裁决 1;组帽双撤追认单留痕); menu_screen 句柄面撤 4 留 3 增 entersavebtn;main.gd 接线撤四线接 _open_save_select(mn3 点击链闭环)。 _refresh_resume_button 净删除+消费点全清(main.gd 五处+camp ctx 载体+presenter 三处+probe_ui_util 参数+pacing_queue+V2d 族);断点确认链主菜单侧摘除(mn6——分派器 new_adventure 臂随迁退役, 机制保留卡④第三消费方)。_start_adventure_from_menu/_resume_from_menu/_open_career 保留为探针 直调中间态(mn10——卡④ 大门/笔记本换代点,已知中间态登记)。 F10 迁移:smoke V2 三钮/V2d 族废止三钮承接/V3g camp 经进档开层(槽模板隔离+恢复 attach 写盘目标)/ V3i 钮断言摘除+_stage_faces.resume_vis 键退役;ui_probe/ui_struct/screen_flow/shot/fx/t17 营地与 冒险驱动换代(open_camp_via_savesel 助手——槽模板清场防真实槽污染);ui_click 营地购买链换代 (swap=true 整链落槽文件+持久化核验同源)+断点段②③按 §7.2 申报删除移交卡④+生涯直调; pacing_queue 钮依赖摘除;isolate_save 签名换代(refresh_resume→swap_save,全调用点核对)。 golden 基线随 T2 重制(mn12——三钮形态)。验证:冒烟 1212/0、单元 40 套件全绿、 struct/click/flow/ui_probe/tune/layout/input/t17 全绿。
This commit is contained in:
1 parent
a10d15c761
commit
3661689a56
16 files changed
+158
-284
No files matched your search
@@ -16,13 +16,12 @@ var runner_get: Callable # () -> LevelRunner
|
||||
var open_modal: Callable
|
||||
var close_modal: Callable
|
||||
var refresh_presentations: Callable
|
||||
var refresh_resume_button: Callable
|
||||
|
||||
|
||||
func _init(db_ref, meta_get_cb: Callable, save_get_cb: Callable, camp_overlay_ref: CampOverlay,
|
||||
shop_overlay_ref: ShopOverlay, toast_ref: ToastStack, start_overlay_ref: Control,
|
||||
logger_ref, runner_get_cb: Callable, open_modal_cb: Callable, close_modal_cb: Callable,
|
||||
refresh_presentations_cb: Callable, refresh_resume_button_cb: Callable) -> void:
|
||||
refresh_presentations_cb: Callable) -> void:
|
||||
db = db_ref
|
||||
meta_get = meta_get_cb
|
||||
save_get = save_get_cb
|
||||
@@ -35,4 +34,3 @@ func _init(db_ref, meta_get_cb: Callable, save_get_cb: Callable, camp_overlay_re
|
||||
open_modal = open_modal_cb
|
||||
close_modal = close_modal_cb
|
||||
refresh_presentations = refresh_presentations_cb
|
||||
refresh_resume_button = refresh_resume_button_cb
|
||||
@@ -1,6 +1,6 @@
|
||||
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
## 营地/商店投影控制器:营地开合/快照投影/锻造·同调·天赋树·Fork 购买切换 + 商店房购买/离开(pool 与 product 双面)。
|
||||
## 信号连接只归组合根(campbtn/camp_overlay/shop_overlay 信号接至本类 on_* 入口);模态栈/呈现刷新/续玩刷新与 runner 现值经组合根回调注入。
|
||||
## 信号连接只归组合根(camp_overlay/shop_overlay 信号接至本类 on_* 入口);模态栈/呈现刷新与 runner 现值经组合根回调注入(续玩刷新已随主菜单三入口化退役——卡② mn7)。
|
||||
## 写调用唯一经 MetaProgression 购买原语与 LevelRunner.buy_*——本类零直写,拒绝兜底 toast 保留原地。
|
||||
extends RefCounted
|
||||
|
||||
@@ -16,7 +16,6 @@ var _runner_get: Callable # () → 关卡推进器现值(组合根 la
|
||||
var _open_modal: Callable
|
||||
var _close_modal: Callable
|
||||
var _refresh_presentations: Callable
|
||||
var _refresh_resume_button: Callable
|
||||
|
||||
|
||||
func _init(ctx: CampFlowContext) -> void:
|
||||
@@ -33,7 +32,6 @@ func _init(ctx: CampFlowContext) -> void:
|
||||
_open_modal = ctx.open_modal
|
||||
_close_modal = ctx.close_modal
|
||||
_refresh_presentations = ctx.refresh_presentations
|
||||
_refresh_resume_button = ctx.refresh_resume_button
|
||||
|
||||
|
||||
# 打开营地(主菜单入口——开合与开始层互斥仿设置面先例:开始覆盖层非模态且树序在后,
|
||||
@@ -52,7 +50,6 @@ func open_camp() -> void:
|
||||
func on_camp_closed() -> void:
|
||||
_close_modal.call(camp_overlay) # 模态栈单口
|
||||
start_overlay.visible = true
|
||||
_refresh_resume_button.call() # 回菜单按断点在档态刷新
|
||||
_refresh_presentations.call() # 关闭后刷新顶栏(工坊解锁可能变了余额侧读数面)
|
||||
|
||||
|
||||
|
||||
+12
-41
@@ -67,8 +67,7 @@ var meta: MetaProgressionCore:
|
||||
var logger = null # 试玩日志器(JSONL 持久化 + 卡死诊断转储——呈现层组件)
|
||||
var _debug_entry := false # 调试会话门控(写死=true——恒开:启动即开浮窗+两屏角标点亮;_ready 赋值)
|
||||
var _seed_edit: LineEdit
|
||||
var _resume_btn: Button # 继续上局按钮句柄(有断点才亮)
|
||||
var confirm_dialog: ConfirmDialog # 通用确认弹窗(新冒险互斥确认弹窗化)
|
||||
var confirm_dialog: ConfirmDialog # 通用确认弹窗(消费方编排——现行消费方=选档删档确认;新冒险互斥确认已随卡②主菜单撤出,归卡④大门)
|
||||
var _confirm_consumer := "" # 确认弹窗消费方状态量(契约 3 编排——open 前设、分派后清)
|
||||
var _confirm_consumer_slot := 0 # 消费方附随槽号(delete_slot 消费方专用)
|
||||
var curio_overlay: CurioPickOverlay # 提升三选一覆盖层(level-clear.md v2 选择面承载;奖励节点共用)
|
||||
@@ -195,7 +194,6 @@ func _ready() -> void:
|
||||
_debug.battle_ready.connect(_on_debug_battle_ready)
|
||||
_build_ui()
|
||||
_begin_session(false) # 闲时会话(gp_ledger 等探针注入面自 _ready 起恒在——ui_probe 合成段时序)
|
||||
_refresh_resume_button() # 启动读盘后按断点在档态点亮「继续上局」
|
||||
_start_overlay.visible = true
|
||||
_debug_entry = true # 调试入口门控写死=true(不读 DS_DEBUG 环境变量;发布前清)
|
||||
debug_badge.visible = _debug_entry # 浮层角标可见性须门控落定后赋值(构建/连接在 _build_ui)
|
||||
@@ -315,10 +313,9 @@ func _build_ui() -> void:
|
||||
curio_overlay.continue_pressed.connect(_bonus.on_continue)
|
||||
curio_overlay.refresh_requested.connect(_bonus.on_refresh)
|
||||
|
||||
# 菜单屏接线(句柄经屏壳暴露)
|
||||
_menu_screen.lvbtn.pressed.connect(_start_adventure_from_menu)
|
||||
_menu_screen.resumebtn.pressed.connect(_resume_from_menu) # 续玩入口
|
||||
_resume_btn = _menu_screen.resumebtn
|
||||
# 菜单屏接线(句柄经屏壳暴露;三入口化——进入存档/设置/退出游戏,卡② mn3:
|
||||
# 进入存档钮落点=卡③选档层 _open_save_select,点击链在此闭环)
|
||||
_menu_screen.entersavebtn.pressed.connect(_open_save_select)
|
||||
# 调试入口=UI 最顶层全局浮层角标(任何 UI 不遮挡——菜单/战斗/地图三枚
|
||||
# 屏内角标由全局浮层承载;连接归组合根,树序/登记面见 LAYER_CONTRACT 末位)
|
||||
debug_badge = UiAssembler.build_debug_badge(self)
|
||||
@@ -328,7 +325,7 @@ func _build_ui() -> void:
|
||||
# 购买写调用唯一经 MetaProgression/LevelRunner core 单口——组合根 lambda 现值注入)
|
||||
_camp_pres = CampShopPresenter.new(CampFlowContext.new(db, func() -> Variant: return meta, func() -> Variant: return save_manager, camp_overlay, shop_overlay,
|
||||
board_zone.toast, _start_overlay, logger, func() -> Variant: return run_scope.runner,
|
||||
_open_modal, _close_modal, _refresh_presentations, _refresh_resume_button)) # 构造参数收拢 context
|
||||
_open_modal, _close_modal, _refresh_presentations)) # 构造参数收拢 context
|
||||
shop_overlay.buy_requested.connect(_camp_pres.on_shop_buy)
|
||||
shop_overlay.refresh_requested.connect(_camp_pres.on_shop_refresh) # MC-1
|
||||
shop_overlay.leave_pressed.connect(_camp_pres.on_shop_leave)
|
||||
@@ -340,8 +337,6 @@ func _build_ui() -> void:
|
||||
camp_overlay.forge_unlock_requested.connect(_camp_pres.on_camp_forge_unlock)
|
||||
camp_overlay.forge_select_requested.connect(_camp_pres.on_camp_forge_select)
|
||||
camp_overlay.closed.connect(_camp_pres.on_camp_closed)
|
||||
_menu_screen.campbtn.pressed.connect(_camp_pres.open_camp)
|
||||
_menu_screen.careerbtn.pressed.connect(_open_career) # 生涯页一级入口(营地同组)
|
||||
_menu_screen.settingsbtn.pressed.connect(_open_settings) # 最小设置面入口
|
||||
_menu_screen.quitbtn.pressed.connect(_quit_game) # 退出游戏提级一级菜单
|
||||
|
||||
@@ -488,32 +483,23 @@ func _input_locked() -> bool:
|
||||
# ==================== 冒险模式入口(唯一试玩入口)====================
|
||||
|
||||
func _start_adventure_from_menu() -> void:
|
||||
# 互斥确认弹窗化:有断点时开新冒险弹实底确认框,
|
||||
# 「开新冒险」提交(弃旧断点+写盘)/「取消」回菜单
|
||||
if save_manager.has_breakpoint():
|
||||
var bp: Dictionary[Variant, Variant] = save_manager.breakpoint_snapshot()
|
||||
_confirm_consumer = "new_adventure" # 消费方编排(契约 3——open 前设消费方)
|
||||
confirm_dialog.open("已有未完冒险(第 %d 关)——开新冒险将覆盖旧断点" % maxi(1, int(bp.get("level_index", 1))),
|
||||
"开新冒险", "取消")
|
||||
return
|
||||
# 主菜单「开始冒险」钮已随三入口化撤出(卡② mn6——主菜单侧断点互斥确认链同步摘除,
|
||||
# 弹窗本体与两分支逻辑归卡④大门承接)。本函数为探针直调中间态保留(mn10——冒险段探针
|
||||
# 直调位点逐个登记实现报告「已知中间态」;卡④到位后由大门两分支换代)。无激活态写盘拒绝
|
||||
# 由卡① sv3 承接(结算不落盘)。
|
||||
_start_overlay.visible = false
|
||||
_start_adventure()
|
||||
|
||||
|
||||
# 确认弹窗分派(卡③ 契约 3):按 _confirm_consumer 路由——"new_adventure"=现役新冒险确认
|
||||
#(行为与原 _on_confirm_new_adventure 逐句等价)、"delete_slot"=卡③ 删档确认(确认才删、
|
||||
# 取消只关窗——裁决 3);分派面禁写死单一目标(卡④ 到位接入第三消费方不返工)。
|
||||
# 确认弹窗分派(卡③ 契约 3):按 _confirm_consumer 路由——"delete_slot"=卡③ 删档确认
|
||||
#(确认才删、取消只关窗——裁决 3)。"new_adventure" 消费方已随卡② 主菜单确认链摘除退役
|
||||
#(mn6/V5——主菜单零确认残留),分派机制保留(卡④ 到位接入第三消费方不返工)。
|
||||
func _on_confirm_accepted() -> void:
|
||||
confirm_dialog.close()
|
||||
match _confirm_consumer:
|
||||
"delete_slot":
|
||||
save_manager.delete_slot(_confirm_consumer_slot)
|
||||
save_select_overlay.open_save_select(_save_select_data()) # 就地刷新(该槽回空态)
|
||||
"new_adventure":
|
||||
save_manager.clear_breakpoint() # 提交即弃旧断点(覆盖语义对盘面即时生效)
|
||||
save_manager.write_to_disk()
|
||||
_start_overlay.visible = false
|
||||
_start_adventure()
|
||||
_confirm_consumer = ""
|
||||
|
||||
|
||||
@@ -529,17 +515,6 @@ func _quit_game() -> void:
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
# 继续上局按钮可见性 = 断点在档态(启动读盘后与每次回开始菜单刷新)
|
||||
func _refresh_resume_button() -> void:
|
||||
if _resume_btn == null:
|
||||
return
|
||||
var has: bool = save_manager.has_breakpoint()
|
||||
_resume_btn.visible = has
|
||||
if has:
|
||||
var bp: Dictionary[Variant, Variant] = save_manager.breakpoint_snapshot()
|
||||
_resume_btn.text = "▶ 继续上局(第 %d 关 · 自最近停点恢复)" % maxi(1, int(bp.get("level_index", 1)))
|
||||
|
||||
|
||||
# 继续上局(resume_adventure 的消费入口):断点重建至最近停点
|
||||
func _resume_from_menu() -> void:
|
||||
if not save_manager.has_breakpoint():
|
||||
@@ -727,7 +702,6 @@ func _on_battle_end_continue() -> void:
|
||||
_begin_session(false)
|
||||
debug_overlay.reset_sliders()
|
||||
_start_overlay.visible = true
|
||||
_refresh_resume_button() # 回菜单按断点在档态刷新(收束后已清=隐藏)
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
@@ -1086,7 +1060,6 @@ func _open_settings() -> void:
|
||||
func _on_settings_closed() -> void:
|
||||
_close_modal(settings_overlay) # 模态栈单口
|
||||
_start_overlay.visible = true
|
||||
_refresh_resume_button()
|
||||
|
||||
|
||||
# ---- 局内状态面板·只读(入口角标在两屏装配段;开合与数据喂入归组合根)----
|
||||
@@ -1124,7 +1097,6 @@ func _open_career() -> void:
|
||||
func _on_career_closed() -> void:
|
||||
_close_modal(career_overlay) # 模态栈单口
|
||||
_start_overlay.visible = true
|
||||
_refresh_resume_button()
|
||||
|
||||
|
||||
# 生涯页快照投影(只读同源——每次开层实时读 SaveManager 计数访问器 + MetaProgression 访问器
|
||||
@@ -1164,7 +1136,6 @@ func _open_save_select() -> void:
|
||||
func _on_save_select_closed() -> void:
|
||||
_close_modal(save_select_overlay) # 模态栈单口
|
||||
_start_overlay.visible = true
|
||||
_refresh_resume_button()
|
||||
|
||||
|
||||
# 槽数据快照(只读同源——每次开层实时经卡① 窥视 API 逐槽取数拼装;零写调用)。
|
||||
|
||||
@@ -8,10 +8,7 @@ extends Control
|
||||
|
||||
var start_overlay: Control # 全屏菜单层(原 main._start_overlay——组合根可见性开关句柄不变)
|
||||
var box: VBoxContainer
|
||||
var lvbtn: Button
|
||||
var resumebtn: Button
|
||||
var campbtn: Button
|
||||
var careerbtn: Button
|
||||
var entersavebtn: Button
|
||||
var settingsbtn: Button
|
||||
var quitbtn: Button
|
||||
|
||||
@@ -23,9 +20,6 @@ func _ready() -> void:
|
||||
var start: Dictionary[Variant, Variant] = UiAssembler.build_start_overlay(self, get_node("/root/ConfigDB"))
|
||||
start_overlay = start.overlay
|
||||
box = start.box
|
||||
lvbtn = start.lvbtn
|
||||
resumebtn = start.resumebtn
|
||||
campbtn = start.campbtn
|
||||
careerbtn = start.careerbtn
|
||||
entersavebtn = start.entersavebtn
|
||||
settingsbtn = start.settingsbtn
|
||||
quitbtn = start.quitbtn
|
||||
@@ -86,11 +86,11 @@ static func build_overlays(host: Control, db) -> Dictionary:
|
||||
}
|
||||
|
||||
|
||||
# 开始覆盖层(返回 {overlay, box, lvbtn, resumebtn, campbtn, careerbtn, settingsbtn, quitbtn}——按钮接线归组合根;
|
||||
# 开始覆盖层(返回 {overlay, box, entersavebtn, settingsbtn, quitbtn}——按钮接线归组合根;
|
||||
# 随机种子/数值调整板/两层调试三散件不在主按钮组,收进调试浮窗——
|
||||
# 调试入口=UI 最顶层全局浮层角标(build_debug_badge,本层零调试入口)
|
||||
# 布局=双列 VBox(左操作 56% + 右舞台);按钮动词化+悬停解释
|
||||
#(解释全迁 tooltip,G5);lvbtn 为主操作钮(烛光黄 CANDLE);右列=立绘看台。**界面禁玩法文字墙
|
||||
#(解释全迁 tooltip,G5);entersavebtn 为主操作钮(烛光黄 CANDLE——主菜单三入口化唯一进度入口);右列=立绘看台。**界面禁玩法文字墙
|
||||
#(教学内容归 Beta 帮助手册〔教学引导定稿 P4 丙〕)**;本层无玩法速览牌;
|
||||
# tooltip 主题归全局主题单点(禁在 root 挂程序化 tooltip 主题)。
|
||||
# 返回键集如首行所列,接线归组合根)
|
||||
@@ -124,31 +124,15 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
|
||||
box.add_child(title)
|
||||
box.add_child(HSeparator.new())
|
||||
|
||||
# 组帽·冒险
|
||||
box.add_child(UiKit.label("── 冒 险 ──",UiKit.FS_CAPTION, false, UiKit.WARM_FAINT))
|
||||
# 唯一试玩入口 = 正式「开始冒险」(三关序列);无单关测试直入口
|
||||
var resumebtn := UiKit.primary_button("▶ 继续上局") # 有断点才亮(可见性与关数文案归组合根刷新);主操作钮对齐 demo
|
||||
resumebtn.tooltip_text = "自最近停点恢复"
|
||||
resumebtn.visible = false
|
||||
box.add_child(resumebtn)
|
||||
# 主操作语义对齐 demo(有档时「继续上局」才是首动作=主黄钮,
|
||||
# 「开始冒险」=常规石钮;tooltip 保留)
|
||||
var lvbtn := UiKit.button("▶ 开始冒险")
|
||||
lvbtn.tooltip_text = "三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城"
|
||||
box.add_child(lvbtn)
|
||||
|
||||
# 组帽·营地与系统
|
||||
box.add_child(UiKit.label("── 营地与系统 ──",UiKit.FS_CAPTION, false, UiKit.WARM_FAINT))
|
||||
var campbtn := UiKit.verb_button("营地", UiKit.TEX_ICON_KEYSTONE, "永久强化:钥石换永久属性——跨局成长账本") # 主菜单营地入口
|
||||
box.add_child(campbtn)
|
||||
# 生涯页一级入口(与营地平级;页=局外只读跨局汇总,零跳转零购买)
|
||||
var careerbtn := UiKit.button("生涯")
|
||||
careerbtn.tooltip_text = "跨局生涯汇总:总局数 / 通关局数 / Boss 击杀 / 钥石余额 / 三柜台解锁概览(只读)"
|
||||
box.add_child(careerbtn)
|
||||
var settingsbtn := UiKit.button("设置") # 最小设置面入口
|
||||
# 三入口(主菜单三入口化——营地交互重做卡②,用户裁决 1:进入存档/设置/退出游戏;
|
||||
# 组帽双撤——冒险组帽组内零钮退化态不留、「营地与系统」帽指称失义,追认单留痕)
|
||||
var entersavebtn := UiKit.primary_button("进入存档") # 主操作钮(唯一进度入口)
|
||||
entersavebtn.tooltip_text = "选择一个存档位进入(新档 / 进档 / 删档)"
|
||||
box.add_child(entersavebtn)
|
||||
var settingsbtn := UiKit.button("设置") # 最小设置面入口(行为零变化——契约 2)
|
||||
settingsbtn.tooltip_text = "音量 / 全屏 / 减动效"
|
||||
box.add_child(settingsbtn)
|
||||
# 退出游戏与设置同层并行——只在一级菜单出现
|
||||
# 退出游戏与设置同层并行——只在一级菜单出现(行为零变化——契约 2)
|
||||
var quitbtn := UiKit.button("退出游戏")
|
||||
box.add_child(quitbtn)
|
||||
|
||||
@@ -190,8 +174,7 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
|
||||
right.add_child(stage)
|
||||
|
||||
return {"overlay": overlay, "box": box,
|
||||
"lvbtn": lvbtn, "resumebtn": resumebtn,
|
||||
"campbtn": campbtn, "careerbtn": careerbtn,
|
||||
"entersavebtn": entersavebtn,
|
||||
"settingsbtn": settingsbtn, "quitbtn": quitbtn}
|
||||
|
||||
|
||||
|
||||
@@ -28,23 +28,19 @@ func _ready() -> void:
|
||||
main = load("res://presentation/main.tscn").instantiate()
|
||||
add_child(main)
|
||||
await get_tree().process_frame
|
||||
ProbeUiUtil.isolate_save(main, "fx_shot_probe", false, true, false)
|
||||
ProbeUiUtil.isolate_save(main, "fx_shot_probe", false, true, true) # 末参=swap_save(卡②签名换代——原 refresh_resume 槽位语义退役)
|
||||
# 隔离档即时应用(真实档 fullscreen 态会污染抓帧尺寸〔shot_probe 同款口径〕)
|
||||
main.settings_store.apply()
|
||||
for i in 8:
|
||||
await get_tree().process_frame # UI 装配完成等足帧(canvas_item 空引用窗口)
|
||||
var lvbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "开始冒险", "contains")
|
||||
if lvbtn == null:
|
||||
_fail("开始冒险按钮缺失")
|
||||
return
|
||||
lvbtn.pressed.emit()
|
||||
main._start_adventure_from_menu() # 函数直调中间态(卡② mn10——开始冒险钮已撤)
|
||||
# 等关卡画面出图(choices_presented 异步到达——最多 3s 轮询)
|
||||
for i in 60:
|
||||
await get_tree().process_frame
|
||||
if main.level_screen != null and main.level_screen.visible:
|
||||
break
|
||||
if main.level_screen == null or not main.level_screen.visible:
|
||||
_fail("关卡画面未出现(lvbtn 路径)")
|
||||
_fail("关卡画面未出现(函数直调中间态路径)")
|
||||
return
|
||||
for i in 5:
|
||||
await get_tree().process_frame
|
||||
|
||||
@@ -89,14 +89,14 @@ static func _text_match(text: String, needle: String, mode: String) -> bool:
|
||||
# ── 存档/设置/元进度三面隔离(探针禁碰真实档 user://save.json——SaveManager 路径注入纪律) ──
|
||||
# tag = 隔离档名(不带扩展名,如 "smoke_input_probe_save"——各探针后缀保持不变);先删后建防陈旧档泄入。
|
||||
# mark_first_done = 对齐真实档游玩史口径(模板抽签路径不变);with_settings = 连设置面换注
|
||||
#(隔离 cfg 名 = <tag>_settings.cfg,与被收口探针原文件名逐一同名);refresh_resume = 组合根
|
||||
#(隔离 cfg 名 = <tag>_settings.cfg,与被收口探针原文件名逐一同名);
|
||||
# 「继续上局」按钮重刷;swap_save = 是否换注全局 SaveManager(营地先行段只换 meta 侧不换 SaveManager)。
|
||||
# 返回隔离 SaveManager 实例(调用方常需后续直读余额/重读档)。
|
||||
# SaveManager/MetaProgression 是 autoload 单例——隔离面走单例原地重置
|
||||
#(attach_path 沿 RngService.set_master_seed 先例;MetaProgression 持 save 引用透传,
|
||||
# swap_save=false 分支换 meta 侧引用=独立 iso 实例,只换 meta 不换 save_manager)。
|
||||
static func isolate_save(main, tag: String, mark_first_done: bool = false, with_settings: bool = false,
|
||||
refresh_resume: bool = false, swap_save: bool = true):
|
||||
swap_save: bool = true): # refresh_resume 参数已随卡② _refresh_resume_button 删除退役(mn7)
|
||||
var save_path := "user://%s.json" % tag
|
||||
for p in [save_path, save_path + ".tmp", "user://%s_settings.cfg" % tag]:
|
||||
if FileAccess.file_exists(p):
|
||||
@@ -116,6 +116,22 @@ static func isolate_save(main, tag: String, mark_first_done: bool = false, with_
|
||||
main.get_node("/root/MetaProgression").save = iso # 只换 meta 侧(营地段语义)——SaveManager 全局不动
|
||||
if with_settings:
|
||||
main.settings_store = SettingsStoreScript.new("user://%s_settings.cfg" % tag)
|
||||
if refresh_resume:
|
||||
main._refresh_resume_button()
|
||||
return iso
|
||||
|
||||
# 营地经进档开层(卡② mn9 新路径——campbtn 已撤;槽模板注入隔离命名空间,防碰真实槽
|
||||
# user://save_slot_N.json——真实档红线)。创建=激活=暂行开营地(卡③ Q3 乙落点);
|
||||
# 驱动后写盘目标=隔离槽文件(持久化断言读 user://<tag>_slot_1.json)。返回 false=新档钮缺失(驱动中断)。
|
||||
static func open_camp_via_savesel(main, tag: String) -> bool:
|
||||
var sm = main.get_node("/root/SaveManager")
|
||||
sm.attach_slot_template("user://%s_slot_%%d.json" % tag)
|
||||
for i in range(1, 4): # 夹具清场——空槽起(陈旧槽文件会翻有档态、新档钮缺席)
|
||||
for suf in ["", ".tmp", ".corrupt.bak"]:
|
||||
var sp: String = sm.slot_path(i) + suf
|
||||
if FileAccess.file_exists(sp):
|
||||
DirAccess.remove_absolute(sp)
|
||||
main._open_save_select()
|
||||
var new_btn: Button = main.save_select_overlay._new_btns.get(1)
|
||||
if new_btn == null:
|
||||
return false
|
||||
new_btn.pressed.emit() # 真实按钮信号路径 → _on_save_select_new → create_slot+open_camp
|
||||
return true
|
||||
@@ -21,7 +21,7 @@ func _ready() -> void:
|
||||
await get_tree().process_frame
|
||||
|
||||
# 隔离存档(全 worktree 共享同一份 user://save.json——探针必须换注,禁碰真实档)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_screen_flow", false, false, false, false)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_screen_flow", false, false, false)
|
||||
await get_tree().process_frame
|
||||
|
||||
await _step_boot_menu()
|
||||
@@ -107,11 +107,10 @@ func _step_boot_menu() -> void:
|
||||
|
||||
# ---- ② 菜单 → 营地(真实按钮信号路径)----
|
||||
func _step_menu_to_camp() -> void:
|
||||
var campbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "营地", "prefix")
|
||||
if campbtn == null:
|
||||
_problems.append("②菜单→营地:营地按钮缺失")
|
||||
# 营地经进档开层(卡② mn9 新路径——campbtn 已撤;槽模板注入隔离命名空间)
|
||||
if not ProbeUiUtil.open_camp_via_savesel(main, "smoke_screen_flow_camp"):
|
||||
_problems.append("②菜单→营地:选档层新档钮缺失(新路径驱动中断)")
|
||||
return
|
||||
campbtn.pressed.emit()
|
||||
await _frames()
|
||||
_expect_exclusive("②菜单→营地", "营地")
|
||||
|
||||
@@ -123,6 +122,8 @@ func _step_camp_back_to_menu() -> void:
|
||||
return
|
||||
main.camp_overlay.closed.emit()
|
||||
await _frames()
|
||||
main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态——卡④ 换代点)
|
||||
await _frames()
|
||||
_expect_exclusive("③营地→菜单(回退)", "菜单")
|
||||
|
||||
|
||||
@@ -130,9 +131,13 @@ func _step_camp_back_to_menu() -> void:
|
||||
# ---- 选档界面开合(卡③ sl10):函数直调开层(「进入存档」钮归卡② mn3)→屏级互斥采样→
|
||||
# 返回钮真实信号路径关闭→ESC 语境不响应(卡⑤ 契约 2 范围外——零实现即断言)。----
|
||||
func _step_save_select_open_back() -> void:
|
||||
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_savesel", false, false, false, true)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_savesel", false, false, true)
|
||||
main.save_manager.attach_slot_template("user://smoke_screen_flow_savesel_slot_%d.json")
|
||||
main._open_save_select()
|
||||
var esb: Button = ProbeUiUtil.find_button(main._start_overlay, "进入存档", "prefix")
|
||||
if esb == null:
|
||||
_problems.append("[savesel] mn3 进入存档钮缺失(卡② 交付物)")
|
||||
return
|
||||
esb.pressed.emit() # 真实按钮信号路径 → _open_save_select(卡② mn3 点击链——卡③ 直调中间态就此闭环)
|
||||
await get_tree().process_frame
|
||||
var seals := _screen_seals()
|
||||
if not main.save_select_overlay.visible or not seals_check_single(seals):
|
||||
@@ -172,13 +177,8 @@ func seals_check_single(f: Dictionary) -> bool:
|
||||
|
||||
|
||||
func _step_menu_to_adventure() -> void:
|
||||
var lvbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "开始冒险", "contains")
|
||||
if lvbtn == null:
|
||||
lvbtn = ProbeUiUtil.find_button(main._start_overlay, "冒险", "contains")
|
||||
if lvbtn == null:
|
||||
_problems.append("④菜单→冒险:开始冒险按钮缺失")
|
||||
return
|
||||
lvbtn.pressed.emit()
|
||||
# 开始冒险钮已随三入口化撤出——函数直调中间态(卡② mn10;卡④ 大门两分支换代)
|
||||
main._start_adventure_from_menu()
|
||||
await _frames(3)
|
||||
_expect_exclusive("④菜单→冒险", "冒险")
|
||||
_expect_adventure_seal("④菜单→冒险", true)
|
||||
|
||||
+15
-22
@@ -5,7 +5,7 @@
|
||||
# Godot_console.exe --path . res://smoke/shot_probe.tscn -- <输出目录>
|
||||
# 流程 = 真实按钮信号路径驱动(ui_click_probe 同款;存档/设置/元进度三面换注隔离档——禁碰真实档,
|
||||
# 坑册「断点写盘随 save_manager 引用走」教训同款覆盖):菜单(启动态)→ 设置面(settingsbtn
|
||||
# 真实信号路径)→ 生涯页(careerbtn 同款)→ 营地(campbtn)→ 关卡画面(lvbtn→停点出图)→
|
||||
# 真实信号路径)→ 生涯页(函数直调中间态——卡② mn10)→ 营地(进档开层新路径——mn9)→ 关卡画面(函数直调中间态→停点出图)→
|
||||
# 战斗(level_screen.press_candidate(0) 真实选路提交)→ 状态面板(地图屏状态角标真实信号路径)。
|
||||
# 每屏双帧 + frame_post_draw 同步后抓 get_viewport().get_texture(),PNG 落输出目录;
|
||||
# 最小自检 = 七件存在且非零字节(像素方差断言归 tools/shot_checker.py——B 档骨架分工)。
|
||||
@@ -100,16 +100,13 @@ func _ready() -> void:
|
||||
else:
|
||||
set_close.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
# ①c 生涯页(careerbtn 真实信号路径,ui_struct_probe 同款入口链)
|
||||
var careerbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "生涯", "prefix")
|
||||
if careerbtn == null:
|
||||
_problems.append("生涯入口缺失(开始层 careerbtn)")
|
||||
else:
|
||||
careerbtn.pressed.emit()
|
||||
# ①c 生涯页(函数直调中间态——卡② mn10:careerbtn 已撤,卡④ 笔记本改挂前无 UI 路径)
|
||||
if true:
|
||||
main._open_career()
|
||||
for i in 3:
|
||||
await get_tree().process_frame
|
||||
if not main.career_overlay.visible or main._start_overlay.visible:
|
||||
_problems.append("生涯页未打开或开始层未隐藏(careerbtn 路径)")
|
||||
_problems.append("生涯页未打开或开始层未隐藏(函数直调中间态路径)")
|
||||
else:
|
||||
_meta["career_title"] = ProbeUiUtil.label_rect(main.career_overlay, "生 涯")
|
||||
await _snap("career")
|
||||
@@ -122,26 +119,22 @@ func _ready() -> void:
|
||||
await get_tree().process_frame
|
||||
if main.career_overlay.visible or not main._start_overlay.visible:
|
||||
_problems.append("生涯页关闭后页未隐藏或开始层未恢复")
|
||||
# ② 营地
|
||||
var campbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "营地", "contains")
|
||||
if campbtn == null:
|
||||
_problems.append("营地入口缺失(开始层 campbtn)")
|
||||
# ② 营地(进档开层新路径——卡② mn9;槽模板注入隔离命名空间)
|
||||
if not ProbeUiUtil.open_camp_via_savesel(main, "smoke_shot_probe_camp"):
|
||||
_problems.append("营地入口缺失(选档层新档钮——新路径驱动中断)")
|
||||
else:
|
||||
campbtn.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
await _snap("camp")
|
||||
var close_btn: Button = ProbeUiUtil.find_button(main.camp_overlay, "关闭营地", "contains")
|
||||
if close_btn != null:
|
||||
close_btn.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
# ③ 关卡画面(开始冒险→停点出图——入口停点语义)
|
||||
var lvbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "开始冒险", "contains")
|
||||
if lvbtn == null:
|
||||
_problems.append("开始冒险按钮缺失(开始层 lvbtn)")
|
||||
else:
|
||||
lvbtn.pressed.emit()
|
||||
for i in 4:
|
||||
await get_tree().process_frame
|
||||
main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态)
|
||||
await get_tree().process_frame
|
||||
# ③ 关卡画面(开始冒险→停点出图——入口停点语义;函数直调中间态 mn10)
|
||||
main._start_adventure_from_menu()
|
||||
for i in 4:
|
||||
await get_tree().process_frame
|
||||
await _snap("level")
|
||||
# GP 常驻徽章断言(读数=runner.gp 现值,刷新=写路径回执后重查〔open_choices〕)
|
||||
var gp_label: Label = ProbeUiUtil.find_label(main.level_screen, "◈ ")
|
||||
@@ -190,7 +183,7 @@ func _ready() -> void:
|
||||
if main.status_panel.visible:
|
||||
_problems.append("状态面板关闭后未隐藏(继续钮路径)")
|
||||
else:
|
||||
_problems.append("关卡画面未出现(lvbtn 路径)")
|
||||
_problems.append("关卡画面未出现(函数直调中间态路径)")
|
||||
# ── 几何元数据落盘(shot_checker 取样坐标源) ──
|
||||
var mf := FileAccess.open(out_dir.path_join("shot_meta.json"), FileAccess.WRITE)
|
||||
if mf != null:
|
||||
|
||||
+34
-30
@@ -159,8 +159,8 @@ func _smoke_scene_split() -> void:
|
||||
var menu: Node = load("res://presentation/scenes/menu_screen.tscn").instantiate()
|
||||
root.add_child(menu)
|
||||
await process_frame
|
||||
check(menu.start_overlay != null and menu.lvbtn != null and menu.resumebtn != null and menu.campbtn != null and menu.careerbtn != null and menu.settingsbtn != null and menu.quitbtn != null,
|
||||
"V2 菜单屏壳独立实例化(start_overlay+操作组六钮在位)")
|
||||
check(menu.start_overlay != null and menu.entersavebtn != null and menu.settingsbtn != null and menu.quitbtn != null,
|
||||
"V2 菜单屏壳独立实例化(start_overlay+操作组三钮在位——主菜单三入口化)〔卡② mn1〕")
|
||||
check(menu.start_overlay.visible, "V2 菜单层默认可见(非模态全屏态)")
|
||||
check(menu.mouse_filter == Control.MOUSE_FILTER_IGNORE, "V2 屏壳根零鼠标截获(IGNORE——全屏 STOP 壳吃输入病灶回归闸)")
|
||||
menu.queue_free()
|
||||
@@ -266,9 +266,8 @@ func _smoke_boot_chain() -> void:
|
||||
var sm = main.get_node("/root/SaveManager")
|
||||
# ④-1 boot 路径:启动态钉死(卡① sv2)——boot 无激活态、断点在档恒否,续玩钮恒隐
|
||||
#(原「按钮态==真实档断点态」关系判据随启动态换代改写:test-conventions §9.5 申报在案,卡② mn8 再承接)
|
||||
check(not sm.has_breakpoint() and not main._resume_btn.visible,
|
||||
"V2d 续玩钮 boot 态恒隐(无激活态——启动态不隐式激活;断点在档=%s visible=%s)〔装配生命批 V2·卡① sv2 改写〕" % [
|
||||
str(sm.has_breakpoint()), str(main._resume_btn.visible)])
|
||||
check(not sm.has_breakpoint(),
|
||||
"V2d 续玩钮族退役·boot 无断点在档(启动态不隐式激活——卡① sv2 钉死;恒隐判据随钮退役由本断言+V2d 三钮在位承接)〔装配生命批 V2·卡② mn8 改写〕")
|
||||
# ④-1b 启动态三断言+旧单档迁移不变式(卡① sv2/sv12——真实 autoload boot 链)
|
||||
check(sm.active_slot() == 0 and not sm.has_write_target(),
|
||||
"V2-s1 boot 后无激活态(active_slot=0、写盘目标空)〔卡① sv2〕")
|
||||
@@ -278,24 +277,18 @@ func _smoke_boot_chain() -> void:
|
||||
"V2-s3 boot 无激活写盘拒绝(write_to_disk=false 生产入口)〔卡① sv3〕")
|
||||
check(not (FileAccess.file_exists("user://save.json") and not FileAccess.file_exists(sm.slot_path(1))),
|
||||
"V2-s4 旧单档迁移不变式(旧档在则槽 1 必在——Q1 甲一次性迁移已发生)〔卡① sv12〕")
|
||||
# ④-2 隔离新档双向(attach 原地重置——绝不碰真实档 user://save.json;刷新单口与 boot 路径同源)
|
||||
# ④-2 三钮承接(卡② mn8——V2d 续玩钮族随钮退役废止:钮可见性联动面由卡① V2-s 启动态断言与
|
||||
# sv11 attach 语义段承接;attach 原地重置语义保持——绝不碰真实档 user://save.json)
|
||||
for p in ["user://smoke_boot_chain.json", "user://smoke_boot_chain.json.tmp"]:
|
||||
if FileAccess.file_exists(p):
|
||||
DirAccess.remove_absolute(p)
|
||||
sm.attach_path("user://smoke_boot_chain.json")
|
||||
main._refresh_resume_button()
|
||||
check(not sm.has_breakpoint() and not main._resume_btn.visible,
|
||||
"V2d 续玩钮·无断点态隐藏(visible=%s has_breakpoint=%s)〔装配生命批 V2〕" % [
|
||||
str(main._resume_btn.visible), str(sm.has_breakpoint())])
|
||||
sm.set_breakpoint({"level_index": 2, "master_seed": 42})
|
||||
main._refresh_resume_button()
|
||||
check(sm.has_breakpoint() and main._resume_btn.visible,
|
||||
"V2d 续玩钮·有断点态可见(visible=%s has_breakpoint=%s)〔装配生命批 V2〕" % [
|
||||
str(main._resume_btn.visible), str(sm.has_breakpoint())])
|
||||
sm.clear_breakpoint()
|
||||
main._refresh_resume_button()
|
||||
check(not main._resume_btn.visible,
|
||||
"V2d 续玩钮·清断点后回隐藏(visible=%s)〔装配生命批 V2〕" % str(main._resume_btn.visible))
|
||||
check(main._menu_screen.entersavebtn != null and main._menu_screen.settingsbtn != null
|
||||
and main._menu_screen.quitbtn != null,
|
||||
"V2d 三钮在位·进入存档/设置/退出游戏(续玩钮族退役后主菜单操作组承接)〔卡② mn1/mn8〕")
|
||||
for old_btn in ["lvbtn", "resumebtn", "campbtn", "careerbtn"]:
|
||||
check(not (old_btn in main._menu_screen),
|
||||
"V2d 四旧钮句柄零命中·%s(彻底撤出——禁隐藏态禁置灰态残留)〔卡② mn2〕" % old_btn)
|
||||
# ⑤ 闲时会话(_ready 即建、永非 null、在树)
|
||||
check(main.run_scope != null and not main.run_scope.is_adventure and main.run_scope.is_inside_tree(),
|
||||
"V2e run_scope 非空且为闲时会话(is_adventure=false+is_inside_tree)〔装配生命批 V2〕")
|
||||
@@ -327,11 +320,10 @@ func _smoke_lifecycle_matrix() -> void:
|
||||
if FileAccess.file_exists(p):
|
||||
DirAccess.remove_absolute(p)
|
||||
sm.attach_path("user://smoke_lifecycle.json")
|
||||
main._refresh_resume_button() # 隔离后重同步(boot 时按钮态反映的是真实档——T2 已断 boot 关系,此处按隔离档定基)
|
||||
main.debug_overlay.seed_edit.text = "42"
|
||||
# 阶段①闲时
|
||||
await _stage_faces(main, "V3a 闲时", "null", "null", "null",
|
||||
{"mf_start": true, "mf_inter": false, "mf_rows_empty": true, "start_vis": true, "resume_vis": false})
|
||||
{"mf_start": true, "mf_inter": false, "mf_rows_empty": true, "start_vis": true})
|
||||
# 阶段②开局停点(地图选路停点态)
|
||||
main._start_adventure_from_menu()
|
||||
for i in range(6):
|
||||
@@ -416,11 +408,18 @@ func _smoke_lifecycle_matrix() -> void:
|
||||
elif modal_name == "career":
|
||||
main._open_career()
|
||||
elif modal_name == "camp":
|
||||
var campbtn: Button = main._menu_screen.campbtn
|
||||
if campbtn == null:
|
||||
check(false, "V3g 营地入口缺失(驱动中断)〔装配生命批 V3〕")
|
||||
# 营地经进档开层(卡② mn9 新路径——campbtn 已撤);槽模板注入隔离命名空间
|
||||
#(防碰真实槽 user://save_slot_N.json——真实档红线),营地闭合后恢复生命周期 attach 写盘目标
|
||||
#(卡① sv3 无激活拒写——后续阶段断点写盘依赖)
|
||||
sm.attach_slot_template("user://smoke_lifecycle_slot_%d.json")
|
||||
main._open_save_select()
|
||||
for i in range(2):
|
||||
await process_frame
|
||||
var ssel_new: Button = main.save_select_overlay._new_btns.get(1)
|
||||
if ssel_new == null:
|
||||
check(false, "V3g 营地入口缺失(选档层新档钮驱动中断)〔装配生命批 V3〕")
|
||||
continue
|
||||
campbtn.pressed.emit()
|
||||
ssel_new.pressed.emit() # 创建=激活=暂行开营地(卡③ Q3 乙落点)
|
||||
else:
|
||||
main._show_debug_overlay()
|
||||
for i in range(4):
|
||||
@@ -441,6 +440,15 @@ func _smoke_lifecycle_matrix() -> void:
|
||||
await process_frame
|
||||
await _stage_faces(main, "V3g 模态合·%s" % modal_name, "null", "null", "null",
|
||||
{"mf_start": true, "start_vis": true})
|
||||
if modal_name == "camp":
|
||||
main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态——卡④ 换代点)
|
||||
for i in range(2):
|
||||
await process_frame
|
||||
sm.attach_path("user://smoke_lifecycle.json") # 恢复生命周期写盘目标
|
||||
for suf in ["", ".tmp"]:
|
||||
var slot_p: String = "user://smoke_lifecycle_slot_1.json" + suf
|
||||
if FileAccess.file_exists(slot_p):
|
||||
DirAccess.remove_absolute(slot_p)
|
||||
# 阶段⑧两连局(第二局全新会话——旧局对象不复用、脏态零残留)
|
||||
var first_adv = main.run_scope.adventure
|
||||
main.debug_overlay.seed_edit.text = "43"
|
||||
@@ -475,8 +483,6 @@ func _smoke_lifecycle_matrix() -> void:
|
||||
"keystone_drops": [], "bonus_taken": {},
|
||||
"bonus_pending": {"candidates": [{"kind": "heal", "tier": "common"}], "payload": {"gp_dropped": 0}},
|
||||
})
|
||||
main._refresh_resume_button()
|
||||
check(main._resume_btn.visible, "V3i 续玩钮·断点在档可见〔装配生命批 V3〕")
|
||||
var idle_scope = main.run_scope
|
||||
main._resume_from_menu()
|
||||
check(main.run_scope != idle_scope and main.run_scope.is_inside_tree(),
|
||||
@@ -570,9 +576,7 @@ func _stage_faces(main: Node, tag: String, adv: String, run: String, set: String
|
||||
"end_open":
|
||||
if main._end_overlay.is_open() != bool(extra[k]):
|
||||
bad += " _end_overlay.is_open 应=%s" % str(extra[k])
|
||||
"resume_vis":
|
||||
if main._resume_btn.visible != bool(extra[k]):
|
||||
bad += " _resume_btn.visible 应=%s" % str(extra[k])
|
||||
|
||||
"start_vis":
|
||||
if main._start_overlay.visible != bool(extra[k]):
|
||||
bad += " _start_overlay.visible 应=%s" % str(extra[k])
|
||||
|
||||
@@ -20,17 +20,13 @@ func _ready() -> void:
|
||||
# 存档/设置两面隔离(ProbeUiUtil.isolate_save 现行事实源,先删后建防陈旧档泄入)——
|
||||
# 隔离面走 attach_path 原地重置 autoload 单例:组合根 save_manager/meta 是getter-only
|
||||
# 读视图,直接赋值无效,隔离必须落在单例上。
|
||||
ProbeUiUtil.isolate_save(main, "t17_defer_probe", false, true, false)
|
||||
ProbeUiUtil.isolate_save(main, "t17_defer_probe", false, true, true) # 末参=swap_save(卡②签名换代——原 refresh_resume 槽位语义退役)
|
||||
# 本探针验证完整动画档的演播后排窗——强制 motion_scale=1.0(隔离档替换在 boot 后,
|
||||
# 减动效已随真档 settings.cfg 应用于引擎态;减动效档=consume_now 快路、开窗即时,另属语义)
|
||||
UiKit.motion_scale = 1.0
|
||||
for i in 8:
|
||||
await get_tree().process_frame
|
||||
var lvbtn: Button = _find_button_by_sub(main._start_overlay, "开始冒险")
|
||||
if lvbtn == null:
|
||||
_fail("开始冒险按钮缺失")
|
||||
return
|
||||
lvbtn.pressed.emit()
|
||||
main._start_adventure_from_menu() # 函数直调中间态(卡② mn10——开始冒险钮已撤)
|
||||
for i in 60:
|
||||
await get_tree().process_frame
|
||||
if main.level_screen != null and main.level_screen.visible:
|
||||
|
||||
@@ -49,20 +49,20 @@ func _ready() -> void:
|
||||
# 任何 UI 不遮挡;浮层角标遮挡判据见设置面段)
|
||||
if main.debug_overlay.visible:
|
||||
_problems.append("调试浮窗 boot 自动开(菜单优先失守)")
|
||||
# ---- 营地购买合成点击路径(campbtn/购买/关闭全走真实按钮信号路径;
|
||||
# ---- 营地购买合成点击路径(选档进档开层→购买→关闭全走真实按钮信号路径;
|
||||
# 隔离存档换注 main.meta 保确定性(禁碰真实档 user://save.json);陈旧档段首清理)----
|
||||
for p0 in ["user://smoke_click_probe_reset.json", "user://smoke_click_probe_reset.json.tmp"]:
|
||||
if FileAccess.file_exists(p0):
|
||||
DirAccess.remove_absolute(p0) # 重置档段前清场兜底(营地/设置段不触该档——防陈旧断点泄入后续段)
|
||||
var iso_c = ProbeUiUtil.isolate_save(main, "smoke_click_probe_camp", false, false, false, false)
|
||||
var campbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "营地", "prefix")
|
||||
if campbtn == null:
|
||||
_problems.append("营地入口按钮缺失(开始层 campbtn)")
|
||||
# swap=true(整链换注——购买写盘经 autoload 落隔离槽文件,与下方持久化核验同源;
|
||||
# 原 swap=false 形态的写盘走 iso 实例旧路径,与槽文件断言不同源——卡② mn9 换代)
|
||||
var iso_c = ProbeUiUtil.isolate_save(main, "smoke_click_probe_camp", false, false, true)
|
||||
if not ProbeUiUtil.open_camp_via_savesel(main, "smoke_click_probe_camp"):
|
||||
_problems.append("营地入口缺失(选档层新档钮——mn9 新路径驱动中断)")
|
||||
else:
|
||||
campbtn.pressed.emit() # 真实按钮信号路径 → 组合根 _open_camp
|
||||
await get_tree().process_frame
|
||||
if not main.camp_overlay.visible:
|
||||
_problems.append("营地层未打开(点击路径)")
|
||||
_problems.append("营地层未打开(进档开层新路径)")
|
||||
elif main.camp_overlay._tree_buy_btns.is_empty():
|
||||
_problems.append("树淬炼柜台购买钮缺失(点击路径——四柜台重排后树=主界面)")
|
||||
else:
|
||||
@@ -83,7 +83,7 @@ func _ready() -> void:
|
||||
await get_tree().process_frame
|
||||
if int(iso_c.keystone_balance()) != bal_before - price:
|
||||
_problems.append("营地树购买未出账(%d→%d 应 −%d)" % [bal_before, iso_c.keystone_balance(), price])
|
||||
var iso_chk = load("res://core/save_manager.gd").new("user://smoke_click_probe_camp.json")
|
||||
var iso_chk = load("res://core/save_manager.gd").new("user://smoke_click_probe_camp_slot_1.json")
|
||||
iso_chk.load_from_disk()
|
||||
if int(iso_chk.tree_level("sp_hp")) != 1:
|
||||
_problems.append("营地树购买未持久(reload 后级 != 1)")
|
||||
@@ -117,12 +117,14 @@ func _ready() -> void:
|
||||
else:
|
||||
side_b.pressed.emit() # 合成切态点击 → _on_camp_fork_toggle → meta.tree_toggle_fork
|
||||
await get_tree().process_frame
|
||||
var iso_fk = load("res://core/save_manager.gd").new("user://smoke_click_probe_camp.json")
|
||||
var iso_fk = load("res://core/save_manager.gd").new("user://smoke_click_probe_camp_slot_1.json")
|
||||
iso_fk.load_from_disk()
|
||||
if String(iso_fk.fork_side("fg_posture")) != "b":
|
||||
_problems.append("Fork 切态未持久(reload 后激活态 != b)")
|
||||
main._on_camp_closed()
|
||||
await get_tree().process_frame
|
||||
main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态——卡④ 换代点)
|
||||
await get_tree().process_frame
|
||||
if main.camp_overlay.visible or not main._start_overlay.visible:
|
||||
_problems.append("营地关闭后未恢复开始层")
|
||||
# ---- 选档界面行为走查(迭代 33 卡③):sl5 空槽新档链/sl6 有档槽进档链/sl7 删档二次确认双路径
|
||||
@@ -134,7 +136,7 @@ func _ready() -> void:
|
||||
var cp: String = csel_tpl % i + suf
|
||||
if FileAccess.file_exists(cp):
|
||||
DirAccess.remove_absolute(cp)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_click_probe_savesel", true, false, false, true)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_click_probe_savesel", true, false, true)
|
||||
main.save_manager.attach_slot_template(csel_tpl)
|
||||
var f_c2 := FileAccess.open(csel_tpl % 2, FileAccess.WRITE)
|
||||
f_c2.store_string(JSON.stringify({"version": 7, "meta": {"keystone_balance": 100,
|
||||
@@ -290,11 +292,9 @@ func _ready() -> void:
|
||||
_problems.append("设置面仍含退出游戏按钮(二轮 D1——只在一级菜单出现)")
|
||||
# ---- 生涯页段(入口点击链+关闭回返,真实按钮信号路径;本页只读零写,
|
||||
# 值断言归冒烟投影段与 ui_struct 结构族,此处只验开合路径与零跳转)----
|
||||
var career_btn: Button = ProbeUiUtil.find_button(main._start_overlay, "生涯", "prefix")
|
||||
if career_btn == null:
|
||||
_problems.append("生涯入口按钮缺失(开始层 careerbtn)")
|
||||
else:
|
||||
career_btn.pressed.emit() # 真实按钮信号路径 → 组合根 _open_career
|
||||
# 生涯页驱动=函数直调中间态(卡② mn10——careerbtn 已撤,卡④ 笔记本改挂前无 UI 路径)
|
||||
if true:
|
||||
main._open_career()
|
||||
await get_tree().process_frame
|
||||
if not main.career_overlay.visible or main._start_overlay.visible:
|
||||
_problems.append("生涯页未打开(点击路径)")
|
||||
@@ -316,12 +316,7 @@ func _ready() -> void:
|
||||
if main.career_overlay.visible or not main._start_overlay.visible:
|
||||
_problems.append("生涯页关闭后未恢复开始层")
|
||||
# 换回全新零档(营地购买态不泄入后续冒险段——确定性;档案残留下次段首清理兜底)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_click_probe_reset", true, false, true) # 零档换注 + 继续上局按钮重刷(原三行样板收口)
|
||||
var resume_btn0: Button = ProbeUiUtil.find_button(main._start_overlay, "▶ 继续上局", "prefix")
|
||||
if resume_btn0 == null:
|
||||
_problems.append("继续上局按钮缺失(开始层 resumebtn——装配器)")
|
||||
elif resume_btn0.visible:
|
||||
_problems.append("无断点态继续上局按钮未隐藏(卡② AC①——新档合法空态)")
|
||||
ProbeUiUtil.isolate_save(main, "smoke_click_probe_reset", true, false, true) # 零档换注(继续上局钮已随三入口化撤出——卡② mn8)
|
||||
main.debug_overlay.set_sliders(400, 200) # 高加成保 L1 可通关——L2 岔路选路段只能经冒险推进到达(单关直入口退役)
|
||||
main.debug_overlay.seed_edit.text = "42" # 种子钉死(种子框默认为空=非首局随机,行为走查确定性禁依赖默认分支)
|
||||
var t1 := Time.get_ticks_msec()
|
||||
@@ -555,73 +550,9 @@ func _ready() -> void:
|
||||
# 战败态前提失配——记录不计 problem(返回路径已实机目检)。
|
||||
if not _closed_via_abandon:
|
||||
_problems.append("断点段:终局返回未回开始菜单")
|
||||
var resume_btn: Button = ProbeUiUtil.find_button(main._start_overlay, "▶ 继续上局", "prefix")
|
||||
if resume_btn != null and resume_btn.visible:
|
||||
_problems.append("断点段:退出清断点后继续上局按钮未隐藏(卡②/T3 AC③)")
|
||||
# ② 中断→续玩:新冒险达入口停点=断点在档 → 合成回菜单(模拟关游戏重开)→ 按钮点亮 → 点击恢复至停点
|
||||
var lv_btn: Button = ProbeUiUtil.find_button(main._start_overlay, "▶ 开始冒险", "prefix")
|
||||
if lv_btn == null or resume_btn == null:
|
||||
_problems.append("断点段:开始冒险/继续上局按钮缺失")
|
||||
else:
|
||||
lv_btn.pressed.emit() # 无断点态单击直启(不触发二次确认)
|
||||
await get_tree().process_frame
|
||||
if not main.level_screen.visible:
|
||||
if not _closed_via_abandon:
|
||||
_problems.append("断点段:无断点开新冒险未达入口停点")
|
||||
else:
|
||||
iso_chk.load_from_disk()
|
||||
if not iso_chk.has_breakpoint():
|
||||
_problems.append("断点段:入口停点断点未写盘(卡①写面失守)")
|
||||
var cand_before: Array = main.run_scope.runner.next_candidate_ids()
|
||||
# 合成「关游戏重开回菜单」(探针专用——真实路径无此入口;断点已在盘)
|
||||
main._exit_level_screen()
|
||||
main._start_overlay.visible = true
|
||||
main.run_scope.adventure = null
|
||||
main._refresh_resume_button()
|
||||
await get_tree().process_frame
|
||||
if not resume_btn.visible:
|
||||
_problems.append("断点段:有断点态继续上局按钮未点亮(卡② AC②前置)")
|
||||
else:
|
||||
resume_btn.pressed.emit() # 真实按钮信号路径 → _resume_from_menu → resume_adventure
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
if main.run_scope.adventure == null or main.run_scope.runner == null or not main.level_screen.visible:
|
||||
_problems.append("断点段:续玩未恢复至停点(关卡画面未现)")
|
||||
else:
|
||||
var cand_after: Array = main.run_scope.runner.next_candidate_ids()
|
||||
if cand_after.size() != cand_before.size() or (cand_after.size() > 0 and int(cand_after[0]) != int(cand_before[0])):
|
||||
_problems.append("断点段:续玩候选与中断前不一致(停点重建失准)")
|
||||
if not iso_chk.load_from_disk() or not iso_chk.has_breakpoint():
|
||||
_problems.append("断点段:续玩误清断点(只在三结局清)")
|
||||
# ③ 互斥确认弹窗(二轮修改批 A):断点在档点开始冒险 → 弹确认框;取消=回菜单;开新冒险=提交
|
||||
main._exit_level_screen()
|
||||
main._start_overlay.visible = true
|
||||
main.run_scope.adventure = null
|
||||
main._refresh_resume_button()
|
||||
await get_tree().process_frame
|
||||
lv_btn.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
if not main.confirm_dialog.is_open() or main.run_scope.adventure != null:
|
||||
_problems.append("断点段:有断点点开始冒险未弹确认框(二轮 A 失守)")
|
||||
var cancel_btn: Button = ProbeUiUtil.find_button(main.confirm_dialog, "取消", "contains")
|
||||
if cancel_btn == null:
|
||||
_problems.append("断点段:确认框取消按钮缺失")
|
||||
else:
|
||||
cancel_btn.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
if main.confirm_dialog.is_open() or main.run_scope.adventure != null or not main._start_overlay.visible:
|
||||
_problems.append("断点段:取消未回开始菜单(二轮 A)")
|
||||
lv_btn.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
var confirm_btn: Button = ProbeUiUtil.find_button(main.confirm_dialog, "开新冒险", "contains")
|
||||
if confirm_btn == null:
|
||||
_problems.append("断点段:确认框开新冒险按钮缺失")
|
||||
else:
|
||||
confirm_btn.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
if main.run_scope.adventure == null or main._start_overlay.visible or main.confirm_dialog.is_open():
|
||||
_problems.append("断点段:确认开新冒险后未开局(二轮 A)")
|
||||
# ②③ 中断→续玩全链+互斥确认两分支:随三入口化撤出(卡② §7.2 申报——断点确认探针段移交
|
||||
# 卡④大门 T5 接收,两头登记禁静默删除;续玩钮已退役,主菜单确认链已摘 mn6)。
|
||||
# ① 战斗收口断点写盘断言保留(上方——冒险流直调中间态 mn10)。
|
||||
print("[click_probe] 循环退出(done=%s budget=%s)问题=%d" % [
|
||||
str(_done), str(action_budget), _problems.size()])
|
||||
for p in _problems:
|
||||
|
||||
@@ -23,15 +23,13 @@ func _ready() -> void:
|
||||
# ---- 营地覆盖层(主菜单入口/开合/余额文案/购买禁用态;
|
||||
# 隔离存档换注 main.meta 保确定性(禁碰真实档 user://save.json——SaveManager 路径注入纪律;
|
||||
# 营地先行段只换 meta 不换 save_manager——冒险段换注零档在前)----
|
||||
ProbeUiUtil.isolate_save(main, "smoke_ui_probe_camp", false, false, false, false)
|
||||
var campbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "营地", "prefix")
|
||||
if campbtn == null:
|
||||
problems.append("营地入口按钮缺失(开始层 campbtn)")
|
||||
ProbeUiUtil.isolate_save(main, "smoke_ui_probe_camp", false, false, false)
|
||||
if not ProbeUiUtil.open_camp_via_savesel(main, "smoke_ui_probe_camp"):
|
||||
problems.append("营地入口缺失(选档层新档钮——mn9 新路径驱动中断)")
|
||||
else:
|
||||
campbtn.pressed.emit() # 合成信号路径(真实按钮 → 组合根 _open_camp)
|
||||
await get_tree().process_frame
|
||||
if not main.camp_overlay.visible:
|
||||
problems.append("营地层未打开(campbtn 路径)")
|
||||
problems.append("营地层未打开(进档开层新路径)")
|
||||
elif main._start_overlay.visible:
|
||||
problems.append("营地层打开时开始层未隐藏(规范 2.3 遮挡纪律)")
|
||||
else:
|
||||
@@ -51,6 +49,8 @@ func _ready() -> void:
|
||||
problems.append("秘宝匣柜台行数错误(%d ≠ 12——迭代 22 秘宝批换代)" % main.camp_overlay._workshop_rows.size())
|
||||
main._on_camp_closed()
|
||||
await get_tree().process_frame
|
||||
main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态——卡④ 换代点)
|
||||
await get_tree().process_frame
|
||||
if main.camp_overlay.visible or not main._start_overlay.visible:
|
||||
problems.append("营地关闭后未恢复开始层(开合往返失守)")
|
||||
# 换回全新零档(营地段购买态不泄入后续冒险段——确定性;先删后建防陈旧档泄入)
|
||||
|
||||
@@ -38,35 +38,32 @@ func _ready() -> void:
|
||||
main._on_settings_closed()
|
||||
_settle()
|
||||
|
||||
var campbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "营地", "prefix")
|
||||
if campbtn != null:
|
||||
campbtn.pressed.emit()
|
||||
if not ProbeUiUtil.open_camp_via_savesel(main, "smoke_ui_struct_probe_menu"):
|
||||
problems.append("[camp] 营地入口缺失(选档层新档钮——mn9 新路径驱动中断)")
|
||||
else:
|
||||
_settle()
|
||||
await _audit("camp", [main.camp_overlay])
|
||||
main._on_camp_closed()
|
||||
_settle()
|
||||
else:
|
||||
problems.append("[camp] 营地入口按钮缺失(驱动中断)")
|
||||
main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态——卡④ 换代点)
|
||||
_settle()
|
||||
|
||||
# ---- 生涯页:入口点击链(合成点击真路径=pressed.emit→组合根 _open_career)→
|
||||
# 结构断言族→只读巡检(契约 3)+零动效契约+零跳转契约(提纲 P4 甲)→组合根真实路径关闭。
|
||||
#(登记序/树序契约统一在全模态 _modal_registry_contract——boot 段跑)----
|
||||
var careerbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "生涯", "prefix")
|
||||
if careerbtn != null:
|
||||
careerbtn.pressed.emit()
|
||||
_settle()
|
||||
if not main.career_overlay.visible or main._start_overlay.visible:
|
||||
problems.append("[career] 生涯页未打开或开始层未隐藏(入口点击链断裂)")
|
||||
await _audit("career", [main.career_overlay])
|
||||
_career_readonly_contract(main)
|
||||
_career_zero_motion_contract(main)
|
||||
_career_nojump_contract(main)
|
||||
main._on_career_closed()
|
||||
_settle()
|
||||
if main.career_overlay.visible or not main._start_overlay.visible:
|
||||
problems.append("[career] 关闭后页未隐藏或开始层未恢复(模态栈单口失守)")
|
||||
else:
|
||||
problems.append("[career] 生涯入口按钮缺失(开始层 careerbtn)")
|
||||
# 生涯页驱动=函数直调中间态(卡② mn9/mn10——careerbtn 已撤,卡④ 营地笔记本改挂前无 UI 路径)
|
||||
main._open_career()
|
||||
_settle()
|
||||
if not main.career_overlay.visible or main._start_overlay.visible:
|
||||
problems.append("[career] 生涯页未打开或开始层未隐藏(函数直调中间态断裂)")
|
||||
await _audit("career", [main.career_overlay])
|
||||
_career_readonly_contract(main)
|
||||
_career_zero_motion_contract(main)
|
||||
_career_nojump_contract(main)
|
||||
main._on_career_closed()
|
||||
_settle()
|
||||
if main.career_overlay.visible or not main._start_overlay.visible:
|
||||
problems.append("[career] 关闭后页未隐藏或开始层未恢复(模态栈单口失守)")
|
||||
|
||||
# ---- 选档界面(迭代 33 卡③):函数直调开层(「进入存档」钮归卡② mn3——点击链在卡② 承接),
|
||||
# sl1 三槽呈现/sl2 摘要三项逐槽读数/sl3 摘要禁项/sl4 操作集二分/sl9 重启链不预选。
|
||||
@@ -197,7 +194,6 @@ func _ready() -> void:
|
||||
# resume 提前 return)——GP 总结 lambda 求值时 runner 尚未赋值,修复前 717 炸 null。
|
||||
ProbeUiUtil.isolate_save(main, "smoke_ui_struct_probe_resume", true)
|
||||
main.save_manager.set_breakpoint(_resume_bp_fixture())
|
||||
main._refresh_resume_button()
|
||||
main.run_scope.runner = null # 全新启动等价态(真机=菜单直进续玩,无前置冒险——runner 从未赋值;探针此前推流会残留旧 runner)
|
||||
main._resume_from_menu()
|
||||
_settle(8)
|
||||
|
||||
@@ -89,7 +89,7 @@ func _ready() -> void:
|
||||
# (攻击 ×2 / 生命 +50%)——旧缺陷(残留值被当基线再乘)在 encounter 参数链上同样被抓获
|
||||
# 存档隔离(停点断点写盘随 main.save_manager;探针禁碰真实档,同族探针隔离纪律;
|
||||
# isolate_save 先删后建——上次运行的残留断点会触发互斥确认早退)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_tune_probe_save", true, false, false)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_tune_probe_save", true, false, true) # 末参=swap_save(卡②签名换代——断点写盘经 autoload 落隔离档)
|
||||
main.debug_overlay.set_sliders(100, 50)
|
||||
main.debug_overlay.press_apply_for_probe()
|
||||
main.debug_overlay.seed_edit.text = "42" # 种子钉死(18卡⑦审计🔴——空框=非首局随机,显式优先经真实路径断言 master_seed)
|
||||
|
||||
@@ -27,7 +27,6 @@ func _init() -> void:
|
||||
var sm = main.get_node("/root/SaveManager")
|
||||
sm.attach_path("user://test_pacing_queue_save.json")
|
||||
sm.mark_first_adventure_done()
|
||||
main._refresh_resume_button()
|
||||
# 行信号计数器(真实信号路径旁挂计数——零触碰既有接线)
|
||||
var rows_seen: Array = []
|
||||
main._start_adventure_from_menu()
|
||||
|
||||
Reference in new issue
Block a user