主卡T3(拆件批wr4/wr5): 应用层收薄+构造注入+信号直连——adventure_runner六转发信号族与_forward_*方法删除(选路快照双职改核心侧受理_on_level_choices_presented直订level信号;stop信号中继删);level_runner构造注入一次给齐(_init收ctx十二键:hero/ledger瘦壳/adv_bucket/attunement/tree_rules活引用/shop_mode/treasure_unlocked/类型轴/凭证出箱/pool_wiring四参——后置setter群八件与set_hero/set_run_ledger退役,_bind_shop全仓仅构造一处,头注补关卡开始信号前零发射契约,八白盒属性内部改直指_shop);adv _start_current_level组包ctx(_inject_level_params退役改_emit_level_started只广播);呈现/测量信号直连(main_adventure_flow _connect_runner_once六信号level_started重取点is_connected守卫重连+三选一订stop();autoplay增订level_started同关守卫重连三信号;curio_interact_controller 14处adventure.stop()改址);测量面残留换代(bp_baseline_dump直连改level_started重连/ui_tune_probe与main_debug_flow keystone读hero());测试直连面换代(breakpoint_resume P5订stop()/adventure_feats信号序观测level_started回调内重连——bind句柄每回调新建不以Callable相等判重);sc3源码断言落hero_ledger_test(_bind_shop全仓仅构造一处/_forward_族零命中)〔拆件批 V5〕。验收:bp1对拍292dumps×27键逐位零漂移(改前/T1/T2/T3四时点一致)+十套件零红+csf集成绿+冒烟17项0失败〔拆件批 V4〕〔拆件批 V5〕

This commit is contained in:
DKChan committed 2026-10-27 03:51:35 +08:00
1 parent 4a9e4300ad
commit 4da7f3e2f2
13 files changed
+188276 -173

No files matched your search

