diff --git a/game/presentation/main_ui_build.gd b/game/presentation/main_ui_build.gd index b535fb7c..043c4475 100644 --- a/game/presentation/main_ui_build.gd +++ b/game/presentation/main_ui_build.gd @@ -92,7 +92,7 @@ static func _build_overlays(root: Variant) -> void: root.ui.modals.shop_overlay = overlays.shop_overlay root.ui.screens.camp_screen = CampScreenScene.instantiate() root.add_child(root.ui.screens.camp_screen) - root.ui.modals.camp_overlay = root.ui.screens.camp_screen.camp_overlay + root.ui.modals.camp.overlay = root.ui.screens.camp_screen.camp_overlay # 营地屏壳插位(夹商店层与设置层之间)由 LAYER_CONTRACT 营地槽统一落位——禁散落 move_child root.ui.modals.legend_overlay.closed.connect(root.ui.modals.flow.close.bind(root.ui.modals.legend_overlay)) root.ui.modals.node_overlay.continue_pressed.connect(root._on_node_continue) @@ -159,7 +159,7 @@ static func _build_menu_wiring(root: Variant) -> void: # 营地/商店投影(本体在 camp_shop_presenter.gd;本类只接线、探针缝保缝转发; # 购买写调用唯一经 MetaProgression/LevelRunner core 单口——组合根 lambda 现值注入) root._camp_pres = CampShopPresenter.new(CampFlowContext.new(root.db, - {"camp_overlay": root.ui.modals.camp_overlay, "shop_overlay": root.ui.modals.shop_overlay, + {"camp_overlay": root.ui.modals.camp.overlay, "shop_overlay": root.ui.modals.shop_overlay, "toast": root.ui.battle.board_zone.toast, "start_overlay": root.ui.screens.start_overlay, "logger": root.logger}, {"meta_get": func() -> Variant: return root.meta, "save_get": func() -> Variant: return root.save_manager, "runner_get": func() -> Variant: return root.run_scope.runner}, @@ -168,14 +168,14 @@ static func _build_menu_wiring(root: Variant) -> void: root.ui.modals.shop_overlay.buy_requested.connect(root._camp_pres.on_shop_buy) root.ui.modals.shop_overlay.refresh_requested.connect(root._camp_pres.on_shop_refresh) # MC-1 root.ui.modals.shop_overlay.leave_pressed.connect(root._camp_pres.on_shop_leave) - root.ui.modals.camp_overlay.buy_requested.connect(root._camp_pres.on_camp_buy) - root.ui.modals.camp_overlay.attune_toggled.connect(root._camp_pres.on_camp_attune_toggle) - root.ui.modals.camp_overlay.tree_buy_requested.connect(root._camp_pres.on_camp_tree_buy) - root.ui.modals.camp_overlay.tree_fork_toggled.connect(root._camp_pres.on_camp_fork_toggle) - root.ui.modals.camp_overlay.forge_buy_requested.connect(root._camp_pres.on_camp_forge_buy) # 锻造三意图(写口唯一归 MetaProgression) - root.ui.modals.camp_overlay.forge_unlock_requested.connect(root._camp_pres.on_camp_forge_unlock) - root.ui.modals.camp_overlay.forge_select_requested.connect(root._camp_pres.on_camp_forge_select) - root.ui.modals.camp_overlay.closed.connect(root._camp_pres.on_camp_closed) + root.ui.modals.camp.overlay.buy_requested.connect(root._camp_pres.on_camp_buy) + root.ui.modals.camp.overlay.attune_toggled.connect(root._camp_pres.on_camp_attune_toggle) + root.ui.modals.camp.overlay.tree_buy_requested.connect(root._camp_pres.on_camp_tree_buy) + root.ui.modals.camp.overlay.tree_fork_toggled.connect(root._camp_pres.on_camp_fork_toggle) + root.ui.modals.camp.overlay.forge_buy_requested.connect(root._camp_pres.on_camp_forge_buy) # 锻造三意图(写口唯一归 MetaProgression) + root.ui.modals.camp.overlay.forge_unlock_requested.connect(root._camp_pres.on_camp_forge_unlock) + root.ui.modals.camp.overlay.forge_select_requested.connect(root._camp_pres.on_camp_forge_select) + root.ui.modals.camp.overlay.closed.connect(root._camp_pres.on_camp_closed) root.ui.screens.menu_screen.settingsbtn.pressed.connect(root._open_settings) # 最小设置面入口 root.ui.screens.menu_screen.quitbtn.pressed.connect(root._quit_game) # 退出游戏提级一级菜单 diff --git a/game/presentation/ui_camp_modals.gd b/game/presentation/ui_camp_modals.gd new file mode 100644 index 00000000..bd7eb23e --- /dev/null +++ b/game/presentation/ui_camp_modals.gd @@ -0,0 +1,7 @@ +## 营地交互域模态句柄子容器:持营地域全部模态句柄(终态六枚=营地场景根+锻造/秘宝/天赋树/图鉴四子界面+Esc 浮窗;现役一枚=CampOverlay 覆盖层)。 +## RefCounted 不挂树;随 UiModals._init 构造(与 flow 同拍)。终态六枚未落满前只持在役枚——禁空占位凑结构。 +## 新营地句柄禁平铺回 ui_modals:营地域句柄寻址一律 ui.modals.camp.X 二层(模态句柄册分域纪律——全量分家另立批)。 +class_name UiCampModals +extends RefCounted + +var overlay: CampOverlay diff --git a/game/presentation/ui_camp_modals.gd.uid b/game/presentation/ui_camp_modals.gd.uid new file mode 100644 index 00000000..ac8a1fa8 --- /dev/null +++ b/game/presentation/ui_camp_modals.gd.uid @@ -0,0 +1 @@ +uid://goaqtequmh8s diff --git a/game/presentation/ui_modals.gd b/game/presentation/ui_modals.gd index e156fa15..e068d317 100644 --- a/game/presentation/ui_modals.gd +++ b/game/presentation/ui_modals.gd @@ -1,4 +1,4 @@ -## 模态层域句柄册:十三个模态覆盖层句柄+模态栈编排(ModalFlow——登记/开合/输入锁谓词)的注册面域容器。 +## 模态层域句柄册:十二个平铺模态句柄+营地交互域子容器(camp)+模态栈编排(ModalFlow——登记/开合/输入锁谓词)的注册面域容器。 ## RefCounted 不挂树;模态登记唯一口=register_layer(anchors 撑满宿主+排入 ModalStack)。 ## flow 随容器构造即建(装配早期注入点经 root.ui.modals.flow.* 取 Callable——晚于 flow 建立时点)。 class_name UiModals @@ -11,7 +11,7 @@ var level_screen: LevelMapScreen var curio_overlay: CurioPickOverlay var end_overlay: BattleEndOverlay var shop_overlay: ShopOverlay -var camp_overlay: CampOverlay +var camp: UiCampModals var settings_overlay: SettingsOverlay var status_panel: StatusPanel var career_overlay: CareerOverlay @@ -22,6 +22,7 @@ var debug_overlay: DebugOverlay func _init() -> void: flow = ModalFlow.new() # 查询/钩子 Callable 由 _build_modal_flow 注入(注入时点不变——注入值面向已在座实例) + camp = UiCampModals.new() # 营地域句柄子容器(分域纪律——营地域句柄禁平铺回本册) func register_layer(m: Control, tags: Array = []) -> void: diff --git a/game/presentation/ui_registry.gd b/game/presentation/ui_registry.gd index bccce61f..6c861d1e 100644 --- a/game/presentation/ui_registry.gd +++ b/game/presentation/ui_registry.gd @@ -58,7 +58,7 @@ func node(key: String) -> Node: "end_overlay": return modals.end_overlay "shop_overlay": return modals.shop_overlay "camp_screen": return screens.camp_screen - "camp_overlay": return modals.camp_overlay + "camp_overlay": return modals.camp.overlay "settings_overlay": return modals.settings_overlay "status_panel": return modals.status_panel "career_overlay": return modals.career_overlay diff --git a/game/probe/screen_flow_probe.gd b/game/probe/screen_flow_probe.gd index 08fb6b30..d90071e5 100644 --- a/game/probe/screen_flow_probe.gd +++ b/game/probe/screen_flow_probe.gd @@ -51,7 +51,7 @@ func _ready() -> void: func _screen_seals() -> Dictionary: return { "菜单": main.ui.screens.start_overlay != null and main.ui.screens.start_overlay.visible, - "营地": main.ui.modals.camp_overlay != null and main.ui.modals.camp_overlay.visible, + "营地": main.ui.modals.camp.overlay != null and main.ui.modals.camp.overlay.visible, "冒险": main.run_scope != null and main.run_scope.is_adventure, "终局": main.ui.modals.end_overlay != null and main.ui.modals.end_overlay.visible, } @@ -117,10 +117,10 @@ func _step_menu_to_camp() -> void: # ---- ③ 营地 → 菜单(回退路径:营地关闭发自覆盖层自身信号)---- func _step_camp_back_to_menu() -> void: - if main.ui.modals.camp_overlay == null: - _problems.append("③营地→菜单:营地覆盖层句柄缺失") + if main.ui.modals.camp.overlay == null: + _problems.append("③营地→菜单:营地覆盖层句柄缺失〔句柄子容器批 V1〕") return - main.ui.modals.camp_overlay.closed.emit() + main.ui.modals.camp.overlay.closed.emit() await _frames() main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态——卡④ 换代点) await _frames() diff --git a/game/probe/shot_probe.gd b/game/probe/shot_probe.gd index 4cc12488..0fe9021d 100644 --- a/game/probe/shot_probe.gd +++ b/game/probe/shot_probe.gd @@ -53,7 +53,7 @@ func _ready() -> void: var top_ry := -1 for c: Node in [main.ui.screens.start_overlay, main.ui.screens.battle_root, main.ui.screens.inter_overlay, main.ui.modals.legend_overlay, main.ui.modals.node_overlay, main.ui.modals.level_screen, main.ui.modals.curio_overlay, - main.ui.modals.end_overlay, main.ui.modals.shop_overlay, main.ui.modals.camp_overlay, main.ui.modals.settings_overlay, + main.ui.modals.end_overlay, main.ui.modals.shop_overlay, main.ui.modals.camp.overlay, main.ui.modals.settings_overlay, main.ui.modals.status_panel, main.ui.modals.career_overlay, main.ui.modals.confirm_dialog, main.ui.modals.debug_overlay]: if c == null or not (c is CanvasItem) or not (c as CanvasItem).visible: continue @@ -121,11 +121,11 @@ func _ready() -> void: _problems.append("生涯页关闭后页未隐藏或开始层未恢复") # ② 营地(进档开层新路径——卡② mn9;槽模板注入隔离命名空间) if not ProbeUiUtil.open_camp_via_savesel(main, "smoke_shot_probe_camp"): - _problems.append("营地入口缺失(选档层新档钮——新路径驱动中断)") + _problems.append("营地入口缺失(选档层新档钮——新路径驱动中断)〔句柄子容器批 V1〕") else: await get_tree().process_frame await _snap("camp") - var close_btn: Button = ProbeUiUtil.find_button(main.ui.modals.camp_overlay, "关闭营地", "contains") + var close_btn: Button = ProbeUiUtil.find_button(main.ui.modals.camp.overlay, "关闭营地", "contains") if close_btn != null: close_btn.pressed.emit() await get_tree().process_frame diff --git a/game/probe/ui_click_probe.gd b/game/probe/ui_click_probe.gd index 23829c8e..6cef204f 100644 --- a/game/probe/ui_click_probe.gd +++ b/game/probe/ui_click_probe.gd @@ -62,98 +62,98 @@ func _ready() -> void: # 原 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 新路径驱动中断)") + _problems.append("营地入口缺失(选档层新档钮——mn9 新路径驱动中断)〔句柄子容器批 V1〕") else: await get_tree().process_frame - if not main.ui.modals.camp_overlay.visible: - _problems.append("营地层未打开(进档开层新路径)") - elif main.ui.modals.camp_overlay._tree_buy_btns.is_empty(): - _problems.append("树淬炼柜台购买钮缺失(点击路径——四柜台重排后树=主界面)") + if not main.ui.modals.camp.overlay.visible: + _problems.append("营地层未打开(进档开层新路径)〔句柄子容器批 V1〕") + elif main.ui.modals.camp.overlay._tree_buy_btns.is_empty(): + _problems.append("树淬炼柜台购买钮缺失(点击路径——四柜台重排后树=主界面)〔句柄子容器批 V1〕") else: # 树钮句柄用后即取(refresh_camp 随刷重建树行板——旧钮 queue_free,跨刷新句柄必失效) iso_c.meta_state._add_keystone(9999) - main.ui.modals.camp_overlay.refresh_camp(main._camp_data()) + main.ui.modals.camp.overlay.refresh_camp(main._camp_data()) await get_tree().process_frame var buy_btn: Button = null - for card in main.ui.modals.camp_overlay._tree_buy_btns: + for card in main.ui.modals.camp.overlay._tree_buy_btns: if String(card.node_id) == "sp_hp": buy_btn = card.btn if buy_btn == null: - _problems.append("脊柱生命行缺失(点击路径)") + _problems.append("脊柱生命行缺失(点击路径)〔句柄子容器批 V1〕") else: var bal_before: int = iso_c.meta_state.keystone_balance() var price: int = int(main.db.crossrun.meta_tree.row_by_id("sp_hp").get("price", 0)) buy_btn.pressed.emit() # 合成购买点击 → _on_camp_tree_buy → meta.tree_buy(写调用唯一归组合根) await get_tree().process_frame if int(iso_c.meta_state.keystone_balance()) != bal_before - price: - _problems.append("营地树购买未出账(%d→%d 应 −%d)" % [bal_before, iso_c.meta_state.keystone_balance(), price]) + _problems.append("营地树购买未出账(%d→%d 应 −%d)〔句柄子容器批 V1〕" % [bal_before, iso_c.meta_state.keystone_balance(), price]) 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.meta_state.tree_state().nodes.get("sp_hp", 0)) != 1: - _problems.append("营地树购买未持久(reload 后级 != 1)") + _problems.append("营地树购买未持久(reload 后级 != 1)〔句柄子容器批 V1〕") # Fork 双态切换点击路径(V20——购=解锁默认 A,钮切 B;前置=同调位 1,先点亮) var socket_btn: Button = null - for card in main.ui.modals.camp_overlay._tree_buy_btns: + for card in main.ui.modals.camp.overlay._tree_buy_btns: if String(card.node_id) == "att_socket1": socket_btn = card.btn if socket_btn != null: socket_btn.pressed.emit() await get_tree().process_frame - main.ui.modals.camp_overlay.refresh_camp(main._camp_data()) + main.ui.modals.camp.overlay.refresh_camp(main._camp_data()) await get_tree().process_frame var fork_btn: Button = null - for card in main.ui.modals.camp_overlay._tree_buy_btns: + for card in main.ui.modals.camp.overlay._tree_buy_btns: if String(card.node_id) == "fork_posture": fork_btn = card.btn if fork_btn == null: - _problems.append("Fork 解锁钮缺失(点击路径)") + _problems.append("Fork 解锁钮缺失(点击路径)〔句柄子容器批 V1〕") else: fork_btn.pressed.emit() await get_tree().process_frame - main.ui.modals.camp_overlay.refresh_camp(main._camp_data()) + main.ui.modals.camp.overlay.refresh_camp(main._camp_data()) await get_tree().process_frame var side_b: Button = null - for fk in main.ui.modals.camp_overlay._tree_fork_btns: + for fk in main.ui.modals.camp.overlay._tree_fork_btns: if String(fk.group) == "fg_posture" and String(fk.side) == "b": side_b = fk.btn if side_b == null: - _problems.append("Fork 双态切换钮缺失(解锁后应展开 a/b 钮)") + _problems.append("Fork 双态切换钮缺失(解锁后应展开 a/b 钮)〔句柄子容器批 V1〕") 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_slot_1.json") iso_fk.load_from_disk() if String(iso_fk.meta_state.tree_state().fork_sides.get("fg_posture", "")) != "b": - _problems.append("Fork 切态未持久(reload 后激活态 != b)") + _problems.append("Fork 切态未持久(reload 后激活态 != b)〔句柄子容器批 V1〕") # ---- 营地六处灰字取色断言(迭代36 wc4——真实入口开营地后按文本锚取 label, # font_color 逐处 == STONE_DEEP;六源位 :167 图鉴锁文/:417+:476 行状态字/:509 同调形态/:513 档位标签/:525 刷新行)---- var camp_labels: Array = [] - _collect_labels_by_text(main.ui.modals.camp_overlay, camp_labels) + _collect_labels_by_text(main.ui.modals.camp.overlay, camp_labels) var atlas_locks := _labels_with_text(camp_labels, "柜台结构位预留") if atlas_locks.is_empty(): - _problems.append("营地灰字:图鉴柜台锁文 label 未找到(wc4 定位锚失守)") + _problems.append("营地灰字:图鉴柜台锁文 label 未找到(wc4 定位锚失守)〔句柄子容器批 V1〕") for l in atlas_locks: if l.get_theme_color("font_color") != UiKit.STONE_DEEP: - _problems.append("营地灰字:图鉴锁文未用 STONE_DEEP(wc4 :167)") + _problems.append("营地灰字:图鉴锁文未用 STONE_DEEP(wc4 :167)〔句柄子容器批 V1〕") # 「未解锁」锚收窄到秘宝匣行容器子树(树行/锻造行也有「未解锁」态字样——非 wc4 目标位) var locked_status: Array = [] - if main.ui.modals.camp_overlay.get("_workshop_holder") != null: + if main.ui.modals.camp.overlay.get("_workshop_holder") != null: var ws_labels: Array = [] - _collect_labels_by_text(main.ui.modals.camp_overlay._workshop_holder, ws_labels) + _collect_labels_by_text(main.ui.modals.camp.overlay._workshop_holder, ws_labels) locked_status = _labels_with_text(ws_labels, "未解锁") if locked_status.is_empty(): - _problems.append("营地灰字:秘宝匣行「未解锁」态 label 未找到(wc4 夹具前提失守——新档应有锁定秘宝行)") + _problems.append("营地灰字:秘宝匣行「未解锁」态 label 未找到(wc4 夹具前提失守——新档应有锁定秘宝行)〔句柄子容器批 V1〕") for l in locked_status: if l.get_theme_color("font_color") != UiKit.STONE_DEEP: - _problems.append("营地灰字:秘宝行「未解锁」态未用 STONE_DEEP(wc4 :417/:476)") + _problems.append("营地灰字:秘宝行「未解锁」态未用 STONE_DEEP(wc4 :417/:476)〔句柄子容器批 V1〕") var form_found := false for l in camp_labels: if l.text == "被动" or l.text == "主动·充能": form_found = true if l.get_theme_color("font_color") != UiKit.STONE_DEEP: - _problems.append("营地灰字:同调形态标签未用 STONE_DEEP(wc4 :509)") + _problems.append("营地灰字:同调形态标签未用 STONE_DEEP(wc4 :509)〔句柄子容器批 V1〕") if not form_found: - _problems.append("营地灰字:同调行形态标签未找到(wc4 定位锚失守——同调段应有行)") + _problems.append("营地灰字:同调行形态标签未找到(wc4 定位锚失守——同调段应有行)〔句柄子容器批 V1〕") var tier_vals := {} for v in UiKit.TREASURE_TIER_LABELS.values(): tier_vals[String(v)] = true @@ -162,23 +162,23 @@ func _ready() -> void: if tier_vals.has(l.text): tier_found = true if l.get_theme_color("font_color") != UiKit.STONE_DEEP: - _problems.append("营地灰字:同调档位标签未用 STONE_DEEP(wc4 :513)") + _problems.append("营地灰字:同调档位标签未用 STONE_DEEP(wc4 :513)〔句柄子容器批 V1〕") if not tier_found: - _problems.append("营地灰字:同调档位标签未找到(wc4 定位锚失守)") + _problems.append("营地灰字:同调档位标签未找到(wc4 定位锚失守)〔句柄子容器批 V1〕") var refresh_inked := false for l in camp_labels: if String(l.text).contains("三选一刷新"): refresh_inked = true if l.get_theme_color("font_color") != UiKit.STONE_DEEP: - _problems.append("营地灰字:刷新行未用 STONE_DEEP(wc4 :525)") + _problems.append("营地灰字:刷新行未用 STONE_DEEP(wc4 :525)〔句柄子容器批 V1〕") if not refresh_inked: - _problems.append("营地灰字:刷新行 label 未找到(wc4 定位锚失守)") + _problems.append("营地灰字:刷新行 label 未找到(wc4 定位锚失守)〔句柄子容器批 V1〕") main._on_camp_closed() await get_tree().process_frame main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态——卡④ 换代点) await get_tree().process_frame - if main.ui.modals.camp_overlay.visible or not main.ui.screens.start_overlay.visible: - _problems.append("营地关闭后未恢复开始层") + if main.ui.modals.camp.overlay.visible or not main.ui.screens.start_overlay.visible: + _problems.append("营地关闭后未恢复开始层〔句柄子容器批 V1〕") # ---- 选档界面行为走查(迭代 33 卡③):sl5 空槽新档链/sl6 有档槽进档链/sl7 删档二次确认双路径 # /sl8 消费方分派单口/sl12 动线序不回闪。开层=函数直调(「进入存档」钮归卡② mn3——中间态在案); # 隔离=attach_slot_template 注入命名空间,夹具按槽直写(卡① 注入口)。---- @@ -208,7 +208,7 @@ func _ready() -> void: new_btn.pressed.emit() # 真实按钮信号路径 → _on_save_select_new → create_slot+open_camp for fi in 3: await get_tree().process_frame - samples.append([main.ui.modals.save_select_overlay.visible, main.ui.modals.camp_overlay.visible, main.ui.screens.start_overlay.visible]) + samples.append([main.ui.modals.save_select_overlay.visible, main.ui.modals.camp.overlay.visible, main.ui.screens.start_overlay.visible]) if samples[0][0]: _problems.append("[savesel] sl12 新档后选档层仍可见(落点开层未发生)") elif not samples[0][1]: @@ -217,7 +217,7 @@ func _ready() -> void: _problems.append("[savesel] sl12 动线序违约:开始层在落点帧恢复(回闪一帧)") if main.save_manager.slots.active_slot() != 1 or not FileAccess.file_exists(csel_tpl % 1): _problems.append("[savesel] sl5 新档链失守(active=%d 应=1 且槽1 白板应落盘)" % main.save_manager.slots.active_slot()) - var occluded: Array = main.ui.modals.flow.stack._occluded.get(main.ui.modals.camp_overlay, []) + var occluded: Array = main.ui.modals.flow.stack._occluded.get(main.ui.modals.camp.overlay, []) if not occluded.has(main.ui.modals.save_select_overlay): _problems.append("[savesel] sl12 选档层被关闭而非栈记账挂起(先关后开形态——遮挡挂起中间态钉死)") if int((JSON.parse_string(FileAccess.get_file_as_string(csel_tpl % 1)) as Dictionary).get("meta", {}).get("keystone_balance", -1)) != 0: @@ -235,7 +235,7 @@ func _ready() -> void: await get_tree().process_frame if main.save_manager.slots.active_slot() != 2: _problems.append("[savesel] sl6 进档链失守(active=%d 应=2——激活该槽)" % main.save_manager.slots.active_slot()) - if not main.ui.modals.camp_overlay.visible or main.ui.modals.save_select_overlay.visible: + if not main.ui.modals.camp.overlay.visible or main.ui.modals.save_select_overlay.visible: _problems.append("[savesel] sl6 落点未开营地层或选档未隐藏") main._on_camp_closed() await get_tree().process_frame diff --git a/game/probe/ui_probe.gd b/game/probe/ui_probe.gd index 50e0d429..22b3790d 100644 --- a/game/probe/ui_probe.gd +++ b/game/probe/ui_probe.gd @@ -25,34 +25,34 @@ func _ready() -> void: # 营地先行段只换 meta 不换 save_manager——冒险段换注零档在前)---- 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 新路径驱动中断)") + problems.append("营地入口缺失(选档层新档钮——mn9 新路径驱动中断)〔句柄子容器批 V1〕") else: await get_tree().process_frame - if not main.ui.modals.camp_overlay.visible: - problems.append("营地层未打开(进档开层新路径)") + if not main.ui.modals.camp.overlay.visible: + problems.append("营地层未打开(进档开层新路径)〔句柄子容器批 V1〕") elif main.ui.screens.start_overlay.visible: - problems.append("营地层打开时开始层未隐藏(规范 2.3 遮挡纪律)") + problems.append("营地层打开时开始层未隐藏(规范 2.3 遮挡纪律)〔句柄子容器批 V1〕") else: - if not String(main.ui.modals.camp_overlay._balance_label.text).begins_with("钥石"): - problems.append("营地余额文案缺失(%s)" % main.ui.modals.camp_overlay._balance_label.text) - if main.ui.modals.camp_overlay._tree_buy_btns.is_empty(): - problems.append("树淬炼柜台购买钮缺失(四柜台重排后树=主界面)") + if not String(main.ui.modals.camp.overlay._balance_label.text).begins_with("钥石"): + problems.append("营地余额文案缺失(%s)〔句柄子容器批 V1〕" % main.ui.modals.camp.overlay._balance_label.text) + if main.ui.modals.camp.overlay._tree_buy_btns.is_empty(): + problems.append("树淬炼柜台购买钮缺失(四柜台重排后树=主界面)〔句柄子容器批 V1〕") else: var btn_by_id := {} - for card2 in main.ui.modals.camp_overlay._tree_buy_btns: + for card2 in main.ui.modals.camp.overlay._tree_buy_btns: btn_by_id[String(card2.node_id)] = card2.btn if not btn_by_id.has("sp_hp") or bool(btn_by_id["sp_hp"].disabled): - problems.append("脊柱生命 L1 白板可购钮未启用(无门槛——can_buy 不含余额面语义)") + problems.append("脊柱生命 L1 白板可购钮未启用(无门槛——can_buy 不含余额面语义)〔句柄子容器批 V1〕") if not btn_by_id.has("att_socket2") or not bool(btn_by_id["att_socket2"].disabled): - problems.append("同调位 2 前置未亮应禁用(点亮前置语义)") - if main.ui.modals.camp_overlay._workshop_rows.size() != 12: - problems.append("秘宝匣柜台行数错误(%d ≠ 12——迭代 22 秘宝批换代)" % main.ui.modals.camp_overlay._workshop_rows.size()) + problems.append("同调位 2 前置未亮应禁用(点亮前置语义)〔句柄子容器批 V1〕") + if main.ui.modals.camp.overlay._workshop_rows.size() != 12: + problems.append("秘宝匣柜台行数错误(%d ≠ 12——迭代 22 秘宝批换代)〔句柄子容器批 V1〕" % main.ui.modals.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.ui.modals.camp_overlay.visible or not main.ui.screens.start_overlay.visible: - problems.append("营地关闭后未恢复开始层(开合往返失守)") + if main.ui.modals.camp.overlay.visible or not main.ui.screens.start_overlay.visible: + problems.append("营地关闭后未恢复开始层(开合往返失守)〔句柄子容器批 V1〕") # 换回全新零档(营地段购买态不泄入后续冒险段——确定性;先删后建防陈旧档泄入) ProbeUiUtil.isolate_save(main, "smoke_ui_probe_camp", true, false, true) main.ui.modals.debug_overlay.seed_edit.text = "42" # 种子钉死(种子框默认为空=非首局随机;本探针 start_single 第五路同吃此框,确定性禁依赖默认分支) diff --git a/game/probe/ui_struct_probe.gd b/game/probe/ui_struct_probe.gd index 842de67b..7f800104 100644 --- a/game/probe/ui_struct_probe.gd +++ b/game/probe/ui_struct_probe.gd @@ -39,15 +39,15 @@ func _ready() -> void: _settle() if not ProbeUiUtil.open_camp_via_savesel(main, "smoke_ui_struct_probe_menu"): - problems.append("[camp] 营地入口缺失(选档层新档钮——mn9 新路径驱动中断)") + problems.append("[camp] 营地入口缺失(选档层新档钮——mn9 新路径驱动中断)〔句柄子容器批 V1〕") else: _settle() - await _audit("camp", [main.ui.modals.camp_overlay]) + await _audit("camp", [main.ui.modals.camp.overlay]) # 营地灰字源 token 扫描(迭代36 wc4 静态半——源内零裸 UiKit.STONE;判别式= # STONE 出现次数 == STONE_DEEP 出现次数,即每处 STONE 都带 _DEEP 后缀) var camp_src := FileAccess.get_file_as_string("res://presentation/views/camp_overlay_view.gd") if camp_src.count("UiKit.STONE") != camp_src.count("UiKit.STONE_DEEP"): - problems.append("[camp] camp_overlay_view.gd 存在裸 UiKit.STONE(非 _DEEP 后缀——wc4 源扫描)") + problems.append("[camp] camp_overlay_view.gd 存在裸 UiKit.STONE(非 _DEEP 后缀——wc4 源扫描)〔句柄子容器批 V1〕") main._on_camp_closed() _settle() main._on_save_select_closed() # 关闭被栈还原的选档层(动线序中间态——卡④ 换代点) diff --git a/game/tests/system_test.gd b/game/tests/system_test.gd index 7814e0a7..3cfe4ee4 100644 --- a/game/tests/system_test.gd +++ b/game/tests/system_test.gd @@ -103,10 +103,10 @@ func _smoke_scene_split() -> void: chain_ok = false chain_detail += " %s(%d)≤%s(%d)" % [chain_prev.name, chain_prev.get_index(), node.name, node.get_index()] chain_prev = node - check(chain_ok, "V1c 合同树序链逐对保序(运行期树序==LAYER_CONTRACT 序;违例:%s)〔装配生命批 V1〕" % chain_detail) + check(chain_ok, "V1c 合同树序链逐对保序(运行期树序==LAYER_CONTRACT 序;违例:%s)〔装配生命批 V1〕〔句柄子容器批 V2〕" % chain_detail) # ③ 探针挂载假设句柄在座(main.X 一级路径——探针迁移面收口证明) - check(main.ui.screens.start_overlay == main.ui.screens.menu_screen.start_overlay and main.ui.modals.camp_overlay == main.ui.screens.camp_screen.camp_overlay and main.ui.modals.level_screen == main.ui.screens.adventure_screen.level_screen and main.ui.screens.battle_root == main.ui.screens.adventure_screen.battle_root and main.ui.battle.board_zone.board_view == main.ui.screens.adventure_screen.board_view, - "V2 组合根句柄指向屏壳成员(探针挂载假设 main.X 零迁移)") + check(main.ui.screens.start_overlay == main.ui.screens.menu_screen.start_overlay and main.ui.modals.camp.overlay == main.ui.screens.camp_screen.camp_overlay and main.ui.modals.level_screen == main.ui.screens.adventure_screen.level_screen and main.ui.screens.battle_root == main.ui.screens.adventure_screen.battle_root and main.ui.battle.board_zone.board_view == main.ui.screens.adventure_screen.board_view, + "V2 组合根句柄指向屏壳成员(探针挂载假设 main.X 零迁移)〔句柄子容器批 V1〕") check(main.run_scope != null and not main.run_scope.is_adventure, "V2 闲时会话自 _ready 即在(永非 null;迭代 27 T3——gp 影子账退役无账本成员)") main.queue_free() @@ -118,7 +118,7 @@ func _smoke_scene_split() -> void: func _topmost_visible_layer(main: Node) -> Node: var candidates: Array[Node] = [main.ui.screens.start_overlay, main.ui.screens.battle_root, main.ui.screens.inter_overlay, main.ui.modals.legend_overlay, main.ui.modals.node_overlay, main.ui.modals.level_screen, main.ui.modals.curio_overlay, - main.ui.modals.end_overlay, main.ui.modals.shop_overlay, main.ui.modals.camp_overlay, main.ui.modals.settings_overlay, + main.ui.modals.end_overlay, main.ui.modals.shop_overlay, main.ui.modals.camp.overlay, main.ui.modals.settings_overlay, main.ui.modals.status_panel, main.ui.modals.career_overlay, main.ui.modals.confirm_dialog, main.ui.modals.debug_overlay] var best: Node = null var best_x := -1