全局 sed 替换 89 处命中清零(S11 绿)。修复: - 移交 3 处保留原词(shop.tres:86 display_name、curio_controller:165-166 玩家文案) - 豁免 enemy.tres:653 历史注记保持"已落籍" - static_scan.sh 词表追加行与头注恢复禁「」引举句式 - S11 规则文件自身不被自身规则误伤(闸门自指豁免生效)
219 lines
9.9 KiB
GDScript
219 lines
9.9 KiB
GDScript
## 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 "通用增益"
|