merge: 迭代 8 二轮修改批——A 互斥确认弹窗/B 结算框实底面板+蜡封徽记/C 结算伤害数字突出/D 退出提级一级菜单+开关换皮(用户一轮目检四裁决,click 探针同步)

This commit is contained in:
DKChan committed 2026-09-29 23:30:52 +08:00
commit 7b491bdeb2
9 files changed
+195 -80

No files matched your search

+34 -23
View File
@@ -39,9 +39,8 @@ var _adventure_mode := false # 冒险模式标记(inter 层确认分派
var logger = null # 试玩日志器(JSONL 持久化 + 卡死诊断转储——呈现层组件)
var _level_active := false
var _seed_edit: LineEdit
var _lvbtn: Button # 开始冒险按钮句柄(迭代 8 卡③——有断点时互斥二次确认文案换面)
var _resume_btn: Button # 继续上局按钮句柄(迭代 8 卡②——有断点才亮)
var _lv_start_armed := false # 新冒险二次确认态(首击置位、二击提交、3s 超时回落——仿放弃确认)
var confirm_dialog: ConfirmDialog # 通用确认弹窗(二轮修改批 A——新冒险互斥确认弹窗化)
var _settlement_stop_pending := false # 卡⑥ 战斗胜利总结结算框挂起态(确认「下一节点」后进选路页)
var _pending_candidates: Array = [] # 结算框挂起期的选路候选暂存(choices_presented 载荷)
var _last_gain_amount := 0 # 最近一笔钱包入账(卡⑥ GP 增量取数面——wallet_changed gain 载荷)
@@ -185,18 +184,21 @@ func _build_ui() -> void:
tune_panel.closed.connect(_close_tune_panel)
tune_panel.apply_requested.connect(_on_tune_apply)
tune_panel.simulate_requested.connect(_on_tune_simulate)
settings_overlay = SettingsOverlay.new(settings_store) # 迭代 8 卡④——最小设置面(音量/全屏/减动效/退出)
settings_overlay = SettingsOverlay.new(settings_store) # 迭代 8 卡④——最小设置面(音量/全屏/减动效)
add_child(settings_overlay)
settings_overlay.closed.connect(_on_settings_closed)
confirm_dialog = ConfirmDialog.new() # 二轮修改批 A——新冒险互斥确认弹窗
add_child(confirm_dialog)
confirm_dialog.confirmed.connect(_on_confirm_new_adventure)
confirm_dialog.cancelled.connect(_on_confirm_cancelled)
_modals = ModalStack.new()
for m: Control in [legend_overlay, review_overlay, node_overlay, level_screen, _end_overlay, shop_overlay, camp_overlay, tune_panel, settings_overlay]:
for m: Control in [legend_overlay, review_overlay, node_overlay, level_screen, _end_overlay, shop_overlay, camp_overlay, tune_panel, settings_overlay, confirm_dialog]:
_register_modal(m)
_tune_sim = TuneSimController.new(db, tune_panel, int(db.hero.max_hp))
var start: Dictionary = UiAssembler.build_start_overlay(self, db)
_start_overlay = start.overlay
_seed_edit = start.seed_edit
_lvbtn = start.lvbtn
_resume_btn = start.resumebtn
start.lvbtn.pressed.connect(_start_adventure_from_menu)
start.resumebtn.pressed.connect(_resume_from_menu) # 迭代 8 卡②——续玩入口
@@ -205,6 +207,7 @@ func _build_ui() -> void:
start.dbgbtn.visible = OS.get_environment("DS_DEBUG") == "1" # 迭代 8 卡④——调试入口默认隐藏门控(DS_DEBUG=1 点亮)
start.campbtn.pressed.connect(_open_camp)
start.settingsbtn.pressed.connect(_open_settings) # 迭代 8 卡④——最小设置面入口
start.quitbtn.pressed.connect(_quit_game) # 二轮修改批 D1——退出游戏提级一级菜单
var inter: Dictionary = UiAssembler.build_inter_overlay(self)
_inter_overlay = inter.overlay
@@ -250,35 +253,44 @@ func _input_locked() -> bool:
# 模态/非战斗期棋盘输入锁(各 overlay 自身可见即锁定)
return legend_overlay.is_open() or review_overlay.is_open() or _end_overlay.is_open() \
or node_overlay.visible or level_screen.visible or shop_overlay.visible or tune_panel.visible \
or _start_overlay.visible or _inter_overlay.visible or settlement == null
or _start_overlay.visible or _inter_overlay.visible or confirm_dialog.visible or settlement == null
# ==================== 冒险模式入口(唯一试玩入口——单关测试直入口退役 2026-09-23 用户拍板)====================
func _start_adventure_from_menu() -> void:
# 互斥二次确认(迭代 8 卡②③):有断点时开新冒险须两击——首击转确认态(文案换面+3s 超时回落,
# 仿放弃确认形态),二击才提交;提交即弃旧断点(clear+写盘——「开新局」覆盖语义对盘面即时生效)
if save_manager != null and save_manager.has_breakpoint() and not _lv_start_armed:
_lv_start_armed = true
if _lvbtn != null:
_lvbtn.text = "已有未完冒险——再点一次开新冒险(旧断点将被覆盖)"
get_tree().create_timer(3.0).timeout.connect(_reset_lv_confirm)
# 互斥确认弹窗化(二轮修改批 A——用户目检裁决「弹窗提示」):有断点时开新冒险弹实底确认框,
# 「开新冒险」提交(弃旧断点+写盘)/「取消」回菜单
if save_manager != null and save_manager.has_breakpoint():
var bp: Dictionary = save_manager.breakpoint_snapshot()
confirm_dialog.open("已有未完冒险(第 %d 关)——开新冒险将覆盖旧断点" % maxi(1, int(bp.get("level_index", 1))),
"开新冒险", "取消")
return
if save_manager != null:
save_manager.clear_breakpoint()
save_manager.write_to_disk()
_lv_start_armed = false
_start_overlay.visible = false
_start_adventure()
func _reset_lv_confirm() -> void:
_lv_start_armed = false
if _lvbtn != null:
_lvbtn.text = "▶ 开始冒险(三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城)"
func _on_confirm_new_adventure() -> void:
confirm_dialog.close()
if save_manager != null:
save_manager.clear_breakpoint() # 提交即弃旧断点(覆盖语义对盘面即时生效)
save_manager.write_to_disk()
_start_overlay.visible = false
_start_adventure()
# 继续上局按钮可见性 = 断点在档态(迭代 8 卡②——启动读盘后与每次回开始菜单刷新;确认态随面复位)
func _on_confirm_cancelled() -> void:
confirm_dialog.close() # 回开始菜单(无状态变更)
# 退出游戏(二轮修改批 D1——一级菜单入口;设置即时落盘后退出)
func _quit_game() -> void:
if settings_store != null:
settings_store.save_settings()
get_tree().quit()
# 继续上局按钮可见性 = 断点在档态(迭代 8 卡②——启动读盘后与每次回开始菜单刷新)
func _refresh_resume_button() -> void:
if _resume_btn == null or save_manager == null:
return
@@ -287,7 +299,6 @@ func _refresh_resume_button() -> void:
if has:
var bp: Dictionary = save_manager.breakpoint_snapshot()
_resume_btn.text = "▶ 继续上局(第 %d 关 · 自最近停点恢复)" % maxi(1, int(bp.get("level_index", 1)))
_reset_lv_confirm()
# 继续上局(迭代 8 卡②——卡① resume_adventure 的消费入口):断点重建至最近停点
+5 -2
View File
@@ -142,8 +142,11 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
box.add_child(dbgbtn)
var campbtn := UiKit.button("营地 · 永久强化(钥石换永久属性——跨局成长账本)") # 元进度实现批——主菜单营地入口(双入口框架的主菜单一侧)
box.add_child(campbtn)
var settingsbtn := UiKit.button("设置(音量 / 全屏 / 减动效 / 退出游戏)") # 迭代 8 卡④——最小设置面入口
var settingsbtn := UiKit.button("设置(音量 / 全屏 / 减动效)") # 迭代 8 卡④——最小设置面入口
box.add_child(settingsbtn)
# 二轮修改批 D1(2026-09-29 用户目检裁决):退出游戏与设置同层并行——只在一级菜单出现
var quitbtn := UiKit.button("退出游戏")
box.add_child(quitbtn)
# 玩法帮助文案(表值驱动——2026-09-16 AP 压速批遗留硬编码 8 随手修正;护甲等级掷点批同步"减伤"→"护甲强化")
var help_text := "玩法:每轮 %d AP——挖开(1AP)/插旗(1AP)/移动(免费)/连锁(免费)。\n每个非封锁格都藏一种格面资源(增伤/护甲强化/回血/爆裂/削弱)。开安全格、标中雷 = 正向兑付;\n开雷格、标错安全格 = 负向兑付——全部在轮末结算逐行兑现;吃掷点的基础攻击按护甲等级判定,无 miss、最低保底 1 点。\n停手:剩余 AP 转存 RAP;弃图刷新:RAP−%d 当场换图继续挖(每轮剩 %d 次)。\n敌人全灭胜、主角倒下负。悬停可看三态光标与可挖域微光。" % [
@@ -154,7 +157,7 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
return {"overlay": overlay, "box": box, "seed_edit": seed_edit,
"lvbtn": lvbtn, "resumebtn": resumebtn, "tunebtn": tunebtn, "dbgbtn": dbgbtn,
"campbtn": campbtn, "settingsbtn": settingsbtn}
"campbtn": campbtn, "settingsbtn": settingsbtn, "quitbtn": quitbtn}
# 调试两层模式的层间过渡覆盖层(历史入口专用)。返回 {overlay, label, next_btn}——接线归组合根
+32 -31
View File
@@ -23,6 +23,9 @@ var _board_rect := Rect2()
func _init() -> void:
# 二轮修改批 B(2026-09-29 用户目检裁决):半透明浮层文字不可读 → 实底石板皮面板形态
#(与营地/设置/图例同族)。半透明氛围 dim 保留(胜利暖纱/失败暮蓝),信息与按钮全部上板;
# 金蜡封 = 面板头部静态徽记(原全屏坠落演出退役——落点被面板遮挡)。
_dim = ColorRect.new()
_dim.color = Color(COL_WARM, 0.0)
_dim.set_anchors_preset(Control.PRESET_FULL_RECT)
@@ -30,33 +33,41 @@ func _init() -> void:
var center := CenterContainer.new()
center.set_anchors_preset(Control.PRESET_FULL_RECT)
_dim.add_child(center)
var panel := PanelContainer.new()
panel.add_theme_stylebox_override("panel", UiKit.panel_skinned(Vector4(16, 14, 16, 14)))
center.add_child(panel)
var box := VBoxContainer.new()
box.custom_minimum_size = Vector2(520, 0)
box.add_theme_constant_override("separation", 12)
center.add_child(box)
_verdict = UiKit.label("", 26, true)
_verdict.add_theme_color_override("font_color", COL_WARM)
panel.add_child(box)
var header := HBoxContainer.new()
header.add_theme_constant_override("separation", 12)
header.alignment = BoxContainer.ALIGNMENT_CENTER
box.add_child(header)
_seal = Panel.new()
_seal.mouse_filter = Control.MOUSE_FILTER_IGNORE
var sb := UiKit.panel_flat(COL_GOLD, UiKit.GOLD_DEEP, 200, 4)
_seal.add_theme_stylebox_override("panel", sb)
_seal.custom_minimum_size = Vector2(34, 34)
_seal.size_flags_vertical = Control.SIZE_SHRINK_CENTER
header.add_child(_seal)
_verdict = UiKit.label("", 24, true)
_verdict.add_theme_color_override("font_color", UiKit.INK_TITLE)
_verdict.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
box.add_child(_verdict)
_verdict.size_flags_vertical = Control.SIZE_SHRINK_CENTER
header.add_child(_verdict)
_gp_line = UiKit.label("", 16, true)
_gp_line.add_theme_color_override("font_color", UiKit.GOLD)
_gp_line.add_theme_color_override("font_color", UiKit.INK_LABEL)
_gp_line.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_gp_line.visible = false
box.add_child(_gp_line)
box.add_child(HSeparator.new())
_review_btn = UiKit.button("明细回看")
_review_btn.pressed.connect(_emit_review_pressed)
box.add_child(_review_btn)
_btn = UiKit.button("继续")
_btn.pressed.connect(_emit_continue_pressed)
box.add_child(_btn)
# 金蜡封占位(胜利):圆形色块落于扫雷图区中央——位置由 set_board_rect 注入
_seal = Panel.new()
_seal.mouse_filter = Control.MOUSE_FILTER_IGNORE
var sb := UiKit.panel_flat(COL_GOLD, UiKit.GOLD_DEEP, 200, 4)
_seal.add_theme_stylebox_override("panel", sb)
_seal.size = Vector2(72, 72)
_seal.visible = false
_seal.top_level = true
add_child(_seal)
visible = false
@@ -66,14 +77,13 @@ func _init() -> void:
func open_victory(verdict_line: String, continue_label: String, board_rect: Rect2, gp_summary: String = "") -> void:
_dim.color = Color(COL_WARM, 0.28)
_verdict.text = verdict_line
_verdict.add_theme_color_override("font_color", UiKit.INK_ON_GOLD)
_seal.visible = true # 胜利徽记(面板头部静态)
_gp_line.text = gp_summary
_gp_line.visible = gp_summary != ""
_btn.text = continue_label
_board_rect = board_rect
visible = true
_play_seal_fall()
_play_crest_assemble() # 碎砖拼纹章(§2.4——样张 v2 冻结批 T3 终稿)
_play_crest_assemble() # 碎砖拼纹章(§2.4——样张 v2 冻结批 T3 终稿;绕面板屏心环收)
_play_flag_recall(0) # 胜利不放旗收回
@@ -81,11 +91,10 @@ func open_defeat(verdict_line: String, continue_label: String, board_rect: Rect2
# 明度不变的暮蓝色相氛围(全屏唯一暮蓝档——§2.5 最静一拍)
_dim.color = Color(COL_DUSK, 0.45)
_verdict.text = verdict_line
_verdict.add_theme_color_override("font_color", COL_WARM)
_gp_line.visible = false # GP 总量+增量归胜利总结结算(OQ14)——失败侧不呈现
_board_rect = board_rect
visible = true
_seal.visible = false
_seal.visible = false # 失败无徽记(暮蓝氛围)
_play_dust_sadle() # 坐砖掸灰(§2.5——终稿)
_play_flag_recall(8)
@@ -104,16 +113,8 @@ func verdict_text() -> String:
return _verdict.text
# 金蜡封自上落下弹跳定格于棋盘中央(§2.4 克制不狂欢——占位级)
func _play_seal_fall() -> void:
var target := _board_rect.get_center() - _seal.size * 0.5
if _board_rect.size == Vector2.ZERO:
target = get_viewport_rect().size * 0.5 - _seal.size * 0.5
_seal.position = Vector2(target.x, -100.0)
_seal.visible = true
var tw := _seal.create_tween()
tw.tween_property(_seal, "position:y", target.y - 26.0, UiKit.motion(0.42)).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
tw.tween_property(_seal, "position:y", target.y, UiKit.motion(0.22)).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
func _fx_center() -> Vector2:
return get_viewport_rect().size * 0.5
# 旗化光点收回(失败——插过的旗逐面化光点收回占位,§2.5)
@@ -147,7 +148,7 @@ var _fx_flag_dots := 0
func _play_crest_assemble() -> void:
_clear_crest_bricks()
_fx_crest_shards = 10
var c := _board_rect.get_center() if _board_rect.size != Vector2.ZERO else get_viewport_rect().size * 0.5
var c := _fx_center()
for i in 10:
var brick := ColorRect.new()
brick.color = UiKit.BRICK if i % 2 == 0 else UiKit.FLOOR # 碎砖=砖面族色(掩尘/裸土——图底同源)
@@ -167,7 +168,7 @@ func _play_crest_assemble() -> void:
# 坐砖掸灰(失败 §2.5——暖灰尘絮自棋盘中带缓缓飘落,最静一拍的运动承载)
func _play_dust_sadle() -> void:
_fx_dust_motes = 8
var base := _board_rect.get_center() if _board_rect.size != Vector2.ZERO else get_viewport_rect().size * 0.5
var base := _fx_center()
for i in 8:
var mote := ColorRect.new()
mote.color = Color(UiKit.WARM_FAINT, 0.85)
+3 -1
View File
@@ -192,7 +192,9 @@ func _format_row(row: Dictionary, agg_count := -1) -> String:
roll_txt += " · ×%d%%" % int(row.tier)
roll_txt += "〕"
var kill := " ⚔击杀!" if row.get("killed", false) else ""
var body := "%s -%d%s%s%s%s" % [name_, v, roll_txt, tail, kill, suffix]
# 二轮修改批 C(2026-09-29 用户目检——「每次结算标出的伤害数字不明显」):
# 伤害值放大加色独立于行文(朱红大一号——数字即信息主角,非同字号色温微差)
var body := "%s [color=#d9402a][size=17]-%d[/size][/color]%s%s%s%s" % [name_, v, roll_txt, tail, kill, suffix]
var body_col := "#e07050" if row.get("killed", false) else ("#9a8a72" if v == 0 else "#e0a050")
if bool(row.get("crit", false)):
return prefix + _gold_frame(body) # nat 最大面暴击 = 金框高亮行
+71
View File
@@ -0,0 +1,71 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# Date: 2026-09-29(迭代 8 二轮修改批 A——新冒险互斥确认弹窗化,用户目检裁决:
# 按钮文字换面 → 实底确认弹窗「开新冒险 + 取消」)
# 通用确认弹窗(实底石板皮面板,与营地/设置/图例同族视觉):open(text, confirm_label, cancel_label)
# 双钮外发 confirmed/cancelled——语义装配归调用方,本类零业务触碰(纯视图边界规范 1.3)。
class_name ConfirmDialog
extends Control
signal confirmed
signal cancelled
var _text: Label
var _confirm_btn: Button
var _cancel_btn: Button
func _init() -> void:
var dim := ColorRect.new()
dim.color = Color(UiKit.DIM, 0.55)
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
add_child(dim)
var center := CenterContainer.new()
center.set_anchors_preset(Control.PRESET_FULL_RECT)
dim.add_child(center)
var panel := PanelContainer.new()
panel.add_theme_stylebox_override("panel", UiKit.panel_skinned(Vector4(14, 12, 14, 12)))
center.add_child(panel)
var box := VBoxContainer.new()
box.custom_minimum_size = Vector2(460, 0)
box.add_theme_constant_override("separation", 12)
panel.add_child(box)
_text = UiKit.label("", 16, false)
_text.add_theme_color_override("font_color", UiKit.INK_TITLE)
_text.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_text.custom_minimum_size = Vector2(430, 0)
box.add_child(_text)
box.add_child(HSeparator.new())
var btn_row := HBoxContainer.new()
btn_row.add_theme_constant_override("separation", 12)
btn_row.alignment = BoxContainer.ALIGNMENT_CENTER
box.add_child(btn_row)
_cancel_btn = UiKit.button("取消")
_cancel_btn.pressed.connect(_emit_cancelled)
btn_row.add_child(_cancel_btn)
_confirm_btn = UiKit.button("确认")
_confirm_btn.pressed.connect(_emit_confirmed)
btn_row.add_child(_confirm_btn)
visible = false
func open(text: String, confirm_label: String, cancel_label: String = "取消") -> void:
_text.text = text
_confirm_btn.text = confirm_label
_cancel_btn.text = cancel_label
visible = true
func close() -> void:
visible = false
func is_open() -> bool:
return visible
func _emit_confirmed() -> void:
confirmed.emit()
func _emit_cancelled() -> void:
cancelled.emit()
@@ -0,0 +1 @@
uid://dhe557khvoq3y
+12 -16
View File
@@ -1,6 +1,6 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# Date: 2026-09-29(迭代 8 卡④ 最小设置面)
# 设置覆盖层(纯视图边界规范 1.3 同款):音量滑杆/全屏/减动效三件+退出游戏+返回。
# 设置覆盖层(纯视图边界规范 1.3 同款):音量滑杆/全屏/减动效三件+返回(退出游戏已提级开始菜单)。
# 生效与持久化全经 SettingsStore 单点(实时应用+即改即存);本类零核心触碰。
# 减动效转正承载(测试调整板旧开关退役——设置面唯一入口,卡④ AC③)。
# 探针接缝:retarget(store) = 隔离存档换注口(同 camp 换注先例);控件引用公有只读供断言。
@@ -12,8 +12,8 @@ signal closed
var _store
var _volume: HSlider
var _volume_val: Label
var _fs_btn: CheckButton
var _motion_btn: CheckButton
var _fs_btn: Button
var _motion_btn: Button
func _init(store) -> void:
@@ -65,22 +65,21 @@ func _build() -> void:
_volume_val.custom_minimum_size = Vector2(60, 0)
vol_row.add_child(_volume_val)
# 全屏(art-bible 1920 档缩放策略冲突条目挂起注记——现行视口恒等拉伸,全屏切换即窗口模式切换)
_fs_btn = CheckButton.new()
_fs_btn.text = "全屏"
# 开关形态(二轮修改批 D2 2026-09-29 用户目检——原生 CheckButton 暗底不显眼,
# 换 UiKit 按钮形态 toggle:文字「全屏:开/关」随态换面)
_fs_btn = UiKit.button("全屏:关")
_fs_btn.toggle_mode = true
_fs_btn.toggled.connect(_on_fullscreen_toggled)
box.add_child(_fs_btn)
# 减动效(battle.md §Transitions 承诺转正——时长减半,结算逐行兑现=信息载体不整体跳过)
_motion_btn = CheckButton.new()
_motion_btn.text = "减动效(动画时长减半——运动敏感/演示用)"
_motion_btn = UiKit.button("减动效:关(动画时长减半——运动敏感/演示用)")
_motion_btn.toggle_mode = true
_motion_btn.toggled.connect(_on_motion_toggled)
box.add_child(_motion_btn)
box.add_child(HSeparator.new())
var quit_btn := UiKit.button("退出游戏")
quit_btn.pressed.connect(_on_quit_pressed)
box.add_child(quit_btn)
# 退出游戏已提级开始菜单(D1——设置面不再承载,用户裁决「退出只在一级菜单出现」)
var close_btn := UiKit.button("返回")
close_btn.pressed.connect(_emit_closed)
box.add_child(close_btn)
@@ -90,7 +89,9 @@ func _sync() -> void:
_volume.set_value_no_signal(roundf(_store.volume_linear * 100.0))
_volume_val.text = "%d%%" % roundi(_store.volume_linear * 100.0)
_fs_btn.set_pressed_no_signal(_store.fullscreen)
_fs_btn.text = "全屏:%s" % ("开" if _store.fullscreen else "关")
_motion_btn.set_pressed_no_signal(_store.reduced_motion)
_motion_btn.text = "减动效:%s(动画时长减半——运动敏感/演示用)" % ("开" if _store.reduced_motion else "关")
func _on_volume_changed(v: float) -> void:
@@ -112,10 +113,5 @@ func _on_motion_toggled(on: bool) -> void:
_store.save_settings()
func _on_quit_pressed() -> void:
_store.save_settings()
get_tree().quit()
func _emit_closed() -> void:
closed.emit()
+36 -7
View File
@@ -100,7 +100,7 @@ func _ready() -> void:
_problems.append("设置面未打开(点击路径)")
else:
# 减动效转正双态(卡④ AC③):开=0.5 引擎态即时生效+落盘持久;关=1.0 回常态
var motion_btn: CheckButton = _find_checkbutton_by_text(main.settings_overlay, "减动效")
var motion_btn: Button = _find_button_by_text(main.settings_overlay, "减动效") # 二轮 D2——开关已换 UiKit toggle 按钮形态
if motion_btn == null:
_problems.append("设置面减动效开关缺失")
else:
@@ -142,6 +142,11 @@ func _ready() -> void:
var legacy_motion = _find_checkbutton_by_text(main.tune_panel, "减动效")
if legacy_motion != null:
_problems.append("调整板减动效旧入口未退役(设置面唯一入口失守——卡④ AC③)")
# D1 断言(二轮):退出游戏只在一级菜单——开始菜单有、设置面无
if _find_button_by_prefix(main._start_overlay, "退出游戏") == null:
_problems.append("开始菜单缺退出游戏按钮(二轮 D1)")
if _find_button_by_prefix(main.settings_overlay, "退出游戏") != null:
_problems.append("设置面仍含退出游戏按钮(二轮 D1——只在一级菜单出现)")
# 换回全新零档(营地购买态不泄入后续冒险段——确定性;档案残留下次段首清理兜底)
for p0 in ["user://smoke_click_probe_reset.json", "user://smoke_click_probe_reset.json.tmp"]:
if FileAccess.file_exists(p0):
@@ -321,7 +326,7 @@ func _ready() -> void:
_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.adventure = null
@@ -329,13 +334,27 @@ func _ready() -> void:
await get_tree().process_frame
lv_btn.pressed.emit()
await get_tree().process_frame
if not main._start_overlay.visible or main.adventure != null:
_problems.append("断点段:有断点首击即开新冒险(互斥二次确认失守卡②③)")
if not main.confirm_dialog.is_open() or main.adventure != null:
_problems.append("断点段:有断点点开始冒险未弹确认框(二轮 A 失守)")
var cancel_btn: Button = _find_button_by_text(main.confirm_dialog, "取消")
if cancel_btn == null:
_problems.append("断点段:确认框取消按钮缺失")
else:
cancel_btn.pressed.emit()
await get_tree().process_frame
if main.confirm_dialog.is_open() or main.adventure != null or not main._start_overlay.visible:
_problems.append("断点段:取消未回开始菜单(二轮 A)")
lv_btn.pressed.emit()
await get_tree().process_frame
await get_tree().process_frame
if main.adventure == null or main._start_overlay.visible:
_problems.append("断点段:二次确认后未开新冒险")
var confirm_btn: Button = _find_button_by_text(main.confirm_dialog, "开新冒险")
if confirm_btn == null:
_problems.append("断点段:确认框开新冒险按钮缺失")
else:
confirm_btn.pressed.emit()
await get_tree().process_frame
await get_tree().process_frame
if main.adventure == null or main._start_overlay.visible or main.confirm_dialog.is_open():
_problems.append("断点段:确认开新冒险后未开局(二轮 A)")
print("[click_probe] 循环退出(done=%s budget=%s)问题=%d" % [
str(_done), str(action_budget), _problems.size()])
for p in _problems:
@@ -526,6 +545,16 @@ func _find_button_by_prefix(root: Node, prefix: String) -> Button:
return null
func _find_button_by_text(root: Node, needle: String) -> Button:
if root is Button and String(root.text).contains(needle):
return root
for child in root.get_children():
var found := _find_button_by_text(child, needle)
if found != null:
return found
return null
func _find_checkbutton_by_text(root: Node, needle: String) -> CheckButton:
if root is CheckButton and String(root.text).contains(needle):
return root
@@ -0,0 +1 @@
uid://fjdvajc5ek85