160 lines
8.0 KiB
GDScript
160 lines
8.0 KiB
GDScript
## 锻造工坊子界面(自 CampOverlay 锻造柜台抽出——承载面迁移,界面逻辑复用零重设计):
|
||
## 钥匙门(树上 forge_workshop 点亮前锁定态零行板零购买路径;点亮=两区六路线行板)。
|
||
## UI 只发意图信号(写口唯一归 MetaProgression 锻造写口族);钮禁用=常态防线(余额/未解锁/满级/已选中)。
|
||
class_name ForgeView
|
||
extends CampSubViewBase
|
||
|
||
signal forge_buy_requested(route_id: String) ## 锻造路线购买意图(写口唯一归 MetaProgression.forge_buy_level)
|
||
signal forge_unlock_requested(route_id: String) ## 锻造路线解锁意图(写口唯一归 MetaProgression.forge_buy_unlock)
|
||
signal forge_select_requested(route_id: String) ## 锻造路线选中意图(写口唯一归 MetaProgression.forge_select)
|
||
|
||
const ROW_PLATE_COL := UiKit.CAMP_ROW_PLATE
|
||
|
||
var _forge_lock_l: Label # 锁定态行(钥匙未点亮)
|
||
var _forge_workbench: VBoxContainer # 工作间(钥匙点亮后展开——两区六路线行板)
|
||
var _forge_zone_weapon: VBoxContainer # 武器锻造区行板容器(三路线)
|
||
var _forge_zone_armor: VBoxContainer # 护甲锻造区行板容器(三路线)
|
||
var _forge_rows: Array[Dictionary] = [] # [{route_id, name_l, lvl_l, status_l, buy_btn, unlock_btn, select_btn, next_price, unlock_price}](open/refresh 重建;探针消费)
|
||
|
||
|
||
func _init() -> void:
|
||
var holder := VBoxContainer.new()
|
||
holder.add_theme_constant_override("separation", 6)
|
||
holder.custom_minimum_size = Vector2(0, 336)
|
||
_forge_lock_l = UiKit.label("🔒 锻造工坊未开放\n\n点亮树上「锻造工坊」钥匙节点后展开工作间。\n(钥匙免费、无前置——树上直接点亮)", UiKit.FS_HINT, false, UiKit.STONE_DEEP)
|
||
_forge_lock_l.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||
_forge_lock_l.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||
_forge_lock_l.custom_minimum_size = Vector2(280, 0)
|
||
_forge_workbench = VBoxContainer.new()
|
||
_forge_workbench.add_theme_constant_override("separation", 6)
|
||
_forge_workbench.visible = false # 默认锁定态(钥匙门未判前零行板——门开才建)
|
||
_forge_zone_weapon = VBoxContainer.new()
|
||
_forge_zone_weapon.add_theme_constant_override("separation", 4)
|
||
_forge_zone_armor = VBoxContainer.new()
|
||
_forge_zone_armor.add_theme_constant_override("separation", 4)
|
||
var wb_wh := UiKit.label("── 武器锻造区 ──", UiKit.FS_HINT, true, UiKit.GOLD_INK)
|
||
_forge_workbench.add_child(wb_wh)
|
||
_forge_workbench.add_child(_forge_zone_weapon)
|
||
var wb_ah := UiKit.label("── 护甲锻造区 ──", UiKit.FS_HINT, true, UiKit.GOLD_INK)
|
||
_forge_workbench.add_child(wb_ah)
|
||
_forge_workbench.add_child(_forge_zone_armor)
|
||
holder.add_child(_forge_lock_l)
|
||
holder.add_child(_forge_workbench)
|
||
var scroll := ScrollContainer.new()
|
||
scroll.custom_minimum_size = Vector2(300, 336)
|
||
scroll.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||
scroll.add_child(holder)
|
||
_build_shell("锻造工坊", UiKit.TEX_ICON_FORGE, scroll)
|
||
|
||
|
||
func refresh_camp(data: Dictionary) -> void:
|
||
_balance_label.text = "钥石 %d" % int(data.get("balance", 0))
|
||
_refresh_key_gate(data)
|
||
_rebuild_forge(data)
|
||
|
||
|
||
# 工作间钥匙门(树上 forge_workshop 行 level 判据——零核心访问,纯视图读投影)
|
||
func _refresh_key_gate(data: Dictionary) -> void:
|
||
var lvl := 0
|
||
for row in (data.get("tree", []) as Array):
|
||
if String(row.get("node_id", "")) == "forge_workshop":
|
||
lvl = int(row.get("level", 0))
|
||
var open := lvl >= 1
|
||
_forge_lock_l.visible = not open
|
||
_forge_workbench.visible = open
|
||
|
||
|
||
# 锻造行板重建(两区六路线;refresh_camp 调用。行结构仿秘宝匣行板:件名+等级+状态+购买/解锁/选中钮)
|
||
func _rebuild_forge(data: Dictionary) -> void:
|
||
for zone in [_forge_zone_weapon, _forge_zone_armor]:
|
||
for c in zone.get_children():
|
||
c.queue_free()
|
||
_forge_rows.clear()
|
||
if not _forge_workbench.visible:
|
||
return # 锁定态(钥匙未点亮):零行板零购买路径——占位纪律延续
|
||
var bal := int(data.get("balance", 0))
|
||
for row in data.get("forge", []):
|
||
var kind := String(row.get("kind", ""))
|
||
var zone: VBoxContainer = _forge_zone_weapon if kind == "weapon" else _forge_zone_armor
|
||
var card := _forge_route_card(row, bal)
|
||
zone.add_child(card["card"])
|
||
_forge_rows.append(card)
|
||
|
||
|
||
## 锻造行板构建域:单路线卡(件名+等级+状态+购买/解锁/选中钮——并联双通道呈现面)
|
||
func _forge_route_card(row: Dictionary, bal: int) -> Dictionary:
|
||
var d := _forge_route_scalars(row)
|
||
var card := PanelContainer.new()
|
||
card.add_theme_stylebox_override("panel", UiKit.panel_flat(ROW_PLATE_COL, UiKit.PANEL_BORDER, UiKit.RADIUS_OBJECT, 1, Vector4(10, 4, 10, 4)))
|
||
var line := HBoxContainer.new()
|
||
line.add_theme_constant_override("separation", 6)
|
||
card.add_child(line)
|
||
var name_l := UiKit.label(String(row.get("display_name", "")), UiKit.FS_HINT, true, UiKit.INK)
|
||
name_l.custom_minimum_size = Vector2(104, 0)
|
||
name_l.clip_text = true
|
||
name_l.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||
line.add_child(name_l)
|
||
var lvl_l := UiKit.label("Lv%d/%d" % [d["lvl"], d["cap_v"]], 13, false, UiKit.INK_LABEL)
|
||
lvl_l.custom_minimum_size = Vector2(44, 0)
|
||
line.add_child(lvl_l)
|
||
var status_l := UiKit.label(_forge_status_text(d, row), UiKit.FS_HINT, false, UiKit.STONE_DEEP)
|
||
status_l.clip_text = true
|
||
status_l.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||
status_l.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
line.add_child(status_l)
|
||
var btns := _forge_route_buttons(d, row, bal, line)
|
||
return {"card": card, "route_id": d["rid"], "name_l": name_l, "lvl_l": lvl_l, "status_l": status_l,
|
||
"buy_btn": btns["buy_btn"], "unlock_btn": btns["unlock_btn"], "select_btn": btns["select_btn"],
|
||
"next_price": d["next_price"], "unlock_price": d["unlock_price"]}
|
||
|
||
|
||
## 锻造行标量束:路线 id/解锁态/初始持有/等级/cap/几何价/解锁价一次取数
|
||
func _forge_route_scalars(row: Dictionary) -> Dictionary:
|
||
return {
|
||
"rid": String(row.get("route_id", "")),
|
||
"unlocked": bool(row.get("unlocked", false)),
|
||
"initial": bool(row.get("initial_owned", false)),
|
||
"lvl": int(row.get("level", 0)),
|
||
"cap_v": int(row.get("cap", 0)),
|
||
"next_price": int(row.get("next_price", 0)),
|
||
"unlock_price": int(row.get("unlock_price", 0)),
|
||
}
|
||
|
||
|
||
## 状态文案域(并联双通道:练满前一档 or 一次性解锁价直购;已满级态)
|
||
func _forge_status_text(d: Dictionary, row: Dictionary) -> String:
|
||
var st_text := "已解锁"
|
||
if not d["unlocked"]:
|
||
if d["initial"]:
|
||
st_text = "未解锁"
|
||
else:
|
||
st_text = "未解锁 · 练满%s 或 %d 钥石直购" % [String(row.get("prereq_name", "")), d["unlock_price"]]
|
||
elif d["lvl"] >= d["cap_v"]:
|
||
st_text = "已满级"
|
||
return st_text
|
||
|
||
|
||
## 三钮域:购买(已解锁未满级——余额不足禁用)/解锁(待解锁非初始——余额不足禁用)/选中(已解锁——当前=禁用态标记)
|
||
func _forge_route_buttons(d: Dictionary, row: Dictionary, bal: int, line: HBoxContainer) -> Dictionary:
|
||
var buy_btn: Button = null
|
||
if d["unlocked"] and d["lvl"] < d["cap_v"]:
|
||
buy_btn = UiKit.button("锻造 %d" % d["next_price"], 0.0) # 行板紧凑钮豁免
|
||
buy_btn.pressed.connect(forge_buy_requested.emit.bind(d["rid"]))
|
||
buy_btn.disabled = bal < d["next_price"]
|
||
line.add_child(buy_btn)
|
||
var unlock_btn: Button = null
|
||
if not d["unlocked"] and not d["initial"]:
|
||
unlock_btn = UiKit.button("解锁 %d" % d["unlock_price"], 0.0) # 行板紧凑钮豁免
|
||
unlock_btn.pressed.connect(forge_unlock_requested.emit.bind(d["rid"]))
|
||
unlock_btn.disabled = bal < d["unlock_price"]
|
||
line.add_child(unlock_btn)
|
||
var select_btn: Button = null
|
||
if d["unlocked"]:
|
||
var sel := bool(row.get("selected", false))
|
||
select_btn = UiKit.button("当前" if sel else "选中", 0.0) # 行板紧凑钮豁免
|
||
select_btn.pressed.connect(forge_select_requested.emit.bind(d["rid"]))
|
||
select_btn.disabled = sel
|
||
line.add_child(select_btn)
|
||
return {"buy_btn": buy_btn, "unlock_btn": unlock_btn, "select_btn": select_btn}
|