Files
gplan-2/game/presentation/views/curio_pick_overlay.gd
T
DKChan b6629d6848 feat(T2-T6): 五词注释换代——完美排雷→完美封印/板级→整图/门票→专长凭证/正主→现行事实源/落籍→已入库
全局 sed 替换 89 处命中清零(S11 绿)。修复:
- 移交 3 处保留原词(shop.tres:86 display_name、curio_controller:165-166 玩家文案)
- 豁免 enemy.tres:653 历史注记保持"已落籍"
- static_scan.sh 词表追加行与头注恢复禁「」引举句式
- S11 规则文件自身不被自身规则误伤(闸门自指豁免生效)
2026-10-20 20:41:50 +08:00

219 lines
9.9 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
## 提升三选一覆盖层(模态):通关停点的三卡点选→确认→兑付反馈两态呈现。
## 文案拼装归 Narrator 经组合根喂入——本类零文案装配。
class_name CurioPickOverlay
extends Control
signal pick_confirmed(item_id: String)
signal continue_pressed
signal refresh_requested # 三选一刷新意图(迭代 11 第①批 T5b——P1 甲 X/Y 双源;重抽归组合根)
var _label: Label
var _choice_box: HBoxContainer # 三卡区(pick 态——M7 bcard 竖卡)
var _confirm_btn: Button # 确认钮(点选后点亮——两段式第二拍)
var _continue_btn: Button # 继续钮(兑付反馈态唯一出口)
var _refresh_btn: Button # 刷新钮(迭代 11 第①批 T5b——余量>0 才显示;M7 升顶条图标钮)
var _refresh_badge: Label # M7 余量角标(图标钮右上——demo ⑥ 同构)
var _refresh_l: Label # 刷新余量读数(X 优先 + Y 冒险池)
var _foot_hint: Label # T7 底注(demo .bonus-foot .hint——pick 态显隐)
var _refresh_allowance := 0 # 组合根投喂免费余量(X/Y——本视图零核心引用)
var _refresh_gp_cost := 0 # 组合根投喂 GP 刷新价(免费位用尽后的付费档读数)
var _selected := "" # 点选暂存(确认前可改选)
var _header := "" # 停点头部文案(选择态保持显示)
var _card_meta: Array[Variant] = [] # open_pick 缓存 [{id, text}]——高亮还原读面
var _bcards: Array[Variant] = [] # M7 bcard 引用列(select 高亮=set_selected)
func _init() -> void:
# 全屏页形态(demo ⑥ #v-bonus——与商店 T6 同壳 page_shell,
# 根底暗档)——56px 通栏顶条(标题+刷新图标钮/角标)+ 居中入账信息行(GP 汇总行承载)+
# bcard 三竖卡(D1 232×352)+ 底部确认主钮与免费选择注记。差异白名单=免费选择/✓章/无价签。
# 状态机不变:pick→result。M7 同构裁决遗产保留。
var page: Dictionary[Variant, Variant] = UiKit.page_shell(self, false)
var top: HBoxContainer = page.top_row
top.add_child(UiKit.label("战利品三选一",UiKit.FS_TITLE, true, UiKit.WARM))
var top_sp := Control.new()
top_sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL
top.add_child(top_sp)
_refresh_btn = UiKit.button("", 0.0) # 图标钮自设 44×44——豁免宽度基准
_refresh_btn.icon = UiKit.load_tex(UiKit.TEX_ICON_REFRESH)
_refresh_btn.custom_minimum_size = Vector2(44, 44)
_refresh_btn.tooltip_text = "刷新候选——装配刷新件 X 优先,Y 为冒险池;不消耗 AP"
_refresh_btn.pressed.connect(_emit_refresh_requested)
_refresh_btn.visible = false
top.add_child(_refresh_btn)
_refresh_badge = UiKit.label("0",UiKit.FS_CAPTION, true, UiKit.INK_ON_GOLD)
_refresh_badge.mouse_filter = Control.MOUSE_FILTER_IGNORE
_refresh_badge.set_anchors_preset(Control.PRESET_TOP_RIGHT)
_refresh_badge.offset_left = -22.0
_refresh_badge.offset_top = -6.0
_refresh_btn.add_child(_refresh_badge)
_refresh_l = UiKit.label("",UiKit.FS_CAPTION, false, UiKit.WARM_SOFT)
_refresh_l.visible = false
top.add_child(_refresh_l)
var box: VBoxContainer = page.box
_label = UiKit.label("",UiKit.FS_BODY, false, UiKit.WARM_SOFT)
_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
box.add_child(_label)
_choice_box = HBoxContainer.new()
_choice_box.add_theme_constant_override("separation", 26) # demo .cards gap 26(T7 对齐)
_choice_box.alignment = BoxContainer.ALIGNMENT_CENTER
_choice_box.size_flags_vertical = Control.SIZE_EXPAND_FILL
box.add_child(_choice_box)
var foot := HBoxContainer.new()
foot.alignment = BoxContainer.ALIGNMENT_CENTER
foot.add_theme_constant_override("separation", 16)
box.add_child(foot)
_confirm_btn = UiKit.primary_button("确认选择")
_confirm_btn.pressed.connect(_on_confirm_pressed)
_confirm_btn.visible = false
foot.add_child(_confirm_btn)
_continue_btn = UiKit.button("继续")
_continue_btn.pressed.connect(_emit_continue_pressed)
_continue_btn.visible = false
foot.add_child(_continue_btn)
_foot_hint = UiKit.label("免费选择 · 刷新不消耗 AP",UiKit.FS_HINT, false, UiKit.WARM_FAINT)
foot.add_child(_foot_hint)
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()
_bcards.clear()
for ch in cards:
var cid := String(ch.get("id", ""))
var full := String(ch.get("text", ""))
var lines := full.split("\n")
var title := lines[0]
var desc := "\n".join(lines.slice(1)) if lines.size() > 1 else ""
var idl := cid.to_lower()
var band := UiKit.tg_band(idl) # 类型色带单点(TG_* 五族同源判定;aoe/blast 归 TG_AOE)
# 类型脚注(T7 判官 checkpoint:demo .bcard .src 底部类型行——实机缺=卡下半空底;词=demo 同款)
var card := UiKit.bcard(title, desc, band, _icon_for_id(idl), "", _type_label(idl))
card.gui_input.connect(func(ev: InputEvent) -> void:
if ev is InputEventMouseButton and ev.pressed and ev.button_index == MOUSE_BUTTON_LEFT:
_select_card(cid))
card.mouse_filter = Control.MOUSE_FILTER_STOP
_choice_box.add_child(card)
_bcards.append(card)
_choice_box.visible = true
_confirm_btn.visible = false
_continue_btn.visible = false
_foot_hint.visible = true # T7 底注=pick 态专属(result 态让位)
_refresh_btn.visible = false # 刷新面随 set_refresh_display 投喂后现形(open 先归零防残留;店内专长凭证面不投喂=无刷新)
_refresh_l.text = ""
visible = true
# 三选一刷新呈现投喂(对齐商店 MC-1 同构——free_left=X/Y 免费位余量〔基础 0〕,
# 免费位用尽转 GP 付费档:gp_cost=本次 GP 刷新价、can_afford=冒险钱包可付;钮常驻选择态,两源皆穷=禁用不隐藏)
func set_refresh_display(free_left: int, gp_cost: int, can_afford: bool) -> void:
_refresh_allowance = maxi(0, int(free_left))
_refresh_gp_cost = maxi(0, int(gp_cost))
_refresh_btn.visible = _refresh_allowance > 0 or _refresh_gp_cost > 0
_refresh_badge.text = str(_refresh_allowance)
_refresh_l.text = "免费 · 不消耗 AP" if _refresh_allowance > 0 else ("刷新 %d GP" % _refresh_gp_cost if _refresh_gp_cost > 0 else "")
_refresh_l.visible = _refresh_l.text != ""
_refresh_btn.tooltip_text = "刷新候选——换一批战利品\n免费 %d 次(刷新件 X 优先 + 冒险池 Y)\nGP 刷新 %d GP\n池源=共享池,与商店货架同源" % [_refresh_allowance, _refresh_gp_cost]
_refresh_btn.disabled = _refresh_allowance <= 0 and not can_afford
func _emit_refresh_requested() -> void:
refresh_requested.emit()
func _select_card(id: String) -> void:
_selected = id
# 选中态=木描边+✓章(demo ⑥;set_selected 逐卡置真值防改选残留)
for i in _bcards.size():
var meta: Dictionary[Variant, Variant] = _card_meta[i] if i < _card_meta.size() else {}
(_bcards[i] as UiKit.BCard).set_selected(String(meta.get("id", "")) == id)
_confirm_btn.visible = true
func _on_confirm_pressed() -> void:
if _selected != "":
pick_confirmed.emit(_selected)
# 探针/测试复用:以真实按钮路径触发点选、确认与继续(树序遮挡纪律——断言走真实信号路径)
func press_card(index: int) -> void:
# M7:卡载体 Button→bcard(gui_input 点选)——真实路径=同一 _select_card 处理器,探针语义不变
if index >= 0 and index < _card_meta.size():
_select_card(String(_card_meta[index].get("id", "")))
func press_confirm() -> void:
_confirm_btn.pressed.emit()
func press_continue() -> void:
_continue_btn.pressed.emit()
# 探针/测试复用:以真实按钮路径触发刷新意图(信号外发——受理归组合根)
func press_refresh() -> void:
_refresh_btn.pressed.emit()
# 兑付反馈态(curio_resolved 到达——结果行追加在头部之后;唯一出口 = 继续)
func show_result(text: String) -> void:
_label.text = _header + "\n" + text
_choice_box.visible = false
_confirm_btn.visible = false
_continue_btn.visible = true
_refresh_btn.visible = false # 刷新=选择态专属功能(结果态停点已兑付——残钮零意图可点)
_foot_hint.visible = false
visible = true
# 收屏(组合根在 continue_pressed 处理毕调——推进下一关同拍)
func close_pick() -> void:
_choice_box.visible = false
_continue_btn.visible = false
_confirm_btn.visible = false
_refresh_btn.visible = false
_foot_hint.visible = false
visible = false
func _emit_continue_pressed() -> void:
continue_pressed.emit()
# M7:id → 手绘图标键(子串映射容错 id 词表演进;缺位=BCard 空图标槽不炸)
func _icon_for_id(idl: String) -> String:
if idl.contains("heal"):
return UiKit.TEX_ICON_MEDKIT
if idl.contains("blast") or idl.contains("magic"):
return UiKit.TEX_ICON_BLAST
if idl.contains("gp") or idl.contains("coin"):
return UiKit.TEX_ICON_COINBAG
if idl.contains("attack"):
return UiKit.TEX_ICON_SWORD
if idl.contains("armor"):
return UiKit.TEX_ICON_SHIELD
if idl.contains("ap") or idl.contains("action"):
return UiKit.TEX_ICON_POUCH
return UiKit.TEX_ICON_COINBAG
# T7 类型脚注词(demo .bcard .src 同款五族——与 tg_band 同域子串判定,卡底填空对齐)
func _type_label(idl: String) -> String:
if idl.contains("heal"):
return "治疗"
if idl.contains("blast") or idl.contains("magic"):
return "魔法"
if idl.contains("pierce"):
return "穿甲"
if idl.contains("aoe"):
return "群伤"
return "通用增益"