## 天赋树子界面(自 CampOverlay 树淬炼柜台抽出——承载面迁移,界面逻辑复用零重设计): ## 树脊柱界面形态=主界面(脉分组行板:节点名/等级/价/购买钮+Fork 双态切换钮段)。 ## UI 只发意图信号(写口唯一归 MetaProgression.tree_buy/tree_buy_fork/tree_toggle_fork)。 class_name TreeView extends CampSubViewBase signal tree_buy_requested(node_id: String) ## 天赋树购买意图(写口唯一归 MetaProgression.tree_buy) signal tree_fork_toggled(group: String, side: String) ## 双态切换意图(一节点双态——零币切态) var _tree_holder: VBoxContainer # 树淬炼内容(脊柱两行+钥匙/socket 行板+Fork 双态钮段) var _tree_buy_btns: Array[Dictionary] = [] # [{node_id, btn}]——树购买/解锁钮登记面(open/refresh 重建时刷新;探针消费) var _tree_fork_btns: Array[Dictionary] = [] # [{group, side, btn}]——Fork 双态切换钮登记面(探针消费) func _init() -> void: _tree_holder = VBoxContainer.new() _tree_holder.add_theme_constant_override("separation", 6) var tree_scroll := ScrollContainer.new() tree_scroll.custom_minimum_size = Vector2(300, 336) tree_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL tree_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED tree_scroll.add_child(_tree_holder) var content := VBoxContainer.new() content.add_child(tree_scroll) _build_shell("天赋树 · 淬炼", "", content) func refresh_camp(data: Dictionary) -> void: _balance_label.text = "钥石 %d" % int(data.get("balance", 0)) _rebuild_tree(data) # 天赋树段重建(脉分组行板:节点名/等级/价/购买钮 + Fork 双态切换钮; # 树数据 = 组合根 _camp_data().tree 投影 [{node_id, display_name, vein, kind, level, price, can_buy, # currency}...] + fork_groups [{group, node_id, active_side, owned, can_buy, price, sides:[{side, display_name, effects}]}]) func _rebuild_tree(data: Dictionary) -> void: for c in _tree_holder.get_children(): c.queue_free() _tree_buy_btns.clear() _tree_fork_btns.clear() var tree: Array[Variant] = data.get("tree", []) as Array var forks: Array[Variant] = data.get("fork_groups", []) as Array var vein_names := {"spine": "·脊柱淬炼·", "forge": "·锻造脉·", "keystone": "·钥石脉·", "attune": "·同调脉·"} var last_vein := "" for row in tree: var vein := String(row.get("vein", "")) if vein != last_vein: last_vein = vein var vh := UiKit.label(String(vein_names.get(vein, vein)), UiKit.FS_HINT, true, UiKit.GOLD_INK) # GOLD_DEEP 对柜台板 2.67:1 越带,换深金墨 5.21:1 _tree_holder.add_child(vh) if String(row.get("kind", "")) == "fork": continue # Fork 行去行板化——由 fork_groups 段承载双态切换钮 _tree_holder.add_child(_tree_row_line(row)) for fg in forks: _tree_holder.add_child(_tree_fork_line(fg)) ## 树行板构建域:节点名(含门槛标记)+购买钮(追加序与锚句随段整体搬迁) func _tree_row_line(row: Dictionary) -> HBoxContainer: var hb := HBoxContainer.new() hb.add_theme_constant_override("separation", 6) var lvl := int(row.get("level", 0)) var cap := int(row.get("cap", 1)) var name_l := UiKit.label("%s Lv%d/%d" % [String(row.get("display_name", "")), lvl, cap], 13, false, UiKit.INK_LABEL) name_l.custom_minimum_size = Vector2(150, 0) name_l.clip_text = true var gate := String(row.get("gate_text", "")) if gate != "": name_l.text += " 🔒" # 等级阈值前置未达标标记(R1 机制位——悬停看门槛;达标后随 refresh 消失) name_l.tooltip_text = "等级门槛:%s" % gate hb.add_child(name_l) var btn := UiKit.button("购买 %d 钥石" % int(row.get("price", 0)), 0.0) # 柜台行板紧凑钮豁免宽度基准 btn.pressed.connect(func(): tree_buy_requested.emit(String(row.get("node_id", "")))) btn.disabled = not bool(row.get("can_buy", false)) hb.add_child(btn) _tree_buy_btns.append({"node_id": String(row.get("node_id", "")), "btn": btn}) return hb ## Fork 双态行板构建域:组状态文案+解锁钮或双态切换钮 func _tree_fork_line(fg: Dictionary) -> HBoxContainer: var group := String(fg.get("group", "")) var active := String(fg.get("active_side", "")) var owned := bool(fg.get("owned", false)) var fb := HBoxContainer.new() fb.add_theme_constant_override("separation", 6) var state_txt := "未解锁" if owned: state_txt = "激活:%s" % active var gl := UiKit.label("%s[%s]" % [String(fg.get("display_name", group)), state_txt], 13, false, UiKit.INK_LABEL) fb.add_child(gl) if not owned: var bb := UiKit.button("解锁 %d 钥石" % int(fg.get("price", 0)), 0.0) # 行板紧凑钮豁免 bb.pressed.connect(func(): tree_buy_requested.emit(String(fg.get("node_id", "")))) bb.disabled = not bool(fg.get("can_buy", false)) fb.add_child(bb) _tree_buy_btns.append({"node_id": String(fg.get("node_id", "")), "btn": bb}) else: for side_row in (fg.get("sides", []) as Array): var sd := String(side_row.get("side", "")) var sb := UiKit.button(String(side_row.get("display_name", sd)), 0.0) # 行板紧凑钮豁免 sb.pressed.connect(func(): tree_fork_toggled.emit(group, sd)) fb.add_child(sb) _tree_fork_btns.append({"group": group, "side": sd, "btn": sb}) return fb