feat(t4): 魔法道具 HUD 面——C 区四槽接线+两步使用交互+叠加层呈现+清空反馈

①hero_info_panel:四槽 gui_input 可点+aux_slot_clicked 信号+set_aux_inventory 投影渲染(空槽虚位/used 暗态/不可用置灰/选中金框/tooltip 全名+语义)
②main:选中态 _aux_use_selection+槽点击(AP 类 target=none 即用/空间类 toggle 选中)+_on_board_action dig 劫持(选中期点格=目标拾取不落挖格;move/flag 不冲突)+_attempt_aux_use(拒绝零消耗 toast 可辨认)+_aux_inventory_projection(字形=名首字;usable 回调接排雷玩法只读面)+use 成功后槽位/叠加层双刷+_on_board_action 行尾槽位重查(授予同步走完)
③叠加层呈现:CellUnit.aux_mark(真视=危险红内缩框)+board_view.set_aux_overlays 投影注入(refresh 消费;预读格=badge_glyph 注入 REWARD_BADGE 字形走 identity_resolver 既有只读面零数据复制;旗格让位不注)
④清空反馈:LevelRunner aux_cleared 快照(payload 已有 T3)→AdventureRunner additive 扩签(big_reward_paid.aux_cleared/summary.aux_cleared_last,_last_aux_cleared 捕获)→main 大奖励屏 toast「上关剩余 N 件魔法道具已随关卡结束清空」
闸:冒烟 577/0+三探针 PASS;T() 拼接病累计八处全自愈(board_view 混行尾归一 LF/adventure_runner _first_script 重复声明去重/两 var 拼接)
This commit is contained in:
DKChan committed 2026-09-29 07:21:58 +08:00
1 parent 63a08d1e01
commit 2f3a87e98f
5 files changed
+184 -3

No files matched your search