+13 -13
View File
@@ -1,7 +1,7 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 三选一交互控制器:三选一停点编排(presented→pick→confirm/refresh→resolved→continue)+ TP0 令牌池卡片文案装配 + 秘宝显示名投影。
## 信号连接只归组合根(curio_overlay/adventure 信号接至本类 on_* 入口);模态栈/演播后排窗/呈现刷新/fatal 经组合根回调注入,adventure/runner 现值注入。
## 兑付写调用唯一经 adventure.pick_curio/apply_node_curio——本类零直写。
## 兑付写调用唯一经 adventure.stop().pick_curio/apply_node_curio——本类零直写。
## 同调装配不可变(冒险中零更换途径)——无替换子交互。
extends RefCounted
@@ -69,7 +69,7 @@ func _skip_empty_stop() -> bool:
toast.show_toast("可用战利品为空——本次三选一跳过", "info")
var adventure = _adventure_get.call()
if adventure != null:
adventure.skip_empty_curio() # core 停点消化(其守卫=仅空候选放行)
adventure.stop().skip_empty_curio() # core 停点消化(其守卫=仅空候选放行)
if _curio_context == "reward_node":
var runner = _runner_get.call()
if runner != null:
@@ -116,7 +116,7 @@ func on_presented(payload: Dictionary) -> void:
func present_node_curio() -> void:
var adventure = _adventure_get.call()
_curio_context = "reward_node"
var node_draw: Dictionary[Variant, Variant] = adventure.node_curio_candidates()
var node_draw: Dictionary[Variant, Variant] = adventure.stop().node_curio_candidates()
var node_cands: Array[Variant] = node_draw.get("candidates", []) as Array
if node_cands.is_empty():
# 空池降级——不开面、不挂节点停点(present_node_curio 未调即未挂),
@@ -128,7 +128,7 @@ func present_node_curio() -> void:
return
_open_modal.call(curio_overlay)
curio_overlay.open_pick(Narrator.node_curio_header(), _curio_card_texts(node_cands))
adventure.present_node_curio(node_cands)
adventure.stop().present_node_curio(node_cands)
_feed_refresh_display(adventure) # 刷新面投喂单点
@@ -147,8 +147,8 @@ func show_pick() -> void:
func _feed_refresh_display(adventure: AdventureRunner) -> void:
var runner = _runner_get.call()
var gp := int(runner.gp) if runner != null else 0
var cost: int = adventure.curio_refresh_gp_cost()
curio_overlay.set_refresh_display(adventure.attune_refresh_left(), cost, gp >= cost)
var cost: int = adventure.stop().curio_refresh_gp_cost()
curio_overlay.set_refresh_display(adventure.stop().attune_refresh_left(), cost, gp >= cost)
func _curio_card_texts(candidates: Array) -> Array:
@@ -181,22 +181,22 @@ func _curio_card_texts(candidates: Array) -> Array:
# 选择面,节点停点在此读在途态重 present——零自动推进契约不破,停点仍在途)
func on_refresh() -> void:
var adventure = _adventure_get.call()
if adventure == null or not adventure.curio_stop_pending():
if adventure == null or not adventure.stop().curio_stop_pending():
return
var runner = _runner_get.call()
var refreshed: bool = adventure.refresh_curio()
var refreshed: bool = adventure.stop().refresh_curio()
if not refreshed:
# 免费位(X/Y)已穷——GP 付费档(先扣钱包后重抽,余额不足拒绝零副作用)
var cost: int = adventure.curio_refresh_gp_cost()
var cost: int = adventure.stop().curio_refresh_gp_cost()
if runner == null or not runner.spend_gp(cost):
toast.show_toast("GP不足——刷新失败", "warn")
return
refreshed = adventure.refresh_curio_paid()
refreshed = adventure.stop().refresh_curio_paid()
_refresh_presentations.call() # 钱包变化上屏(对齐商店购买后刷新面)
if not refreshed:
return
if _curio_context == "reward_node":
var st: Dictionary[Variant, Variant] = adventure.node_curio_pending_state()
var st: Dictionary[Variant, Variant] = adventure.stop().node_curio_pending_state()
curio_overlay.open_pick(Narrator.node_curio_header(), _curio_card_texts(st.get("candidates", []) as Array))
_feed_refresh_display(adventure)
@@ -210,14 +210,14 @@ func on_pick_confirmed(item_id: String) -> void:
var kind := parts[0]
var tier := parts[1] if parts.size() > 1 else ""
var rid := parts[2] if parts.size() > 2 else ""
var ok: bool = adventure.apply_node_curio(kind, tier, rid) if _curio_context == "reward_node" else adventure.pick_curio(kind, tier, rid)
var ok: bool = adventure.stop().apply_node_curio(kind, tier, rid) if _curio_context == "reward_node" else adventure.stop().pick_curio(kind, tier, rid)
if not ok:
push_error("[bonus_interact] 三选一兑付被拒——见输出日志")
return
# T5——节点渠道专长凭证拿到即开:候选已被替换为专长面,本地读在途态重绘(零 emit——context 保持 reward_node,
# 后续兑付/确认仍走节点路径回图选路)
if _curio_context == "reward_node" and kind == "feat_ticket":
var st2: Dictionary[Variant, Variant] = adventure.node_curio_pending_state()
var st2: Dictionary[Variant, Variant] = adventure.stop().node_curio_pending_state()
curio_overlay.open_pick(Narrator.node_curio_header(), _curio_card_texts(st2.get("candidates", []) as Array))
+23 -10
View File
@@ -4,20 +4,15 @@
## 局态仍全局住在 run_scope 节点:本件零成员态、零信号连接新增(连接语句随原段搬运)。
extends RefCounted
# 冒险编排构建+接线(开新局/续玩共用——信号连接只在组合根;断点注入同口)
# 冒险编排构建+接线(开新局/续玩共用——信号连接只在组合根;断点注入同口)。
# 信号直连(拆件批 T3):runner 六信号在 level_started 重取点重连(旧实例连接随引用释放消亡——
# is_connected 守卫恰好一次);三选一信号面归停点件(每冒险一次——接线恰一次)。
static func _wire_adventure(root: Variant) -> void:
root.run_scope.adventure = AdventureRunner.new(root.db, root.get_node(root.AUTOLOAD_PATH_RNG))
root.run_scope.adventure.step_row.connect(root._on_step_row)
root.run_scope.adventure.round_started.connect(root._on_round_started)
root.run_scope.adventure.board_changed.connect(root._on_board_changed)
root.run_scope.adventure.node_entered.connect(root._on_runner_node)
root.run_scope.adventure.choices_presented.connect(root._on_choices_presented)
root.run_scope.adventure.wallet_changed.connect(root._on_wallet_changed)
# 三选一信号族接线
root.run_scope.adventure.curio_choice_presented.connect(root._bonus.on_presented)
root.run_scope.adventure.curio_resolved.connect(root._bonus.on_resolved)
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.set_save_manager(root.save_manager) # 断点承载注入(停点快照写盘;调试/模拟不经过此路径)
@@ -26,6 +21,8 @@ static func _wire_adventure(root: Variant) -> void:
# 本回调返回后才有 choices_presented 到达——入口选路层随即弹出)
static func _on_adventure_level_started(root: Variant, level_index: int, display_name: String) -> void:
root.run_scope.runner = root.run_scope.adventure.runner()
# runner 信号直连(拆件批 T3——六转发族退役后的重取点重连;恰好一次断言 sc1 守卫承载)
_connect_runner_once(root)
# 开场行传当前生效值(runner.effective_atk/effective_max_hp 与战斗面板同源:
# 表值+永久强化 flat+加算区 flat 后乘调试浮窗 pct,本回调时点 runner 已带全部加成);「含面板加成」
# 后缀判断认任一加成源——永久强化 atk/max_hp flat 或调试浮窗 pct 或局内加算区 atk/max_hp
@@ -39,6 +36,22 @@ static func _on_adventure_level_started(root: Variant, level_index: int, display
root.log_view.append_bb(root.Narrator.level_open_line(display_name, int(root.run_scope.adventure.master_seed),
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:
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],
]
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:
# 冒险模式:runner 逐关更替——每次节点事件重取(单关模式幂等);须先于 board_changed 回退读面
if root.run_scope.is_adventure and root.run_scope.adventure != null:
+1 -1
View File
@@ -58,7 +58,7 @@ static func _debug_run_data(root: Variant) -> Dictionary:
if r == null:
return {"seed": seed_txt, "level": "—", "node": "—", "hp": "—", "gp": "—", "keystone": "—"}
return {"seed": seed_txt, "level": int(root.run_scope.adventure.level_index), "node": int(r.node_index),
"hp": "%d/%d" % [int(r.hero_hp), int(r.effective_max_hp())], "gp": int(r.gp), "keystone": int(root.run_scope.adventure.keystone)}
"hp": "%d/%d" % [int(r.hero_hp), int(r.effective_max_hp())], "gp": int(r.gp), "keystone": root.run_scope.adventure.hero().keystone_gained()}