Files
gplan-2/game/presentation/views/battle_log_view.gd
T
DKChan 32fdf957fd refactor(代码术语): 卡① flag→seal 全族换代+game/ 禁用词清扫(迭代 31 卡①)
标识符面:flag_*→seal_ 族(含 Godot 信号 flag_judged→seal_judged 与连接/回调同名、
FACTS 两键 flags_count→seals_count/dug_under_flag→dug_under_seal 全链、
.tres 键名与 schema .gd 同批同步);显式豁免零改动=size_flags_*(Godot 布局属性)+_fatal_flag。
中文面:金币→GP(金币袋→GP 袋)/插旗→封印/雷格→危险格/惩罚格→危险格/旗→封印·封印印记族,
game/ 内 *.gd/.tres/.md/.json 四类禁用词与 flag 双双零命中(V1/V4)。
守卫字面量不动(被检查的禁字不是使用):smoke_all V21 零「雷/旗」检查面、
ui_font_asset_test 字形集攻/雷/旗/封 保持原断言逻辑。
代拍板:板面单字槽 glyph「旗」→「封」(禁字纪律+单字位宽,消费面四处同名随动)。
素材换代(2026-10-18 用户裁案甲):assets/art/board/flag_seal.png→seal_mark.png(素材不入 git,
盘上改名+导入重刷),代码两处 res:// 字符串+COL_FLAG/CURSOR_FLAG 常量同步,
闸件四处随批(run_all_gates.sh/render_gate.sh/golden_baseline_refresh.sh/path_check.py)。
anchor.json 键名手改,重锚与改前改后 diff 随本卡收口(同裁案甲)。

