Files
gplan-2/game/presentation/views/pause_overlay.gd
T
DKChan 96fc61c701 feat(tree): 迭代21天赋树实装批 T1-T6 主体——12节点换代+六键接线+营地四柜台(2026-10-12 U0)
T1 schema 换代:MetaTreeTable FORK_GROUPS 4→3(fg_mastery 退役)/RULE_KEYS 2→6(sense/economy 四键扩签)/
  fork 单行双态(effects_a/b+name_a/b、每组恰一校验)/row 字段退役(行门槛主语=节点等级 level_gate)/
  requires 只留点亮前置(R1 裁撤案执行);meta_tree.tres 33→12 行重排(脊柱2/锻造2含彩蛋/钥石2/同调6,
  att_socket1 改根节点无前置,easter_ley 摘 atk/armor_class 分量=契约9)
T2 购买与彩蛋面:tree_can_buy easter 拒购+行门槛换轴;tree_buy_fork=解锁默认A;tree_toggle_fork 零币切态;
  tree_rule_keys 按激活态 effects_a/b 投影;_check_easter_egg 特化判定(两线拉满+socket全解锁);营地树行板双态钮
T3 六键接线:EVENTS+flag_missed/FACTS+battle_index(L2 扩签两处);rebuild 六键合成订阅
  (posture 窗=battle_index&&round_index 双闸/sense 两组=counter 闸+记账双行 domain:adventure 限次2次 provisional);
  level_runner battle_index 注入(visited battle 型计数);_judge_flag 去重闸后 flag_missed 发射(契约12);
  聚=_roll_gp_drop 入账前×1.5 provisional(escrow 不乘);散=_spend_discounted ×80%(current_price/pool_price
  双计价点,刷新价不折=§11②定义边界);_start_current_level 限次按关清零(_reset_tree_limited_counters 可测口)
T4 注入换代:hero_override=树淬炼flat+FORGE_ROUTE_BONUS预留0(命中不注入=契约6);Attunement.slots 判定源切
  树点亮数(谓词表退役);tree_buy(ks_refresh) 同账路由 buy_attune_refresh(V15 双入口)
T5 旧档废弃与删除:save_manager tree_struct=2 结构版本标记+_normalize 白名单重建+树域废弃重置(禁迁移折算);
  migrate_tree/buy_forge/forge_flat/forge_level/forge_price/meta_forge_row/forge_products 行族/
  attunement_growth 表+访问器/生涯页三投影/career forge_total 全删;treasure_item_table UNLOCK_COUNTER_KEYS 内联;
  verifier_batch 花费策略换代树节点;MC slots 画像常量3
T6 营地统一:四柜台并排横滚(树淬炼主界面/锻造工坊钥匙门+零交互占位面板/秘宝匣钥匙门+内容迁入/图鉴常开);
  暂停层锻造段连带删;camp data forge 投影删
存量红修复:_flush_pending_reveals 三处空 source_class 补 fx_reveal+类级豁免(a57489e9 落地件,冒烟51行)
测试随批:smoke 树段全重写(V1/V2/V3/V8/V9/V16)+_smoke_tree_rules V10 行为段(窗/限次/守侧五场景编排rig/聚散
  同种子对拍)+单元 tree_rules_v11_test(六键合成行闭集校验)+run_all 22 套;ui_probe/ui_click_probe 换代树点击路径
轻闸全绿:冒烟886/0+run_all 22套+probe --click 全绿
2026-10-12 07:54:38 +08:00

