Files
gplan-2/game/presentation/main_overlay_flow.gd
T
DKChan 5a0e7069c1 卡④T4(迭代47·营地场景图批): 大门两分支+ConfirmDialog三钮化+三钮消费方编排+篝火二次确认动线——点大门永远先出确认/cancelled恒无变更退回营地
- ConfirmDialog三钮化(契约3/Q5甲): open_three增设次钮+secondary_confirmed信号——双钮调用方零改动(open隐藏次钮);钮序=[取消][次选项][确认]
- 大门两分支(裁决5): 有断点=三出口弹窗(继续上一段冒险/开始新冒险/取消,open_three)+无断点=是否开始新冒险(是/否);点大门永远先出确认不直接进冒险;cancelled恒=无变更退回营地
- 消费方编排扩展(卡③契约3机制零重构): _confirm_consumer新增gate/gate_new/campfire_leave三消费方+_on_confirm_secondary次确认分派——继续接现役续玩编排(_resume_from_menu同源)/开始接现役开局编排(_start_adventure同源)/冒险发起后营地场景屏隐藏(presenter.on_camp_closed关层收闭=营地与选档层同收+开始层恢复,T3已建);main_ui_build补secondary_confirmed接线
- 篝火动线: 二次确认(camp.md v2.2裁定走ConfirmDialog先例)→确认离场=on_camp_closed;命中只火堆已随T2布局表(560,640,160,80)
- _refresh_resume_button不复用(随卡②删——大门两分支直读has_breakpoint无钮可刷);终局落点不变量T0互证=现役终局continue回主菜单不改
- main.gd零新增成员(分派扩match臂+新方法,15/15保持)
- 验证: 全流程孤检绿(10项:篝火cancel/confirm/大门无断点cancel/confirm/次钮隐藏/三钮形态/次确认开局/主确认续玩no-op——临时件不入库,T5探针承载正式验收);S9/S10/S13归基线
2026-11-01 18:11:42 +08:00