+14 -1
View File
@@ -82,7 +82,15 @@ var tex_flag: Texture2D = null # ④ 旗
# 变异角标(迭代 6 T6——程序化,tex_mutation 纹带槽留给变异纹带六型自产批):
# "flat_damage" = 未开格伤害型变异,左下角危险红三角(开格有代价的策略纹理标记)
var mutation_mark := "":
# 叠加层标记(迭代 7 T4——魔法道具板级叠加层的格面呈现;派生信息层零回写):
# "mine_reveal" = 真视格(危险红内缩框——「这格是雷」的确定决策标记,插旗照常计费);
# "reward_preview" 格不复用本字段——预读徽章走 badge_glyph 注入(board_view refresh 注入 REWARD_BADGE 字形)
var aux_mark := "":
set(v):
if aux_mark != v:
aux_mark = v
queue_redraw()
var mutation_mark := ":":
set(v):
if mutation_mark != v:
mutation_mark = v
@@ -175,6 +183,11 @@ func _draw() -> void:
draw_texture_rect(tex_mutation, rect, false)
# ②' 变异角标(迭代 6 T6):左下角危险红三角(危险红=「开此格有代价」语义位,与雷族同源;
# 尺寸随格边比例——灰色可辨辅助=红对砖面明度差,禁喧宾)
# ②" 魔法道具叠加层(迭代 7 T4):真视格=危险红内缩框(策略纹理——确定决策输入不喧宾)
if aux_mark == "mine_reveal":
var inset := edge * 0.14
draw_rect(Rect2(inset, inset, edge - inset * 2.0, edge - inset * 2.0),
Color(UiKit.RED_MINE, 0.9), false, 2.0)
if mutation_mark == "flat_damage":
var mw := edge * 0.28
var mpts := PackedVector2Array([Vector2(0, edge - mw), Vector2(0, edge), Vector2(mw, edge)])
+22
View File
@@ -98,6 +98,8 @@ var _minesweeper = null # 排雷玩法 只读查询引用(refresh
var _identity_cb := Callable() # 地图战斗资源 身份解析回调(组合根注入只读面)——Vector2i → Dictionary/null
var _mask_cb := Callable() # 地形变异 数字遮蔽回调(组合根注入只读面)——Vector2i → bool(true = 该格数字不显示)
var _vmark_cb := Callable() # 地形变异 角标回调(迭代 6 T6 只读面)——Vector2i → String("flat_damage"=伤害型变异未开格;""=无)
var _aux_reveal := {} # 魔法道具 真视集(迭代 7 T4——Vector2i → true;组合根 set_aux_overlays 注入投影)
var _aux_preview := {} # 魔法道具 预读集(同上——未开格徽章呈现挂点)
var _diggable := {} # 可挖域(8 向相邻未开格)——呼吸微光作用集
var _breath_t := 0.0
var _contact_unit: Node2D = null # 接触带承载单元(=英雄格 CellUnit;rebuild 随清场复位)
@@ -193,6 +195,16 @@ func set_variant_mask_resolver(cb: Callable) -> void:
func set_variant_mark_resolver(cb: Callable) -> void:
_vmark_cb = cb
# 魔法道具叠加层投影注入(迭代 7 T4——组合根在 use 成功/三清后调;refresh 消费)
func set_aux_overlays(reveal_cells: Array, preview_cells: Array) -> void:
_aux_reveal.clear()
_aux_preview.clear()
for c in reveal_cells:
_aux_reveal[Vector2i(c)] = true
for c in preview_cells:
_aux_preview[Vector2i(c)] = true
refresh()
# SubViewport 主题/字体显式注入挂点(Phase B 两舞台复用——SubViewport 不自动继承主场景 Control 主题;
# 本项目无自定义主题,缺省 = 引擎回退字体,与旧 Button 渲染同源)
@@ -722,6 +734,16 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
# 地面投影:北邻墙格在本已开格北缘投渐隐暗带(ITB 同款高度线索——带宽按格边比例常量)
if north_in and not _minesweeper.is_revealed(north_n):
u.proj_band = u.edge * WALL_PROJECTION_FRAC
# ②( 魔法道具叠加层(迭代 7 T4):真视格=红内缩框;预读格=奖励身份徽章(identity_resolver 既有
# 只读面取字形——零数据复制,badge 位复用);已开格标记自然退位(refresh 逐拍重算)
if not revealed:
u.aux_mark = "mine_reveal" if _aux_reveal.has(c) else ""
if _aux_preview.has(c) and glyph == "":
var pid = _identity_cb.call(c) if _identity_cb.is_valid() else null
if pid != null and REWARD_BADGE.has(String(pid.get("cell_type", ""))):
glyph = String(REWARD_BADGE[String(pid.get("cell_type", ""))])
digit_col = COL_GOLD
u.badge_glyph = glyph
# ②' 变异角标(迭代 6 T6):未开格带伤害型变异 → 危险红角标(已开=威胁已兑现标记退位);
# 回调缺位 = 无标记(程序化角标,tex_mutation 纹带槽留给变异纹带自产批)
if not revealed and _vmark_cb.is_valid():
@@ -14,7 +14,11 @@ const COL_INK := UiKit.INK
var _atk_label: Label
var _armor_label: Label
var item_slots: HBoxContainer # 魔法道具槽(预留——4 空槽占位;数量/交互形态待魔法道具批定稿)
signal aux_slot_clicked(handle: int) # 迭代 7 T4——槽点击(组合根消费:AP 类即用/空间类进选中态)
var item_slots: HBoxContainer # 魔法道具槽(迭代 7 T4 接线——库存条常读+两步交互第一步)
var _slot_panels: Array = [] # 槽 PanelContainer 引用(选中高亮/置灰重刷)
var _selected_handle := 0 # 选中态(0=无;组合根回写维持单源)
var _slot_handles: Array = [] # 槽位→handle 映射(set_aux_inventory 刷新)
var _bonus_section: VBoxContainer # 本关强化(预留——空态隐藏,接线归大奖励/锻造呈现批)
var _bonus_list: VBoxContainer
@@ -54,8 +58,13 @@ func _init() -> void:
slot.custom_minimum_size = Vector2(48, 48)
slot.add_theme_stylebox_override("panel",
UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER, 0, 1, Vector4(4, 4, 4, 4)))
slot.mouse_filter = Control.MOUSE_FILTER_IGNORE
var idx := i
slot.gui_input.connect(func(ev: InputEvent):
if ev is InputEventMouseButton and ev.pressed and ev.button_index == MOUSE_BUTTON_LEFT:
# 空槽/越界槽点击=取消选中(handle 0);有效槽发其 handle(组合根判 AP 即用/进选中态)
aux_slot_clicked.emit(_slot_handles[idx] if idx < _slot_handles.size() else 0))
item_slots.add_child(slot)
_slot_panels.append(slot)
# 本关强化(预留):锻造/大奖励/关卡奖励节点的属性提升——中循环数据因改变战斗数学准入;
# 与战斗内状态效果(B 区站桩,随战斗消散)分区,防「战斗结束被清」误读;空态整节隐藏
@@ -110,3 +119,40 @@ func _data_line() -> Label:
l.clip_text = true
l.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
return l
# ---- 魔法道具库存条(迭代 7 T4——C 区四槽常读+两步交互第一步)----
# 投影行 = {handle, glyph, name, used, usable}(组合根组装:字形=道具名首字;数据源 runner 级库存只读面)。
# 空槽=虚位;used=暗态「已用」保留占位(Used 不可逆——受理序展示语义);不可用=置灰(板级零信息);
# selected=金框高亮(两步交互第一步的可见态)。tooltip=全名+维度语义。
func set_aux_inventory(items: Array, selected_handle: int) -> void:
_selected_handle = selected_handle
_slot_handles.clear()
for i in 4:
var slot: PanelContainer = _slot_panels[i]
for c in slot.get_children():
c.queue_free()
if i >= items.size():
_slot_handles.append(0)
slot.tooltip_text = "魔法道具槽(空)"
slot.add_theme_stylebox_override("panel",
UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER, 0, 1, Vector4(4, 4, 4, 4)))
continue
var rec: Dictionary = items[i]
_slot_handles.append(int(rec.get("handle", 0)))
var used := bool(rec.get("used", false))
var usable := bool(rec.get("usable", true))
var selected := selected_handle != 0 and int(rec.get("handle", 0)) == selected_handle
var glyph := UiKit.label(String(rec.get("glyph", "?")), 20, true)
glyph.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
glyph.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
glyph.set_anchors_preset(Control.PRESET_FULL_RECT)
glyph.mouse_filter = Control.MOUSE_FILTER_IGNORE
if used:
glyph.add_theme_color_override("font_color", UiKit.STONE_FAINT)
elif not usable:
glyph.add_theme_color_override("font_color", UiKit.STONE)
slot.add_child(glyph)
var border_col: Color = UiKit.GOLD if selected else UiKit.PANEL_BORDER
slot.add_theme_stylebox_override("panel",
UiKit.panel_flat(UiKit.PANEL_DATA, border_col, 0, 1 if not selected else 2, Vector4(4, 4, 4, 4)))
slot.tooltip_text = "%s%s" % [String(rec.get("name", "")), "(已用)" if used else ("(不可用——当前无有效目标)" if not usable else "")]