iter47-卡3:卡⑤(迭代47·Esc浮窗与营地顶栏批): Esc浮窗四态路由+CampHudBand顶栏栏+设置语境分支+断言批+审计补差+master取用+camp.md v2.3定稿吸收(半透明遮罩0.6场景根留底/Esc先关窗Q1甲换代)——终态六枚落满

This commit is contained in:
DKChan committed 2026-11-01 23:44:29 +08:00
1 parent bbeeea77e0
commit 6208a9cd1a
37 files changed
+1117 -107

No files matched your search

+74 -1
View File
@@ -27,6 +27,7 @@ func _ready() -> void:
await _step_boot_menu()
await _step_menu_to_camp()
await _step_camp_back_to_menu()
await _step_camp_esc_and_hud() # 卡⑤——Esc 四态路由/三出口/设置语境分支/HUD 读数
await _step_save_select_open_back() # 迭代 33 卡③ sl10——选档开合+返回路径+ESC 语境不响应
await _step_menu_to_adventure()
await _step_level_to_battle_and_back()
@@ -122,7 +123,9 @@ func _step_camp_back_to_menu() -> void:
return
main.ui.modals.camp.scene.object_pressed.emit(&"campfire")
await _frames()
main.ui.modals.confirm_dialog.confirmed.emit() # 二次确认离场(回主菜单——卡④ T4)
if not main.ui.modals.confirm_dialog.visible:
_problems.append("③篝火:二次确认弹窗未现(camp.md v2.2 必须先确认)〔营地图批 V7〕")
main.ui.modals.confirm_dialog.confirmed.emit() # 二次确认离场(confirmed 先于关层——卡④ T4)
await _frames()
_expect_exclusive("③营地→菜单(回退)", "菜单")
@@ -229,3 +232,73 @@ func _step_end_back_to_menu() -> void:
_expect_exclusive("⑦终局→菜单", "菜单")
if main.run_scope != null and main.run_scope.is_adventure:
_problems.append("⑦终局→菜单:冒险态未收束(run_scope 仍标 is_adventure)")
# ---- ③' 营地 Esc 浮窗+HUD(卡⑤——真实键盘合成路径 push_input;四态路由+三出口+语境分支+余额单口)----
func _step_camp_esc_and_hud() -> void:
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_esc", false, false, true)
if not ProbeUiUtil.open_camp_via_savesel(main, "smoke_screen_flow_esc"):
_problems.append("[esc] 营地入口缺失(选档层新档钮驱动中断)〔ESC批 V1〕")
return
await _frames()
_push_esc()
await _frames()
if not main.ui.modals.camp.esc_overlay.visible:
_problems.append("[esc] 营地根态 Esc 未唤起浮窗(契约 9③)〔ESC批 V1〕〔ESC批 B1〕")
_push_esc()
await _frames()
if main.ui.modals.camp.esc_overlay.visible:
_problems.append("[esc] 再按 Esc 未关浮窗(Q2 同键单义切换失守)〔ESC批 V1〕")
_push_esc(true) # echo 连发(真实键盘长按形态)
await _frames()
if main.ui.modals.camp.esc_overlay.visible:
_problems.append("[esc] echo 事件唤起浮窗(触发沿 pressed 且非 echo 失守)〔ESC批 V1〕")
main.ui.modals.camp.scene.object_pressed.emit(&"dummy") # 子界面开态
await _frames()
_push_esc()
await _frames()
if main.ui.modals.camp.tree.visible:
_problems.append("[esc] 子界面开态 Esc 未关窗(camp.md v2.3 定稿——先关最上层窗)〔ESC批 V1〕")
if main.ui.modals.camp.esc_overlay.visible:
_problems.append("[esc] 关窗同拍唤起浮窗(先关窗后浮窗——两拍应分离)〔ESC批 V1〕")
await _frames()
# HUD 余额(契约 5 时机③——夹具直写后显式触发才变;禁 band 自刷假设)
main.meta.meta_state._add_keystone(9999)
main._camp_pres.views.refresh_bus.refresh(main._camp_data()) # 显式触发刷新单口
var band: Control = main.ui.modals.camp.scene.get_node("HudBandSlot").get_child(0)
if not String(band._badge.value_label.text).begins_with("钥石 9999"):
_problems.append("[esc] HUD 余额读数≠存档单口现值(直写+显式触发未变)〔ESC批 V6〕〔ESC批 B2〕")
# 设置开在浮窗之上→Esc 无反馈且浮窗不误关(契约 9①);关设置回浮窗不回主菜单(契约 3 语境分支)
_push_esc()
await _frames()
main._on_esc_settings()
await _frames()
if not main.ui.modals.settings_overlay.visible:
_problems.append("[esc] 浮窗设置出口断裂〔ESC批 V4〕")
_push_esc()
await _frames()
if not main.ui.modals.camp.esc_overlay.visible:
_problems.append("[esc] 设置开态 Esc 误关浮窗(契约 9①——浮窗不隔层关闭)〔ESC批 V1〕")
main._on_settings_closed()
await _frames()
if not main.ui.modals.camp.esc_overlay.visible or main.ui.screens.start_overlay.visible:
_problems.append("[esc] 关设置后未回浮窗或回弹主菜单(契约 3 语境分支失守)〔ESC批 V4〕〔ESC批 B3〕")
# 返回主菜单动线(契约 4——浮窗自收+营地隐+选档收+菜单显)
main.ui.modals.camp.esc_overlay.return_requested.emit()
await _frames()
if main.ui.modals.camp.esc_overlay.visible or main.ui.modals.camp.scene.visible or main.ui.modals.save_select_overlay.visible or not main.ui.screens.start_overlay.visible:
_problems.append("[esc] 返回主菜单动线失守(浮窗自收/营地隐/选档收/菜单显)〔ESC批 V3〕〔ESC批 B3〕")
# 非营地语境(boot 菜单)Esc→无响应(契约 9④ 回归面)
_push_esc()
await _frames()
if main.ui.modals.camp.esc_overlay.visible:
_problems.append("[esc] 非营地语境 Esc 唤起浮窗(契约 9④ 失守)〔ESC批 V1〕")
func _push_esc(echo := false) -> void:
var ev := InputEventKey.new()
ev.keycode = KEY_ESCAPE
ev.physical_keycode = KEY_ESCAPE
ev.pressed = true
ev.echo = echo
main.get_viewport().push_input(ev, true) # 真实键盘合成路径(:153 先例——push_input 不更新 Input 单例动作态)
+5 -5
View File
@@ -88,11 +88,11 @@ func _ready() -> void:
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)〔句柄子容器批 V1〕" % [bal_before, iso_c.meta_state.keystone_balance(), price])
_problems.append("营地树购买未出账(%d→%d 应 −%d)〔句柄子容器批 V1〕〔营地图批 V4〕" % [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)〔句柄子容器批 V1〕")
_problems.append("营地树购买未持久(reload 后级 != 1)〔句柄子容器批 V1〕〔营地图批 V4〕")
# Fork 双态切换点击路径(V20——购=解锁默认 A,钮切 B;前置=同调位 1,先点亮)
var socket_btn: Button = null
for card in main.ui.modals.camp.tree._tree_buy_btns:
@@ -177,10 +177,10 @@ func _ready() -> void:
_collect_labels_by_text(main.ui.modals.camp.codex, codex_labels)
var atlas_locks := _labels_with_text(codex_labels, "结构位预留")
if atlas_locks.is_empty():
_problems.append("营地灰字:图鉴锁文 label 未找到(wc4 定位锚失守——锚随形态订正去『柜台』)〔句柄子容器批 V1〕")
_problems.append("营地灰字:图鉴锁文 label 未找到(wc4 定位锚失守——锚随形态订正去『柜台』)〔句柄子容器批 V1〕〔营地图批 V6〕")
for l in atlas_locks:
if l.get_theme_color("font_color") != UiKit.STONE_DEEP:
_problems.append("营地灰字:图鉴锁文未用 STONE_DEEP(wc4 :167)〔句柄子容器批 V1〕")
_problems.append("营地灰字:图鉴锁文未用 STONE_DEEP(wc4 :167)〔句柄子容器批 V1〕〔营地图批 V6〕")
main.ui.modals.camp.codex.closed.emit()
await get_tree().process_frame
main._on_camp_closed() # 关层收闭(营地与选档层同收+开始层恢复——卡④ T3)
@@ -702,7 +702,7 @@ func _ready() -> void:
main.ui.modals.confirm_dialog.confirmed.emit() # 「是」→开始新冒险
await get_tree().process_frame
if not main.run_scope.is_adventure or main.ui.modals.camp.scene.visible:
_problems.append("大门确认:冒险未发起或营地场景屏未隐藏〔营地图批 V3〕")
_problems.append("大门确认:冒险未发起或营地场景屏未隐藏〔营地图批 V3〕〔营地图批 B1〕")
# 有断点三出口(选路停点形注入——同开场行③ set_breakpoint 先例)
main.save_manager.set_breakpoint({
"master_seed": 42, "rng_counter": 0, "hero_hp": 30, "gp": 10, "keystone": 0,
+55
View File
@@ -104,6 +104,51 @@ func _ready() -> void:
_settle()
if main.ui.modals.career_overlay.visible or main.ui.screens.start_overlay.visible:
problems.append("[career] 关闭后页未隐藏或开始层回弹(营地语境分支失守)〔营地图批 V5〕")
# ---- Esc 浮窗结构段(卡⑤——三钮在位且仅三+零动效契约+登记序在册+debug_badge 不波及)----
main._camp_pres.open_camp()
_settle()
main.ui.modals.camp.scene.object_pressed.emit(&"gate")
_settle()
main.ui.modals.confirm_dialog.cancelled.emit() # 关大门弹窗(清场——浮窗段前提)
_settle()
var push_esc := func() -> void:
var ev := InputEventKey.new()
ev.keycode = KEY_ESCAPE
ev.physical_keycode = KEY_ESCAPE
ev.pressed = true
main.get_viewport().push_input(ev, true)
push_esc.call()
_settle()
if not main.ui.modals.camp.esc_overlay.visible:
problems.append("[esc] 浮窗未唤起(结构段前提——营地语境 Esc 路由)〔ESC批 V1〕")
var esc_btns := _buttons(main.ui.modals.camp.esc_overlay).size()
if esc_btns != 3:
problems.append("[esc] 浮窗三钮在位且仅三(实得 %d——禁第四钮)〔ESC批 V2〕" % esc_btns)
var esc_static := FileAccess.get_file_as_string("res://presentation/views/camp_esc_overlay.gd") + FileAccess.get_file_as_string("res://presentation/main_esc_flow.gd")
if esc_static.contains("create_tween") or esc_static.contains("UiKit.motion"):
problems.append("[esc] 浮窗双件源码存在动效令牌(契约 6 零动效——直开直关)〔ESC批 V7〕")
var esc_anim := _count_animplayers(main.ui.modals.camp.esc_overlay)
if esc_anim != 0:
problems.append("[esc] 浮窗子树 AnimationPlayer 非零(契约 6 零动效)〔ESC批 V7〕")
var esc_src := FileAccess.get_file_as_string("res://presentation/views/camp_esc_overlay.gd") + FileAccess.get_file_as_string("res://presentation/main_esc_flow.gd")
if esc_src.is_empty():
problems.append("[esc] 零动效扫描面为空(源文件读失败——非空前置失守)〔ESC批 V7〕")
# 退出项接线断言(卡⑤ V5——绑信号连接与调用链;headless 不可真退=静态判据+观测面局限申报)
var quit_wired := false
for c in main.ui.modals.camp.esc_overlay.quit_requested.get_connections():
if c.callable.get_method() == "_on_esc_quit":
quit_wired = true
if not quit_wired:
problems.append("[esc] 退出钮接线断链(quit_requested 连接目标≠_on_esc_quit)〔ESC批 V5〕")
var quit_chain := FileAccess.get_file_as_string("res://presentation/main.gd") + FileAccess.get_file_as_string("res://presentation/main_esc_flow.gd")
if not quit_chain.contains("MainEscFlow._on_quit(self)") or not quit_chain.contains("root._quit_game()"):
problems.append("[esc] 退出调用链断裂(_on_esc_quit→_on_quit→_quit_game)〔ESC批 V5〕")
if main.ui.screens.debug_badge.visible:
problems.append("[esc] 浮窗开态 debug_badge 可见(发布态恒隐——float 类不注册 ModalStack 应零波及)〔ESC批 V8〕")
push_esc.call()
_settle()
if main.ui.modals.camp.esc_overlay.visible:
problems.append("[esc] 再按 Esc 未关浮窗(结构段收尾——Q2 单义切换)〔ESC批 V1〕")
main._on_camp_closed() # 关营地复归菜单语境(后续选档段前提)
_settle()
@@ -756,3 +801,13 @@ func _start_columns_contract(main: Node) -> void:
if box.get_global_rect().intersects(right.get_global_rect()):
problems.append("[start][columns] 左列 %s 与右列 %s 相交(双列叠放回归——M2 缺陷闸)" % [
box.get_global_rect(), right.get_global_rect()])
# AnimationPlayer 全子树收集(零动效契约扫描面——_buttons 同款递归形态)
func _count_animplayers(node: Node) -> int:
var out := 0
if node is AnimationPlayer:
out += 1
for child in node.get_children():
out += _count_animplayers(child)
return out