186 lines
9.7 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
## 组合根覆盖层流程承接件:设置/状态面板/生涯页/选档界面/图例/钱包事件的开合与数据投喂。
## 本件是 main.gd 同名函数的逐字搬运(成员访问改 root 前缀)——main 侧留同名薄委托,探针 main.X 路径零改动。
## 全部开合走组合根模态编排口(root.ui.modals.flow.open/close);本件零成员态。
extends RefCounted
static func _open_settings(root: Variant) -> void:
root.ui.screens.start_overlay.visible = false
root.ui.modals.flow.open(root.ui.modals.settings_overlay) # 模态栈单口
static func _on_settings_closed(root: Variant) -> void:
root.ui.modals.flow.close(root.ui.modals.settings_overlay) # 模态栈单口
root.ui.screens.start_overlay.visible = true
# ---- 局内状态面板·只读(入口角标在两屏装配段;开合与数据喂入归组合根)----
# 状态面板快照投影(数据只读同源:每次开层实时读访问器现值拼装——
# 快照仅服务单次开层生命周期(open_status 重建各行),跨开层零持有;零写调用。
# 八键换代(迭代 36 卡③):跨关解锁概览退役(营地/生涯承载)——只留本局信息;
# ledger 直取下标(键缺失=致命,禁 .get 缺省留门——fail-fast 红线);禁 null 守卫软回退
# (两入口开层时 runner 恒在役——状态面板卡 F3 证据链)
static func _status_data(root: Variant) -> Dictionary:
return HudPresenter.status_data(root.db, root.meta, root.run_scope.runner, root._treasure_ui)
static func _open_status_panel(root: Variant) -> void:
root.ui.modals.flow.open(root.ui.modals.status_panel) # 模态栈单口(开层前排空排播队列——既有层同款行为,目检确认项)
root.ui.modals.status_panel.open_status(_status_data(root))
static func _on_status_closed(root: Variant) -> void:
root.ui.modals.flow.close(root.ui.modals.status_panel) # 模态栈单口
static func _open_career(root: Variant) -> void:
root.ui.screens.start_overlay.visible = false
root.ui.modals.flow.open(root.ui.modals.career_overlay) # 模态栈单口
root.ui.modals.career_overlay.open_career(HudPresenter.career_data(root.db, root.save_manager, root.meta))
static func _on_career_closed(root: Variant) -> void:
root.ui.modals.flow.close(root.ui.modals.career_overlay) # 模态栈单口
if not root.ui.modals.camp.scene.visible: # 营地语境关生涯不回开始层(笔记本入口——卡④ T3;栈已复现场景根)
root.ui.screens.start_overlay.visible = true
# ---- 营地场景点选路由(卡④ T3/T4——场景根 object_pressed 组合根分派)----
# 大门两分支(裁决 5,Q5 甲):点大门永远先出确认不直接进冒险——有断点=三出口弹窗
#(继续上一段冒险/开始新冒险/取消),无断点=是否开始新冒险(是/否);cancelled 恒=无变更退回营地。
# 篝火回主菜单必须二次确认(camp.md v2.2 裁定);确认后营地层与选档层同收+开始层恢复(关层收闭)。
static func _on_camp_object_pressed(root: Variant, key: StringName) -> void:
match key:
&"forge":
root._camp_pres.open_camp_forge()
&"chest":
root._camp_pres.open_camp_treasure()
&"dummy":
root._camp_pres.open_camp_tree()
&"board":
root._camp_pres.open_camp_codex()
&"notebook":
_open_career(root) # 生涯页入口改挂帐篷旁笔记本(CareerOverlay 本体零改——卡④ T3)
&"gate":
_open_gate_confirm(root)
&"campfire":
root._confirm_consumer = "campfire_leave"
root.ui.modals.confirm_dialog.open("确定离开营地回到主菜单?", "离开", "留下")
static func _open_gate_confirm(root: Variant) -> void:
if root.save_manager.has_breakpoint():
root._confirm_consumer = "gate"
root.ui.modals.confirm_dialog.open_three("有未完成的冒险——继续上一段冒险,还是开始新冒险?",
"继续上一段冒险", "开始新冒险", "取消")
return
root._confirm_consumer = "gate_new"
root.ui.modals.confirm_dialog.open("是否开始新冒险?", "是", "否")
# 生涯页快照投影 —— 承接体见 HudPresenter.career_data(开层调用点直接改引)
# ==================== 选档界面(营地交互重做卡③)====================
# 开层(模态栈单口;与开始层互斥=career 同款先例)。「进入存档」钮归卡② mn3——本函数为
# 该钮的唯一落点(卡③ 批内探针函数直调=中间态,实现报告「已知中间态」登记)。
static func _open_save_select(root: Variant) -> void:
root.ui.screens.start_overlay.visible = false
root.ui.modals.flow.open(root.ui.modals.save_select_overlay) # 模态栈单口
root.ui.modals.save_select_overlay.open_save_select(HudPresenter.save_select_data(root.save_manager))
static func _on_save_select_closed(root: Variant) -> void:
root.ui.modals.flow.close(root.ui.modals.save_select_overlay) # 模态栈单口
root.ui.screens.start_overlay.visible = true
# 槽数据快照 —— 承接体见 HudPresenter.save_select_data(开层调用点直接改引)
# 空槽新档链(卡④ T3 换代:落点=营地场景根——CampOverlay 随四柜台拆解退役):卡① 创建=激活=白板落盘,
# 落点开层。动线序(禁先关后开):先落点开层(开始层保持隐藏),选档层被模态栈遮挡隐藏、不关闭。
static func _on_save_select_new(root: Variant, slot: int) -> void:
root.save_manager.slots.create_slot(slot)
root._camp_pres.open_camp()
# 有档槽进档链(契约 8 进档即激活):卡① 激活+读盘(兜底/拒读链按槽成立)→落点=营地场景根(卡④ T3)。
static func _on_save_select_load(root: Variant, slot: int) -> void:
root.save_manager.slots.activate_slot(slot)
root._camp_pres.open_camp()
# 删档链(契约 3):第一次点击只出确认窗(消费方编排——open 前设消费方=delete_slot),
# 确认才删、取消不删;禁长按删/一次点击即删/撤销式软删。
static func _on_save_select_delete(root: Variant, slot: int) -> void:
root._confirm_consumer = "delete_slot"
root._confirm_consumer_slot = slot
root.ui.modals.flow.open(root.ui.modals.confirm_dialog) # 模态栈单口(显示编排/挂起兜底/遮挡记账——与其余覆盖层同口)
root.ui.modals.confirm_dialog.open("删除存档位 %d?删除后该档不可恢复。" % slot, "删除", "取消")
# 入口角标点击(两屏同款处理器):P1 守卫兜底——其他模态开着即拒开(常态防线=角标置灰,
# 探针 pressed.emit 绕过 disabled 时由此兜住;地图屏自身的登记开态不计——has_open_excluding)
static func _on_status_badge_pressed(root: Variant) -> void:
var map_on: bool = root.ui.modals.level_screen != null and root.ui.modals.level_screen.visible
# P1 守卫兜底——其他模态开着即拒开(常态防线=角标置灰,探针 pressed.emit 绕过 disabled 时由此兜住;
# 地图屏自身的登记开态不计;判据排除调试浮窗:对局中浮窗开着时状态角标仍可点)
if (map_on and root.ui.modals.flow.badge_greyed_map()) or (not map_on and root.ui.modals.flow.badge_greyed_battle()):
return
_open_status_panel(root)
# 入口角标可见性/置灰同步(P1 丁+守卫——单一同步点):战斗屏角标=对局内且地图屏未激活;
# 地图屏角标=随屏;置灰=登记册上除地图屏自身外任一层开着(防「看得见点不着」态)。
# 调用面=模态开合单口与屏级互斥口(凡影响开态/屏态的路径必经其一)。
static func _sync_status_entry(root: Variant) -> void:
if root.ui.modals.status_panel == null or root.ui.modals.flow == null or root.ui.battle.board_zone == null or root.ui.modals.level_screen == null:
return
var map_on: bool = root.ui.modals.level_screen.visible
root.ui.battle.board_zone.status_badge.visible = root.run_scope.level_active and not map_on
root.ui.modals.level_screen.status_badge.visible = map_on
# 置灰判据为排除式(调试浮窗开态不计入:对局中浮窗开着时角标仍可点)
root.ui.battle.board_zone.status_badge.disabled = root.ui.modals.flow.badge_greyed_battle() # 互斥域谓词
root.ui.modals.level_screen.status_badge.disabled = root.ui.modals.flow.badge_greyed_map()
# 调试浮层角标(全局浮层任何 UI 不遮挡——可见性不随场景变,只抬 offset
# 避让:地图屏底栏 85px 常驻,角标抬至底栏上方 16px;其余场景右下角 16px 贴底)
root.ui.screens.debug_badge.offset_bottom = -101.0 if map_on else -16.0
static func _on_camp_closed(root: Variant) -> void:
root._camp_pres.on_camp_closed()
static func _camp_data(root: Variant) -> Dictionary:
return HudPresenter.camp_data(root._camp_pres)
static func _on_wallet_changed(root: Variant, event: String, gp: int, extra: Dictionary) -> void:
# wallet 行族转发(到账/购买/清零——试玩日志验收取数面)+ 常驻余额与在开商店覆盖层重刷
root.logger.log_wallet(event, gp, extra)
if String(event) == "gain":
root.run_scope.last_gain_amount = int(extra.get("amount", 0)) # GP 增量取数(每战恰一笔 gain)
if root.ui.modals.shop_overlay.visible and root.run_scope.runner != null:
if root.run_scope.runner.shop.is_shop_pool():
root.ui.modals.shop_overlay.refresh_shelf_state(int(root.run_scope.runner.gp)) # pool 面余额联动(货架内容仅买后重抽变)
else:
root.ui.modals.shop_overlay.refresh_state(root.run_scope.runner.shop.shop_products(), int(root.run_scope.runner.gp))
root._refresh_presentations()
static func _on_legend_toggled(root: Variant) -> void:
if root.ui.modals.legend_overlay.is_open():
root.ui.modals.flow.close(root.ui.modals.legend_overlay)
else:
root.ui.modals.flow.open(root.ui.modals.legend_overlay)