143 lines
6.5 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VERTICAL SLICE - NOT FOR PRODUCTION
# 局内暂停层·只读(迭代 17 卡③ 暂停层只读入口批 2026-10-06——需求卡片 v1.1;事实源=06-待办清单
# 「解锁界面与钥石呈现的交互形态(残余:暂停层只读入口)」)。
# 裁决落形:P1 丁=入口为战斗屏 HUD / 关卡地图屏常驻角标(入口装配在 ui_assembler/两屏,本类不含入口);
# P2 甲=登记 modal_stack 设置层同档(确认弹窗之前)带 dim 遮罩;P3 甲=展示钥石余额+进度概览
# (道具工坊六件解锁态 / 天赋树已购概览——层内行序与分组复用营地屏同序;属性锻造三行段随
# 迭代 21 柜台退役连带删除——数据源 forge_levels 域已清退);P4 甲=进出零动效直开直关
# (无 tween 无 AnimationPlayer——R5)。
# 只读契约:R4 数据只读同源——账面快照由组合根 open_pause 喂入(每次开层实时读 MetaProgression
# 访问器重建,快照仅用单次开层生命周期,跨开层零持有);本类零核心访问、零写通路——唯一信号
# closed(关闭意图,组合根经模态栈单口收口)。R1 公共件单点:全部构成件经 UiKit 工厂产出
#(modal_shell/panel_skinned/label/button/keystone_badge),零裸色值零自建样式。
class_name PauseOverlay
extends Control
signal closed
var _balance_badge: UiKit.KeystoneBadge # 钥石余额徽(badge 工厂件——Q10 甲)
var _workshop_holder: VBoxContainer
var _tree_label: Label
func _init() -> void:
var shell: Dictionary = UiKit.modal_shell(self, Color(UiKit.DIM, 0.55), Vector2(560, 0), 10, true,
UiKit.panel_skinned(Vector4(20, 16, 20, 16))) # 石板皮(缺位回退数据板——同设置面先例)
var box: VBoxContainer = shell.box
var title := UiKit.label("暂停",UiKit.FS_TITLE, true, UiKit.INK_TITLE)
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
box.add_child(title)
var hint := UiKit.label("查看本局钥石与永久强化进度(只读——购买请回营地)",UiKit.FS_HINT, false, UiKit.INK_HINT)
hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
box.add_child(hint)
# 钥石余额行(badge 工厂件——与营地顶栏钥石徽同形制)
var bal_row := HBoxContainer.new()
bal_row.alignment = BoxContainer.ALIGNMENT_CENTER
box.add_child(bal_row)
_balance_badge = UiKit.keystone_badge("钥石 0")
bal_row.add_child(_balance_badge)
box.add_child(HSeparator.new())
_section_head(box, "道具工坊 · 解锁态")
_workshop_holder = _section_holder(box)
_section_head(box, "天赋树 · 已购概览")
_tree_label = UiKit.label("",UiKit.FS_HINT, false, UiKit.INK_LABEL)
_tree_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
box.add_child(_tree_label)
box.add_child(HSeparator.new())
var close_row := HBoxContainer.new()
close_row.alignment = BoxContainer.ALIGNMENT_CENTER
box.add_child(close_row)
var close_btn := UiKit.button("继续", 90.0) # 紧凑返回钮(设置面先例形制;文案=代拍板白名单「继续」级措辞)
close_btn.tooltip_text = "关闭暂停层,继续当前冒险(本层只读,不发生任何购买或修改)"
close_btn.pressed.connect(_emit_closed)
close_row.add_child(close_btn)
visible = false # 显式初始化——不靠树序巧合(缺陷⑤家族纪律)
# 分组小节头(营地屏分组同构——fs 副标题档深墨)
func _section_head(box: VBoxContainer, text: String) -> void:
var head := UiKit.label(text,UiKit.FS_BODY, true, UiKit.INK_LABEL)
box.add_child(head)
func _section_holder(box: VBoxContainer) -> VBoxContainer:
var holder := VBoxContainer.new()
holder.add_theme_constant_override("separation", 4)
box.add_child(holder)
return holder
# ---- 开层(组合根唯一调用口——快照随开随建,R4 单次开层生命周期口径)----
func open_pause(data: Dictionary) -> void:
_balance_badge.set_text("钥石 %d" % int(data.get("balance", 0)))
_rebuild_workshop(data)
_rebuild_tree(data)
visible = true
# 道具工坊六行(解锁态文案与营地柜台同口径——退役/封存/已解锁/未解锁;进度=解锁判定量读数)
func _rebuild_workshop(data: Dictionary) -> void:
for c in _workshop_holder.get_children():
c.queue_free()
for row in (data.get("workshop", []) as Array):
var line := HBoxContainer.new()
line.add_theme_constant_override("separation", 8)
var name_l := UiKit.label(String(row.get("display_name", "")),UiKit.FS_HINT, true, UiKit.INK)
name_l.custom_minimum_size = Vector2(120, 0)
name_l.clip_text = true
name_l.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
line.add_child(name_l)
var prog_l := UiKit.label("累计通关 %d/%d 次" % [int(row.get("progress", 0)), int(row.get("threshold", 0))],UiKit.FS_HINT, false, UiKit.INK_HINT)
prog_l.custom_minimum_size = Vector2(150, 0)
prog_l.clip_text = true
prog_l.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
line.add_child(prog_l)
var st_l := UiKit.label(_workshop_state_text(row),UiKit.FS_HINT, true, UiKit.INK_LABEL)
st_l.size_flags_horizontal = Control.SIZE_EXPAND_FILL
line.add_child(st_l)
_workshop_holder.add_child(line)
# 解锁态文案(camp_overlay_view.refresh_camp 同款判据——退役 > 封存 > 已解锁 > 未解锁)
func _workshop_state_text(row: Dictionary) -> String:
if bool(row.get("retired", false)):
return "已退役"
if bool(row.get("deferred", false)) and bool(row.get("unlocked", false)):
return "已解锁 · 能力封存中"
if bool(row.get("unlocked", false)):
return "已解锁"
return "未解锁"
# 天赋树已购概览(单条聚合文案——已购节点等级 + Fork 组激活侧;零已购=空态句)
func _rebuild_tree(data: Dictionary) -> void:
var owned: Array[String] = []
for row in (data.get("tree", []) as Array):
var lvl := int(row.get("level", 0))
if lvl > 0:
owned.append("%s Lv%d/%d" % [String(row.get("display_name", "")), lvl, int(row.get("cap", 1))])
for fg in (data.get("fork_groups", []) as Array):
var active := String(fg.get("active_side", ""))
if active == "":
continue
var side_name := active
for sd in (fg.get("sides", []) as Array):
if String(sd.get("side", "")) == active:
side_name = String(sd.get("display_name", active))
break
owned.append("%s·激活 %s" % [String(fg.get("display_name", "")), side_name])
if owned.is_empty():
_tree_label.text = "尚未购买任何节点(天赋树在营地主柜台)"
else:
_tree_label.text = "已购 %d 项:%s" % [owned.size(), " · ".join(owned)]
func _emit_closed() -> void:
closed.emit()