diff --git a/game/core/adventure_runner.gd b/game/core/adventure_runner.gd index cb7e866d..d6101e4b 100644 --- a/game/core/adventure_runner.gd +++ b/game/core/adventure_runner.gd @@ -67,7 +67,7 @@ var summary := {} # 最近一次结算的冒险摘要( var _runner: LevelRunner # 当前关卡行进器(每关新建——关卡域状态天然隔离) var _pending_next_level := false # 大奖励已兑付、等 continue_to_next_level 确认 var _last_level_payload := {} # 最近一次关卡结束载荷(失败结算的败退节点明细来源——数值验证取数面) -var _override := [0, 0] # TunePanel 百分比通道 [atk_pct, hp_pct](每关新 runner 都要应用) +var _override := [0, 0] # 调试浮窗百分比通道 [atk_pct, hp_pct](每关新 runner 都要应用) var _base_override := {"atk": 0, "max_hp": 0, "armor_class": 0} var _first_script := false # 首次脚本模式(关卡节点图生成 v0.4——true = 全关零抽签取池内模板 0;测量夹具恒 false) # 永久强化 flat 注入(元进度实现批——冒险开始参数面 params.hero_override 存入,共享给 LevelRunner;全零 = 白板) var _last_aux_cleared := 0 # additive(迭代 7 T4——最近一次关卡末清空计数,summary 取数面) @@ -136,7 +136,7 @@ func start_adventure(seed_val: int, params: Dictionary = {}) -> bool: _relics = [] for r in relic_seed: _relics.append(String(r)) - ledger["hero_hp"] = effective_max_hp() # 生命账本置满(生效上限口径——T17 修复:含 TunePanel pct,与战斗内同源) + ledger["hero_hp"] = effective_max_hp() # 生命账本置满(生效上限口径——T17 修复:含调试浮窗 pct,与战斗内同源) state = "running" return _start_current_level() @@ -201,7 +201,7 @@ func resume_adventure(bp: Dictionary, params: Dictionary = {}) -> bool: # 生命账本越界钳制(T17——spawn 守卫 EC16 免疫):断点可能由旧口径版本写出(如调试上限 # 调高期带出的账本值 > 新口径生效上限,实例:hero_hp=28 > 基础 26)——恢复后钳到生效上限, # 否则首战 spawn「hero_hp 入参越界」拒收 → 「敌人系统 spawn 被拒」fatal。上限 = 表值+永久 - # 强化 flat+加算区 flat 后乘 TunePanel pct(effective_max_hp 同式——此刻加算区尚未恢复, + # 强化 flat+加算区 flat 后乘调试浮窗 pct(effective_max_hp 同式——此刻加算区尚未恢复, # 钳制用 flat 已含的保守口径即可,加算区恢复后其余战斗照常)。 ledger["hero_hp"] = mini(int(ledger.get("hero_hp", 0)), maxi(1, int(round(float(int(db.hero.max_hp) + int(_base_override.get("max_hp", 0))) * (100.0 + float(_override[1])) / 100.0)))) @@ -289,7 +289,7 @@ func _token_identity(tok: Dictionary) -> String: return String(tok.get("kind", "")) -# TunePanel 百分比通道(测试面板覆盖——每关新 runner 都要应用;正式侧归元进度) +# 调试浮窗百分比通道(测试工具覆盖——每关新 runner 都要应用;正式侧归元进度) func set_hero_override(atk_pct: int, hp_pct: int) -> void: _override = [atk_pct, hp_pct] if _runner != null: @@ -297,7 +297,7 @@ func set_hero_override(atk_pct: int, hp_pct: int) -> void: # 冒险账本侧生效上限(T17 修复——账本置满/回血封顶与战斗内上限同式同源): -# (表值 + 永久强化 flat + 加算区 flat)后乘 TunePanel 百分比——叠加次序与 LevelRunner.effective_max_hp +# (表值 + 永久强化 flat + 加算区 flat)后乘调试浮窗百分比——叠加次序与 LevelRunner.effective_max_hp # 逐字一致。旧口径两处只算 flat 不乘 pct:调生命上限 26→104 时开局血仍 26(账本 26 / 战斗内 104)、 # 通关 20% 回血封顶按 26 算。pct=0(模拟/冒烟默认)时乘法恒等——MC 锚零漂移。 func effective_max_hp() -> int: @@ -868,7 +868,7 @@ func _on_level_finished(payload: Dictionary) -> void: # 通关兑付(非末关恰一次;迭代 10 三层奖励框架):部分回血先行 → 加权洗牌掷 3 → 三选一停点 #(顺序即契约——回血按当刻账本与上限结算,选择停点零自动推进) var hp_before := int(ledger.get("hero_hp", 0)) - var max_eff := effective_max_hp() # T17 修复:回血封顶口径含 TunePanel pct(同战斗内上限) + var max_eff := effective_max_hp() # T17 修复:回血封顶口径含调试浮窗 pct(同战斗内上限) var heal := mini(int(floor(float(max_eff) * float(int(db.adventure.clear_heal_pct)) / 100.0)), max_eff - hp_before) ledger["hero_hp"] = hp_before + heal # 置位先于 emit(信号同步派发——处理器内立即确认时 _pending_next_level 必须已就位) diff --git a/game/core/level_runner.gd b/game/core/level_runner.gd index 286d1630..93be736e 100644 --- a/game/core/level_runner.gd +++ b/game/core/level_runner.gd @@ -15,7 +15,7 @@ # 对应 GDD:关卡节点地图 v1.0(图版结构——本文件为 P1 批实现位;命名规范见 CLAUDE.md) # GP+商店房实施批(2026-09-21):GP 冒险钱包(战斗完成入账 clamp ≥0 · 冒险收束清零)+ 统一冒险 # 加算区 bonus{atk,max_hp,armor_class}(商店购买与关卡大奖励共用账本——战斗开始参数 = 基础表值 + -# 加算区,TunePanel 百分比在加算之后乘)+ 商店房节点兑付(开覆盖层/购买出账/离开回选路确认—— +# 加算区,调试浮窗百分比在加算之后乘)+ 商店房节点兑付(开覆盖层/购买出账/离开回选路确认—— # 复用 continue_after_node 兑付确认纪律,零自动推进)。 # 冒险结构实现批(2026-09-21)——接口漂移清偿登记(06 清单「切片行进代码与定稿的接口漂移」①②③⑥⑦): # ① 种子域归冒险结构:start_level 旧路径(单关测试模式)保留自调 rng.new_adventure;新路径 @@ -105,7 +105,7 @@ func set_hero_override(atk_pct: int, hp_pct: int) -> void: # 叠加次序(元进度实现批钉死):表值 → 永久强化 flat(base_override)→ 加算区 flat(bonus)先加 -# → TunePanel 百分比后乘(调整板 = 测试工具恒乘最后——代拍板 6,与 GP 批既有次序兼容) +# → 调试浮窗百分比后乘(调试数值工具恒乘最后——代拍板 6,与 GP 批既有次序兼容) func effective_atk() -> int: var base: int = int(db.hero.atk) + int(base_override.get("atk", 0)) + int(bonus.get("atk", 0)) return maxi(1, int(round(float(base) * (100.0 + float(hero_atk_pct)) / 100.0))) @@ -116,7 +116,7 @@ func effective_max_hp() -> int: return maxi(1, int(round(float(base) * (100.0 + float(hero_hp_pct)) / 100.0))) -# 护甲等级生效值(永久强化 flat + 加算区 armor_class 轴——无 TunePanel 百分比通道,纯 flat) +# 护甲等级生效值(永久强化 flat + 加算区 armor_class 轴——无调试浮窗百分比通道,纯 flat) func effective_ac() -> int: return maxi(0, int(db.hero.armor_class) + int(base_override.get("armor_class", 0)) + int(bonus.get("armor_class", 0))) diff --git a/game/presentation/camp_shop_presenter.gd b/game/presentation/camp_shop_presenter.gd index 5662abf6..1a47bbda 100644 --- a/game/presentation/camp_shop_presenter.gd +++ b/game/presentation/camp_shop_presenter.gd @@ -13,7 +13,7 @@ var _save_get: Callable # () → 存档承载现值(同上——营 var camp_overlay: CampOverlay var shop_overlay: ShopOverlay var toast: ToastStack -var start_overlay: Control # 开始层互斥面(开合仿 TunePanel 先例——非模态且树序在后,规范 2.3) +var start_overlay: Control # 开始层互斥面(开合仿设置面先例——非模态且树序在后,规范 2.3) var logger # 试玩日志(ux_reject 取数面) var _runner_get: Callable # () → 关卡推进器现值(组合根 lambda——随局更替) var _open_modal: Callable @@ -41,7 +41,7 @@ func _init(db_ref, meta_get: Callable, save_get: Callable, camp_overlay_ref: Cam _refresh_resume_button = refresh_resume_button -# 打开营地(主菜单入口——开合与开始层互斥仿 TunePanel 先例:开始覆盖层非模态且树序在后, +# 打开营地(主菜单入口——开合与开始层互斥仿设置面先例:开始覆盖层非模态且树序在后, # 规范 2.3 遮挡纪律;打开时先刷工坊解锁——达标未解锁就地入账) func open_camp() -> void: var meta = _meta_get.call() diff --git a/game/presentation/main.gd b/game/presentation/main.gd index ed57389b..3fd6e52c 100644 --- a/game/presentation/main.gd +++ b/game/presentation/main.gd @@ -118,10 +118,10 @@ var shop_overlay: ShopOverlay # 商店覆盖层(GP+商店房实施 var camp_overlay: CampOverlay # 营地覆盖层(元进度实现批——主菜单营地入口兑付呈现) var settings_store # 系统级设置独立存储(迭代 8 卡④——音量/全屏/减动效) var settings_overlay: SettingsOverlay # 设置覆盖层(迭代 8 卡④——最小设置面) -var tune_panel: TunePanel +var debug_overlay: DebugOverlay # 调试浮窗(迭代 14.5 调试整合批——种子/数值调整/批量模拟/两层调试入口收一) var _modals = null # 模态层级状态机(modal_stack.gd——缺陷⑤纪律载体) -var _tune_sim = null # 调整板批量模拟控制器(tune_sim_controller.gd) +var _tune_sim = null # 调试浮窗批量模拟控制器(tune_sim_controller.gd) var _hints_shown := {} # 一次性非模态提示去重(每 run 一次:chord/no_adjacent) var _refresh_used_round := 0 # 本轮已受理刷新次数(遥测 round_refresh_index——每轮 round_started 归零) var _boss_active := false # Boss 遭遇变体(阶段指示附 Boss 名) @@ -242,15 +242,14 @@ func _build_ui() -> void: logger.ap_per_round = int(db.action_economy.ap_per_round) # 模态覆盖层(登记序 = 树序 = z 遮挡序:图例 < 明细回看 < 节点 < 关卡画面 < 三选一 < 终局 - # < 商店 < 营地 < 调整板 < 设置 < 确认弹窗) - var overlays: Dictionary = UiAssembler.build_overlays(self, db, int(db.hero.atk), int(db.hero.max_hp)) + # < 商店 < 营地 < 设置 < 确认弹窗 < 调试浮窗) + var overlays: Dictionary = UiAssembler.build_overlays(self, db) legend_overlay = overlays.legend_overlay review_overlay = overlays.review_overlay node_overlay = overlays.node_overlay _end_overlay = overlays.end_overlay shop_overlay = overlays.shop_overlay camp_overlay = overlays.camp_overlay - tune_panel = overlays.tune_panel level_screen = LevelMapScreen.new() add_child(level_screen) # 树序 = 模态登记序 = z 遮挡序(缺陷⑤纪律)——关卡画面须夹在节点层与商店层之间 @@ -263,9 +262,6 @@ func _build_ui() -> void: level_screen.abandon_requested.connect(_on_abandon_requested) # 放弃入口(2026-09-21 用户拍板——台账 119) _end_overlay.review_pressed.connect(_on_end_review) _end_overlay.continue_pressed.connect(_on_battle_end_continue) - 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 卡④——最小设置面(音量/全屏/减动效) add_child(settings_overlay) settings_overlay.closed.connect(_on_settings_closed) @@ -287,12 +283,10 @@ func _build_ui() -> void: var start: Dictionary = UiAssembler.build_start_overlay(self, db) _start_overlay = start.overlay - _seed_edit = start.seed_edit _resume_btn = start.resumebtn start.lvbtn.pressed.connect(_start_adventure_from_menu) start.resumebtn.pressed.connect(_resume_from_menu) # 迭代 8 卡②——续玩入口 - start.tunebtn.pressed.connect(_show_tune_panel) - start.dbgbtn.pressed.connect(_start_debug_levels) + start.dbgbtn.pressed.connect(_show_debug_overlay) # 迭代 14.5——调试角标入口(浮窗,非平级主按钮) start.dbgbtn.visible = OS.get_environment("DS_DEBUG") == "1" # 迭代 8 卡④——调试入口默认隐藏门控(DS_DEBUG=1 点亮) # 营地/商店投影(T4/D4 拆件批——迁 camp_shop_presenter.gd;本类只接线、探针缝保缝转发; # 购买写调用唯一经 MetaProgression/LevelRunner core 单口——组合根 lambda 现值注入) @@ -326,11 +320,22 @@ func _build_ui() -> void: confirm_dialog.confirmed.connect(_on_confirm_new_adventure) confirm_dialog.cancelled.connect(_on_confirm_cancelled) + # 调试浮窗(迭代 14.5 调试整合批——主菜单三散件收一:随机种子/数值调整/批量模拟/两层调试入口)。 + # 树序在开始层与确认弹窗之后 = 浮于菜单之上的 Dialog(不隐藏开始层——与确认弹窗同款形态, + # 旧 TunePanel「与开始层互斥」形态退役);入口仅开始覆盖层角标(DS_DEBUG=1 门控) + debug_overlay = DebugOverlay.new(db, int(db.hero.atk), int(db.hero.max_hp)) + add_child(debug_overlay) + _seed_edit = debug_overlay.seed_edit # 种子读取面随浮窗迁入(_seed_value 唯一消费点不变) + debug_overlay.closed.connect(_on_modal_closed.bind(debug_overlay)) + debug_overlay.apply_requested.connect(_on_tune_apply) + debug_overlay.simulate_requested.connect(_on_tune_simulate) + debug_overlay.debug_levels_requested.connect(_start_debug_levels) + # 模态登记(缺陷⑤纪律——登记序 = 树序:含 move_child 调位后的关卡画面/三选一终位) _modals = ModalStack.new() - for m: Control in [legend_overlay, review_overlay, node_overlay, level_screen, bonus_overlay, _end_overlay, shop_overlay, camp_overlay, tune_panel, settings_overlay, confirm_dialog]: + for m: Control in [legend_overlay, review_overlay, node_overlay, level_screen, bonus_overlay, _end_overlay, shop_overlay, camp_overlay, settings_overlay, confirm_dialog, debug_overlay]: _register_modal(m) - _tune_sim = TuneSimController.new(db, tune_panel, int(db.hero.max_hp)) + _tune_sim = TuneSimController.new(db, debug_overlay, int(db.hero.max_hp)) func _fatal_screen(msg: String) -> void: @@ -432,7 +437,7 @@ func _resume_from_menu() -> void: _reset_run_scope() log_view.clear() logger.start_session(int(bp.get("master_seed", 0))) - adventure.set_hero_override(tune_panel.atk_pct(), tune_panel.hp_pct()) + adventure.set_hero_override(debug_overlay.atk_pct(), debug_overlay.hp_pct()) if not adventure.resume_adventure(bp, {"hero_override": meta.hero_override() if meta != null else {}, "aux_unlocked": _aux.unlocked_set()}): _fatal_screen("续玩恢复失败——见输出日志") return @@ -467,7 +472,7 @@ func _start_adventure() -> void: log_view.clear() var seed_val := _seed_value() logger.start_session(seed_val) - adventure.set_hero_override(tune_panel.atk_pct(), tune_panel.hp_pct()) + adventure.set_hero_override(debug_overlay.atk_pct(), debug_overlay.hp_pct()) # 永久强化注入(元进度实现批):冒险开始参数面——meta 现算 override 显式传参(全零 = 白板) # 首次冒险脚本(关卡节点图生成 v0.4):存档布尔位 false = 全关固定模板 0(教学重放);置位后逐关抽签 var first_script: bool = not save_manager.is_first_adventure_done() @@ -482,7 +487,7 @@ func _on_adventure_level_started(level_index: int, display_name: String) -> void runner = adventure.runner() log_view.append_bb(Narrator.level_open_line(display_name, int(adventure.master_seed), int(db.hero.atk), int(db.hero.max_hp), - tune_panel.atk_pct() > 0 or tune_panel.hp_pct() > 0)) + debug_overlay.atk_pct() > 0 or debug_overlay.hp_pct() > 0)) func _reset_run_scope() -> void: @@ -580,7 +585,7 @@ func _on_battle_end_continue() -> void: settlement = null adventure = null _adventure_mode = false - tune_panel.reset_sliders() + debug_overlay.reset_sliders() _start_overlay.visible = true _refresh_resume_button() # 迭代 8 卡②——回菜单按断点在档态刷新(收束后已清=隐藏) _refresh_presentations() @@ -593,13 +598,15 @@ func _on_end_review() -> void: # ==================== 调试模式(连续两层——编排归 debug_session.gd; -# 单场遭遇用户入口已删(2026-09-13 用户裁决)——debug_session.start_single 原语仅探针使用) +# 单场遭遇用户入口已删(2026-09-13 用户裁决)——debug_session.start_single 原语仅探针使用; +# 入口 2026-10-04 迁调试浮窗(debug_levels_requested 接线)) # T4/D3 收口注记:本节处理器(battle_created/battle_ready/override/seed)系组合根绑定面—— # settlement 写与 _wire_battle=ADR-0001 组合根 essence,override/seed 取数面在组合根 UI 态 -#(tune_panel/_seed_edit)——不迁移,信号连接留本根(契约 3)。==================== +#(debug_overlay/_seed_edit)——不迁移,信号连接留本根(契约 3)。==================== func _start_debug_levels() -> void: - tune_panel.reset_sliders() + debug_overlay.reset_sliders() + _close_modal(debug_overlay) # 浮窗内入口发起——随开随收(对局期不可再开:门禁在 _show_debug_overlay) _start_overlay.visible = false log_view.clear() log_view.append_bb(Narrator.debug_open_line(_seed_value(), 1, true)) @@ -633,12 +640,12 @@ func _on_inter_next_pressed() -> void: _fatal_screen("战斗启动失败——见输出日志") -# E4:加成生效值供给(debug_session 注入 Callable——每次从面板百分比现算,经 encounter 传参零表写; +# E4:加成生效值供给(debug_session 注入 Callable——每次从浮窗百分比现算,经 encounter 传参零表写; # 原表写路径 _apply_hero_override/_scaled_override 已废除,双写叠加 6→18→54 整类隐患随之移除; -# 合成式单点在 UiKit.scaled——与 TunePanel 生效值预览共用,本类不再持有同式私有实现) +# 合成式单点在 UiKit.scaled——与调试浮窗生效值预览共用,本类不再持有同式私有实现) func _debug_hero_override() -> Dictionary: - return {"atk": UiKit.scaled(int(db.hero.atk), tune_panel.atk_pct()), - "max_hp": UiKit.scaled(int(db.hero.max_hp), tune_panel.hp_pct())} + return {"atk": UiKit.scaled(int(db.hero.atk), debug_overlay.atk_pct()), + "max_hp": UiKit.scaled(int(db.hero.max_hp), debug_overlay.hp_pct())} # 奖励徽章身份解析(组合根守卫:仅挖掘期 Active 相位内查询——地图战斗资源 Ready 域外零读、零诊断噪音; @@ -1096,22 +1103,23 @@ func _on_diagnose_pressed() -> void: board_zone.toast.show_toast("已转储诊断: " + path, "info") -# ==================== 数值调整板(加成应用/批量模拟编排——组合根承接,视图纯 UI)==================== +# ==================== 调试浮窗(迭代 14.5 整合批——原数值调整板节收编;开合/应用/模拟编排组合根承接)==================== -func _show_tune_panel() -> void: - _start_overlay.visible = false - _open_modal(tune_panel) # 模态栈单口(T3 收口批) +func _show_debug_overlay() -> void: + # 门禁(用户裁 2026-10-04:仅开始菜单可开,对局中不可达):入口角标宿主即开始层, + # 此护栏防御未来调用面(含探针直呼);浮窗树序在开始层之后 = 悬浮其上,不隐藏菜单 + if not _start_overlay.visible: + return + _open_modal(debug_overlay) # 模态栈单口 -func _close_tune_panel() -> void: - _close_modal(tune_panel) # 模态栈单口(T3 收口批) - _start_overlay.visible = true - _refresh_resume_button() # 迭代 8 卡②——回菜单按断点在档态刷新 +func _close_debug_overlay() -> void: + _close_modal(debug_overlay) # 模态栈单口——开始层全程未隐藏,无需恢复 func _on_tune_apply(atk_pct: int, hp_pct: int) -> void: - # E4:加成无持久态可"落"——各战斗开局经 _debug_hero_override/runner 现算生效(面板仅关闭回开始层) - _close_tune_panel() + # E4:加成无持久态可"落"——各战斗开局经 _debug_hero_override/runner 现算生效(应用=关闭浮窗) + _close_debug_overlay() func _on_tune_simulate(n: int) -> void: diff --git a/game/presentation/tune_sim_controller.gd b/game/presentation/tune_sim_controller.gd index 9df1f240..d4908920 100644 --- a/game/presentation/tune_sim_controller.gd +++ b/game/presentation/tune_sim_controller.gd @@ -13,7 +13,7 @@ const SEED_BASE := 4200 # 模拟种子基(与历史实现同源——同种 const PlaytestLogger := preload("res://presentation/playtest_logger.gd") # 试玩日志(同层依赖——运行时 load 收敛为 preload 常量) var db -var panel # TunePanel setter 面:atk_pct/hp_pct/set_sim_running/set_sim_progress/set_sim_report +var panel # 调试浮窗 setter 面:atk_pct/hp_pct/set_sim_running/set_sim_progress/set_sim_report var _base_hp := 0 # 报告中的"基础 HP"口径注记值 var _driver = null # 关卡自动策略驱动(调用方注入;null = 旧行为运行时 load 兜底) diff --git a/game/presentation/ui_assembler.gd b/game/presentation/ui_assembler.gd index ed93f39f..b39f5748 100644 --- a/game/presentation/ui_assembler.gd +++ b/game/presentation/ui_assembler.gd @@ -61,9 +61,10 @@ static func build_battle_ui(root: Control, db) -> Dictionary: } -# 模态覆盖层组(z 序 = 登记序:图例 < 明细回看 < 节点 < 终局 < 商店 < 调整板)。 -# 返回 {legend_overlay, review_overlay, node_overlay, end_overlay, shop_overlay, tune_panel};调用方按本序 addChild。 -static func build_overlays(host: Control, db, base_atk: int, base_hp: int) -> Dictionary: +# 模态覆盖层组(z 序 = 登记序:图例 < 明细回看 < 节点 < 终局 < 商店)。 +# 返回 {legend_overlay, review_overlay, node_overlay, end_overlay, shop_overlay, camp_overlay};调用方按本序 addChild。 +# (调整板已随迭代 14.5 调试整合批退役——调试浮窗由组合根直构挂树序最末,见 main._build_ui) +static func build_overlays(host: Control, db) -> Dictionary: var legend_overlay := LegendOverlay.new(int(db.action_economy.rap_refresh_cost)) # 打磨包 2026-09-29——RAP 行表值注入 host.add_child(legend_overlay) @@ -80,14 +81,10 @@ static func build_overlays(host: Control, db, base_atk: int, base_hp: int) -> Di var shop_overlay := ShopOverlay.new() host.add_child(shop_overlay) - # 营地覆盖层(元进度实现批 2026-09-21——主菜单营地入口兑付呈现;开合仿 TunePanel 与开始层互斥) + # 营地覆盖层(元进度实现批 2026-09-21——主菜单营地入口兑付呈现;开合与开始层互斥仿设置面先例) var camp_overlay := CampOverlay.new() host.add_child(camp_overlay) - var tune_panel := TunePanel.new(db, base_atk, base_hp) - tune_panel.visible = false # 显式初始化——原版依赖"被不透明开始层遮蔽"的树序巧合(缺陷⑤家族);模态锁输入以 visible 为准 - host.add_child(tune_panel) - return { "legend_overlay": legend_overlay, "review_overlay": review_overlay, @@ -95,12 +92,12 @@ static func build_overlays(host: Control, db, base_atk: int, base_hp: int) -> Di "end_overlay": end_overlay, "shop_overlay": shop_overlay, "camp_overlay": camp_overlay, - "tune_panel": tune_panel, } -# 开始覆盖层(返回 {overlay, box, seed_edit, lvbtn, tunebtn, dbgbtn}——按钮接线归组合根; -# 单场遭遇用户入口已删(2026-09-13 用户裁决——单场原语仅探针经 debug_session.start_single 使用)) +# 开始覆盖层(返回 {overlay, box, lvbtn, resumebtn, campbtn, settingsbtn, quitbtn, dbgbtn}——按钮接线归组合根; +# 迭代 14.5 调试整合批:随机种子/数值调整板/两层调试三散件撤出主按钮组,收进调试浮窗—— +# 本层只留右下角「调试」角标入口(DS_DEBUG=1 门控归组合根),dbgbtn 即该角标) static func build_start_overlay(host: Control, db = null) -> Dictionary: var overlay := overlay_bg(host, UiKit.BG_OVERLAY) # 石纹底噪底层(样张 v2 冻结批 T2——z 序=dim 之上/内容之下;缺位不挂即回退平色) @@ -121,26 +118,12 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary: box.add_child(sub) box.add_child(HSeparator.new()) - var seed_row := HBoxContainer.new() - box.add_child(seed_row) - # 字号下限(v3.5 批 B3——正文 ≥16)+暗底显式暖白 - var seed_label := UiKit.label("随机种子:", 16, false, UiKit.WARM) - seed_row.add_child(seed_label) - var seed_edit := LineEdit.new() - seed_edit.text = "42" - seed_edit.custom_minimum_size = Vector2(120, 0) - seed_row.add_child(seed_edit) - # 唯一试玩入口 = 正式「开始冒险」(三关序列);单关测试直入口(L2/L3)退役(2026-09-23 用户拍板) var resumebtn := UiKit.button("▶ 继续上局(自最近停点恢复)") # 迭代 8 卡②——有断点才亮(可见性归组合根刷新) resumebtn.visible = false box.add_child(resumebtn) var lvbtn := UiKit.button("▶ 开始冒险(三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城)") box.add_child(lvbtn) - var tunebtn := UiKit.button("测试用 · 角色数值调整板(模拟天赋树属性提升)") - box.add_child(tunebtn) - var dbgbtn := UiKit.button("调试 · 连续关卡两层(HP 关内延续)") - box.add_child(dbgbtn) var campbtn := UiKit.button("营地 · 永久强化(钥石换永久属性——跨局成长账本)") # 元进度实现批——主菜单营地入口(双入口框架的主菜单一侧) box.add_child(campbtn) var settingsbtn := UiKit.button("设置(音量 / 全屏 / 减动效)") # 迭代 8 卡④——最小设置面入口 @@ -149,6 +132,13 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary: var quitbtn := UiKit.button("退出游戏") box.add_child(quitbtn) + # 迭代 14.5 调试整合批——调试入口收右下角标(与主按钮组非平级;DS_DEBUG=1 点亮,可见性归组合根)。 + # margin 16px 角距;字号降档与主按钮拉开层级 + var dbgbtn := UiKit.button("调试") + dbgbtn.add_theme_font_size_override("font_size", 13) + dbgbtn.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_RIGHT, Control.PRESET_MODE_MINSIZE, 16) + overlay.add_child(dbgbtn) + # 玩法帮助文案(表值驱动——2026-09-16 AP 压速批遗留硬编码 8 随手修正;护甲等级掷点批同步"减伤"→"护甲强化") var help_text := "玩法:每轮 %d AP——挖开(1AP)/插旗(1AP)/移动(免费)/连锁(免费)。\n每个非封锁格都藏一种格面资源(增伤/护甲强化/回血/爆裂/削弱)。开安全格、标中雷 = 正向兑付;\n开雷格、标错安全格 = 负向兑付——全部在轮末结算逐行兑现;吃掷点的基础攻击按护甲等级判定,无 miss、最低保底 1 点。\n停手:剩余 AP 转存 RAP;弃图刷新:RAP−%d 当场换图继续挖(每轮剩 %d 次)。\n敌人全灭胜、主角倒下负。悬停可看三态光标与可挖域微光。\n地形变异:第二关起 Boss 图带整图变异(贫矿脉——回复与护甲资源减少、攻击资源增多;开战横幅与 HUD 角标常驻提示)。" % [ int(db.action_economy.ap_per_round), int(db.action_economy.rap_refresh_cost), int(db.action_economy.refresh_cap_per_round)] @@ -156,9 +146,9 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary: var help := UiKit.label(help_text, 16, false, UiKit.WARM) box.add_child(help) - return {"overlay": overlay, "box": box, "seed_edit": seed_edit, - "lvbtn": lvbtn, "resumebtn": resumebtn, "tunebtn": tunebtn, "dbgbtn": dbgbtn, - "campbtn": campbtn, "settingsbtn": settingsbtn, "quitbtn": quitbtn} + return {"overlay": overlay, "box": box, + "lvbtn": lvbtn, "resumebtn": resumebtn, + "campbtn": campbtn, "settingsbtn": settingsbtn, "quitbtn": quitbtn, "dbgbtn": dbgbtn} # 调试两层模式的层间过渡覆盖层(历史入口专用)。返回 {overlay, label, next_btn}——接线归组合根 diff --git a/game/presentation/views/camp_overlay_view.gd b/game/presentation/views/camp_overlay_view.gd index 90970c67..9e2d6d4d 100644 --- a/game/presentation/views/camp_overlay_view.gd +++ b/game/presentation/views/camp_overlay_view.gd @@ -4,7 +4,7 @@ # 三柜台列(属性锻造/道具工坊/奖励格图鉴,头带深棕+米色板身+内嵌行板,暗底→亮板双色墨制)+ # 底栏关闭钮/操作注记;最近冒险收底栏条带。信号面/投影契约零变化:buy_requested(attr)/closed、 # open_camp(data)/refresh_camp(data)、_forge_rows 行结构 {attr,level_l,price_l,btn}(探针依赖)。 -# 挂接方式:开合与开始层互斥仿 TunePanel 先例(开始覆盖层非模态且树序在后——打开本层前由组合根 +# 挂接方式:开合与开始层互斥仿设置面先例(开始覆盖层非模态且树序在后——打开本层前由组合根 # 隐藏开始层,规范 2.3 遮挡纪律)。 # 高内聚边界:纯视图 setter 面——账本快照经组合根喂入(MetaProgression 只读投影),购买/关闭 # 意图经信号外发——零核心写调用、零 MetaProgression 持有。 diff --git a/game/presentation/views/ui_kit.gd b/game/presentation/views/ui_kit.gd index 73eb135f..3af5fc6c 100644 --- a/game/presentation/views/ui_kit.gd +++ b/game/presentation/views/ui_kit.gd @@ -104,7 +104,7 @@ const DOT_OFF := PANEL_BORDER # ── 减动效(battle.md §Transitions 内建承诺:开启时时长减半;结算逐行兑现为信息载体降速不跳过)── -# 切片期入口 = TunePanel 开关(设置独立于存档两分制——正式设置层载体随设置批落位) +# 唯一入口 = 设置面开关(迭代 8 卡④ 转正;切片期调整板开关已随其退役,调整板本体 14.5 收进调试浮窗) static var motion_scale := 1.0 # 1.0 常态 / 0.5 减动效 # 全部呈现层 tween 时长经本函数包装——新增动效一律 UiKit.motion(秒),禁再写裸时长字面量 @@ -232,7 +232,7 @@ static func modal_shell(parent: Control, dim_color: Color, min_size := Vector2.Z return {"dim": dim, "center": center, "panel": panel, "box": box} -# 属性百分比合成(main._debug_hero_override 与 TunePanel 生效值预览共用单点——两处同式实现收口) +# 属性百分比合成(main._debug_hero_override 与调试浮窗生效值预览共用单点——两处同式实现收口) static func scaled(base: int, pct: int) -> int: return maxi(1, int(round(float(base) * (100.0 + float(pct)) / 100.0))) diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index 8acb1cc5..eaed7315 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -368,7 +368,7 @@ func _smoke_adventure() -> void: var hp_before: int = int(p.get("hp_before", -1)) var hp_after: int = int(p.get("hp_after", -1)) # 模拟档 v3.4 商店贪心购血合法抬升(L2/L3 店在 Boss 前)——回血口径窗口 = 加算区件 + 购血余量 0..15 - # T17 账本口径修复随批:置满/回血封顶改生效上限口径(flat 后乘 TunePanel pct)——窗口同步 ×5(本段 pct=400) + # T17 账本口径修复随批:置满/回血封顶改生效上限口径(flat 后乘调试浮窗 pct)——窗口同步 ×5(本段 pct=400) var heal_ok_i := false for extra in 46: var m := int(round(float(int(_db.hero.max_hp) + hp_acc + extra) * 5.0)) @@ -393,7 +393,7 @@ func _smoke_adventure() -> void: check(ks_gain_ok, "钥石逐杀入账(首杀档位 + 累计逐位)") check(resolve_ok, "点选恰兑付选中一件(值=令牌档位表值;未选项零生效)") var seq: Array = st["encounter_max_hp_seq"] - var k := 5.0 # hp+400 ⇒ TunePanel 百分比后乘 ×5(加算先加、百分比后乘——生效次序口径) + var k := 5.0 # hp+400 ⇒ 调试浮窗百分比后乘 ×5(加算先加、百分比后乘——生效次序口径) var exp_base := maxi(1, int(round(float(int(_db.hero.max_hp)) * k))) # 模拟档 v3.4 商店贪心购血(数值修复批)合法抬升——上限窗口 = 基础 + 加算区 3 件 + 购血余量; # TP0 数值对后 max_hp 件有大生命 +10(rare 档)——上界按大件最坏构成 3×10+购血 15=+45(TP0 放宽) @@ -512,7 +512,7 @@ func _smoke_adventure() -> void: var expect_acc: int = acc_shop + (int(a8._bonus_result.get("value", 0)) if picked2 == "max_hp" else 0) check(int(a8.bonus.get("max_hp", -1)) == expect_acc, "三选一属性件与商店购买同账累加(max_hp=%d = %d + 三选一%s)" % [int(a8.bonus.get("max_hp", -1)), acc_shop, picked2]) - var max_eff8: int = a8.effective_max_hp() # T17 口径修复随批:账本生效上限含 TunePanel pct(a8 已 set 400) + var max_eff8: int = a8.effective_max_hp() # T17 口径修复随批:账本生效上限含调试浮窗 pct(a8 已 set 400) check(int(a8.ledger["hero_hp"]) <= max_eff8, "通关部分回血封顶(hp %d ≤ 生效上限 %d——血回满语义退役)" % [int(a8.ledger["hero_hp"]), max_eff8]) check(a8.continue_to_next_level(), "兑付后推进受理(下一关开始)") @@ -3599,7 +3599,7 @@ func _smoke_shop_room() -> void: by_id = _shop_products_by_id(runner.shop_products()) check(int(by_id["atk_up"]["price"]) == 8 and int(by_id["atk_up"]["purchased"]) == 1, "atk_up 二购现价 = 4+2+2=8(步长 2 × 已购 1 档,现价现算)") - # 行进段百分比归零(购买/生效断言按加算区裸值口径——TunePanel 百分比后乘;hp 快照钳到新口径上限防 spawn 越界,测试通道) + # 行进段百分比归零(购买/生效断言按加算区裸值口径——调试浮窗百分比后乘;hp 快照钳到新口径上限防 spawn 越界,测试通道) runner.set_hero_override(0, 0) runner.hero_hp = mini(runner.hero_hp, runner.effective_max_hp()) # hp_up:上限与当前生命同步 +3(封顶新上限) diff --git a/game/smoke/ui_click_probe.gd b/game/smoke/ui_click_probe.gd index 7ccd89ba..356056d3 100644 --- a/game/smoke/ui_click_probe.gd +++ b/game/smoke/ui_click_probe.gd @@ -141,8 +141,8 @@ func _ready() -> void: await get_tree().process_frame if main.settings_overlay.visible or not main._start_overlay.visible: _problems.append("设置面关闭后未恢复开始层") - # 旧入口退役断言(卡④ AC③——测试调整板不再含减动效开关) - var legacy_motion = ProbeUiUtil.find_check_button(main.tune_panel, "减动效") + # 旧入口退役断言(卡④ AC③——测试调整板不再含减动效开关;14.5 起载体=调试浮窗) + var legacy_motion = ProbeUiUtil.find_check_button(main.debug_overlay, "减动效") if legacy_motion != null: _problems.append("调整板减动效旧入口未退役(设置面唯一入口失守——卡④ AC③)") # D1 断言(二轮):退出游戏只在一级菜单——开始菜单有、设置面无 @@ -157,7 +157,7 @@ func _ready() -> void: _problems.append("继续上局按钮缺失(开始层 resumebtn——装配器)") elif resume_btn0.visible: _problems.append("无断点态继续上局按钮未隐藏(卡② AC①——新档合法空态)") - main.tune_panel.set_sliders(400, 200) # 高加成保 L1 可通关——L2 岔路选路段只能经冒险推进到达(单关直入口退役) + main.debug_overlay.set_sliders(400, 200) # 高加成保 L1 可通关——L2 岔路选路段只能经冒险推进到达(单关直入口退役) var t1 := Time.get_ticks_msec() main._start_adventure_from_menu() await get_tree().process_frame diff --git a/game/smoke/ui_tune_probe.gd b/game/smoke/ui_tune_probe.gd index 43c48be8..a86abfd2 100644 --- a/game/smoke/ui_tune_probe.gd +++ b/game/smoke/ui_tune_probe.gd @@ -1,7 +1,8 @@ # VERTICAL SLICE - NOT FOR PRODUCTION # Date: 2026-09-11(2026-09-12 code-review 修复批重写——加成应用契约改为组合根单一应用路径) -# 数值调整板场景探针(playtest 缺陷⑤回归载体——面板此前被不透明开始覆盖层遮挡 = "点击无反应"): -# 驱动真实 UI 路径——打开可见性 / 滑条联动 / 应用(apply_requested → 组合根)/ +# 调试浮窗场景探针(2026-10-04 迭代 14.5 调试整合批随批改接——原数值调整板整体收进 debug_overlay, +# 浮窗形态悬浮于开始菜单之上不隐藏菜单;playtest 缺陷⑤回归载体沿袭): +# 驱动真实 UI 路径——打开可见性(浮于菜单之上+树序在后)/ 滑条联动 / 应用(apply_requested → 组合根)/ # 重置 / 批量模拟全链路(N=10)/ E4 回归断言(hero 表运行期不可变 + 单次加成经 encounter 生效)。 # 运行:Godot_console.exe --headless --path . res://smoke/ui_tune_probe.tscn extends Node @@ -22,41 +23,44 @@ func _ready() -> void: var base_hp := int(main.db.hero.max_hp) var boosted_atk := base_atk * 2 # 攻击滑条 100 → ×2 var boosted_hp := int(round(base_hp * 1.5)) # 生命滑条 50 → +50% - # ① 打开可见性(缺陷⑤回归:打开面板必须隐藏不透明的开始覆盖层) - main._show_tune_panel() - if not main.tune_panel.visible: - problems.append("面板未打开") - if main._start_overlay.visible: - problems.append("开始覆盖层未隐藏——面板被遮挡(缺陷⑤复发)") + # ① 打开可见性(14.5 浮窗形态:悬浮于菜单之上——开始层不隐藏,树序必须在开始层之后 = 绘制在上; + # 旧「打开必须隐藏开始层」断言随互斥形态退役) + main._show_debug_overlay() + if not main.debug_overlay.visible: + problems.append("调试浮窗未打开") + if not main._start_overlay.visible: + problems.append("开始覆盖层被隐藏——浮窗应悬浮于菜单之上(14.5 形态失守)") + if main.debug_overlay.get_index() < main._start_overlay.get_index(): + problems.append("调试浮窗树序在开始层之前——遮挡关系失守") # ② 滑条 → 生效预览联动 - main.tune_panel.set_sliders(100, 50) - if str(boosted_atk) not in main.tune_panel.effect_text() or str(boosted_hp) not in main.tune_panel.effect_text(): - problems.append("生效预览未联动(%s)" % main.tune_panel.effect_text()) + main.debug_overlay.set_sliders(100, 50) + if str(boosted_atk) not in main.debug_overlay.effect_text() or str(boosted_hp) not in main.debug_overlay.effect_text(): + problems.append("生效预览未联动(%s)" % main.debug_overlay.effect_text()) # ③ 应用(真实信号路径:apply_requested → 组合根)——E4 后加成零表写,生效断言移至 ⑧ 战斗快照 - main.tune_panel.press_apply_for_probe() - # ④ 重置(重开面板 → 重置按钮真实路径;面板百分比归零——下一场战斗生效值回到基线) - main._show_tune_panel() - main.tune_panel.press_reset_for_probe() + main.debug_overlay.press_apply_for_probe() + # ④ 重置(重开浮窗 → 重置按钮真实路径;面板百分比归零——下一场战斗生效值回到基线) + main._show_debug_overlay() + main.debug_overlay.press_reset_for_probe() # ⑤ 批量模拟全链路(N=10——走 level_autoplay 与 headless 扫描同口径;表基线由组合根复位) - main.tune_panel.set_sliders(100, 0) - main.tune_panel.set_sim_count(10) - main.tune_panel.press_simulate_for_probe() + main.debug_overlay.set_sliders(100, 0) + main.debug_overlay.set_sim_count(10) + main.debug_overlay.press_simulate_for_probe() var guard := SIM_GUARD_FRAMES - while main.tune_panel.is_running() and guard > 0: + while main.debug_overlay.is_running() and guard > 0: guard -= 1 await get_tree().process_frame - if main.tune_panel.is_running(): + if main.debug_overlay.is_running(): problems.append("模拟未在预算帧内完成(疑似挂死)") - var out: String = main.tune_panel.output_text() + var out: String = main.debug_overlay.output_text() if not out.contains("通关率"): problems.append("模拟输出缺通关率") if not out.contains("败北节点"): problems.append("模拟输出缺败北节点") if "N=10" not in out: problems.append("模拟输出 N 标注错误(%s)" % out.substr(0, 40)) - # ⑥ 关闭 → 回开始界面 - main._close_tune_panel() - if main.tune_panel.visible or not main._start_overlay.visible: + # ⑥ 关闭 → 浮窗收起、开始层全程在屏 + main._close_debug_overlay() + if main.debug_overlay.visible or not main._start_overlay.visible: problems.append("关闭后层级状态错误") # ⑦ hero 表运行期不可变(E4 收口回归断言:任何代码 reintroduce 表写在此被抓获——原"表值残留"断言语义升级) if int(main.db.hero.atk) != base_atk or int(main.db.hero.max_hp) != base_hp: @@ -66,8 +70,8 @@ func _ready() -> void: # 存档隔离(迭代 8 卡①——停点断点写盘随 main.save_manager;探针禁碰真实档,同族探针隔离纪律; # isolate_save 先删后建——上次运行的残留断点会触发互斥确认早退) ProbeUiUtil.isolate_save(main, "smoke_tune_probe_save", true, false, false) - main.tune_panel.set_sliders(100, 50) - main.tune_panel.press_apply_for_probe() + main.debug_overlay.set_sliders(100, 50) + main.debug_overlay.press_apply_for_probe() main._start_adventure_from_menu() # 完整冒险路径(唯一试玩入口;_start_single 按语义清零滑条 = 恒基线,不承载加成断言) await get_tree().process_frame await get_tree().process_frame