diff --git a/game/presentation/battle_narrator.gd b/game/presentation/battle_narrator.gd index 13040dce..2bac84f1 100644 --- a/game/presentation/battle_narrator.gd +++ b/game/presentation/battle_narrator.gd @@ -6,24 +6,24 @@ extends RefCounted -# 节点进入横幅(棋盘日志——battle/boss 用;节点编号 = 行进器编号空间读面) +# 节点进入横幅(棋盘日志——battle/boss 用;节点编号 = 行进器编号空间读面;行色 = UiKit.HEX_* 语义档单点) static func node_banner(runner, node: Dictionary, t: String) -> String: - return "[color=#e0b860]── 节点 %d/%d · %s(编号 %d)──[/color]" % [ + return "[color=#%s]── 节点 %d/%d · %s(编号 %d)──[/color]" % [UiKit.HEX_LOG_GAIN, runner.node_index + 1, runner.nodes().size(), "Boss 房" if t == "boss" else "战斗", runner.node_id_of(node)] static func reward_line() -> String: - return "[color=#d0c090]关卡奖励点(节点内容待定——直通)[/color]" + return "[color=#%s]关卡奖励点(节点内容待定——直通)[/color]" % UiKit.HEX_ROUTE_NOTE static func rest_line(healed: int, hp: int, max_hp: int) -> String: - return "[color=#7cc47c]恢复点:回复 %d HP(→ %d/%d)[/color]" % [healed, hp, max_hp] + return "[color=#%s]恢复点:回复 %d HP(→ %d/%d)[/color]" % [UiKit.HEX_LOG_HEAL, healed, hp, max_hp] # 商店房行(GP+商店房实施批——到达即开店;购买/离开归玩家意图) static func shop_line(gp: int) -> String: - return "[color=#e0b860]商店房:金币 %d——购买即时生效,离开后选下一跳[/color]" % gp + return "[color=#%s]商店房:金币 %d——购买即时生效,离开后选下一跳[/color]" % [UiKit.HEX_LOG_GAIN, gp] # 选路口行(零自动推进停点——战斗胜利/兑付确认后出现) @@ -31,18 +31,18 @@ static func route_line(candidates: Array, runner) -> String: var names: Array[String] = [] for cand in candidates: names.append("节点 %d" % runner.node_id_of(cand)) - return "[color=#e0b860]── 岔路口:可选下一跳 %s ──[/color]" % " / ".join(names) + return "[color=#%s]── 岔路口:可选下一跳 %s ──[/color]" % [UiKit.HEX_LOG_GAIN, " / ".join(names)] # 关卡开场行(种子/加成口径注记——面板加成是否生效由调用方传入) static func level_open_line(level_display: String, seed_val: int, atk: int, max_hp: int, boosted: bool) -> String: - return "[color=#c8a860]%s · 种子 %d · 攻击 %d / 生命 %d%s[/color]" % [ + return "[color=#%s]%s · 种子 %d · 攻击 %d / 生命 %d%s[/color]" % [UiKit.HEX_SEED_NOTE, level_display, seed_val, atk, max_hp, "(含面板加成)" if boosted else ""] # 调试开场行 static func debug_open_line(seed_val: int, level: int, level_mode: bool) -> String: - return "[color=#c8a860]种子 %d · 遭遇 %d 层%s[/color]" % [ + return "[color=#%s]种子 %d · 遭遇 %d 层%s[/color]" % [UiKit.HEX_SEED_NOTE, seed_val, level, "(关卡模式 · HP 延续)" if level_mode else ""] diff --git a/game/presentation/hud_presenter.gd b/game/presentation/hud_presenter.gd index 6b926a05..6333a3eb 100644 --- a/game/presentation/hud_presenter.gd +++ b/game/presentation/hud_presenter.gd @@ -151,7 +151,7 @@ static func outcome_text(outcome: Dictionary) -> String: static func tune_sim_report(n: int, atk_pct: int, hp_pct: int, wins: int, dmg_all: Array, hp_left_win: Array, hp_boss: Array, rounds_all: Array, death_nodes: Dictionary, base_hp: int) -> String: var lines: Array[String] = [] lines.append("[b]模拟 N=%d(atk+%d%% / hp+%d%%)[/b]" % [n, atk_pct, hp_pct]) - lines.append("通关率 [color=#80d080]%.0f%%[/color](%d/%d)" % [100.0 * float(wins) / float(maxi(1, n)), wins, n]) + lines.append("通关率 [color=#%s]%.0f%%[/color](%d/%d)" % [UiKit.HEX_LOG_WIN, 100.0 * float(wins) / float(maxi(1, n)), wins, n]) lines.append("整关承伤:均 %.1f · p90 %.0f(基础 HP %d)" % [_mean(dmg_all), _p90(dmg_all), base_hp]) if not hp_left_win.is_empty(): lines.append("通关剩余 HP 均 %.1f · 进 Boss HP 均 %.1f" % [_mean(hp_left_win), _mean(hp_boss)]) diff --git a/game/presentation/main.gd b/game/presentation/main.gd index fc156228..87af7d65 100644 --- a/game/presentation/main.gd +++ b/game/presentation/main.gd @@ -268,8 +268,7 @@ func _build_ui() -> void: func _fatal_screen(msg: String) -> void: - var l := UiKit.label(msg, 20, true) - l.add_theme_color_override("font_color", UiKit.RED_ALERT) + var l := UiKit.label(msg, 20, true, UiKit.RED_ALERT) l.set_anchors_preset(Control.PRESET_CENTER) add_child(l) @@ -689,14 +688,11 @@ func _on_inter_next_pressed() -> void: # E4:加成生效值供给(debug_session 注入 Callable——每次从面板百分比现算,经 encounter 传参零表写; -# 原表写路径 _apply_hero_override/_scaled_override 已废除,双写叠加 6→18→54 整类隐患随之移除) +# 原表写路径 _apply_hero_override/_scaled_override 已废除,双写叠加 6→18→54 整类隐患随之移除; +# 合成式单点在 UiKit.scaled——与 TunePanel 生效值预览共用,本类不再持有同式私有实现) func _debug_hero_override() -> Dictionary: - return {"atk": _scaled(int(db.hero.atk), tune_panel.atk_pct()), - "max_hp": _scaled(int(db.hero.max_hp), tune_panel.hp_pct())} - - -func _scaled(base: int, pct: int) -> int: - return maxi(1, int(round(float(base) * (100.0 + float(pct)) / 100.0))) + return {"atk": UiKit.scaled(int(db.hero.atk), tune_panel.atk_pct()), + "max_hp": UiKit.scaled(int(db.hero.max_hp), tune_panel.hp_pct())} # 奖励徽章身份解析(组合根守卫:仅挖掘期 Active 相位内查询——地图战斗资源 Ready 域外零读、零诊断噪音; diff --git a/game/presentation/ui_assembler.gd b/game/presentation/ui_assembler.gd index cc9a81e8..a790725f 100644 --- a/game/presentation/ui_assembler.gd +++ b/game/presentation/ui_assembler.gd @@ -114,18 +114,17 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary: bd.mouse_filter = Control.MOUSE_FILTER_IGNORE overlay.add_child(bd) var box := overlay_box(overlay) - var title := UiKit.label("Dungeon Sweeper", 34, true) - title.add_theme_color_override("font_color", UiKit.WARM) + var title := UiKit.label("Dungeon Sweeper", 34, true, UiKit.WARM) box.add_child(title) - var sub := UiKit.label("战斗屏战斗屏改造批 —— 扫雷的因,逐行兑现的果", 16, false) - sub.add_theme_color_override("font_color", UiKit.WARM) # 对比度修复(v3.5 批 B3——WARM_SOFT 对深石底实测 3.54:1→暖白 ≥6:1) + # 对比度修复(v3.5 批 B3——WARM_SOFT 对深石底实测 3.54:1→暖白 ≥6:1) + var sub := UiKit.label("战斗屏战斗屏改造批 —— 扫雷的因,逐行兑现的果", 16, false, UiKit.WARM) box.add_child(sub) box.add_child(HSeparator.new()) var seed_row := HBoxContainer.new() box.add_child(seed_row) - var seed_label := UiKit.label("随机种子:", 16, false) # 字号下限(v3.5 批 B3——正文 ≥16)+暗底显式暖白 - seed_label.add_theme_color_override("font_color", UiKit.WARM) + # 字号下限(v3.5 批 B3——正文 ≥16)+暗底显式暖白 + var seed_label := UiKit.label("随机种子:", 16, false, UiKit.WARM) seed_row.add_child(seed_label) var seed_edit := LineEdit.new() seed_edit.text = "42" @@ -153,9 +152,8 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary: # 玩法帮助文案(表值驱动——2026-09-16 AP 压速批遗留硬编码 8 随手修正;护甲等级掷点批同步"减伤"→"护甲强化") var help_text := "玩法:每轮 %d AP——挖开(1AP)/插旗(1AP)/移动(免费)/连锁(免费)。\n每个非封锁格都藏一种格面资源(增伤/护甲强化/回血/爆裂/削弱)。开安全格、标中雷 = 正向兑付;\n开雷格、标错安全格 = 负向兑付——全部在轮末结算逐行兑现;吃掷点的基础攻击按护甲等级判定,无 miss、最低保底 1 点。\n停手:剩余 AP 转存 RAP;弃图刷新:RAP−%d 当场换图继续挖(每轮剩 %d 次)。\n敌人全灭胜、主角倒下负。悬停可看三态光标与可挖域微光。" % [ int(db.action_economy.ap_per_round), int(db.action_economy.rap_refresh_cost), int(db.action_economy.refresh_cap_per_round)] - var help := UiKit.label(help_text, 16, false) # 字号下限(v3.5 批 B3——正文 ≥16) - # 对比度修复(v3.5 批 B3——WARM_FAINT 对深石底实测 2.58:1→暖白 ≥6:1;暗底双色墨制) - help.add_theme_color_override("font_color", UiKit.WARM) + # 字号下限(v3.5 批 B3——正文 ≥16);对比度修复(v3.5 批 B3——WARM_FAINT 对深石底实测 2.58:1→暖白 ≥6:1;暗底双色墨制) + var help := UiKit.label(help_text, 16, false, UiKit.WARM) box.add_child(help) return {"overlay": overlay, "box": box, "seed_edit": seed_edit, @@ -167,8 +165,7 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary: static func build_inter_overlay(host: Control) -> Dictionary: var overlay := overlay_bg(host, Color(0, 0, 0, 0.6)) var box := overlay_box(overlay) - var label := UiKit.label("", 24, true) - label.add_theme_color_override("font_color", UiKit.WARM) + var label := UiKit.label("", 24, true, UiKit.WARM) box.add_child(label) var next_btn := UiKit.button("进入下一层") box.add_child(next_btn) diff --git a/game/presentation/views/ap_bar_view.gd b/game/presentation/views/ap_bar_view.gd index f6ff1a42..c4afab2c 100644 --- a/game/presentation/views/ap_bar_view.gd +++ b/game/presentation/views/ap_bar_view.gd @@ -71,8 +71,7 @@ func _init() -> void: _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 = UiKit.label("", 11, false, UiKit.STONE_FAINT) _rap_feedback.size_flags_vertical = Control.SIZE_SHRINK_CENTER row.add_child(_rap_feedback) @@ -81,8 +80,7 @@ func _init() -> void: _confirm_row.add_theme_constant_override("separation", 4) _confirm_row.visible = false row.add_child(_confirm_row) - _confirm_lab = UiKit.label("RAP−%d · 旧板旗作废" % refresh_cost, 14, true) - _confirm_lab.add_theme_color_override("font_color", COL_INK) + _confirm_lab = UiKit.label("RAP−%d · 旧板旗作废" % refresh_cost, 14, true, COL_INK) _confirm_row.add_child(_confirm_lab) var confirm_btn := UiKit.button("确认弃图") confirm_btn.pressed.connect(_disarm_and_fire) @@ -153,21 +151,21 @@ func set_rap(rap: int) -> void: _rap_feedback.text = "" -# 资源面拒绝反馈(pattern 1 resource_face 腿):RAP 数字脉冲(RAP<8 弃图刷新被拒) -func pulse_rap() -> void: +# 资源读数拒绝脉冲单点(pattern 1 resource_face 腿——RAP/AP 两份逐字重复合并:朱红脉冲一拍回白) +func _pulse(label: Label) -> 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)) + tw.tween_property(label, "modulate", Color(1.0, 0.4, 0.3), UiKit.motion(0.1)) + tw.tween_property(label, "modulate", Color(1, 1, 1), UiKit.motion(0.25)) + + +func pulse_rap() -> void: + _pulse(_rap_label) 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) + _rap_dots.add_child(_make_dot(8.0, true)) # RAP 点阵 8px 窄档(随读数字号)——建点单点共用 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 @@ -226,14 +224,14 @@ func _disarm() -> void: # 资源面拒绝反馈(pattern 1 resource_face 腿):AP 数字脉冲 func pulse_ap() -> void: - var tw := create_tween() - tw.tween_property(_ap_label, "modulate", Color(1.0, 0.4, 0.3), UiKit.motion(0.1)) - tw.tween_property(_ap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.25)) + _pulse(_ap_label) -func _make_dot() -> ColorRect: +# 点阵建点单点(AP 10px / RAP 8px 两套建点参数化合并;初始色=熄灭档——投影循环当拍覆写) +func _make_dot(px := 10.0, shrink_center := false) -> ColorRect: var d := ColorRect.new() - d.custom_minimum_size = Vector2(10, 10) + d.custom_minimum_size = Vector2(px, px) + d.size_flags_vertical = Control.SIZE_SHRINK_CENTER if shrink_center else Control.SIZE_FILL d.color = COL_DOT_OFF d.mouse_filter = Control.MOUSE_FILTER_IGNORE return d diff --git a/game/presentation/views/battle_end_overlay.gd b/game/presentation/views/battle_end_overlay.gd index d66f6e2e..d985efff 100644 --- a/game/presentation/views/battle_end_overlay.gd +++ b/game/presentation/views/battle_end_overlay.gd @@ -24,22 +24,13 @@ var _board_rect := Rect2() func _init() -> void: # 二轮修改批 B(2026-09-29 用户目检裁决):半透明浮层文字不可读 → 实底石板皮面板形态 - #(与营地/设置/图例同族)。半透明氛围 dim 保留(胜利暖纱/失败暮蓝),信息与按钮全部上板; - # 金蜡封 = 面板头部静态徽记(原全屏坠落演出退役——落点被面板遮挡)。 - _dim = ColorRect.new() - _dim.color = Color(COL_WARM, 0.0) - _dim.set_anchors_preset(Control.PRESET_FULL_RECT) - add_child(_dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - _dim.add_child(center) - var panel := PanelContainer.new() - panel.add_theme_stylebox_override("panel", UiKit.panel_skinned(Vector4(16, 14, 16, 14))) - center.add_child(panel) - var box := VBoxContainer.new() - box.custom_minimum_size = Vector2(520, 0) - box.add_theme_constant_override("separation", 12) - panel.add_child(box) + #(与营地/设置/图例同族)。半透明氛围 dim 保留(胜利暖纱/失败暮蓝——open_* 就地换色),信息与 + # 按钮全部上板;金蜡封 = 面板头部静态徽记(原全屏坠落演出退役——落点被面板遮挡)。 + # 骨架经 UiKit.modal_shell(T4 收口批);_dim 引用摘出供 open_* 换氛围色。 + var shell := UiKit.modal_shell(self, Color(COL_WARM, 0.0), Vector2(520, 0), 12, true, + UiKit.panel_skinned(Vector4(16, 14, 16, 14))) + _dim = shell.dim + var box: VBoxContainer = shell.box var header := HBoxContainer.new() header.add_theme_constant_override("separation", 12) header.alignment = BoxContainer.ALIGNMENT_CENTER @@ -51,13 +42,11 @@ func _init() -> void: _seal.custom_minimum_size = Vector2(34, 34) _seal.size_flags_vertical = Control.SIZE_SHRINK_CENTER header.add_child(_seal) - _verdict = UiKit.label("", 24, true) - _verdict.add_theme_color_override("font_color", UiKit.INK_TITLE) + _verdict = UiKit.label("", 24, true, UiKit.INK_TITLE) _verdict.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _verdict.size_flags_vertical = Control.SIZE_SHRINK_CENTER header.add_child(_verdict) - _gp_line = UiKit.label("", 16, true) - _gp_line.add_theme_color_override("font_color", UiKit.INK_LABEL) + _gp_line = UiKit.label("", 16, true, UiKit.INK_LABEL) _gp_line.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _gp_line.visible = false box.add_child(_gp_line) diff --git a/game/presentation/views/battle_log_view.gd b/game/presentation/views/battle_log_view.gd index 8fcbf463..009cb04e 100644 --- a/game/presentation/views/battle_log_view.gd +++ b/game/presentation/views/battle_log_view.gd @@ -40,15 +40,13 @@ func _init(db_ref) -> void: add_child(vb) var head := HBoxContainer.new() vb.add_child(head) - _summary = UiKit.label("", 16, false) # 对比度修复(v3.5 批 B3 2026-09-30——明细条灰字对深灰底实测 2.63:1):暗底双色墨制=暖白族 - _summary.add_theme_color_override("font_color", UiKit.WARM) + _summary = UiKit.label("", 16, false, UiKit.WARM) _summary.custom_minimum_size = Vector2(0, BAND_H_DIG - 4) _summary.clip_text = true _summary.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS head.add_child(_summary) - _hint = UiKit.label("结算明细 ▸ 点击展开回看", 14, false) - _hint.add_theme_color_override("font_color", UiKit.WARM) # 辅助提示(≥14 辅助档)随上暖白 + _hint = UiKit.label("结算明细 ▸ 点击展开回看", 14, false, UiKit.WARM) # 辅助提示(≥14 辅助档)随上暖白 _hint.size_flags_horizontal = Control.SIZE_SHRINK_END head.add_child(_hint) _log = RichTextLabel.new() @@ -162,7 +160,7 @@ func _gold_frame(text: String) -> String: func _format_row(row: Dictionary, agg_count := -1) -> String: var src := _source_label(String(row.get("source_class", ""))) var round_no: int = int(row.get("round_index", 0)) - var prefix := " [color=#9a8a72]R%d%s[/color] " % [round_no, ("·" + src) if src != "" else ""] + var prefix := " [color=#%s]R%d%s[/color] " % [UiKit.HEX_LOG_ROUND, round_no, ("·" + src) if src != "" else ""] var hl := String(row.get("highlight", "")) var v: int = int(row.get("value", 0)) var name_: String = String(row.get("display_name", "")) @@ -174,12 +172,12 @@ func _format_row(row: Dictionary, agg_count := -1) -> String: # GP 型效果行(GP+商店房实施批 2026-09-21):「金币袋 +3」兑付反馈——value = 本行 ±power, # escrow = 战斗内缓冲现值(入钱包在战斗末一次上抛——呈现语义与增益池分账) if String(row.get("effect_id", "")) in ["gp_gain", "gp_loss"]: - var gp_col := "#e0b860" if v > 0 else "#c47c7c" + var gp_col := UiKit.HEX_LOG_GAIN if v > 0 else UiKit.HEX_LOG_LOSS var gp_body := "%s %+d(战斗暂存 %+d)%s" % [name_, v, int(row.get("escrow", 0)), suffix] return prefix + (_gold_frame(gp_body) if hl != "" else "[color=%s]%s[/color]" % [gp_col, gp_body]) # 效果行 value = 单次贡献值,pool_value = 池合成值——禁相加呈现(战斗结算 呈现细则) var pool: int = int(row.get("pool_value", 0)) - var col := "#7cc47c" if v > 0 else "#c47c7c" + var col := UiKit.HEX_LOG_HEAL if v > 0 else UiKit.HEX_LOG_LOSS var body := "%s 单次%+d(池 %+d)%s" % [name_, v, pool, suffix] return prefix + (_gold_frame(body) if hl != "" else "[color=%s]%s[/color]" % [col, body]) "damage": @@ -197,29 +195,29 @@ func _format_row(row: Dictionary, agg_count := -1) -> String: var kill := " ⚔击杀!" if row.get("killed", false) else "" # 二轮修改批 C(2026-09-29 用户目检——「每次结算标出的伤害数字不明显」): # 伤害值放大加色独立于行文(朱红大一号——数字即信息主角,非同字号色温微差) - var body := "%s [color=#d9402a][size=17]-%d[/size][/color]%s%s%s%s" % [name_, v, roll_txt, tail, kill, suffix] - var body_col := "#e07050" if row.get("killed", false) else ("#9a8a72" if v == 0 else "#e0a050") + var body := "%s [color=#%s][size=17]-%d[/size][/color]%s%s%s%s" % [name_, UiKit.HEX_LOG_DMG_NUM, v, roll_txt, tail, kill, suffix] + var body_col := UiKit.HEX_LOG_DMG_KILL if row.get("killed", false) else (UiKit.HEX_LOG_ROUND if v == 0 else UiKit.HEX_LOG_DMG_BODY) if bool(row.get("crit", false)): return prefix + _gold_frame(body) # nat 最大面暴击 = 金框高亮行 return prefix + "[color=%s]%s[/color]" % [body_col, body] "heal": - return prefix + "[color=#7cc47c]%s +%d%s%s[/color]" % [name_, v, tail, suffix] + return prefix + "[color=#%s]%s +%d%s%s[/color]" % [UiKit.HEX_LOG_HEAL, name_, v, tail, suffix] "reward_ineffective": # 未生效类行:⚠ icon + 划线形状冗余(非色相独载)+ 聚合计数 var n := (" ×%d" % agg_count) if agg_count > 1 else "" - return prefix + "[s][color=#b08060]⚠ %s%s[/color][/s]%s" % [name_, n, suffix] + return prefix + "[s][color=#%s]⚠ %s%s[/color][/s]%s" % [UiKit.HEX_LOG_VOIDED, name_, n, suffix] "flag_miss": var body := "✗ %s%s" % [name_, "(本板完美排雷已破——归因此旗)" if hl == "perfect_broken" else ""] - return prefix + (_gold_frame(body) if hl == "perfect_broken" else "[color=#9a8a72]%s[/color]" % body) + return prefix + (_gold_frame(body) if hl == "perfect_broken" else "[color=#%s]%s[/color]" % [UiKit.HEX_LOG_ROUND, body]) "cast": # 施放行(敌人技能池批——蓄力行 charge 改型):增益技 0 伤害施放,具名技能 - return prefix + "[color=#b09a72]✦ %s%s[/color]" % [name_, suffix] + return prefix + "[color=#%s]✦ %s%s[/color]" % [UiKit.HEX_LOG_CAST, name_, suffix] "decay": - return prefix + "[color=#8a9ab0]状态衰减 ×%d[/color]" % v + return prefix + "[color=#%s]状态衰减 ×%d[/color]" % [UiKit.HEX_LOG_DECAY, v] "verdict": if int(row.value) == 1: - return "[color=#80d080][b]◆ %s[/b][/color]" % name_ - return "[color=#e0b860][b]◆ %s[/b][/color]" % name_ + return "[color=#%s][b]◆ %s[/b][/color]" % [UiKit.HEX_LOG_WIN, name_] + return "[color=#%s][b]◆ %s[/b][/color]" % [UiKit.HEX_LOG_GAIN, name_] "highlight": return prefix + _gold_frame("★ %s" % name_) return prefix + name_ + suffix diff --git a/game/presentation/views/battle_stage_view.gd b/game/presentation/views/battle_stage_view.gd index daf77336..abd2e62b 100644 --- a/game/presentation/views/battle_stage_view.gd +++ b/game/presentation/views/battle_stage_view.gd @@ -25,6 +25,7 @@ const _STANDEE_BODY := preload("res://presentation/views/standee_body.gd") const _CONTENT_MARGINS := Rect2(6, 4, 6, 4) # 原 PanelContainer stylebox 内容边距(子面几何零漂移) const _STANDEE_W := 150.0 # 站桩盒宽(旧 StandeeView custom_minimum_size) const _STANDEE_GAP := 8.0 # 敌站桩间距(旧 enemy_box HBox separation) +const STAGE_CENTER_HINT := "兑现演出区\n(结算期:光带 → 弹道 → 受击)" # 演出区占位文案(set_settle_focus 恢复态同源——字面量双写退役) var hero_standee: Node2D # StandeeBody——主角站桩本体(世界内;slot_row = 壳层伴随件引用) var round_label: Label @@ -42,17 +43,18 @@ var world: Node2D # StageWorld(preload 脚本实例——Node2D 世 func _init(db_ref) -> void: custom_minimum_size = Vector2(0, 252) # 面板底(圣经 v3.5 批 B4 2026-09-30——§6.1 舞台正面目标落码:B 区=地窟看台,世界底层暗背景 - # Color8(62,52,42)=方向稿 render_battle_screen 取值——替换原浅石板皮〔实测 L0.027 旧深底与 - # 上半米黄割裂的 opposite 端——v3.5 定暖暗中档〕;描边=PANEL_BORDER 同方向稿) + # =方向稿 render_battle_screen 取值(值单点收 UiKit.STAGE_BG——T4 裸色收口)——替换原浅石板皮 + # 〔实测 L0.027 旧深底与上半米黄割裂的 opposite 端——v3.5 定暖暗中档〕;描边=PANEL_BORDER 同方向稿) var bg := Panel.new() - var sb := UiKit.panel_flat(Color8(62, 52, 42), UiKit.PANEL_BORDER, 0, 1) + var sb := UiKit.panel_flat(UiKit.STAGE_BG, UiKit.PANEL_BORDER, 0, 1) bg.add_theme_stylebox_override("panel", sb) bg.set_anchors_preset(Control.PRESET_FULL_RECT) bg.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(bg) - # 顶光柱氛围层(§6.1 光源氛围——方向稿四柱:x 基准 110/900/1055/1210@1280,暖光 (255,236,200) - # 自顶向下 60 段渐宽窄渐隐〔顶 α26→0〕;绘制在暗底之上/世界站桩之下——层序=bg < 光柱 < 世界) + # 顶光柱氛围层(§6.1 光源氛围——方向稿四柱:x 基准 110/900/1055/1210@1280,暖光(值单点收 + # UiKit.BEAM_LIGHT——T4 裸色收口)自顶向下 60 段渐宽窄渐隐〔顶 α26→0〕;绘制在暗底之上/ + # 世界站桩之下——层序=bg < 光柱 < 世界) var beams := Control.new() beams.set_anchors_preset(Control.PRESET_FULL_RECT) beams.mouse_filter = Control.MOUSE_FILTER_IGNORE @@ -86,9 +88,8 @@ func _init(db_ref) -> void: vb.offset_bottom = -_CONTENT_MARGINS.size.y add_child(vb) - round_label = UiKit.label("第 — 轮 · —", 15, true) + round_label = UiKit.label("第 — 轮 · —", 15, true, UiKit.WARM) # 暗底双色墨制(v3.5 批 B4——原深墨对暗底不可读) round_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - round_label.add_theme_color_override("font_color", UiKit.WARM) # 暗底双色墨制(v3.5 批 B4——原深墨对暗底不可读) vb.add_child(round_label) _row = HBoxContainer.new() @@ -103,8 +104,7 @@ func _init(db_ref) -> void: var center_col := VBoxContainer.new() center_col.alignment = BoxContainer.ALIGNMENT_CENTER center.add_child(center_col) - stage_center = UiKit.label("兑现演出区\n(结算期:光带 → 弹道 → 受击)", 13, false) - stage_center.add_theme_color_override("font_color", UiKit.WARM_SOFT) # 暗底双色墨制(原 STONE_FAINT 对暗底不可读) + stage_center = UiKit.label(STAGE_CENTER_HINT, 13, false, UiKit.WARM_SOFT) # 暗底双色墨制(原 STONE_FAINT 对暗底不可读) stage_center.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER center_col.add_child(stage_center) _row.add_child(center) @@ -146,7 +146,7 @@ func _draw_light_beams(c: Control) -> void: var a := int(26.0 * (1.0 - float(i) / 60.0)) var half := 46.0 - float(i) / 3.0 c.draw_rect(Rect2(x0 - half, 0.0, half * 2.0, 40.0 + float(i) * 3.0), - Color8(255, 236, 200, a), true) + Color(UiKit.BEAM_LIGHT, float(a) / 255.0), true) func _make_slot_companion(parent: Control) -> StatusSlotRow: @@ -314,31 +314,27 @@ func on_step_row_fx(row: Dictionary) -> void: # 主角受击演出(迭代 6 T5 拆早退——旧「敌→主角零反馈」):弹道到达拍对齐, # 受击态+闪白+打击火花+击杀塌陷与敌方路径同密度(演出对等——计划书 §1.4) hero_standee.set_hero_state("hit") # 受击态(短驻自回 idle) - var hero_arrived := func(): - hero_standee.play_hit_impact() - hero_standee.flash_hit() - if bool(row.get("killed", false)): - hero_standee.mark_dead() - if get_tree() != null: - get_tree().create_timer(UiKit.motion(0.33)).timeout.connect(hero_arrived) - else: - hero_arrived.call() + _schedule_arrival_fx(hero_standee, bool(row.get("killed", false))) return hero_standee.set_hero_state("attack") # 我方攻击行——attack 态(短驻自回) var card: Node2D = _card_by_name(target) if card == null: return - # 弹道到达拍对齐(迭代 6 T4 终稿):闪白/打击火花/击杀塌陷延迟 ≈弹道飞行时长 - # (play_projectile 0.16+0.19)——呈现链序=弹道→闪白+火花→血条(投影刷新)→灰化塌陷。 - # 行突发同拍多定时器互不干扰(flash 重启语义/死亡幂等守卫);卡片提前释放=守卫跳过; - # 树外(防御)=即时执行不调度。 + _schedule_arrival_fx(card, bool(row.get("killed", false))) + + +# 弹道到达拍调度单点(主角受击/敌方受击两份「0.33s 定时器+到达 lambda」同构块合并——T4 杂并批): +# 闪白/打击火花/击杀塌陷延迟 ≈弹道飞行时长(play_projectile 0.16+0.19)——呈现链序=弹道→闪白+火花 +# →血条(投影刷新)→灰化塌陷。行突发同拍多定时器互不干扰(flash 重启语义/死亡幂等守卫); +# 本体提前释放=is_instance_valid 守卫跳过;树外(防御)=即时执行不调度。 +func _schedule_arrival_fx(body: Node2D, killed: bool) -> void: var arrived := func(): - if not is_instance_valid(card): + if not is_instance_valid(body): return - card.play_hit_impact() - card.flash_hit() - if bool(row.get("killed", false)): - card.mark_dead() + body.play_hit_impact() + body.flash_hit() + if killed: + body.mark_dead() if get_tree() != null: get_tree().create_timer(UiKit.motion(0.33)).timeout.connect(arrived) else: @@ -381,4 +377,4 @@ func settle_hero_idle() -> void: # 结算期 B 区第一注视点切换(能量 7/10 清算调性):结算中占位文案退位——兑现演出由 # SettlementFxView 弹道/光带本体接管(演出链批);挖掘期恢复教学占位文案 func set_settle_focus(on: bool) -> void: - stage_center.text = "" if on else "兑现演出区\n(结算期:光带 → 弹道 → 受击)" + stage_center.text = "" if on else STAGE_CENTER_HINT diff --git a/game/presentation/views/board_fx_view.gd b/game/presentation/views/board_fx_view.gd index c852c5b5..84df2360 100644 --- a/game/presentation/views/board_fx_view.gd +++ b/game/presentation/views/board_fx_view.gd @@ -17,8 +17,7 @@ var _banner: Label func _init() -> void: mouse_filter = Control.MOUSE_FILTER_IGNORE set_anchors_preset(Control.PRESET_FULL_RECT) - _banner = UiKit.label("", 26, true) - _banner.add_theme_color_override("font_color", COL_GOLD) + _banner = UiKit.label("", 26, true, COL_GOLD) _banner.set_anchors_preset(Control.PRESET_CENTER_TOP) _banner.grow_horizontal = Control.GROW_DIRECTION_BOTH _banner.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER diff --git a/game/presentation/views/board_view.gd b/game/presentation/views/board_view.gd index 18fc7b89..3ddaee05 100644 --- a/game/presentation/views/board_view.gd +++ b/game/presentation/views/board_view.gd @@ -858,24 +858,11 @@ func _reset_breath() -> void: func _load_board_tiles(board_type: String = "dungeon") -> void: if board_type == "": board_type = "dungeon" - var t := { - "wall_center": UiKit.load_tex(TILE_WALL_FMT % ["wall_center", board_type]), - "wall_center_crack": UiKit.load_tex(TILE_WALL_FMT % ["wall_center_crack", board_type]), - "wall_center_speckle": UiKit.load_tex(TILE_WALL_FMT % ["wall_center_speckle", board_type]), - "wall_n": UiKit.load_tex(TILE_WALL_FMT % ["wall_n", board_type]), - "wall_s": UiKit.load_tex(TILE_WALL_FMT % ["wall_s", board_type]), - "wall_w": UiKit.load_tex(TILE_WALL_FMT % ["wall_w", board_type]), - "wall_nw": UiKit.load_tex(TILE_WALL_FMT % ["wall_nw", board_type]), - "wall_sw": UiKit.load_tex(TILE_WALL_FMT % ["wall_sw", board_type]), - "wall_hrun": UiKit.load_tex(TILE_WALL_FMT % ["wall_hrun", board_type]), - "wall_vrun": UiKit.load_tex(TILE_WALL_FMT % ["wall_vrun", board_type]), - "wall_end_n": UiKit.load_tex(TILE_WALL_FMT % ["wall_end_n", board_type]), - "wall_end_s": UiKit.load_tex(TILE_WALL_FMT % ["wall_end_s", board_type]), - "wall_end_w": UiKit.load_tex(TILE_WALL_FMT % ["wall_end_w", board_type]), - "wall_lone": UiKit.load_tex(TILE_WALL_FMT % ["wall_lone", board_type]), - "wall_in_nw": UiKit.load_tex(TILE_WALL_FMT % ["wall_in_nw", board_type]), - "wall_in_sw": UiKit.load_tex(TILE_WALL_FMT % ["wall_in_sw", board_type]), - } + # 16 墙瓦片装载循环节(词表 TILE_WALL_NAMES 单点——T4 杂并:手写 16 条字典项重复退役; + # 词表本身被 terrain_tile_sets_test 直读,保留) + var t := {} + for wall_name in TILE_WALL_NAMES: + t[wall_name] = UiKit.load_tex(TILE_WALL_FMT % [wall_name, board_type]) var floors: Array[Texture2D] = [] for i in range(1, TILE_FLOOR_VARIANTS + 1): floors.append(UiKit.load_tex(TILE_FLOOR_FMT % [board_type, i])) diff --git a/game/presentation/views/board_world.gd b/game/presentation/views/board_world.gd index 85fda58a..71c9b922 100644 --- a/game/presentation/views/board_world.gd +++ b/game/presentation/views/board_world.gd @@ -76,7 +76,7 @@ var cols := 0: # 列数(正面悬崖竖缝数 = cols−1) set(v): cols = v queue_redraw() -var mat := Color8(201, 175, 131) # 材质锚色(掩尘 #C9AF83——侧面由此派生明暗;BoardView 传入) +var mat: Color = UiKit.BRICK # 材质锚色(掩尘 #C9AF83 与 UiKit.BRICK 同值——T4 裸色收口改引单点;侧面由此派生明暗,BoardView 传入可覆写) func _draw() -> void: diff --git a/game/presentation/views/bonus_pick_overlay.gd b/game/presentation/views/bonus_pick_overlay.gd index 4c4b47e3..e4742f6e 100644 --- a/game/presentation/views/bonus_pick_overlay.gd +++ b/game/presentation/views/bonus_pick_overlay.gd @@ -22,18 +22,8 @@ var _card_meta: Array = [] # open_pick 缓存 [{id, text}]— func _init() -> void: - var dim := ColorRect.new() - dim.color = Color(0, 0, 0, 0.6) - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - var box := VBoxContainer.new() - box.add_theme_constant_override("separation", 12) - center.add_child(box) - _label = UiKit.label("", 20, true) - _label.add_theme_color_override("font_color", UiKit.WARM) + var box: VBoxContainer = UiKit.modal_shell(self, Color(0, 0, 0, 0.6)).box + _label = UiKit.label("", 20, true, UiKit.WARM) _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER box.add_child(_label) _choice_box = HBoxContainer.new() @@ -49,7 +39,7 @@ func _init() -> void: _replace_box.alignment = BoxContainer.ALIGNMENT_CENTER box.add_child(_replace_box) _continue_btn = UiKit.button("继续") - _continue_btn.pressed.connect(func(): continue_pressed.emit()) + _continue_btn.pressed.connect(_emit_continue_pressed) _continue_btn.visible = false box.add_child(_continue_btn) visible = false @@ -68,7 +58,7 @@ func open_pick(header: String, cards: Array) -> void: var cid := String(ch.get("id", "")) var btn := UiKit.button(String(ch.get("text", ""))) btn.custom_minimum_size = Vector2(170, 88) - btn.pressed.connect(func(): _select_card(cid)) + btn.pressed.connect(_select_card.bind(cid)) # 具名方法 bind(仓内惯例——内联 lambda 退役) _choice_box.add_child(btn) _choice_box.visible = true _confirm_btn.visible = false @@ -129,10 +119,10 @@ func open_replace(items: Array, incoming_name: String, holding: int, slots: int) for it in items: var tag: int = int(it.get("index", it.get("handle", -1))) # 通关渠道=携带序号 / 节点渠道=库存句柄(核心分发面裁决) var btn := UiKit.button("丢弃「%s」换新" % String(it.get("display_name", it.get("item_id", "")))) - btn.pressed.connect(func(): replace_chosen.emit(tag)) + btn.pressed.connect(_emit_replace_chosen.bind(tag)) _replace_box.add_child(btn) var decline := UiKit.button("放弃新件(不获取)") - decline.pressed.connect(func(): replace_chosen.emit(-1)) + decline.pressed.connect(_emit_replace_chosen.bind(-1)) _replace_box.add_child(decline) _choice_box.visible = false _confirm_btn.visible = false @@ -148,3 +138,11 @@ func close_pick() -> void: _continue_btn.visible = false _confirm_btn.visible = false visible = false + + +func _emit_continue_pressed() -> void: + continue_pressed.emit() + + +func _emit_replace_chosen(tag: int) -> void: + replace_chosen.emit(tag) diff --git a/game/presentation/views/camp_overlay_view.gd b/game/presentation/views/camp_overlay_view.gd index 7f46d85a..b778be23 100644 --- a/game/presentation/views/camp_overlay_view.gd +++ b/game/presentation/views/camp_overlay_view.gd @@ -15,10 +15,10 @@ signal buy_requested(attr: String) signal closed const ATTR_LABELS := {"atk": "攻击", "max_hp": "生命上限", "armor_class": "护甲"} # 档位文案轴(数据契约 attr 词表,与 ShopOverlay 同款) -# 方向稿取色(4-camp.png——柜台头带深棕/行板暖米;双色墨=亮板配深墨) -const HEADER_BAND_COL := Color8(122, 82, 50) -const ROW_PLATE_COL := Color8(240, 230, 206) -const BADGE_PANEL_COL := Color8(40, 32, 24) +# 方向稿取色(4-camp.png——柜台头带深棕/行板暖米;双色墨=亮板配深墨)——值单点收 UiKit(T4 裸色收口批) +const HEADER_BAND_COL := UiKit.CAMP_HEADER_BAND +const ROW_PLATE_COL := UiKit.CAMP_ROW_PLATE +const BADGE_PANEL_COL := UiKit.CAMP_BADGE_PANEL var _balance_label: Label var _forge_holder: VBoxContainer @@ -29,10 +29,7 @@ var _recent_list: Label # 最近冒险(逐行拼接 label——只读 func _init() -> void: - var dim := ColorRect.new() - dim.color = Color(0, 0, 0, 0.45) # 方向稿=石纹底透出(浅 dim——石纹全屏底担当氛围) - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - add_child(dim) + var dim := UiKit.modal_dim(self, Color(0, 0, 0, 0.45)) # 方向稿=石纹底透出(浅 dim——石纹全屏底担当氛围) # 石纹底噪(样张 v2 冻结件——start overlay 同款;缺位不挂即回退平 dim) var bd_tex := UiKit.load_tex(UiKit.TEX_BACKDROP_STONE) if bd_tex != null: @@ -65,11 +62,9 @@ func _init() -> void: top.add_child(plaque) var plaque_col := VBoxContainer.new() plaque.add_child(plaque_col) - var title := UiKit.label("营地 · 永久强化", 22, true) - title.add_theme_color_override("font_color", UiKit.INK_TITLE) + var title := UiKit.label("营地 · 永久强化", 22, true, UiKit.INK_TITLE) plaque_col.add_child(title) - var sub := UiKit.label("跨局成长账本——钥石换永久属性", 13, false) - sub.add_theme_color_override("font_color", UiKit.STONE) + var sub := UiKit.label("跨局成长账本——钥石换永久属性", 13, false, UiKit.STONE) plaque_col.add_child(sub) var spacer := Control.new() spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL @@ -84,8 +79,7 @@ func _init() -> void: var keystone_icon := UiKit.icon_rect(UiKit.TEX_ICON_KEYSTONE, 18) # 缺位 null → 纯文本回退 if keystone_icon != null: bal_row.add_child(keystone_icon) - _balance_label = UiKit.label("钥石 0", 18, true) - _balance_label.add_theme_color_override("font_color", UiKit.GOLD) + _balance_label = UiKit.label("钥石 0", 18, true, UiKit.GOLD) bal_row.add_child(_balance_label) # ── 三柜台列(方向稿同构:头带深棕+米色板身)── @@ -102,8 +96,7 @@ func _init() -> void: mid.add_child(_counter_panel("道具工坊", UiKit.TEX_ICON_WORKSHOP, _workshop_holder, 356)) var atlas_holder := VBoxContainer.new() mid.add_child(_counter_panel("奖励格图鉴", UiKit.TEX_ICON_ATLAS, atlas_holder, 356)) - var lock_l := UiKit.label(" —— 柜台结构位预留:内容排 Alpha(地图战斗资源差异化批)", 13, false) - lock_l.add_theme_color_override("font_color", UiKit.STONE) + var lock_l := UiKit.label(" —— 柜台结构位预留:内容排 Alpha(地图战斗资源差异化批)", 13, false, UiKit.STONE) lock_l.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART lock_l.custom_minimum_size = Vector2(300, 0) atlas_holder.add_child(lock_l) @@ -117,12 +110,10 @@ func _init() -> void: var spacer2 := Control.new() spacer2.size_flags_horizontal = Control.SIZE_EXPAND_FILL bottom.add_child(spacer2) - var caption := UiKit.label("每购得一件永久强化,对应柜台亮起一格暖光 · 价格为钥石", 13, false) - caption.add_theme_color_override("font_color", UiKit.WARM_SOFT) + var caption := UiKit.label("每购得一件永久强化,对应柜台亮起一格暖光 · 价格为钥石", 13, false, UiKit.WARM_SOFT) bottom.add_child(caption) col.add_child(bottom) - _recent_list = UiKit.label("", 13, false) - _recent_list.add_theme_color_override("font_color", UiKit.WARM_SOFT) + _recent_list = UiKit.label("", 13, false, UiKit.WARM_SOFT) _recent_list.clip_text = true _recent_list.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS col.add_child(_recent_list) @@ -148,8 +139,7 @@ func _counter_panel(title_text: String, icon_path: String, holder: VBoxContainer var ic := UiKit.icon_rect(icon_path, 16) # 缺位 null → 纯文本回退 if ic != null: head.add_child(ic) - var l := UiKit.label(title_text, 16, true) - l.add_theme_color_override("font_color", UiKit.WARM) + var l := UiKit.label(title_text, 16, true, UiKit.WARM) head.add_child(l) vbox.add_child(holder) return panel @@ -223,16 +213,13 @@ func _build_forge_row(holder: VBoxContainer, row: Dictionary) -> Dictionary: line.add_theme_constant_override("separation", 12) card.add_child(line) var attr := String(row.get("attr", "")) - var name_l := UiKit.label("%s %+d/级" % [String(row.get("display_name", "")), int(row.get("flat", 0))], 14, true) - name_l.add_theme_color_override("font_color", UiKit.INK) + var name_l := UiKit.label("%s %+d/级" % [String(row.get("display_name", "")), int(row.get("flat", 0))], 14, true, UiKit.INK) name_l.custom_minimum_size = Vector2(132, 0) line.add_child(name_l) - var level_l := UiKit.label("", 14, false) - level_l.add_theme_color_override("font_color", UiKit.INK) + var level_l := UiKit.label("", 14, false, UiKit.INK) level_l.custom_minimum_size = Vector2(44, 0) line.add_child(level_l) - var price_l := UiKit.label("", 14, false) - price_l.add_theme_color_override("font_color", UiKit.STONE) + var price_l := UiKit.label("", 14, false, UiKit.STONE) price_l.custom_minimum_size = Vector2(64, 0) line.add_child(price_l) var btn := UiKit.button("锻造 +1 级") @@ -252,16 +239,14 @@ func _rebuild_workshop(data: Dictionary) -> void: var line := HBoxContainer.new() line.add_theme_constant_override("separation", 12) card.add_child(line) - var name_l := UiKit.label(String(row.get("display_name", "")), 14, true) - name_l.add_theme_color_override("font_color", UiKit.INK) + var name_l := UiKit.label(String(row.get("display_name", "")), 14, true, UiKit.INK) name_l.custom_minimum_size = Vector2(132, 0) line.add_child(name_l) - var progress_l := UiKit.label("", 13, false) - progress_l.add_theme_color_override("font_color", UiKit.STONE) + var progress_l := UiKit.label("", 13, false, UiKit.STONE) progress_l.custom_minimum_size = Vector2(110, 0) line.add_child(progress_l) - var status_l := UiKit.label("", 13, true) - status_l.add_theme_color_override("font_color", UiKit.STONE) + # 状态色随卡⑭ 亮板双色墨制(深墨族替代暖白族)——色随刷新态条件赋值,非机械两行式(T4 收口保留) + var status_l := UiKit.label("", 13, true, UiKit.STONE) line.add_child(status_l) _workshop_holder.add_child(card) _workshop_rows.append({"item_id": String(row.get("item_id", "")), "progress_l": progress_l, "status_l": status_l}) diff --git a/game/presentation/views/confirm_dialog.gd b/game/presentation/views/confirm_dialog.gd index 68e72138..41f8364e 100644 --- a/game/presentation/views/confirm_dialog.gd +++ b/game/presentation/views/confirm_dialog.gd @@ -15,22 +15,9 @@ var _cancel_btn: Button func _init() -> void: - var dim := ColorRect.new() - dim.color = Color(UiKit.DIM, 0.55) - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - var panel := PanelContainer.new() - panel.add_theme_stylebox_override("panel", UiKit.panel_skinned(Vector4(14, 12, 14, 12))) - center.add_child(panel) - var box := VBoxContainer.new() - box.custom_minimum_size = Vector2(460, 0) - box.add_theme_constant_override("separation", 12) - panel.add_child(box) - _text = UiKit.label("", 16, false) - _text.add_theme_color_override("font_color", UiKit.INK_TITLE) + var box: VBoxContainer = UiKit.modal_shell(self, Color(UiKit.DIM, 0.55), Vector2(460, 0), 12, + true, UiKit.panel_skinned(Vector4(14, 12, 14, 12))).box + _text = UiKit.label("", 16, false, UiKit.INK_TITLE) _text.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART _text.custom_minimum_size = Vector2(430, 0) box.add_child(_text) diff --git a/game/presentation/views/hero_info_panel_view.gd b/game/presentation/views/hero_info_panel_view.gd index 35e6bb99..0ae0f173 100644 --- a/game/presentation/views/hero_info_panel_view.gd +++ b/game/presentation/views/hero_info_panel_view.gd @@ -94,8 +94,7 @@ func set_level_bonuses(lines: Array) -> void: _bonus_list.remove_child(c) c.queue_free() for line in lines: - var l := UiKit.label(String(line), 16, false) # 字号下限(v3.5 批 B3——正文 ≥16) - l.add_theme_color_override("font_color", COL_INK) + var l := UiKit.label(String(line), 16, false, COL_INK) # 字号下限(v3.5 批 B3——正文 ≥16) _bonus_list.add_child(l) _bonus_section.visible = not lines.is_empty() @@ -115,10 +114,9 @@ func armor_text() -> String: func _data_line() -> Label: - var l := UiKit.label("", 16, false) # 对比度修复(v3.5 批 B3 2026-09-30——非粗体 label 默认浅灰对米色数据框仅 1.31:1, # 实测=ui-redesign 对比报告 §一):显式主墨(对 PANEL_DATA ≈10:1) - l.add_theme_color_override("font_color", UiKit.INK) + var l := UiKit.label("", 16, false, UiKit.INK) l.clip_text = true l.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS return l @@ -150,6 +148,7 @@ func set_aux_inventory(items: Array, selected_handle: int) -> void: glyph.vertical_alignment = VERTICAL_ALIGNMENT_CENTER glyph.set_anchors_preset(Control.PRESET_FULL_RECT) glyph.mouse_filter = Control.MOUSE_FILTER_IGNORE + # 墨色随 used/usable 条件赋值——非机械两行式,T4 收口保留原分支 if used: glyph.add_theme_color_override("font_color", UiKit.STONE_FAINT) elif not usable: diff --git a/game/presentation/views/legend_overlay.gd b/game/presentation/views/legend_overlay.gd index 16d6c57c..f0eb03b3 100644 --- a/game/presentation/views/legend_overlay.gd +++ b/game/presentation/views/legend_overlay.gd @@ -27,23 +27,12 @@ var _rap_cost := -1 # <0 = 不渲染 RAP 行(打磨包 2026-09-29——构 func _init(rap_cost: int = -1) -> void: _rap_cost = rap_cost - var dim := ColorRect.new() - dim.color = Color(UiKit.DIM, 0.55) - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.gui_input.connect(_on_dim_gui_input) - add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - _panel = PanelContainer.new() - _panel.add_theme_stylebox_override("panel", UiKit.panel_skinned(Vector4(12, 10, 12, 10))) # 石板皮(T2;缺位回退 flat) - center.add_child(_panel) - var box := VBoxContainer.new() - box.custom_minimum_size = Vector2(520, 0) - box.add_theme_constant_override("separation", 6) - _panel.add_child(box) - var title := UiKit.label("图例 · 格态", 20, true) - title.add_theme_color_override("font_color", UiKit.INK_TITLE) # 亮底墨字(§7.2 数据素面) + var shell := UiKit.modal_shell(self, Color(UiKit.DIM, 0.55), Vector2(520, 0), 6, true, + UiKit.panel_skinned(Vector4(12, 10, 12, 10))) # 石板皮(T2;缺位回退 flat) + _panel = shell.panel + (shell.dim as ColorRect).gui_input.connect(_on_dim_gui_input) + var box: VBoxContainer = shell.box + var title := UiKit.label("图例 · 格态", 20, true, UiKit.INK_TITLE) # 亮底墨字(§7.2 数据素面) box.add_child(title) box.add_child(HSeparator.new()) for e in ENTRIES: @@ -53,8 +42,7 @@ func _init(rap_cost: int = -1) -> void: chip.custom_minimum_size = Vector2(18, 18) chip.color = Color(e[0]) row.add_child(chip) - var lab := UiKit.label("%s —— %s" % [e[1], e[2]], 13, false) - lab.add_theme_color_override("font_color", UiKit.INK_LABEL) # 亮底墨字(§7.2 数据素面) + var lab := UiKit.label("%s —— %s" % [e[1], e[2]], 13, false, UiKit.INK_LABEL) # 亮底墨字(§7.2 数据素面) lab.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART lab.custom_minimum_size = Vector2(440, 0) row.add_child(lab) @@ -66,10 +54,9 @@ func _init(rap_cost: int = -1) -> void: rap_row.add_theme_constant_override("separation", 8) var rap_chip := ColorRect.new() rap_chip.custom_minimum_size = Vector2(18, 18) - rap_chip.color = Color("#F0A828") + rap_chip.color = UiKit.GOLD # 同 #F0A828——金徽章同源单点(T4 裸色收口) rap_row.add_child(rap_chip) - var rap_lab := UiKit.label("RAP 储备行动点 —— 停手时剩余 AP 转存;弃图刷新消耗 RAP−%d(旧板旗作废,AP 保留继续挖)" % _rap_cost, 13, false) - rap_lab.add_theme_color_override("font_color", UiKit.INK_LABEL) + var rap_lab := UiKit.label("RAP 储备行动点 —— 停手时剩余 AP 转存;弃图刷新消耗 RAP−%d(旧板旗作废,AP 保留继续挖)" % _rap_cost, 13, false, UiKit.INK_LABEL) rap_lab.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART rap_lab.custom_minimum_size = Vector2(440, 0) rap_row.add_child(rap_lab) diff --git a/game/presentation/views/level_map_screen.gd b/game/presentation/views/level_map_screen.gd index c11a005a..63330777 100644 --- a/game/presentation/views/level_map_screen.gd +++ b/game/presentation/views/level_map_screen.gd @@ -38,9 +38,13 @@ const TITLE_ENTRY := "出发——选择首个节点" # 入口停点 const TITLE_SINGLE := "继续前进" # 单链停点 const TITLE_FORK := "选择下一节点" # 岔路停点 const NODE_HALF := Vector2(26, 18) # 节点方块半宽高(52×36 占位画布参数——样张批终稿) +const LAYER_BASE_X := 70 # 首层节点原点 x(画布拟合与布局公式共用——T4 杂并:双写退役) +const LAYER_STEP_X := 122 # 层间横向步距(同上) +const SLOT_BASE_Y := 52 # 槽位原点 y(同上) +const SLOT_STEP_Y := 58 # 同层槽位纵向步距(同上) const HIT_PAD := 6.0 # 图上命中外扩(指宽容差) const CONFIRM_WINDOW_S := 3.0 # 放弃确认态窗口(秒——超时回落) -const COL_HP_BAR_BACK := Color8(40, 34, 28) # 迷你血条深底(样张 v1 冻结——对暗面板可辨) +const COL_HP_BAR_BACK := UiKit.HP_BAR_BACK # 迷你血条深底(样张 v1 冻结——对暗面板可辨;值单点收 UiKit) var _runner = null var _title: Label @@ -92,8 +96,7 @@ func _init() -> void: var top := HBoxContainer.new() top.add_theme_constant_override("separation", 12) box.add_child(top) - _level_label = UiKit.label("", 16, true) - _level_label.add_theme_color_override("font_color", UiKit.WARM) + _level_label = UiKit.label("", 16, true, UiKit.WARM) _level_label.custom_minimum_size.x = 420 top.add_child(_level_label) var gp_box := PanelContainer.new() @@ -102,11 +105,9 @@ func _init() -> void: var gp_row := HBoxContainer.new() gp_row.add_theme_constant_override("separation", 6) gp_box.add_child(gp_row) - _gp_value = UiKit.label("", 16, true) - _gp_value.add_theme_color_override("font_color", UiKit.GOLD) + _gp_value = UiKit.label("", 16, true, UiKit.GOLD) gp_row.add_child(_gp_value) - _title = UiKit.label(TITLE_FORK, 18, true) - _title.add_theme_color_override("font_color", UiKit.WARM) + _title = UiKit.label(TITLE_FORK, 18, true, UiKit.WARM) _title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER box.add_child(_title) # 节点图画布(图上点击 = 唯一提交通道——布局决策 2;mouse_filter STOP 接悬停/点击) @@ -130,11 +131,9 @@ func _init() -> void: _bonus_row.add_child(bonus_box) var bonus_inner := VBoxContainer.new() bonus_box.add_child(bonus_inner) - var bonus_cap := UiKit.label("本关加成", 12, false) - bonus_cap.add_theme_color_override("font_color", UiKit.WARM_SOFT) + var bonus_cap := UiKit.label("本关加成", 12, false, UiKit.WARM_SOFT) bonus_inner.add_child(bonus_cap) - _bonus_value = UiKit.label("", 15, true) - _bonus_value.add_theme_color_override("font_color", UiKit.WARM) + _bonus_value = UiKit.label("", 15, true, UiKit.WARM) bonus_inner.add_child(_bonus_value) bottom.add_child(_bonus_row) var spacer := Control.new() @@ -148,25 +147,24 @@ func _init() -> void: visible = false -# 状态数据框工厂(直角细线数据框——pattern 5 族;hp_box = 带迷你血条。墨色按样张 v1 冻结: -# 暗底标签 WARM_SOFT/读数 WARM——§7.1 数据素面墨来自世界的墨在暗底侧的落法,L3 ≥4.5:1) +# 状态数据框工厂(直角细线数据框——pattern 5 族;with_bar = 带迷你血条(生命框),值读数随行挂回 +# _hp_value/_attr_value(T4 杂并:旧「caption == "生命"」文案做控制流退役——分组判据复用 with_bar)。 +# 墨色按样张 v1 冻结:暗底标签 WARM_SOFT/读数 WARM——§7.1 数据素面墨来自世界的墨在暗底侧的落法,L3 ≥4.5:1) func _status_box(caption: String, with_bar: bool) -> PanelContainer: var panel := PanelContainer.new() panel.add_theme_stylebox_override("panel", UiKit.panel_flat(UiKit.DARK_UPCOMING, UiKit.PANEL_BORDER, 0, 1)) var inner := VBoxContainer.new() panel.add_child(inner) - var cap := UiKit.label(caption, 12, false) - cap.add_theme_color_override("font_color", UiKit.WARM_SOFT) + var cap := UiKit.label(caption, 12, false, UiKit.WARM_SOFT) inner.add_child(cap) if with_bar: _hp_bar = Control.new() _hp_bar.custom_minimum_size = Vector2(120, 6) _hp_bar.draw.connect(_draw_hp_bar.bind(_hp_bar)) inner.add_child(_hp_bar) - var value := UiKit.label("", 15, true) - value.add_theme_color_override("font_color", UiKit.WARM) + var value := UiKit.label("", 15, true, UiKit.WARM) inner.add_child(value) - if caption == "生命": + if with_bar: _hp_value = value else: _attr_value = value @@ -174,7 +172,7 @@ func _status_box(caption: String, with_bar: bool) -> PanelContainer: func _draw_hp_bar(bar: Control) -> void: - # 迷你血条(样张 v1 冻结:深底 Color8(40,34,28)(对暗面板可辨)+金填充——比例 = hero_hp / effective_max_hp) + # 迷你血条(样张 v1 冻结:深底 UiKit.HP_BAR_BACK #28221C(对暗面板可辨)+金填充——比例 = hero_hp / effective_max_hp) if _runner == null: return var max_hp := maxi(1, _runner.effective_max_hp()) @@ -268,7 +266,8 @@ func _fit_canvas(nodes: Array) -> void: maxl = maxi(maxl, int(layer[k])) for k in slot.keys(): maxslot = maxi(maxslot, int(slot[k])) - _content_size = Vector2(70 + maxl * 122 + NODE_HALF.x + 8.0, 52 + maxslot * 58 + NODE_HALF.y + 8.0) + _content_size = Vector2(LAYER_BASE_X + maxl * LAYER_STEP_X + NODE_HALF.x + 8.0, + SLOT_BASE_Y + maxslot * SLOT_STEP_Y + NODE_HALF.y + 8.0) _content_size = _content_size.max(Vector2(620, 240)) # 下限 = 旧定值画布(小图观感不变) _canvas.custom_minimum_size = _content_size @@ -450,7 +449,8 @@ func _layout(nodes: Array, canvas: Control) -> Dictionary: var pos := {} var origin := (canvas.size - _content_size) / 2.0 for node in nodes: - pos[node] = origin + Vector2(70 + int(layer[node]) * 122, 52 + int(slot[node]) * 58) + pos[node] = origin + Vector2(LAYER_BASE_X + int(layer[node]) * LAYER_STEP_X, + SLOT_BASE_Y + int(slot[node]) * SLOT_STEP_Y) return pos diff --git a/game/presentation/views/node_overlay.gd b/game/presentation/views/node_overlay.gd index e80f9a8e..370f5a96 100644 --- a/game/presentation/views/node_overlay.gd +++ b/game/presentation/views/node_overlay.gd @@ -12,18 +12,8 @@ var _btn: Button func _init() -> void: - var dim := ColorRect.new() - dim.color = Color(0, 0, 0, 0.6) - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - var box := VBoxContainer.new() - box.add_theme_constant_override("separation", 12) - center.add_child(box) - _label = UiKit.label("", 20, true) - _label.add_theme_color_override("font_color", UiKit.WARM) + var box: VBoxContainer = UiKit.modal_shell(self, Color(0, 0, 0, 0.6)).box + _label = UiKit.label("", 20, true, UiKit.WARM) _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER box.add_child(_label) _btn = UiKit.button("继续") diff --git a/game/presentation/views/settings_overlay.gd b/game/presentation/views/settings_overlay.gd index c42d08f9..b5bf026b 100644 --- a/game/presentation/views/settings_overlay.gd +++ b/game/presentation/views/settings_overlay.gd @@ -30,23 +30,11 @@ func retarget(store) -> void: func _build() -> void: - var dim := ColorRect.new() - dim.color = UiKit.BG_OVERLAY - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - var box := VBoxContainer.new() - box.custom_minimum_size = Vector2(560, 0) - box.add_theme_constant_override("separation", 8) - center.add_child(box) + var box: VBoxContainer = UiKit.modal_shell(self, UiKit.BG_OVERLAY, Vector2(560, 0), 8).box - var title := UiKit.label("设置", 26, true) - title.add_theme_color_override("font_color", UiKit.WARM) + var title := UiKit.label("设置", 26, true, UiKit.WARM) box.add_child(title) - var hint := UiKit.label("系统级设置——独立存储不随存档(一安装一份,删游戏才消失)", 13, false) - hint.add_theme_color_override("font_color", UiKit.WARM_SOFT) + var hint := UiKit.label("系统级设置——独立存储不随存档(一安装一份,删游戏才消失)", 13, false, UiKit.WARM_SOFT) box.add_child(hint) box.add_child(HSeparator.new()) diff --git a/game/presentation/views/settlement_fx_view.gd b/game/presentation/views/settlement_fx_view.gd index da07d3a1..5221032a 100644 --- a/game/presentation/views/settlement_fx_view.gd +++ b/game/presentation/views/settlement_fx_view.gd @@ -47,8 +47,7 @@ func play_round_sweep(board_rect: Rect2) -> void: # 跨区弹道:glyph 字形自 from 飞向 to(0.35s + 轻微上抛弧线 + 终点淡出,自动回收)—— # 开格之因 → 站桩之果的因果可视承载(P2);crit 弹道由调用方传加重标记 func play_projectile(from: Vector2, to: Vector2, glyph: String, col: Color, crit: bool = false) -> void: - var shot := UiKit.label(glyph, 22 if crit else 16, true) - shot.add_theme_color_override("font_color", col) + var shot := UiKit.label(glyph, 22 if crit else 16, true, col) shot.mouse_filter = Control.MOUSE_FILTER_IGNORE shot.size = Vector2(24, 24) shot.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER @@ -92,8 +91,7 @@ func play_damage_number(pos: Vector2, text: String, col: Color, crit: bool = fal _fx_damage_marks += 1 # T17 修复(用户实机「完全没看到伤害数字」):26/32px 大字+1.1s 驻留——旧 20px/0.7s 在 # 结算排播节奏下视觉存在感不足;描边 4→6 同步加重(亮舞台底上保读数)。 - var lab := UiKit.label(text, 32 if crit else 26, true) - lab.add_theme_color_override("font_color", col) + var lab := UiKit.label(text, 32 if crit else 26, true, col) lab.add_theme_color_override("font_outline_color", Color(0.1, 0.08, 0.06, 0.9)) lab.add_theme_constant_override("outline_size", 6) lab.mouse_filter = Control.MOUSE_FILTER_IGNORE @@ -130,8 +128,7 @@ func play_round_banner(ri: int) -> void: var banner := Panel.new() banner.mouse_filter = Control.MOUSE_FILTER_IGNORE banner.add_theme_stylebox_override("panel", UiKit.panel_flat(Color(UiKit.BG_OVERLAY, 0.88), UiKit.GOLD_DEEP, 8, 2)) - var lab := UiKit.label("第 %d 轮" % ri, 22, true) - lab.add_theme_color_override("font_color", UiKit.GOLD) + var lab := UiKit.label("第 %d 轮" % ri, 22, true, UiKit.GOLD) lab.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) lab.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER lab.vertical_alignment = VERTICAL_ALIGNMENT_CENTER diff --git a/game/presentation/views/settlement_review_overlay.gd b/game/presentation/views/settlement_review_overlay.gd index 10e4ea3b..c9c0068d 100644 --- a/game/presentation/views/settlement_review_overlay.gd +++ b/game/presentation/views/settlement_review_overlay.gd @@ -11,20 +11,9 @@ var _log: RichTextLabel func _init() -> void: - var dim := ColorRect.new() - dim.color = Color(UiKit.DIM, 0.62) - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.gui_input.connect(_on_dim_gui_input) - add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - var panel := PanelContainer.new() - center.add_child(panel) - var box := VBoxContainer.new() - box.custom_minimum_size = Vector2(760, 560) - box.add_theme_constant_override("separation", 6) - panel.add_child(box) + var shell := UiKit.modal_shell(self, Color(UiKit.DIM, 0.62), Vector2(760, 560), 6, true) + (shell.dim as ColorRect).gui_input.connect(_on_dim_gui_input) + var box: VBoxContainer = shell.box box.add_child(UiKit.label("结算明细回看(完整流水 · 逐行归因)", 18, true)) _log = RichTextLabel.new() _log.bbcode_enabled = true diff --git a/game/presentation/views/shop_overlay_view.gd b/game/presentation/views/shop_overlay_view.gd index 7a515259..8f778a86 100644 --- a/game/presentation/views/shop_overlay_view.gd +++ b/game/presentation/views/shop_overlay_view.gd @@ -19,22 +19,11 @@ var _card_rows: Array[Dictionary] = [] # [{product_id, price, bought, btn}]— func _init() -> void: - var dim := ColorRect.new() - dim.color = Color(0, 0, 0, 0.6) - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - var box := VBoxContainer.new() - box.add_theme_constant_override("separation", 12) - center.add_child(box) - var title := UiKit.label("商店", 26, true) - title.add_theme_color_override("font_color", UiKit.WARM) + var box: VBoxContainer = UiKit.modal_shell(self, Color(0, 0, 0, 0.6)).box + var title := UiKit.label("商店", 26, true, UiKit.WARM) title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER box.add_child(title) - _gp_label = UiKit.label("金币 0", 18, true) - _gp_label.add_theme_color_override("font_color", UiKit.GOLD) + _gp_label = UiKit.label("金币 0", 18, true, UiKit.GOLD) _gp_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER box.add_child(_gp_label) _cards_box = VBoxContainer.new() @@ -82,12 +71,10 @@ func _build_card(p: Dictionary) -> Dictionary: var name_l := UiKit.label(_card_title(p), 15, true) name_l.custom_minimum_size = Vector2(190, 0) row.add_child(name_l) - var price_l := UiKit.label("", 14, false) - price_l.add_theme_color_override("font_color", UiKit.WARM_SOFT) + var price_l := UiKit.label("", 14, false, UiKit.WARM_SOFT) price_l.custom_minimum_size = Vector2(110, 0) row.add_child(price_l) - var bought_l := UiKit.label("", 14, false) - bought_l.add_theme_color_override("font_color", UiKit.WARM_FAINT) + var bought_l := UiKit.label("", 14, false, UiKit.WARM_FAINT) row.add_child(bought_l) var btn := UiKit.button("购买") btn.pressed.connect(_emit_buy_requested.bind(p)) diff --git a/game/presentation/views/standee_body.gd b/game/presentation/views/standee_body.gd index e43c2ee4..47bfc9b2 100644 --- a/game/presentation/views/standee_body.gd +++ b/game/presentation/views/standee_body.gd @@ -143,8 +143,7 @@ func set_effects_cleared_feedback() -> void: return 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) + var note := UiKit.label("状态随战斗结束消散", 11, false, UiKit.STONE_FAINT) note.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER note.mouse_filter = Control.MOUSE_FILTER_IGNORE var parent := slot_row.get_parent() @@ -418,11 +417,11 @@ func _draw() -> void: var ang := TAU * float(i) / 24.0 pts.append(sh_center + Vector2(cos(ang) * sh_rx, sin(ang) * sh_ry)) draw_colored_polygon(pts, Color(0, 0, 0, 0.27)) - # 石板地台(v3.5——方向稿取色:板身 (150,130,100)/描边 (90,76,58)/顶缘受光线 2px (196,172,132); - # 几何沿用现行底座位〔margin 26/高 10→方向稿 18/12——按方向稿对齐〕) - draw_rect(Rect2(18.0, box.y - 18.0, box.x - 36.0, 12.0), Color8(150, 130, 100), true) - draw_rect(Rect2(18.0, box.y - 18.0, box.x - 36.0, 12.0), Color8(90, 76, 58), false, 1.0) - draw_rect(Rect2(18.0, box.y - 18.0, box.x - 36.0, 2.0), Color8(196, 172, 132), true) + # 石板地台(v3.5——方向稿取色:板身/描边/顶缘受光线 2px——取色单点收 UiKit.STAND_STONE 族 + # (T4 裸色收口);几何沿用现行底座位〔margin 26/高 10→方向稿 18/12——按方向稿对齐〕) + draw_rect(Rect2(18.0, box.y - 18.0, box.x - 36.0, 12.0), UiKit.STAND_STONE, true) + draw_rect(Rect2(18.0, box.y - 18.0, box.x - 36.0, 12.0), UiKit.STAND_STONE_EDGE, false, 1.0) + draw_rect(Rect2(18.0, box.y - 18.0, box.x - 36.0, 2.0), UiKit.STAND_STONE_RIM, true) # 血条(直角递减):敌附顺位徽标(GOLD_DEEP ①②③)——旧 top VBox 几何等价(左 8 / 右 -8) var bar_x := 8.0 diff --git a/game/presentation/views/status_slot_row.gd b/game/presentation/views/status_slot_row.gd index 8557bb1a..b62e3911 100644 --- a/game/presentation/views/status_slot_row.gd +++ b/game/presentation/views/status_slot_row.gd @@ -64,8 +64,7 @@ func _init() -> void: _tip.visible = false var sb := UiKit.panel_flat(UiKit.TIP_BG, UiKit.GOLD, 2, 1, Vector4(6, 3, 6, 3)) _tip.add_theme_stylebox_override("panel", sb) - _tip_label = UiKit.label("", 13, false) - _tip_label.add_theme_color_override("font_color", UiKit.WARM) + _tip_label = UiKit.label("", 13, false, UiKit.WARM) _tip_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART _tip_label.custom_minimum_size = Vector2(210, 0) _tip.add_child(_tip_label) diff --git a/game/presentation/views/toast_stack.gd b/game/presentation/views/toast_stack.gd index 03f199a5..755a9798 100644 --- a/game/presentation/views/toast_stack.gd +++ b/game/presentation/views/toast_stack.gd @@ -43,8 +43,7 @@ func show_toast(text: String, tone: String = "info") -> void: col = COL_GOLD sb.border_color = col row.add_theme_stylebox_override("panel", sb) - var lab := UiKit.label(("⚠ " if tone == "warn" else "") + text, 14, tone != "info") - lab.add_theme_color_override("font_color", col) + var lab := UiKit.label(("⚠ " if tone == "warn" else "") + text, 14, tone != "info", col) lab.clip_text = true row.add_child(lab) _slot_box.add_child(row) diff --git a/game/presentation/views/tune_panel.gd b/game/presentation/views/tune_panel.gd index 54b7e619..01b9edfe 100644 --- a/game/presentation/views/tune_panel.gd +++ b/game/presentation/views/tune_panel.gd @@ -110,35 +110,23 @@ func _reset_btn_pressed() -> void: func effective_atk() -> int: - return _scaled(_base_atk, atk_pct()) + return UiKit.scaled(_base_atk, atk_pct()) func effective_max_hp() -> int: - return _scaled(_base_hp, hp_pct()) + return UiKit.scaled(_base_hp, hp_pct()) # ---- 内部构建 ---- func _build() -> void: - var dim := ColorRect.new() - dim.color = UiKit.BG_OVERLAY - dim.set_anchors_preset(Control.PRESET_FULL_RECT) - add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - var box := VBoxContainer.new() - box.custom_minimum_size = Vector2(640, 0) - box.add_theme_constant_override("separation", 8) - center.add_child(box) + var box: VBoxContainer = UiKit.modal_shell(self, UiKit.BG_OVERLAY, Vector2(640, 0), 8).box - var title := UiKit.label("测试用 · 角色数值调整板", 26, true) - title.add_theme_color_override("font_color", UiKit.WARM) + var title := UiKit.label("测试用 · 角色数值调整板", 26, true, UiKit.WARM) box.add_child(title) var desc := UiKit.label( "模拟玩家在循环中解锁天赋获得的属性提升(仅测试工具,不落盘)。\n百分比叠加基础值:攻击 %d / 生命 %d。影响所有模式(手动与模拟)。" % [_base_atk, _base_hp], - 13, false) - desc.add_theme_color_override("font_color", UiKit.WARM_SOFT) + 13, false, UiKit.WARM_SOFT) box.add_child(desc) box.add_child(HSeparator.new()) @@ -210,10 +198,6 @@ func _sync_labels() -> void: _base_atk, effective_atk(), _base_hp, effective_max_hp()] -func _scaled(base: int, pct: int) -> int: - return maxi(1, int(round(float(base) * (100.0 + float(pct)) / 100.0))) - - func _emit_simulate_requested() -> void: simulate_requested.emit(int(_sim_count.value)) diff --git a/game/presentation/views/ui_kit.gd b/game/presentation/views/ui_kit.gd index 09e339a9..14b81b8a 100644 --- a/game/presentation/views/ui_kit.gd +++ b/game/presentation/views/ui_kit.gd @@ -73,10 +73,36 @@ const DIM := Color(0.08, 0.06, 0.05) # 遮罩基色(用时乘 alpha const TOAST_BG := Color(0.94, 0.91, 0.84, 0.95) # toast 面底 const TIP_BG := Color(0.16, 0.12, 0.09, 0.96) # tooltip 深底 +# 呈现杂色档(T4 裸色收口批 2026-10-02——各视图裸 Color8 字面量单点化;值 = 收口时各来源行现值快照) +const STAGE_BG := Color8(62, 52, 42) # B 区舞台暗底(方向稿 render_battle_screen——battle_stage_view 面板底) +const BEAM_LIGHT := Color8(255, 236, 200) # B 区顶光柱暖光(用时乘 alpha 渐隐——battle_stage_view 光柱层) +const STAND_STONE := Color8(150, 130, 100) # 站桩石板地台·板身(standee_body 方向稿取色) +const STAND_STONE_EDGE := Color8(90, 76, 58) # 站桩石板地台·描边 +const STAND_STONE_RIM := Color8(196, 172, 132) # 站桩石板地台·顶缘受光线(与 board_cell_unit.FACADE_HIGHLIGHT_COL 异源同值——并档归清扫卡) +const CAMP_HEADER_BAND := Color8(122, 82, 50) # 营地柜台头带深棕(4-camp.png 方向稿取色) +const CAMP_ROW_PLATE := Color8(240, 230, 206) # 营地行板暖米(同上) +const CAMP_BADGE_PANEL := Color8(40, 32, 24) # 营地钥石徽暗底(同上) +const HP_BAR_BACK := Color8(40, 34, 28) # 迷你血条深底(关卡画面样张 v1 冻结——对暗面板可辨) + # BBCode 十六进制(RichTextLabel 用;与上同值) const HEX_GOLD := "f0a828" const HEX_INK := "33261b" const HEX_ON_GOLD := "3a2a08" +# 结算行/叙事行语义档(T4 收口批——battle_log_view 行格式化与 narrator 横幅行的裸 hex 单点化; +# 名随呈现语义、值 = 2026-09 起各行现值快照,色值逐字节不变) +const HEX_LOG_ROUND := "9a8a72" # 轮次前缀/零值行暖灰石 +const HEX_LOG_GAIN := "e0b860" # 收益金(GP 袋/商店行/败判定/节点横幅) +const HEX_LOG_LOSS := "c47c7c" # 损失红(GP 流失/负效果) +const HEX_LOG_HEAL := "7cc47c" # 治疗绿(效果正值/治疗行/恢复点行) +const HEX_LOG_DMG_NUM := "d9402a" # 伤害数字朱(放大加色——数字即信息主角) +const HEX_LOG_DMG_KILL := "e07050" # 击杀行正文橙红 +const HEX_LOG_DMG_BODY := "e0a050" # 伤害行正文橙 +const HEX_LOG_VOIDED := "b08060" # 未生效行暗橙(⚠ 划线) +const HEX_LOG_CAST := "b09a72" # 施放行暖石(✦ 具名技能) +const HEX_LOG_DECAY := "8a9ab0" # 状态衰减蓝灰 +const HEX_LOG_WIN := "80d080" # 胜利判定绿(模拟报告通关率同档) +const HEX_ROUTE_NOTE := "d0c090" # 奖励点预告暗金(narrator 行) +const HEX_SEED_NOTE := "c8a860" # 种子/开场行暗金(narrator 行) # 语义别名(同值异名——语义站点用别名,值仍单点) const DOT_OFF := PANEL_BORDER @@ -163,15 +189,59 @@ static func panel_flat(bg: Color, border: Color, corner: int = 0, border_w: int return sb -static func label(text: String, size: int, bold: bool) -> Label: +# color 缺省哨兵 = alpha<0(真实用色不取负 alpha)——传色即一次到位(旧「label() 后跟 +# add_theme_color_override」两行式收单行);省略时保持旧默认:bold=INK_LABEL / 非 bold=主题缺省 +static func label(text: String, size: int, bold: bool, color: Color = Color(-1, -1, -1, -1)) -> Label: var l := Label.new() l.text = text l.add_theme_font_size_override("font_size", size) - if bold: + if color.a >= 0.0: + l.add_theme_color_override("font_color", color) + elif bold: l.add_theme_color_override("font_color", INK_LABEL) return l +# ── 模态壳工厂(T4 收口批 2026-10-02——各 overlay 手搓 dim+Center+VBox/Panel 骨架单点化)── +# dim = 全屏半透明遮罩(全屏锚定纪律同既有各 overlay);center 全屏锚定居中;with_panel = 内容包 +# PanelContainer(panel_sb 缺省 = 主题默认板——settlement_review 同款);box = 内容列 +#(min_size/separation 参数化,min_size ZERO = 不设)。返回 Dictionary{dim, center, panel, box} +#——探针直读的私有件由调用方按名摘引,结构同名同层级不变。 +static func modal_dim(parent: Control, dim_color: Color) -> ColorRect: + var dim := ColorRect.new() + dim.color = dim_color + dim.set_anchors_preset(Control.PRESET_FULL_RECT) + parent.add_child(dim) + return dim + + +static func modal_shell(parent: Control, dim_color: Color, min_size := Vector2.ZERO, separation := 12, + with_panel := false, panel_sb: StyleBox = null) -> Dictionary: + var dim := modal_dim(parent, dim_color) + var center := CenterContainer.new() + center.set_anchors_preset(Control.PRESET_FULL_RECT) + dim.add_child(center) + var panel: PanelContainer = null + var host: Control = center + if with_panel: + panel = PanelContainer.new() + if panel_sb != null: + panel.add_theme_stylebox_override("panel", panel_sb) + center.add_child(panel) + host = panel + var box := VBoxContainer.new() + if min_size != Vector2.ZERO: + box.custom_minimum_size = min_size + box.add_theme_constant_override("separation", separation) + host.add_child(box) + return {"dim": dim, "center": center, "panel": panel, "box": box} + + +# 属性百分比合成(main._debug_hero_override 与 TunePanel 生效值预览共用单点——两处同式实现收口) +static func scaled(base: int, pct: int) -> int: + return maxi(1, int(round(float(base) * (100.0 + float(pct)) / 100.0))) + + static func button(text: String) -> Button: var b := Button.new() b.text = text