- 四view新件(自CampOverlay承载面迁移,界面逻辑复用零重设计契约4): forge_view(钥匙门+两区六路线行板)/treasure_view(12件行板+同调装配段+Y升级行+钥匙门)/tree_view(脉分组行板+Fork双态)/codex_view(占位挂起壳,锁文随形态订正『柜台』称谓L2)——各带返回钮发closed(关层归presenter);公共壳CampSubViewBase(实底dim+铭牌+钥石徽+返回钮) - CampRefreshBus新件: 各写口尾→现开界面刷新+场景根HUD一闸(卡⑤HUD同口挂接;非autoload非信号广播——组合根单点推送);presenter八写口尾refresh_camp→bus.refresh(F9:七口+on_camp_buy双尾) - 承载形态(§9-2拍板): 单一内页切换=场景根留底——模态栈open只隐上方登记层(modal_stack.gd:27实测),四子界面登记于场景根之上且实底遮挡,双开互斥靠遮挡天然成立;V2断言按留底派生(T5落) - ui_registry: LAYER_CONTRACT camp_overlay槽→camp_scene(shell camp_screen)+forge/treasure/tree/codex_view四槽;node()改经modals.camp.X二层(卡⑥契约2);ui_camp_modals五枚成员(overlay枚随退役删除——卡⑥契约4) - camp_screen: 持camp_scene取代CampOverlay成员;main_ui_build: 场景装配(布局表ConfigDB注入)+四view实例化+信号接线(意图→presenter/closed bind携视图/object_pressed→组合根路由) - presenter承接面: 五目标改线(ctx.views束——成员预算12≤15)+open_camp_forge/treasure/tree/codex四开层口+on_camp_sub_closed+on_camp_closed关层收闭(营地层与选档层同收+开始层恢复);main_overlay_flow._on_camp_object_pressed五物件路由(gate/campfire归T4)+生涯营地语境关层分支(笔记本改挂——CareerOverlay本体零改);main.gd薄委托零新增成员 - 退役: camp_overlay_view.gd删除(吸收即死);旧形态断言同批摘除(test-conventions §5.5):theme_projection等高源码断言+最近冒险行投影段(卡面削弱申报授权:注销,条带Q4=甲撤下) - 同批迁移: forge_workbench_test承载类camp_overlay_view→forge_view+_forge._X扁平化(断言零改12项绿);system_test三处机械随迁(V2实例化/:108同一性链/:121候选清单——camp_scene句柄更名) - 验证: 冒烟boot PASS(15项0失败——装配全链通)+全流程孤检绿(12项:五句柄/铺层/点选路由四子界面/返回/生涯改挂/营地语境分支/关层收闭——临时件不入库);S9/S10/S13归基线(codex头注日期清偿/_build_shell超局部变量按顶栏底栏拆)
106 lines
5.3 KiB
GDScript
106 lines
5.3 KiB
GDScript
## 天赋树子界面(自 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
|