iter52-卡3:迭代52卡③(presentation层封装修复): A1三类42字段公开化(280处改址)+A2拆件子件公开面(vitals14/motion14/board_hover七口)+B族组合根交接面(18服务+12句柄口,束参两处,on_*保私有)+C族杂项(UiKit三工厂/构造交付)——presentation私取sweep恒零(V1-V4,105checks),main.gd例外键32与ui_kit例外键23落基线(§3.2误测0/0反哺点),探针测试22处引用迁移,渲染golden与探针套件零转红; 验收档中

This commit is contained in:
DKChan committed 2026-11-05 03:04:21 +08:00
1 parent f2c3a3887d
commit 67024cb9ec
42 files changed
+1391 -679

No files matched your search

+44 -44
View File
@@ -7,22 +7,22 @@ extends RefCounted
# 冒险编排构建+接线(开新局/续玩共用——信号连接只在组合根;断点注入同口)。
# 信号直连(拆件批 T3):runner 六信号在 level_started 重取点重连(旧实例连接随引用释放消亡——
# is_connected 守卫恰好一次);三选一信号面归停点件(每冒险一次——接线恰一次)。
static func _wire_adventure(root: Variant) -> void:
static func wire_adventure(root: Variant, handlers: Dictionary) -> void:
root.run_scope.adventure = AdventureRunner.new(root.db, root.get_node(root.AUTOLOAD_PATH_RNG))
root.run_scope.adventure.adventure_finished.connect(root._on_adventure_finished)
root.run_scope.adventure.level_started.connect(root._on_adventure_level_started)
root.run_scope.adventure.stop().curio_choice_presented.connect(root._bonus.on_presented)
root.run_scope.adventure.stop().curio_resolved.connect(root._bonus.on_resolved)
root.run_scope.adventure.adventure_finished.connect(handlers["adventure_finished"])
root.run_scope.adventure.level_started.connect(handlers["level_started"])
root.run_scope.adventure.stop().curio_choice_presented.connect(root.bonus().on_presented)
root.run_scope.adventure.stop().curio_resolved.connect(root.bonus().on_resolved)
root.run_scope.adventure.set_save_manager(root.save_manager) # 断点承载注入(停点快照写盘;调试/模拟不经过此路径)
# 每关开始(冒险模式):重取 runner 实例 + 层名行(L1 与单关模式同序——层名行随首战横幅后到达;
# 本回调返回后才有 choices_presented 到达——入口选路层随即弹出)
static func _on_adventure_level_started(root: Variant, level_index: int, display_name: String) -> void:
static func on_adventure_level_started(root: Variant, level_index: int, display_name: String, handlers: Dictionary) -> void:
root.run_scope.runner = root.run_scope.adventure.runner()
# runner 信号直连(拆件批 T3——六转发族退役后的重取点重连;恰好一次断言 sc1 守卫承载)
_connect_runner_once(root)
_connect_runner_once(root, handlers)
# 开场行传当前生效值(runner.effective_atk/effective_max_hp 与战斗面板同源:
# 表值+永久强化 flat+加算区 flat 后乘调试浮窗 pct,本回调时点 runner 已带全部加成);「含面板加成」
# 后缀判断认任一加成源——永久强化 atk/max_hp flat 或调试浮窗 pct 或局内加算区 atk/max_hp
@@ -37,22 +37,22 @@ static func _on_adventure_level_started(root: Variant, level_index: int, display
root.run_scope.runner.effective_atk(), root.run_scope.runner.effective_max_hp(), boosted))
# runner 六信号重连(is_connected 守卫——未连即接;守卫失败 push_error=重连恰好一次契约承载)
static func _connect_runner_once(root: Variant) -> void:
static func _connect_runner_once(root: Variant, handlers: Dictionary) -> void:
var r = root.run_scope.runner
if r == null:
push_error("[冒险流程] runner 信号重连失败——level_started 后 runner 为空")
return
var pairs := [
[r.step_row, root._on_step_row], [r.round_started, root._on_round_started],
[r.board_changed, root._on_board_changed], [r.node_entered, root._on_runner_node],
[r.choices_presented, root._on_choices_presented], [r.wallet_changed, root._on_wallet_changed],
[r.step_row, handlers["step_row"]], [r.round_started, handlers["round_started"]],
[r.board_changed, handlers["board_changed"]], [r.node_entered, handlers["runner_node"]],
[r.choices_presented, handlers["choices_presented"]], [r.wallet_changed, handlers["wallet_changed"]],
]
for pair in pairs:
if not (pair[0] as Signal).is_connected(pair[1]):
(pair[0] as Signal).connect(pair[1])
static func _on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -> void:
static func on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -> void:
# 冒险模式:runner 逐关更替——每次节点事件重取(单关模式幂等);须先于 board_changed 回退读面
if root.run_scope.is_adventure and root.run_scope.adventure != null:
root.run_scope.runner = root.run_scope.adventure.runner()
@@ -61,12 +61,12 @@ static func _on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -
root.run_scope.settlement = root.run_scope.runner.current_battle() # 呈现层统一读 settlement(与调试模式共用接线)
root.logger.attach_battle(root.run_scope.settlement)
root.run_scope.boss_active = t == "boss"
root._show_board_fx_for_node(t)
root.show_board_fx_for_node(t)
root.ui.battle.log_view.append_bb(root.Narrator.node_banner(root.run_scope.runner, node, t))
elif t == "reward":
# 奖励节点三选一(与关卡完成三选一共享同池同权重同上限;CurioPickOverlay 共用面)。
# 呈现编排归 curio_interact_controller.present_node_curio。
root._bonus.present_node_curio()
root.bonus().present_node_curio()
root.ui.battle.log_view.append_bb(root.Narrator.reward_line())
elif t == "rest":
var healed: int = int(info.get("healed", 0))
@@ -87,20 +87,20 @@ static func _on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -
root.ui.modals.menu.shop_overlay.set_visit_info(-1, 1.0) # legacy 面无爬价行(off 对照承载)
root.ui.battle.log_view.append_bb(root.Narrator.shop_line(int(root.run_scope.runner.gp)))
root.logger.log_node(node, info, root.run_scope.runner.node_index)
root._refresh_presentations()
root.refresh_presentations()
# ---- 冒险模式终局面(三选一选择面 / 冒险结算屏)----
# 冒险结算(completed/failed/abandoned):复用 BattleEndOverlay——摘要五件事 + 钥石入账明细进文案
static func _on_adventure_finished(root: Variant, summary: Dictionary) -> void:
static func on_adventure_finished(root: Variant, summary: Dictionary) -> void:
root.run_scope.level_active = false
var result: String = String(summary.get("result", ""))
root.run_scope.settlement = null
_exit_level_screen(root) # 终局兜底:独立屏在开态(放弃入口)也先回战斗屏呈现摘要——屏级互斥单一出口
root._sync_status_entry() # 离局熄灭状态面板入口角标(防菜单误现)
root._sync_settlement_visuals() # → 全关
exit_level_screen(root) # 终局兜底:独立屏在开态(放弃入口)也先回战斗屏呈现摘要——屏级互斥单一出口
root.sync_status_entry() # 离局熄灭状态面板入口角标(防菜单误现)
root.sync_settlement_visuals() # → 全关
HudPresenter.battle_end_feedback(root.ui.battle.stage, root.ui.battle.board_zone.ap_bar, false) # 灰化/idle 回正/状态全清——HUD 单通道
# 存档入账:settle = Boss 两档入账 + 工坊解锁 + 摘要入档 + 写盘(唯一写档点不变——
# 调试两层不经过本处理器,天然不写档不污染生涯数据)。
@@ -108,7 +108,7 @@ static func _on_adventure_finished(root: Variant, summary: Dictionary) -> void:
detail.assign(root.meta.settle_adventure(summary))
var text: String = root.Narrator.adventure_summary_text(summary)
if not detail.is_empty():
text += "\n" + root.Narrator.keystone_settle_text(detail, root._bonus.item_name_lookup())
text += "\n" + root.Narrator.keystone_settle_text(detail, root.bonus().item_name_lookup())
if result == "completed":
root.ui.modals.run.end_overlay.open_victory(text, "返回冒险", root.ui.battle.board_zone.board_view.get_global_rect(),
{"gp_summary": "本局 GP 入账 · 合计 %d" % int(summary.get("gp_final", 0))}) # GP 行(取数=summary gp_final 清账前快照);钥石明细已在 text(keystone_settle_text)——三行账
@@ -118,52 +118,52 @@ static func _on_adventure_finished(root: Variant, summary: Dictionary) -> void:
if root.run_scope.runner != null:
root.run_scope.runner.restore_hero_base()
root.ui.flow.open_after_playback(root.ui.modals.run.end_overlay)
root._refresh_presentations()
root.refresh_presentations()
static func _on_battle_end_continue(root: Variant) -> void:
static func on_battle_end_continue(root: Variant) -> void:
# 终局出口:返回开始界面(冒险摘要留档试玩日志;钥石在收束时入存档)
root.ui.flow.close(root.ui.modals.run.end_overlay)
root.ui.modals.run.end_overlay.close()
# 三选一停点挂起分支:战斗总结结算(Boss 胜利钥石增量行)确认后进三选一面
if root._bonus.resume_if_pending(): # 三选一停点在途恢复入口(curio_interact_controller)
if root.bonus().resume_if_pending(): # 三选一停点在途恢复入口(curio_interact_controller)
return
# 挂起分派:战斗胜利总结结算框的「下一节点」≠ 终局——进选路页(暂存候选恢复呈现)
if root.run_scope.settlement_stop_timer.is_armed():
root.run_scope.settlement_stop_timer.disarm()
_enter_level_screen(root)
enter_level_screen(root)
root.ui.modals.run.level_screen.set_feat_holdings(" · ".join(HudPresenter.feat_holdings_lines(root.db, root.run_scope.runner.feats_held())))
root.ui.modals.run.level_screen.open_choices(root.run_scope.pending_candidates, root.run_scope.runner)
root.ui.modals.run.level_screen.apply_status(level_map_status_payload(root.run_scope.runner))
root.run_scope.pending_candidates = []
root._refresh_presentations()
root.refresh_presentations()
return
# 会话收束:run_scope 整节点 queue_free()(帧末回收)——新闲时会话即建,
# 局态封印/账本/模态挂起全复位(局态字段清单见 run_scope.gd)
root._debug.reset()
root._begin_session(false)
root.debug().reset()
root.begin_session(false)
root.ui.modals.menu.debug_overlay.reset_sliders()
root.ui.screens.start_overlay.visible = true
root._refresh_presentations()
root.refresh_presentations()
static func _on_inter_next_pressed(root: Variant) -> void:
static func on_inter_next_pressed(root: Variant) -> void:
root.ui.screens.inter_overlay.visible = false
if root.run_scope.is_adventure:
# 冒险模式:大奖励屏确认 → 进下一关(AdventureRunner 序列推进——零自动推进的冒险级停点)
if root.run_scope.adventure != null and not root.run_scope.adventure.continue_to_next_level():
root._fatal_screen("关卡推进失败——见输出日志")
root.fatal_screen("关卡推进失败——见输出日志")
return
if not root._debug.next_layer():
root._fatal_screen("战斗启动失败——见输出日志")
if not root.debug().next_layer():
root.fatal_screen("战斗启动失败——见输出日志")
static func _on_node_continue(root: Variant) -> void:
static func on_node_continue(root: Variant) -> void:
root.ui.flow.close(root.ui.modals.run.node_overlay)
if root.run_scope.runner != null:
# 确认 ≠ 推进——兑付确认后经 choices_presented 弹出选路口
root.run_scope.runner.continue_after_node()
static func _on_choices_presented(root: Variant, candidates: Array) -> void:
static func on_choices_presented(root: Variant, candidates: Array) -> void:
# 零自动推进的停点呈现:整幅节点图 + 图上点击选路(战斗胜利/兑付确认统一到达此处)
if root.run_scope.runner == null:
return
@@ -180,38 +180,38 @@ static func _on_choices_presented(root: Variant, candidates: Array) -> void:
root.ui.battle.board_zone.board_view.get_global_rect(),
{"gp_summary": "战利品 GP +%d · 合计 %d" % [root.run_scope.last_gain_amount, int(root.run_scope.runner.gp)]})
root.ui.flow.open_after_playback(root.ui.modals.run.end_overlay)
root._refresh_presentations()
root.refresh_presentations()
return
_enter_level_screen(root)
enter_level_screen(root)
root.ui.modals.run.level_screen.set_feat_holdings(" · ".join(HudPresenter.feat_holdings_lines(root.db, root.run_scope.runner.feats_held())))
root.ui.modals.run.level_screen.open_choices(candidates, root.run_scope.runner)
root.ui.modals.run.level_screen.apply_status(level_map_status_payload(root.run_scope.runner))
root._refresh_presentations()
root.refresh_presentations()
static func _on_route_chosen(root: Variant, node_id: int) -> void:
static func on_route_chosen(root: Variant, node_id: int) -> void:
# 视图已按节点类型定去留——战斗/Boss 出屏(visible=false,此处收栈
# 记录一致性+回战斗屏);奖励/恢复/商店本屏保持激活(兑付覆盖层由节点事件域内弹出,模态栈
# 打开低层时自动隐藏本屏、关闭自动恢复)
if not root.ui.modals.run.level_screen.visible:
root.ui.flow.close(root.ui.modals.run.level_screen)
_exit_level_screen(root)
exit_level_screen(root)
if root.run_scope.runner != null and not root.run_scope.runner.pick_next_node(node_id):
push_error("[组合根] 选路被拒(编号 %d 不在候选)" % node_id)
static func _enter_level_screen(root: Variant) -> void:
static func enter_level_screen(root: Variant) -> void:
root.run_scope.level_screen_active = true
root.ui.screens.battle_root.visible = false
root.ui.flow.open(root.ui.modals.run.level_screen)
root._sync_status_entry() # 屏级互斥切换同步(_open_modal 单口不识屏级状态)
root.sync_status_entry() # 屏级互斥切换同步(_open_modal 单口不识屏级状态)
static func _exit_level_screen(root: Variant) -> void:
static func exit_level_screen(root: Variant) -> void:
root.run_scope.level_screen_active = false
root.ui.screens.battle_root.visible = true
if root.ui.modals.run.level_screen.visible:
root.ui.flow.close(root.ui.modals.run.level_screen)
root._sync_status_entry() # 同上
root.sync_status_entry() # 同上
# 选路屏状态栏装配(视图零核心态拼装——architecture §1.3:读核心态→拼展示文案集中于装配器)。
@@ -243,7 +243,7 @@ static func level_map_status_payload(runner: LevelRunner) -> Dictionary:
"bonus_row_visible": not parts.is_empty(),
}
static func _on_abandon_requested(root: Variant) -> void:
static func on_abandon_requested(root: Variant) -> void:
# 放弃入口(冒险结构.md 已放开「MVP 无界面入口」后置条款;
# 入口挂选路停点 = 天然非战斗期,拒绝分支仅防御在案):受理 → 冒险放弃结算(同失败型,
# 已获大奖励不追回)→ adventure_finished 同步到达 → 终局面收层