基线读数(改前,主区 ed2dfaf6):冒烟 1151 检查 0 失败/单元 34 套全绿/探针 --click
存量红仅 screen_flow_probe(user:// 断点污染在册已知项)。
改后同批读数(本 worktree):冒烟 1151 检查 0 失败/探针 --click 同一存量红、其余全绿。
2026-10-19 02:52:38 +08:00

221 lines
8.7 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## VERTICAL SLICE - NOT FOR PRODUCTION
## B 区结算明细带——战斗结算步骤流到玩家文案的全部行格式化规则内聚于此(挖掘期收起 1 行上轮摘要、结算期实时流)。
class_name BattleLogView
extends PanelContainer
const BAND_H_DIG := 24
const BAND_H_SETTLE := 84
const AGG_TYPES := ["reward_ineffective"]
const COL_GOLD := UiKit.HEX_GOLD
var _db
var _log: RichTextLabel
var _summary: Label
var _hint: Label
var _mode := "dig" # dig = 收起摘要 / settle = 实时流(模式归组合根驱动)
var _round_rows: Array[Dictionary] = [] # 本结算轮行缓冲(上轮摘要构建源)
var _pending_agg := {} # 聚合计数行 pending(type+batch_key → {row, count})
func _init(db_ref) -> void:
_db = db_ref
custom_minimum_size = Vector2(0, BAND_H_DIG)
size_flags_vertical = Control.SIZE_SHRINK_END
var vb := VBoxContainer.new()
vb.add_theme_constant_override("separation", 2)
add_child(vb)
var head := HBoxContainer.new()
vb.add_child(head)
# 对比度修复(v3.5 批 B3 2026-09-30——明细条灰字对深灰底实测 2.63:1):暗底双色墨制=暖白族
_summary = UiKit.label("",UiKit.FS_BODY, 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("上轮摘要(回看归「生涯」)",UiKit.FS_HINT, false, UiKit.WARM) # 辅助提示(≥14 辅助档)随上暖白
_hint.size_flags_horizontal = Control.SIZE_SHRINK_END
head.add_child(_hint)
_log = RichTextLabel.new()
_log.bbcode_enabled = true
_log.scroll_following = true
_log.custom_minimum_size = Vector2(0, BAND_H_SETTLE - 26)
_log.clip_contents = true
_log.scroll_active = true
vb.add_child(_log)
_log.visible = false
func set_mode(mode: String) -> void:
if _mode == mode:
return
_mode = mode
var settle := mode == "settle"
_log.visible = settle
_summary.visible = not settle
custom_minimum_size = Vector2(0, BAND_H_SETTLE if settle else BAND_H_DIG)
func mode() -> String:
return _mode
func clear() -> void:
_log.clear()
_round_rows.clear()
_pending_agg = {}
_summary.text = ""
# 每结算轮结束(下一轮开始/终局)——刷新挖掘期"上轮摘要"行
func finish_settlement_round() -> void:
_flush_pending_agg()
if _round_rows.is_empty():
return
var parts: Array[String] = []
for bb in _round_rows:
parts.append(_strip_bb(str(bb)))
var text := "上轮: " + " | ".join(parts)
if text.length() > 190:
text = text.substr(0, 190) + "…"
_summary.text = text
_round_rows.clear()
func append_bb(bb: String) -> void:
_flush_pending_agg()
_log.append_text(bb + "\n")
func append_row(row: Dictionary) -> void:
if AGG_TYPES.has(String(row.get("type", ""))):
_accumulate_agg(row)
return
_flush_pending_agg()
var bb := _format_row(row)
_round_rows.append(bb)
_log.append_text(bb + "\n")
func parsed_text() -> String:
return _log.get_parsed_text()
# M9(P-C7 裁):带点击回看入口退役——冒险中不给数据回看(归「生涯」06 登记);带保留单行摘要显示
# ---- 聚合计数(未生效类行防逐行惩罚轰炸——pattern 3 聚合纪律) ----
func _accumulate_agg(row: Dictionary) -> void:
var key := "%s|%s" % [String(row.get("type", "")), String(row.get("batch_key", ""))]
if _pending_agg.has(key):
_pending_agg[key]["count"] = int(_pending_agg[key]["count"]) + 1
else:
_flush_pending_agg()
_pending_agg[key] = {"row": row, "count": 1}
func _flush_pending_agg() -> void:
if _pending_agg.is_empty():
return
for key in _pending_agg:
var item: Dictionary[Variant, Variant] = _pending_agg[key]
var row: Dictionary[Variant, Variant] = item["row"]
var count: int = item["count"]
var bb := _format_row(row, count)
_round_rows.append(bb)
_log.append_text(bb + "\n")
_pending_agg = {}
# ---- 行格式化(模板「{行为} {值} → {目标}(来源)」) ----
func _source_label(src_key: String) -> String:
if src_key == "":
return ""
return String(_db.settlement.source_label_map.get(src_key, src_key))
func _gold_frame(text: String) -> String:
# highlight 金框强调(形状+色彩双通道:■ 前缀 + 金底)
return "[bgcolor=%s][color=#%s]■ %s[/color][/bgcolor]" % [COL_GOLD, UiKit.HEX_ON_GOLD, text]
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=#%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", ""))
var target := String(row.get("target", ""))
var tail := " → %s" % target if target != "" else ""
var suffix := "(%s)" % src if src != "" else ""
match String(row.get("type", "")):
"effect":
# GP 型效果行(GP+商店房实施批 2026-09-21):「GP 袋 +3」兑付反馈——value = 本行 ±power,
# escrow = 战斗内缓冲现值(入钱包在战斗末一次上抛——呈现语义与增益池分账)
if String(row.get("effect_id", "")) in ["gp_gain", "gp_loss"]:
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 := 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":
# 伤害行无行上拆行文案——基线+伏击与三分量两旧归因拆行已随伏击退役批(2026-09-20)
# 与充能退役批(2026-09-19)出协议,行上归因读数只剩掷点档位随行
# 护甲等级掷点留档(2026-09-16 掷点批——掷点读数与档位随行可读;吃掷点分量恒带,棋盘来源行不带)
var roll_txt := ""
if row.get("roll", null) != null:
roll_txt = "〔掷 %d vs 护甲 %d" % [int(row.roll), int(row.ac)]
if bool(row.get("crit", false)):
roll_txt += " · 暴击×%d" % int(_db.settlement.crit_multiplier)
elif int(row.tier) < 100:
roll_txt += " · ×%d%%" % int(row.tier)
roll_txt += "〕"
var kill := " ⚔击杀!" if row.get("killed", false) else ""
# 二轮修改批 C(2026-09-29 用户目检——「每次结算标出的伤害数字不明显」):
# 伤害值放大加色独立于行文(朱红大一号——数字即信息主角,非同字号色温微差)
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=#%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=#%s]⚠ %s%s[/color][/s]%s" % [UiKit.HEX_LOG_VOIDED, name_, n, suffix]
"seal_miss":
var body := "✗ %s%s" % [name_, "(本板完美排雷已破——归因此封印)" if hl == "perfect_broken" else ""]
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=#%s]✦ %s%s[/color]" % [UiKit.HEX_LOG_CAST, name_, suffix]
"decay":
return prefix + "[color=#%s]状态衰减 ×%d[/color]" % [UiKit.HEX_LOG_DECAY, v]
"verdict":
if int(row.value) == 1:
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
func _strip_bb(bb: String) -> String:
var out := ""
var in_tag := false
for ch in bb:
if ch == "[":
in_tag = true
elif ch == "]":
in_tag = false
elif not in_tag:
out += ch
return out.replace(" ", " ").strip_edges()