merge: C 区精简批——信息归属拍板代码实装(2026-09-26)
This commit is contained in:
commit
764e216f5d
9 files changed
+203
-224
No files matched your search
@@ -15,30 +15,24 @@ extends RefCounted
|
||||
|
||||
|
||||
# 每次结算行/轮次/节点变化/动作返回后调用(组合根全量重查装配)
|
||||
# 2026-09-26 C 区精简批:钱包 GP/钥石投喂退役(中/大循环资源迁出战斗屏——信息归属拍板);
|
||||
# HP/状态效果单投喂 B 区站桩(原 B/C 双投喂为重复展示——信息归属拍板单一展示面原则)
|
||||
static func refresh(stage: BattleStageView, info: HeroInfoPanelView, ap_bar: ApBarView,
|
||||
settlement, runner, level_active: bool, db, refresh_remaining: int, gp_label: Label = null,
|
||||
keystone_label: Label = null, keystone_balance: int = 0) -> void:
|
||||
# GP 余额常驻(GP+商店房实施批 2026-09-21——A 区顶栏邻接位;runner 缺位 = 非冒险态按 0 读数)
|
||||
if gp_label != null:
|
||||
gp_label.text = "金币 %d" % (int(runner.gp) if runner != null else 0)
|
||||
# 钥石余额常驻(元进度实现批 2026-09-21——A 区顶栏邻接位;数据源 MetaProgression 账本,购买/收束后随全量重查刷新)
|
||||
if keystone_label != null:
|
||||
keystone_label.text = "钥石 %d" % keystone_balance
|
||||
settlement, runner, level_active: bool, db, refresh_remaining: int) -> void:
|
||||
if settlement == null:
|
||||
_refresh_out_of_battle(stage, info, runner, level_active, db)
|
||||
_refresh_out_of_battle(stage, info, ap_bar, runner, level_active, db)
|
||||
return
|
||||
var s: Dictionary = settlement.presentation_snapshot()
|
||||
var hero: Dictionary = s.hero
|
||||
if hero.is_empty() or not bool(hero.get("alive", false)):
|
||||
_refresh_out_of_battle(stage, info, runner, level_active, db)
|
||||
_refresh_out_of_battle(stage, info, ap_bar, runner, level_active, db)
|
||||
return
|
||||
_refresh_hero(stage, info, s)
|
||||
_refresh_economy(info, ap_bar, s, db, refresh_remaining)
|
||||
_refresh_economy(ap_bar, s, db, refresh_remaining)
|
||||
stage.set_enemies(s.enemies)
|
||||
info.set_status_effects(s.hero_effects)
|
||||
|
||||
|
||||
# ---- B 区主角站桩 + C 区数据框 ----
|
||||
# ---- B 区主角站桩(HP/状态唯一展示面)+ C 区数据框(攻击/AC) ----
|
||||
|
||||
static func _refresh_hero(stage: BattleStageView, info: HeroInfoPanelView, s: Dictionary) -> void:
|
||||
var hero: Dictionary = s.hero
|
||||
@@ -55,19 +49,19 @@ static func _refresh_hero(stage: BattleStageView, info: HeroInfoPanelView, s: Di
|
||||
var mod_text := ""
|
||||
if mod_total != 0:
|
||||
mod_text = "(%+d%% %s)" % [mod_total, "·".join(sources)]
|
||||
# B 区站桩只挂血条+状态小图标(2026-09-20 全站桩拍板)——攻击值等规划数据归 C 区数据框
|
||||
# B 区站桩 = HP 与状态效果唯一展示面(2026-09-26 信息归属拍板)——C 区不再重复投喂
|
||||
stage.hero_standee.set_hero(hp, max_hp)
|
||||
stage.hero_standee.set_effects(s.hero_effects)
|
||||
info.set_hero(hp, max_hp)
|
||||
info.set_attack(atk, mod_text)
|
||||
# 我方 AC 唯一展示面 = C 区(2026-09-26 二轮拍板补入)——快照 armor_class 含战斗内 ac_up 折算
|
||||
info.set_armor(int(hero.get("armor_class", 0)))
|
||||
|
||||
|
||||
# ---- 行动经济(AP 点阵 / RAP / 弃图刷新按钮态) ----
|
||||
# ---- 行动经济(AP 点阵 / RAP / 弃图刷新按钮态——RAP 读数 2026-09-26 自 C 区迁入本条) ----
|
||||
|
||||
static func _refresh_economy(info: HeroInfoPanelView, ap_bar: ApBarView, s: Dictionary, db, refresh_remaining: int) -> void:
|
||||
static func _refresh_economy(ap_bar: ApBarView, s: Dictionary, db, refresh_remaining: int) -> void:
|
||||
ap_bar.set_ap(int(s.ap), int(db.action_economy.ap_per_round))
|
||||
# RAP 活值投影(C 区点阵)——清零反馈分支(行动经济 D1 义务)依赖本处持续投喂才会可达
|
||||
info.set_rap(int(s.rap), int(db.action_economy.rap_refresh_cost))
|
||||
ap_bar.set_rap(int(s.rap))
|
||||
var digging := String(s.phase) == ActionEconomy.PHASE_ACTIVE
|
||||
ap_bar.set_refresh_state(refresh_remaining,
|
||||
bool(s.can_refresh) and digging) # Waiting 代理已随 OQ12 退役——UI 仅挖掘期受理
|
||||
@@ -76,16 +70,16 @@ static func _refresh_economy(info: HeroInfoPanelView, ap_bar: ApBarView, s: Dict
|
||||
|
||||
# 战斗外(节点间隙/关卡结束)——HP 读 runner 携带值
|
||||
static func _refresh_out_of_battle(stage: BattleStageView, info: HeroInfoPanelView,
|
||||
runner, level_active: bool, db) -> void:
|
||||
ap_bar: ApBarView, runner, level_active: bool, db) -> void:
|
||||
if not level_active:
|
||||
return
|
||||
if runner != null:
|
||||
info.set_hero(runner.hero_hp, runner.effective_max_hp())
|
||||
info.set_attack(runner.effective_atk(), "(关卡推进中)")
|
||||
info.set_armor(runner.effective_ac())
|
||||
stage.hero_standee.set_hero(runner.hero_hp, runner.effective_max_hp())
|
||||
stage.hero_standee.set_effects([])
|
||||
stage.clear_enemies() # 节点间隙清敌方站桩残位(死亡瞬间的灰化呈现已在结算行驱动完成)
|
||||
info.set_rap(0, int(db.action_economy.rap_refresh_cost)) # battle_over RAP 清零反馈(行动经济 义务)
|
||||
ap_bar.set_rap(0) # battle_over RAP 清零反馈(行动经济 义务——载体 2026-09-26 迁 AP 条)
|
||||
|
||||
|
||||
# 三源拒绝可感知(排雷玩法 reject_reason/sub_reason → 玩家文案;pattern 1 双源拒绝反馈)
|
||||
|
||||
@@ -52,13 +52,11 @@ var _debug = null
|
||||
# 由关卡画面本体选路覆盖层承载;E 区道具面板随可选类删除下线)
|
||||
var stage: BattleStageView # B 区(含 log_view 明细带)
|
||||
var log_view: BattleLogView
|
||||
var info_panel: HeroInfoPanelView # C 区(含钱包行——原 A 区顶栏 GP/钥石余额常驻位)
|
||||
var info_panel: HeroInfoPanelView # C 区(攻击/AC 数据框+两预留区——2026-09-26 信息归属拍板精简)
|
||||
var board_zone: BoardZoneView # D 区(含 ap_bar/board_view/toast/fx)
|
||||
var board_view: BoardView # 探针兼容别名(= board_zone.board_view)
|
||||
var ap_bar: ApBarView # 探针兼容别名(= board_zone.ap_bar)
|
||||
var settlement_fx: SettlementFxView # 结算演出覆盖层(跨区弹道/光带——A–D 之上、模态之下)
|
||||
var gp_label: Label # GP 余额常驻位(C 区钱包行——文案装配归 HudPresenter)
|
||||
var keystone_label: Label # 钥石余额常驻位(C 区钱包行——文案装配归 HudPresenter)
|
||||
# 模态 overlay(z 序 = 登记序;pattern 6 层级纪律)
|
||||
var legend_overlay: LegendOverlay
|
||||
var review_overlay: SettlementReviewOverlay
|
||||
@@ -102,8 +100,6 @@ func _build_ui() -> void:
|
||||
var root := VBoxContainer.new()
|
||||
add_child(root)
|
||||
var battle_ui: Dictionary = UiAssembler.build_battle_ui(root, db)
|
||||
gp_label = battle_ui.gp_label
|
||||
keystone_label = battle_ui.keystone_label
|
||||
stage = battle_ui.stage
|
||||
log_view = battle_ui.log_view
|
||||
info_panel = battle_ui.info_panel
|
||||
@@ -310,7 +306,7 @@ func _on_adventure_finished(summary: Dictionary) -> void:
|
||||
settlement = null
|
||||
_close_modal(route_overlay) # 终局兜底(放弃入口新场景:选路层在开态——走模态栈恢复其遮挡面;未开过时 close 容错)
|
||||
_sync_settlement_visuals() # → 全关
|
||||
info_panel.set_status_cleared_feedback() # 状态槽全清可见反馈(增益状态×4④)
|
||||
stage.hero_standee.set_effects_cleared_feedback() # 状态全清可见反馈(增益状态×4④——载体 2026-09-26 迁 B 区站桩)
|
||||
stage.gray_all_enemies() # 死亡兜底:站桩灰化残位(禁瞬消语义的战斗收尾面)
|
||||
# 存档入账(元进度实现批):settle = Boss 两档入账 + 工坊解锁 + 摘要入档 + 写盘(唯一写档点不变——
|
||||
# 调试两层不经过本处理器,天然不写档不污染生涯数据)。
|
||||
@@ -441,8 +437,8 @@ func _on_battle_finished(payload: Dictionary) -> void:
|
||||
var result: String = String(payload.get("result", ""))
|
||||
_sync_settlement_visuals() # → 全关(battle_over 反馈面)
|
||||
stage.gray_all_enemies() # 死亡兜底:站桩灰化残位(禁瞬消语义的战斗收尾面)
|
||||
info_panel.set_rap(0, int(db.action_economy.rap_refresh_cost)) # RAP 清零滚动 + 微文案
|
||||
info_panel.set_status_cleared_feedback() # 状态槽全清可见反馈(增益状态×4④)
|
||||
ap_bar.set_rap(0) # RAP 清零脉冲 + 微文案(载体 2026-09-26 迁 D 区 AP 条)
|
||||
stage.hero_standee.set_effects_cleared_feedback() # 状态全清可见反馈(增益状态×4④——载体迁 B 区站桩)
|
||||
var decision: Dictionary = _debug.on_battle_finished(payload)
|
||||
match String(decision.outcome):
|
||||
"next_layer":
|
||||
@@ -734,7 +730,7 @@ func _on_refresh_confirmed() -> void:
|
||||
logger.log_ux("ux_refresh_attempt", {"result": result, "round_refresh_index": _refresh_used_round + 1})
|
||||
if result == "rejected_rap":
|
||||
board_zone.toast.show_toast("RAP 不足 · 还差 %d 点(弃图刷新需 8)" % (cost - rap), "warn")
|
||||
info_panel.pulse_rap()
|
||||
ap_bar.pulse_rap()
|
||||
else:
|
||||
board_zone.toast.show_toast("本轮刷新次数已用完(每轮 2 次)", "warn")
|
||||
board_view.refresh()
|
||||
@@ -757,8 +753,7 @@ func _handle_outcome_feedback(outcome: Dictionary) -> void:
|
||||
func _refresh_presentations() -> void:
|
||||
# 每个核心信号/写调用返回后的全量重查装配(更新触发注记——无推送信号,命令式重查)
|
||||
var refresh_remaining: int = maxi(0, int(db.action_economy.refresh_cap_per_round) - _refresh_used_round)
|
||||
HudPresenter.refresh(stage, info_panel, ap_bar, settlement, runner, _level_active, db, refresh_remaining,
|
||||
gp_label, keystone_label, meta.keystone_balance() if meta != null else 0)
|
||||
HudPresenter.refresh(stage, info_panel, ap_bar, settlement, runner, _level_active, db, refresh_remaining)
|
||||
_sync_settlement_visuals()
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ extends RefCounted
|
||||
# 进度由关卡画面本体(选路覆盖层整图)承载,28px 纵向空间拨给 C/D 底行 520→548;E 区道具面板
|
||||
# 已随可选类删除下线,2026-09-15 格面资源批)。
|
||||
# + 结算演出覆盖层(A–D 之上、模态之下——跨区弹道/光带载体,结算演出链批 2026-09-20)。
|
||||
# 返回句柄字典:{gp_label, keystone_label, stage, log_view, info_panel, board_zone, board_view, ap_bar, settlement_fx}
|
||||
# 返回句柄字典:{stage, log_view, info_panel, board_zone, board_view, ap_bar, settlement_fx}
|
||||
# (gp_label/keystone_label 随 2026-09-26 信息归属拍板退役——GP/钥石迁出战斗屏,句柄不再透出)
|
||||
static func build_battle_ui(root: Control, db) -> Dictionary:
|
||||
# set_anchors_and_offsets_preset(非 set_anchors_preset):后者会把控件重置回最小内容尺寸
|
||||
# (实测 927×613——缩顶、棋盘 45px 格 ×10 行超出 D 区 333px 高被裁,2026-09-13 用户报告回归)
|
||||
@@ -39,11 +40,9 @@ static func build_battle_ui(root: Control, db) -> Dictionary:
|
||||
var settlement_fx := SettlementFxView.new()
|
||||
root.add_child(settlement_fx)
|
||||
|
||||
# GP/钥石余额常驻位(GP+商店房实施批 2026-09-21 原居 A 区顶栏——顶栏退役后迁 C 区底行,
|
||||
# 句柄经 info_panel 视图成员透出;文案装配归 HudPresenter,此处只透传引用)
|
||||
# GP/钥石余额位已随 2026-09-26 信息归属拍板退役(中/大循环资源迁出战斗屏——
|
||||
# GP 去向 = 关卡画面+战斗结算画面、钥石去向 = 结算画面+营地,呈现归对应 UX spec 批次)
|
||||
return {
|
||||
"gp_label": info_panel.gp_label,
|
||||
"keystone_label": info_panel.keystone_label,
|
||||
"stage": stage,
|
||||
"log_view": stage.log_view,
|
||||
"info_panel": info_panel,
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# 实现 GDD:design/ux/battle.md(D 区 AP 条 44px——点阵+数字〔pattern 5 点阵资源显示〕、
|
||||
# 停手按钮居左、图例+弃图刷新按钮居右〔雷图右上角〕;弃图刷新确认微交互与常规确认不同位
|
||||
# 〔pattern 7 破坏性确认异位:RAP 扣费 · 旧板旗作废显式代价〕)。
|
||||
# 2026-09-26 信息归属批:RAP 读数(点阵+数字)自 C 区迁入本条、置弃图刷新按钮左邻
|
||||
# (RAP 唯一消费口 = 弃图刷新——就近原则;RAP 清零反馈/资源拒绝脉冲载体随迁)。
|
||||
# Date: 2026-09-12
|
||||
# 高内聚边界:纯视图——意图经信号外发(stop_pressed/refresh_confirmed/legend_toggled),
|
||||
# 状态由组合根经 setter 注入;刷新可用性预判 = RAP≥8 读数(行动经济 无推送信号——每次调用返回后重查)。
|
||||
@@ -24,6 +26,10 @@ var _btn_refresh: Button
|
||||
var _refresh_sub: Label
|
||||
var _confirm_row: HBoxContainer
|
||||
var _confirm_lab: Label
|
||||
var _rap_dots: HBoxContainer
|
||||
var _rap_label: Label
|
||||
var _rap_feedback: Label
|
||||
var _last_rap := 0 # 上次投影值(清零反馈判据——禁解析自身 label 文本当状态)
|
||||
var refresh_cost: int = 0 # 表值驱动(装配经 set_refresh_cost 注入 ActionEconomyTable.rap_refresh_cost)
|
||||
var _confirm_armed := false
|
||||
var _arm_tween: Tween
|
||||
@@ -56,6 +62,20 @@ func _init() -> void:
|
||||
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_child(spacer)
|
||||
|
||||
# RAP 读数(2026-09-26 信息归属拍板自 C 区迁入):RAP 唯一消费口 = 弃图刷新——资源数字贴消费按钮
|
||||
# (就近原则);扣费文案「RAP−%d」已在刷新按钮副行,此处不重复代价提示(单一展示面原则)
|
||||
_rap_dots = HBoxContainer.new()
|
||||
_rap_dots.add_theme_constant_override("separation", 2)
|
||||
_rap_dots.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
row.add_child(_rap_dots)
|
||||
_rap_label = UiKit.label("RAP 0", 14, true)
|
||||
_rap_label.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
row.add_child(_rap_label)
|
||||
_rap_feedback = UiKit.label("", 11, false)
|
||||
_rap_feedback.add_theme_color_override("font_color", UiKit.STONE_FAINT)
|
||||
_rap_feedback.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
row.add_child(_rap_feedback)
|
||||
|
||||
# 破坏性确认异位(pattern 7):确认 chips 出现在刷新按钮左方——与常规"按钮自身确认"不同位
|
||||
_confirm_row = HBoxContainer.new()
|
||||
_confirm_row.add_theme_constant_override("separation", 4)
|
||||
@@ -117,6 +137,42 @@ func set_stop_enabled(on: bool) -> void:
|
||||
_btn_stop.disabled = not on
|
||||
|
||||
|
||||
# RAP 活值投影(点阵+数字——pattern 5 双承载);清零反馈分支(行动经济 D1 义务)依赖持续投喂可达
|
||||
func set_rap(rap: int) -> void:
|
||||
var prev := _last_rap
|
||||
_last_rap = rap
|
||||
_rap_label.text = "RAP %d" % rap
|
||||
_render_rap_dots(rap)
|
||||
if prev > 0 and rap == 0:
|
||||
# battle_over RAP 清零可见反馈(行动经济 D1 义务):数字脉冲 + 微文案(载体自 C 区迁入)
|
||||
_rap_feedback.text = "随战斗结束消散"
|
||||
var tw := create_tween()
|
||||
tw.tween_property(_rap_label, "modulate", Color(1.4, 1.2, 0.7), UiKit.motion(0.12))
|
||||
tw.tween_property(_rap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.3))
|
||||
elif rap > 0:
|
||||
_rap_feedback.text = ""
|
||||
|
||||
|
||||
# 资源面拒绝反馈(pattern 1 resource_face 腿):RAP 数字脉冲(RAP<8 弃图刷新被拒)
|
||||
func pulse_rap() -> void:
|
||||
var tw := create_tween()
|
||||
tw.tween_property(_rap_label, "modulate", Color(1.0, 0.4, 0.3), UiKit.motion(0.1))
|
||||
tw.tween_property(_rap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.25))
|
||||
|
||||
|
||||
func _render_rap_dots(rap: int) -> void:
|
||||
var shown := mini(rap, 16)
|
||||
while _rap_dots.get_child_count() < shown:
|
||||
var d := ColorRect.new()
|
||||
d.custom_minimum_size = Vector2(8, 8)
|
||||
d.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
d.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_rap_dots.add_child(d)
|
||||
for i in _rap_dots.get_child_count():
|
||||
var d: ColorRect = _rap_dots.get_child(i)
|
||||
d.color = COL_GOLD if i < shown else COL_DOT_OFF
|
||||
|
||||
|
||||
func set_legend_enabled(on: bool) -> void:
|
||||
_btn_legend.disabled = not on
|
||||
|
||||
|
||||
@@ -1,29 +1,22 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(C 区角色信息 240×548〔底行 520→548——停点前移批 2026-09-23,
|
||||
# 原 A 区顶栏空间并入〕——HP/攻击(+修正)/RAP 直角细线数据框
|
||||
# 〔修正来源角标〕、状态效果槽 ×4、小人立绘占位;RAP 清零可见反馈〔行动经济 义务〕;
|
||||
# 状态槽空态 = 槽隐藏上移补位〔EC12〕)。
|
||||
# Date: 2026-09-12
|
||||
# 高内聚边界:纯视图 setter 面——装配(含修正文案)归 hud_presenter.gd;定长槽 + clip_contents
|
||||
# 实现 GDD:design/ux/battle.md(C 区角色信息 240×548——2026-09-26 信息归属拍板精简:
|
||||
# 攻击(+修正来源角标)/护甲 AC 数据框 + 魔法道具槽(预留)+ 本关强化列表(预留)。
|
||||
# HP 条/立绘占位/状态效果槽/RAP 池/GP/钥石退役——HP 与状态唯一展示面 = B 区站桩(同一数据
|
||||
# hud_presenter 双投喂 B/C 两区的重复展示);RAP 迁 D 区 AP 条(贴弃图刷新消费口);
|
||||
# GP(中循环)/钥石(大循环)迁出战斗屏)。
|
||||
# Date: 2026-09-12(2026-09-26 C 区精简批重写)
|
||||
# 高内聚边界:纯视图 setter 面——装配(含修正文案/AC 投喂)归 hud_presenter.gd;定长槽 + clip_contents
|
||||
# (缺陷①回归约束)。
|
||||
class_name HeroInfoPanelView
|
||||
extends PanelContainer
|
||||
|
||||
const COL_INK := UiKit.INK
|
||||
const COL_GOLD := UiKit.GOLD
|
||||
const COL_DOT_OFF := UiKit.DOT_OFF
|
||||
|
||||
var _hp_bar: ProgressBar
|
||||
var _hp_label: Label
|
||||
var _atk_label: Label
|
||||
var _rap_dots: HBoxContainer
|
||||
var _rap_label: Label
|
||||
var _rap_feedback: Label
|
||||
var _status_feedback: Label
|
||||
var slot_row: StatusSlotRow
|
||||
var gp_label: Label # 冒险钱包余额常驻位(停点前移批 2026-09-23——原 A 区顶栏迁入 C 区底行)
|
||||
var keystone_label: Label # 钥石余额常驻位(同上——文案装配归 HudPresenter)
|
||||
var _last_rap := 0 # 上次投影值(清零反馈判据——禁解析自身 label 文本当状态)
|
||||
var _armor_label: Label
|
||||
var item_slots: HBoxContainer # 魔法道具槽(预留——4 空槽占位;数量/交互形态待魔法道具批定稿)
|
||||
var _bonus_section: VBoxContainer # 本关强化(预留——空态隐藏,接线归大奖励/锻造呈现批)
|
||||
var _bonus_list: VBoxContainer
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
@@ -36,68 +29,35 @@ func _init() -> void:
|
||||
add_child(col)
|
||||
|
||||
col.add_child(UiKit.label("探险者", 16, true))
|
||||
_hp_bar = ProgressBar.new()
|
||||
_hp_bar.custom_minimum_size = Vector2(0, 12)
|
||||
_hp_bar.show_percentage = false
|
||||
col.add_child(_hp_bar)
|
||||
_hp_label = _data_line()
|
||||
col.add_child(_hp_label)
|
||||
_atk_label = _data_line()
|
||||
col.add_child(_atk_label)
|
||||
_armor_label = _data_line()
|
||||
col.add_child(_armor_label)
|
||||
|
||||
# RAP 框(pattern 5 点阵资源显示——点阵图形 + 数字精确值双承载)
|
||||
var rap_head := HBoxContainer.new()
|
||||
rap_head.add_theme_constant_override("separation", 6)
|
||||
col.add_child(rap_head)
|
||||
_rap_dots = HBoxContainer.new()
|
||||
_rap_dots.add_theme_constant_override("separation", 2)
|
||||
rap_head.add_child(_rap_dots)
|
||||
_rap_label = UiKit.label("RAP 0", 13, true)
|
||||
rap_head.add_child(_rap_label)
|
||||
_rap_feedback = UiKit.label("", 12, false)
|
||||
_rap_feedback.add_theme_color_override("font_color", UiKit.STONE_FAINT)
|
||||
col.add_child(_rap_feedback)
|
||||
# 魔法道具槽(预留):随身战斗用道具的唯一展示面——空槽占位承诺格子在此,
|
||||
# 不预设交互(挖掘期指向交互归 E 区既有裁决);终稿样式/槽位数归魔法道具批
|
||||
col.add_child(UiKit.label("魔法道具", 14, true))
|
||||
item_slots = HBoxContainer.new()
|
||||
item_slots.add_theme_constant_override("separation", 6)
|
||||
col.add_child(item_slots)
|
||||
for i in 4:
|
||||
var slot := PanelContainer.new()
|
||||
slot.custom_minimum_size = Vector2(40, 40)
|
||||
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
|
||||
item_slots.add_child(slot)
|
||||
|
||||
col.add_child(UiKit.label("状态效果", 14, true))
|
||||
slot_row = StatusSlotRow.new()
|
||||
col.add_child(slot_row)
|
||||
_status_feedback = UiKit.label("", 12, false)
|
||||
_status_feedback.add_theme_color_override("font_color", UiKit.STONE_FAINT)
|
||||
col.add_child(_status_feedback)
|
||||
|
||||
# 小人立绘占位(程序化色块——真实立绘归 战斗表现)
|
||||
var portrait := ColorRect.new()
|
||||
portrait.color = Color(UiKit.HERO_BLUE, 56.0 / 255.0) # 原 Color8(46, 110, 142, 56)
|
||||
portrait.custom_minimum_size = Vector2(0, 120)
|
||||
portrait.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
col.add_child(portrait)
|
||||
var portrait_glyph := UiKit.label("小人立绘占位", 13, false)
|
||||
portrait_glyph.add_theme_color_override("font_color", COL_INK)
|
||||
portrait_glyph.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
portrait_glyph.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
portrait_glyph.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
portrait_glyph.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
portrait.add_child(portrait_glyph)
|
||||
|
||||
# 钱包行(停点前移批 2026-09-23:A 区 28px 顶栏退役——GP/钥石余额常驻位迁本面板底行,
|
||||
# 建节点归视图、文案装配归 HudPresenter,句柄经 ui_assembler 透传组合根)
|
||||
var wallet_row := HBoxContainer.new()
|
||||
wallet_row.add_theme_constant_override("separation", 10)
|
||||
col.add_child(wallet_row)
|
||||
gp_label = UiKit.label("金币 0", 15, true)
|
||||
gp_label.add_theme_color_override("font_color", UiKit.GOLD_DEEP)
|
||||
wallet_row.add_child(gp_label)
|
||||
keystone_label = UiKit.label("钥石 0", 15, true)
|
||||
keystone_label.add_theme_color_override("font_color", UiKit.GOLD)
|
||||
keystone_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
keystone_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
wallet_row.add_child(keystone_label)
|
||||
|
||||
|
||||
func set_hero(hp: int, max_hp: int) -> void:
|
||||
_hp_bar.max_value = maxi(1, max_hp)
|
||||
_hp_bar.value = hp
|
||||
_hp_label.text = "HP %d / %d" % [hp, max_hp]
|
||||
# 本关强化(预留):锻造/大奖励/关卡奖励节点的属性提升——中循环数据因改变战斗数学准入;
|
||||
# 与战斗内状态效果(B 区站桩,随战斗消散)分区,防「战斗结束被清」误读;空态整节隐藏
|
||||
_bonus_section = VBoxContainer.new()
|
||||
_bonus_section.add_theme_constant_override("separation", 4)
|
||||
_bonus_section.visible = false
|
||||
col.add_child(_bonus_section)
|
||||
_bonus_section.add_child(UiKit.label("本关强化", 14, true))
|
||||
_bonus_list = VBoxContainer.new()
|
||||
_bonus_list.add_theme_constant_override("separation", 2)
|
||||
_bonus_section.add_child(_bonus_list)
|
||||
|
||||
|
||||
func set_attack(atk: int, mod_text: String) -> void:
|
||||
@@ -105,68 +65,35 @@ func set_attack(atk: int, mod_text: String) -> void:
|
||||
_atk_label.text = "攻击 %d %s" % [atk, mod_text]
|
||||
|
||||
|
||||
func set_rap(rap: int, cap_hint: int) -> void:
|
||||
var prev := _last_rap
|
||||
_last_rap = rap
|
||||
_rap_label.text = "RAP %d(攒 %d 刷图)" % [rap, cap_hint]
|
||||
_render_rap_dots(rap)
|
||||
if prev > 0 and rap == 0:
|
||||
# battle_over RAP 清零可见反馈(行动经济 D1 义务):数字滚动归零 + 微文案占位
|
||||
_rap_feedback.text = "随战斗结束消散"
|
||||
var tw := create_tween()
|
||||
tw.tween_property(_rap_label, "modulate", Color(1.4, 1.2, 0.7), UiKit.motion(0.12))
|
||||
tw.tween_property(_rap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.3))
|
||||
elif rap > 0:
|
||||
_rap_feedback.text = ""
|
||||
func set_armor(ac: int) -> void:
|
||||
# 护甲 AC(2026-09-26 二轮拍板补入)——我方 AC 唯一展示面;掷点判定轴受击侧可读性
|
||||
_armor_label.text = "护甲 AC %d" % ac
|
||||
|
||||
|
||||
func set_status_effects(effects: Array) -> void:
|
||||
slot_row.set_effects(effects)
|
||||
_status_feedback.text = ""
|
||||
|
||||
|
||||
# battle_over:状态槽全清可见反馈(逐槽化光 + 微文案——增益状态×4④)
|
||||
func set_status_cleared_feedback() -> void:
|
||||
slot_row.set_cleared_feedback()
|
||||
_status_feedback.text = "状态随战斗结束消散"
|
||||
# 本关强化列表(预留接线面):lines = 文案行数组(如「锻造 +2 攻击」)——空数组 = 整节隐藏
|
||||
func set_level_bonuses(lines: Array) -> void:
|
||||
for c in _bonus_list.get_children():
|
||||
_bonus_list.remove_child(c)
|
||||
c.queue_free()
|
||||
for line in lines:
|
||||
var l := UiKit.label(String(line), 13, false)
|
||||
l.add_theme_color_override("font_color", COL_INK)
|
||||
_bonus_list.add_child(l)
|
||||
_bonus_section.visible = not lines.is_empty()
|
||||
|
||||
|
||||
func set_idle() -> void:
|
||||
_hp_bar.value = 0
|
||||
_hp_label.text = "HP —"
|
||||
_atk_label.text = "攻击 —"
|
||||
_last_rap = 0
|
||||
_render_rap_dots(0)
|
||||
_rap_label.text = "RAP —"
|
||||
slot_row.set_effects([])
|
||||
_armor_label.text = "护甲 AC —"
|
||||
set_level_bonuses([])
|
||||
|
||||
|
||||
func hp_text() -> String:
|
||||
return _hp_label.text
|
||||
func attack_text() -> String:
|
||||
return _atk_label.text
|
||||
|
||||
|
||||
func rap_text() -> String:
|
||||
return _rap_label.text
|
||||
|
||||
|
||||
# 资源面拒绝反馈(pattern 1 resource_face 腿):RAP 数字脉冲
|
||||
func pulse_rap() -> void:
|
||||
var tw := create_tween()
|
||||
tw.tween_property(_rap_label, "modulate", Color(1.0, 0.4, 0.3), UiKit.motion(0.1))
|
||||
tw.tween_property(_rap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.25))
|
||||
|
||||
|
||||
func _render_rap_dots(rap: int) -> void:
|
||||
var shown := mini(rap, 16)
|
||||
while _rap_dots.get_child_count() < shown:
|
||||
var d := ColorRect.new()
|
||||
d.custom_minimum_size = Vector2(8, 8)
|
||||
d.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
d.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_rap_dots.add_child(d)
|
||||
for i in _rap_dots.get_child_count():
|
||||
var d: ColorRect = _rap_dots.get_child(i)
|
||||
d.color = COL_GOLD if i < shown else COL_DOT_OFF
|
||||
func armor_text() -> String:
|
||||
return _armor_label.text
|
||||
|
||||
|
||||
func _data_line() -> Label:
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# 实现 GDD:design/ux/battle.md(B 区全站桩形态——2026-09-20 用户看对照样张拍板,台账 99:
|
||||
# 主角与敌人均为无框立绘+底座,英雄卡/敌人卡卡片式整体退役禁再提)。
|
||||
# 形态契约:无框立绘(程序占位字形;set_portrait_texture = 资产挂点,战斗表现样张批落位零代码换装)
|
||||
# + 底座;血条悬浮头顶;状态小图标一排挂血条正下方(2026-09-24 状态图标接入批:定稿 PNG 纹理
|
||||
# 取代程序化占位字形,极性染色退役——绿↑红↓极性语言内化于图标本体;层数 ×N 角标保留;
|
||||
# 词汇单点复用 StatusSlotRow.EFFECT_ICON,未知键同款 fail-fast + ? 占位)。
|
||||
# + 底座;血条悬浮头顶;状态效果唯一展示面挂血条正下方(2026-09-26 C 区精简批:compact 档
|
||||
# StatusSlotRow 组件整体迁入——定稿 PNG 图标+层数 ×N 角标+悬停 tooltip〔来源+语义+剩余〕,
|
||||
# tooltip 义务自 C 区状态槽并入;空态 = 图标行隐藏)。
|
||||
# 敌方专属:顺位徽标悬浮头顶;意图三档动作动画占位(表现层升级批拍板:不显示技能名——普攻零表示 /
|
||||
# 攻击系 ⚔ / 增益系 ✦ / 妨害系 ☠ / 蓄力 = ⚔ 金档;开轮摇定播一次性短动画后静帧保持,
|
||||
# 挖掘期不循环——art-bible §2.1 能量纪律,终稿动画密度归战斗表现批);底座下 护甲类型图标+名字
|
||||
@@ -28,7 +28,9 @@ var _platform: Panel
|
||||
var _hp_bar: ProgressBar
|
||||
var _order_badge: Label = null
|
||||
var _intent_badge: Label = null
|
||||
var _status_row: HBoxContainer
|
||||
var _top_row: VBoxContainer
|
||||
var slot_row: StatusSlotRow # 状态效果唯一展示面(2026-09-26 C 区精简批——compact 档组件整体迁入;
|
||||
# 悬停 tooltip 来源+语义+剩余 义务随之从 C 区状态槽并入,主角/敌方共用)
|
||||
var _name_line: HBoxContainer = null
|
||||
var _armor_icon: Label = null
|
||||
var _name_label: Label = null
|
||||
@@ -46,6 +48,7 @@ func _init(kind: String = "enemy") -> void:
|
||||
|
||||
# 头顶悬浮层:血条(敌附顺位徽标)+ 状态小图标行
|
||||
var top := VBoxContainer.new()
|
||||
_top_row = top
|
||||
top.set_anchors_preset(Control.PRESET_TOP_WIDE)
|
||||
top.offset_left = 8.0
|
||||
top.offset_right = -8.0
|
||||
@@ -64,10 +67,12 @@ func _init(kind: String = "enemy") -> void:
|
||||
_hp_bar.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_hp_bar.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
hp_row.add_child(_hp_bar)
|
||||
_status_row = HBoxContainer.new()
|
||||
_status_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
_status_row.add_theme_constant_override("separation", 4)
|
||||
top.add_child(_status_row)
|
||||
slot_row = StatusSlotRow.new()
|
||||
slot_row.compact = true # 站桩迷你档——图标 16px+层数角标,tooltip 全明细
|
||||
slot_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
slot_row.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
slot_row.mouse_filter = Control.MOUSE_FILTER_IGNORE # 行容器放行鼠标事件给槽位(悬停 tooltip)
|
||||
top.add_child(slot_row)
|
||||
|
||||
# 立绘(程序占位字形)
|
||||
_portrait = UiKit.label("人" if kind == "hero" else "敌", 42, true)
|
||||
@@ -164,32 +169,28 @@ func set_idle() -> void:
|
||||
set_effects([])
|
||||
|
||||
|
||||
# 主角/敌方共用——状态小图标行重建(B 区迷你版:定稿纹理 16px + 层数 ×N 角标;
|
||||
# 完整 tooltip 义务归 C 区状态槽。2026-09-24 状态图标接入批:占位字形+极性染色退役)
|
||||
# 主角/敌方共用——状态效果唯一展示面(2026-09-26 C 区精简批:compact 档 StatusSlotRow 整体迁入,
|
||||
# 原 B 区迷你字形行退役;悬停 tooltip(来源+语义+剩余结算次数)义务自 C 区状态槽并入本组件;
|
||||
# 空态 = 图标行隐藏不占位(增益状态 EC12))
|
||||
func set_effects(effects: Array) -> void:
|
||||
for c in _status_row.get_children():
|
||||
_status_row.remove_child(c)
|
||||
c.queue_free()
|
||||
for eff in effects:
|
||||
var tex := _icon_tex(String(eff.get("effect_id", "")))
|
||||
var layers := maxi(1, int(eff.get("layers", 1)))
|
||||
if tex != null:
|
||||
var icon := TextureRect.new()
|
||||
icon.texture = tex
|
||||
icon.custom_minimum_size = Vector2(16, 16) # 32px 源 ÷2 整数档缩放
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
|
||||
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_status_row.add_child(icon)
|
||||
else:
|
||||
var ph := UiKit.label(StatusSlotRow.ICON_PLACEHOLDER, 12, true) # release 回退占位(debug 已断言)
|
||||
ph.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_status_row.add_child(ph)
|
||||
if layers > 1:
|
||||
var lab := UiKit.label("×%d" % layers, 12, true)
|
||||
lab.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_status_row.add_child(lab)
|
||||
slot_row.set_effects(effects)
|
||||
slot_row.visible = not effects.is_empty()
|
||||
|
||||
|
||||
# battle_over:状态图标行全清可见反馈(增益状态×4④ 载体迁移——逐槽化光 + 微文案,
|
||||
# 自 C 区状态槽迁入;主角侧调用,敌方不适用)
|
||||
func set_effects_cleared_feedback() -> void:
|
||||
slot_row.visible = true
|
||||
slot_row.set_cleared_feedback()
|
||||
var note := UiKit.label("状态随战斗结束消散", 11, false)
|
||||
note.add_theme_color_override("font_color", UiKit.STONE_FAINT)
|
||||
note.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
note.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_top_row.add_child(note)
|
||||
var tw := create_tween()
|
||||
tw.tween_interval(1.2)
|
||||
tw.tween_property(note, "modulate:a", 0.0, UiKit.motion(0.8))
|
||||
tw.tween_callback(note.queue_free)
|
||||
|
||||
|
||||
func set_order(i: int) -> void:
|
||||
@@ -321,13 +322,3 @@ func _refresh_portrait_glyph() -> void:
|
||||
_portrait.text = "█" # 最大体量
|
||||
_:
|
||||
_portrait.text = "敌"
|
||||
|
||||
|
||||
# 状态图标键解析(词汇单点复用 C 区 StatusSlotRow——HUD框架:查不到的键按错误处理,
|
||||
# 立即断言 + ? 占位 + 诊断,禁止静默显示空图标)
|
||||
func _icon_tex(effect_id: String) -> Texture2D:
|
||||
if StatusSlotRow.EFFECT_ICON.has(effect_id):
|
||||
return StatusSlotRow.EFFECT_ICON[effect_id]
|
||||
push_error("[站桩] 未知状态图标键(映射表外键——立即断言): %s" % effect_id)
|
||||
assert(false, "未知状态图标键: " + effect_id)
|
||||
return null
|
||||
@@ -53,6 +53,7 @@ var _tip: PanelContainer
|
||||
var _tip_label: Label
|
||||
var _slots: Array[PanelContainer] = [] # 槽引用数组持有——tooltip _tip 悬停后入子节点表,按位序 get_child 会误取(BUG-0001)
|
||||
var _cleared_feedback := false
|
||||
var compact := false # B 区站桩迷你档(2026-09-26 C 区精简批):16px 图标+层数角标、无 meta 行——tooltip 义务随组件迁入站桩
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
@@ -103,17 +104,22 @@ func _sync_slots(n: int) -> void:
|
||||
|
||||
func _make_slot() -> PanelContainer:
|
||||
var slot := PanelContainer.new()
|
||||
slot.custom_minimum_size = Vector2(50, 46)
|
||||
var sb := UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER)
|
||||
slot.add_theme_stylebox_override("panel", sb)
|
||||
if compact:
|
||||
slot.add_theme_stylebox_override("panel",
|
||||
UiKit.panel_flat(Color(0, 0, 0, 0.18), UiKit.PANEL_BORDER, 2, 1, Vector4(2, 1, 2, 1)))
|
||||
else:
|
||||
slot.custom_minimum_size = Vector2(50, 46)
|
||||
slot.add_theme_stylebox_override("panel", UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER))
|
||||
slot.mouse_entered.connect(_on_slot_hover.bind(slot))
|
||||
slot.mouse_exited.connect(func(): _tip.visible = false)
|
||||
var col := VBoxContainer.new()
|
||||
col.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
if compact:
|
||||
col.add_theme_constant_override("separation", 0)
|
||||
slot.add_child(col)
|
||||
# 定稿纹理图标(32px 源 → 24px 槽内呈现;线性过滤匹配抗锯齿矢量风源图)
|
||||
var icon := TextureRect.new()
|
||||
icon.custom_minimum_size = Vector2(24, 24)
|
||||
icon.custom_minimum_size = Vector2(24, 24) if not compact else Vector2(16, 16)
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
|
||||
@@ -130,16 +136,25 @@ func _fill_slot(slot: PanelContainer, eff: Dictionary) -> void:
|
||||
slot.set_meta("eff", eff)
|
||||
var col := slot.get_child(0) as VBoxContainer
|
||||
var icon := col.get_child(0) as TextureRect
|
||||
var tex := _icon_tex(String(eff.effect_id))
|
||||
icon.visible = tex != null
|
||||
icon.texture = tex
|
||||
var layers := int(eff.get("layers", 1))
|
||||
if compact:
|
||||
# 迷你档:层数角标挂图标下方(×N)——槽随内容自适应,无 meta 行/剩余点(悬停 tooltip 承载全部明细)
|
||||
var tag := col.get_child(1) as Label
|
||||
tag.text = "×%d" % layers if layers > 1 else ""
|
||||
tag.add_theme_font_size_override("font_size", 10)
|
||||
if tex == null:
|
||||
tag.text = (ICON_PLACEHOLDER + tag.text).strip_edges()
|
||||
return
|
||||
var meta := col.get_child(1) as Label
|
||||
# 层数角标 + 剩余结算次数点(● 未耗余量)——叠层数字呈现逻辑保持不动
|
||||
var dots := ""
|
||||
var left: int = int(eff.get("remaining_settlements", 0))
|
||||
for i in maxi(left, 1):
|
||||
dots += "●" if i < left else "○"
|
||||
meta.text = "×%d %s" % [int(eff.get("layers", 1)), dots]
|
||||
var tex := _icon_tex(String(eff.effect_id))
|
||||
icon.visible = tex != null
|
||||
icon.texture = tex
|
||||
meta.text = "×%d %s" % [layers, dots]
|
||||
if tex == null:
|
||||
meta.text = ICON_PLACEHOLDER + " " + meta.text # release 回退占位(debug 已断言)
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ func _run_modal_probes_once() -> void:
|
||||
_problems.append("明细回看关闭后未恢复")
|
||||
# ③ tooltip(状态效果槽悬停——来源+语义+剩余):有槽可见时触发
|
||||
if not _tested_tooltip:
|
||||
var row = main.info_panel.slot_row
|
||||
var row = main.stage.hero_standee.slot_row # 状态 tooltip 载体 2026-09-26 迁 B 区站桩
|
||||
for child in row.get_children():
|
||||
if child is PanelContainer and child.visible and child.has_meta("eff"):
|
||||
_tested_tooltip = true
|
||||
|
||||
@@ -85,8 +85,8 @@ func _ready() -> void:
|
||||
problems.append("棋盘格未生成(cells=0)")
|
||||
if main.board_view.board() == null:
|
||||
problems.append("board 未装载")
|
||||
if main.info_panel.hp_text().begins_with("HP —") or main.info_panel.hp_text().contains("—"):
|
||||
problems.append("C 区血量未显示(%s)" % main.info_panel.hp_text())
|
||||
if main.info_panel.attack_text().contains("—") or main.info_panel.armor_text().contains("—"):
|
||||
problems.append("C 区攻击/护甲未显示(%s | %s)" % [main.info_panel.attack_text(), main.info_panel.armor_text()])
|
||||
if main.settlement == null or main.settlement.battle_result != "":
|
||||
problems.append("首战未处于进行中")
|
||||
if not main.log_view.parsed_text().contains("节点 1/"):
|
||||
@@ -102,8 +102,10 @@ func _ready() -> void:
|
||||
problems.append("D 区弃图刷新按钮文案缺失")
|
||||
if main.board_zone.toast == null:
|
||||
problems.append("D 区 toast 槽缺失")
|
||||
if main.info_panel.slot_row == null:
|
||||
problems.append("C 区状态效果槽缺失")
|
||||
if main.info_panel.item_slots == null or main.info_panel.item_slots.get_child_count() != 4:
|
||||
problems.append("C 区魔法道具槽(预留)缺失")
|
||||
if main.stage.hero_standee.slot_row == null:
|
||||
problems.append("B 区站桩状态行缺失(状态效果唯一展示面——2026-09-26 C 区精简批)")
|
||||
if main.log_view.mode() != "dig" or main.log_view.custom_minimum_size.y != 24.0:
|
||||
problems.append("B 区明细带挖掘期应收起 24px(mode=%s h=%s)" % [main.log_view.mode(), str(main.log_view.custom_minimum_size.y)])
|
||||
# E 区道具面板已随可选类删除下线(格面资源批 2026-09-15)——四区构建由其余断言覆盖
|
||||
@@ -124,7 +126,7 @@ func _ready() -> void:
|
||||
if main.stage.hero_standee == null or main.stage.hero_standee._hp_bar == null:
|
||||
problems.append("B 区主角站桩缺失")
|
||||
# ---- BUG-0001 回归(tooltip 入树后 set_effects 槽位不错位——结算软锁修复沉淀)----
|
||||
var slots_row = main.info_panel.slot_row
|
||||
var slots_row = main.stage.hero_standee.slot_row # BUG-0001 回归随组件迁入站桩(tooltip/槽位错位同源)
|
||||
var probe_eff: Array = [{"effect_id": "attack_up", "display_name": "增伤", "layers": 1,
|
||||
"remaining_settlements": 1, "source_class": "safe_cell", "round_index": 1, "effective_value": 50}]
|
||||
slots_row.set_effects(probe_eff)
|
||||
@@ -195,7 +197,7 @@ func _ready() -> void:
|
||||
if problems.is_empty():
|
||||
print("[ui_probe] PASS — cells=%d board=%dx%d hp='%s' enemies=%d ap_dots=%d" % [
|
||||
main.board_view._cells.size(), main.board_view.board().width, main.board_view.board().height,
|
||||
main.info_panel.hp_text(),
|
||||
main.info_panel.attack_text(),
|
||||
main.stage.enemy_box.get_child_count(), main.ap_bar._dots.get_child_count()])
|
||||
get_tree().quit(0)
|
||||
else:
|
||||
|
||||
Reference in new issue
Block a user