diff --git a/game/core/adventure_runner.gd b/game/core/adventure_runner.gd index 3bc1846a..4f081e65 100644 --- a/game/core/adventure_runner.gd +++ b/game/core/adventure_runner.gd @@ -344,6 +344,19 @@ func continue_to_next_level() -> bool: return _start_current_level() +# 停点空候选消化(2026-10-06 用户令——池空=三选一环节整体跳过:候选 0 件时停点视同已处理, +# 呈现层跳开选择面直接走后续推进。仅空候选合法;非空停点拒绝——零自动推进契约不破,正常 +# 消化仍只走 pick_curio/apply_node_curio 兑付。触发源=渠道白名单过滤后池空(关卡 Boss 通关 +# 渠道只出专长,专长零配置/旧档 deck 无 relic 余库即空集)。) +func skip_empty_curio() -> bool: + if _curio_pending.is_empty(): + return false + if not (_curio_pending.get("candidates", []) as Array).is_empty(): + return false + _curio_pending = {} + return true + + # ---- 提升三选一(迭代 10 奖励重构批——选择停点零自动推进、重复兑付被拒;兑付恰一件、未选项零生效)---- # 候选令牌匹配(身份键恒等——属性加成型特性 kind+tier、规则改写型特性 feat_id;迭代 12 T1 规则改写型特性带) diff --git a/game/presentation/curio_interact_controller.gd b/game/presentation/curio_interact_controller.gd index e3d3c346..fffbe0db 100644 --- a/game/presentation/curio_interact_controller.gd +++ b/game/presentation/curio_interact_controller.gd @@ -61,14 +61,39 @@ func has_pending() -> bool: return not _pending_curio.is_empty() -# 续玩停点恢复入口(true=已接手呈现,调用方中止后续分派) +# 续玩停点恢复入口(true=已接手呈现,调用方中止后续分派)。空候选降级(2026-10-06 用户令): +# 候选 0 件不开选择面(空面无卡无钮=死面)——消化停点后按上下文直落后续推进(战斗总结面已 +# 给过玩家确认拍,三选一环节整体跳过) func resume_if_pending() -> bool: if _pending_curio.is_empty(): return false + if (_pending_curio.get("candidates", []) as Array).is_empty(): + return _skip_empty_stop() show_pick() return true +# 停点空候选跳过(2026-10-06 用户令——「选出来 0 个则直接跳过该环节」):分派与 on_continue +# 同构(level_clear=推进下一关 / reward_node=兑付确认回图选路 / feat_ticket=只关面回店), +# 差异仅零面可收——curio_overlay 未开不 close。core 停点经 skip_empty_curio 消化后推进 +#(continue_to_next_level 的「停点未兑付拒推进」守卫因此放行)。 +func _skip_empty_stop() -> bool: + toast.show_toast("可用战利品为空——本次三选一跳过", "info") + var adventure = _adventure_get.call() + if adventure != null: + adventure.skip_empty_curio() # core 停点消化(其守卫=仅空候选放行) + if _curio_context == "reward_node": + var runner = _runner_get.call() + if runner != null: + runner.continue_after_node() + elif _curio_context == "level_clear" and bool(_adventure_mode_get.call()): + if not adventure.continue_to_next_level(): + _fatal_screen.call("关卡推进失败——见输出日志") + # feat_ticket = 只消化停点回店(零推进——与 on_continue 同构) + _pending_curio = {} + return true + + # 三选一停点(非末关通关恰一次):Boss 胜利先经战斗总结结算面(settlement-summary v1.1——钥石 # 增量行在其上),确认后进三选一面(level-clear.md v2);续玩停点恢复同入口(零自动推进契约) func on_presented(payload: Dictionary) -> void: @@ -76,6 +101,10 @@ func on_presented(payload: Dictionary) -> void: # T5 店内门票兑付——临时停点开专长三选一面(零胜利总结面;确认后只关面回店) _pending_curio = payload.duplicate(true) _curio_context = "feat_ticket" + if (_pending_curio.get("candidates", []) as Array).is_empty(): + # 空候选防御(2026-10-06 用户令——零卡不开死面;core _redeem_feat_ticket 守卫外的末道) + _skip_empty_stop() + return _open_modal.call(curio_overlay) curio_overlay.open_pick(Narrator.node_curio_header(), _curio_card_texts(payload.get("candidates", []) as Array)) return @@ -102,6 +131,14 @@ func present_node_curio() -> void: _curio_context = "reward_node" var node_draw: Dictionary = adventure.node_curio_candidates() var node_cands: Array = node_draw.get("candidates", []) as Array + if node_cands.is_empty(): + # 空池降级(2026-10-06 用户令)——不开面、不挂节点停点(present_node_curio 未调即未挂), + # 兑付确认直落回图选路(auto-sim「node_entered 回调内立即 continue_after_node」先例) + toast.show_toast("可用战利品为空——本次三选一跳过", "info") + var runner = _runner_get.call() + if runner != null: + runner.continue_after_node() + return _open_modal.call(curio_overlay) curio_overlay.open_pick(Narrator.node_curio_header(), _curio_card_texts(node_cands, node_draw.get("aux_detail", []) as Array)) adventure.present_node_curio(node_cands, node_draw.get("aux_detail", []) as Array)