iter10 T3-T9: 奖励重构实装——adventure表扩列(回血20/池六种/权重/上限/同调位过渡键)+boss_keystone重锚3-2+rng扩签reward_pick+E-S加权洗牌+三选一停点(零自动推进/可中断)+加算区四轴AP(BattleOrchestrator排队兑现)+钥石逐杀掉落(收束无二次派生)+同调位约束(停点替换两路/战斗沉没/节点拒绝)+BonusPickOverlay+Narrator文案族+save v3迁移+冒烟619/0(+23断言)+断点P5往返单测+run_all 15套全绿

This commit is contained in:
DKChan committed 2026-10-01 04:30:13 +08:00
1 parent 49b263fbc8
commit 71502ceecd
18 files changed
+992 -169

No files matched your search

@@ -0,0 +1,150 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# Date: 2026-10-01(迭代 10 奖励重构批——level-clear.md v2 三选一选择面承载)
# 提升三选一覆盖层(模态):非末关通关的选择停点呈现——部分回血反馈 + 三卡点选 + 确认兑付 +
# 同调位替换子交互。高内聚边界:文案拼装归 Narrator(组合根喂入),选择意图经信号外发;
# 视图零核心引用。交互范式 = node_overlay choice_box 按钮族 + 选路两段式(点选→确认)复用,零新原语。
# 状态机:pick(三卡点选→确认)→ [replace(满位 N+1 选 N)] → result(兑付反馈→继续)。
class_name BonusPickOverlay
extends Control
signal pick_confirmed(item_id: String)
signal replace_chosen(discard_index: int) # -1 = 放弃新件不获取
signal continue_pressed
var _label: Label
var _choice_box: HBoxContainer # 三卡按钮区(pick 态)
var _replace_box: VBoxContainer # 替换子面板(replace 态)
var _confirm_btn: Button # 确认钮(点选后点亮——两段式第二拍)
var _continue_btn: Button # 继续钮(兑付反馈态唯一出口)
var _selected := "" # 点选暂存(确认前可改选)
var _header := "" # 停点头部文案(选择态保持显示)
var _card_meta: Array = [] # open_pick 缓存 [{id, text}]——高亮还原读面
func _init() -> void:
var dim := ColorRect.new()
dim.color = Color(0, 0, 0, 0.6)
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
add_child(dim)
var center := CenterContainer.new()
center.set_anchors_preset(Control.PRESET_FULL_RECT)
dim.add_child(center)
var box := VBoxContainer.new()
box.add_theme_constant_override("separation", 12)
center.add_child(box)
_label = UiKit.label("", 20, true)
_label.add_theme_color_override("font_color", UiKit.WARM)
_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
box.add_child(_label)
_choice_box = HBoxContainer.new()
_choice_box.add_theme_constant_override("separation", 12)
_choice_box.alignment = BoxContainer.ALIGNMENT_CENTER
box.add_child(_choice_box)
_confirm_btn = UiKit.button("确认选择")
_confirm_btn.pressed.connect(_on_confirm_pressed)
_confirm_btn.visible = false
box.add_child(_confirm_btn)
_replace_box = VBoxContainer.new()
_replace_box.add_theme_constant_override("separation", 8)
_replace_box.alignment = BoxContainer.ALIGNMENT_CENTER
box.add_child(_replace_box)
_continue_btn = UiKit.button("继续")
_continue_btn.pressed.connect(func(): continue_pressed.emit())
_continue_btn.visible = false
box.add_child(_continue_btn)
visible = false
# 选择态:header = 停点头部(回血+钥石增量行,Narrator 装配);cards = [{id, text}]
#(组合根组装——视图纯呈现)。确认前可改选;确认经 pick_confirmed 外发。
func open_pick(header: String, cards: Array) -> void:
_header = header
_label.text = header
_selected = ""
_card_meta = (cards as Array).duplicate(true)
for c in _choice_box.get_children():
c.queue_free()
for ch in cards:
var cid := String(ch.get("id", ""))
var btn := UiKit.button(String(ch.get("text", "")))
btn.custom_minimum_size = Vector2(170, 88)
btn.pressed.connect(func(): _select_card(cid))
_choice_box.add_child(btn)
_choice_box.visible = true
_confirm_btn.visible = false
_replace_box.visible = false
_continue_btn.visible = false
visible = true
func _select_card(id: String) -> void:
_selected = id
for i in _choice_box.get_child_count():
var btn := _choice_box.get_child(i) as Button
var meta: Dictionary = _card_meta[i] if i < _card_meta.size() else {}
var base_text := String(meta.get("text", ""))
btn.text = ("✓ " + base_text) if String(meta.get("id", "")) == id else base_text
_confirm_btn.visible = true
func _on_confirm_pressed() -> void:
if _selected != "":
pick_confirmed.emit(_selected)
# 探针/测试复用:以真实按钮路径触发点选、确认与继续(树序遮挡纪律——断言走真实信号路径)
func press_card(index: int) -> void:
if index >= 0 and index < _choice_box.get_child_count():
(_choice_box.get_child(index) as Button).pressed.emit()
func press_confirm() -> void:
_confirm_btn.pressed.emit()
func press_continue() -> void:
_continue_btn.pressed.emit()
func selected_id() -> String:
return _selected
# 兑付反馈态(bonus_resolved 到达——结果行追加在头部之后;唯一出口 = 继续)
func show_result(text: String) -> void:
_label.text = _header + "\n" + text
_choice_box.visible = false
_confirm_btn.visible = false
_replace_box.visible = false
_continue_btn.visible = true
visible = true
# 同调位替换子态(aux_replace_presented 到达):items = [{index, item_id, display_name}](组合根
# 喂显示名)。两路出口:丢旧收新(逐件钮)/ 放弃新件——终态恒 ≤ 同调位由核心受理面保证。
func open_replace(items: Array, incoming_name: String, holding: int, slots: int) -> void:
_label.text = "同调位已满(%d/%d)——收下「%s」需丢弃一件已有道具,或放弃新件" % [holding, slots, incoming_name]
for c in _replace_box.get_children():
c.queue_free()
for it in items:
var idx := int(it.get("index", -1))
var btn := UiKit.button("丢弃「%s」换新" % String(it.get("display_name", it.get("item_id", ""))))
btn.pressed.connect(func(): replace_chosen.emit(idx))
_replace_box.add_child(btn)
var decline := UiKit.button("放弃新件(不获取)")
decline.pressed.connect(func(): replace_chosen.emit(-1))
_replace_box.add_child(decline)
_choice_box.visible = false
_confirm_btn.visible = false
_replace_box.visible = true
_continue_btn.visible = false
visible = true
# 收屏(组合根在 continue_pressed 处理毕调——推进下一关同拍)
func close_pick() -> void:
_choice_box.visible = false
_replace_box.visible = false
_continue_btn.visible = false
_confirm_btn.visible = false
visible = false
@@ -0,0 +1 @@
uid://dqlecn1dxpg0i