按 code-conventions §1.4.1 第三轮定稿执行:core 22+schemas 18+presentation 根 14+views 28,全部头注 #→##、删日期/变更叙事/GDD 与架构反向链接/字段与域清单/机制描述,保留职责摘要+真实使用约束(防事故禁令/单一入口/信号契约每信号一行)。main.gd 31→5 行、save_manager 45→5 行、adventure_runner 37→5 行为最大单件。子代理分模块执行(波一 core+schemas、波二 presentation+views,并发≤2)。验收=tools/verify_comment_only_change.py 逐字节校验(82 文件头注区外逐行一致=零行为变更)+audit_file_headers 全绿;纯注释批免冒烟(先例 5843270)
151 lines
7.6 KiB
GDScript
151 lines
7.6 KiB
GDScript
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||
## 结算行排播泵:逻辑先行零回压,行按段分组阶梯延迟进明细带。
|
||
## 硬契约:只做信号的后置消费——结算顺序/结果/时序逻辑零改动;减动效开=延迟归零同帧直落,行呈现不跳过。
|
||
## 开模态前必须 flush()——明细回看/停点/终局面所见明细带恒完整。
|
||
## 视图句柄与 refresh_request/pump_ended 回调由组合根注入——本类零信号连接。
|
||
extends Node
|
||
|
||
const PACE_SEGMENT_GAP := 0.3 # 段间阶梯延迟(代拍板:白名单 0.2–0.4s 内取值,追认清单呈报)
|
||
const PACE_ROW_GAP := 0.22 # 段内间隔(三轮 #3 上调 0.06→0.22——逐条演出可感知,配合数字浮现/状态脉冲)
|
||
|
||
var _rows: Array[Variant] = [] # 待排播行(step_row 载荷原样入队;__round_line 标记=轮首分隔行)
|
||
var _pace_wait := 0.0 # 距下一行排播的剩余秒(_process 消耗)
|
||
var _prev_segment := "" # 上一排播行的段型(段间/段内延迟判据)
|
||
var _was_pumping := false # 排播活跃边沿(T17——末行消费帧触发结算视觉回挖掘态刷新)
|
||
|
||
# 组合根注入面(_build_ui 装配——呈现句柄 + 演播完边沿的呈现刷新回调)
|
||
var log_view: BattleLogView
|
||
var stage: BattleStageView
|
||
var board_zone: BoardZoneView
|
||
var settlement_fx: SettlementFxView
|
||
var board_view: BoardView
|
||
var refresh_request := Callable() # () → 组合根 _refresh_presentations(行尾直呼/演播完边沿 call_deferred)
|
||
var pump_ended := Callable() # () → 组合根锁期点击重放入口(T17 v3.1——演播完边沿 call_deferred;空回调安全)
|
||
|
||
|
||
# 队列只读面(探针/测试经组合根委托属性读——共享同一 Array 引用,读数即实况)
|
||
func pending_rows() -> Array:
|
||
return _rows
|
||
|
||
|
||
# 入队(常态路径——减动效关;step_row 载荷原样,零加工)
|
||
func enqueue(row: Dictionary) -> void:
|
||
_rows.append(row)
|
||
|
||
|
||
# 同帧直落(减动效快路——延迟归零,行呈现不跳过;轮首分隔行减动效分支同用此口)
|
||
func consume_now(row: Dictionary) -> void:
|
||
_consume_row(row)
|
||
|
||
|
||
# 段间延迟取数面(减动效双态断言用——开=0 归零,行不跳过;常态=段间/段内两档)
|
||
func pace_delay_for(prev_seg: String, next_seg: String) -> float:
|
||
if UiKit.motion_scale < 1.0:
|
||
return 0.0
|
||
return PACE_SEGMENT_GAP if prev_seg != next_seg else PACE_ROW_GAP
|
||
|
||
|
||
# 强制排空(模态开启前调用——明细回看/停点覆盖层/终局面所见明细带恒完整)
|
||
func flush() -> void:
|
||
while not _rows.is_empty():
|
||
_consume_row(_rows.pop_front())
|
||
_pace_wait = 0.0
|
||
_prev_segment = ""
|
||
|
||
|
||
func _process(delta: float) -> void:
|
||
# 排播泵(卡⑦——演出层帧驱动;队列空=零开销直返)
|
||
if _rows.is_empty():
|
||
_pace_wait = 0.0
|
||
_prev_segment = ""
|
||
if _was_pumping:
|
||
# 演播完边沿:结算视觉期由排播队列承载(_is_settling 排播项),队列排空的翻转
|
||
# 无核心信号驱动——此处主动刷回挖掘态(去饱和解除/明细带收起/mode=dig)。
|
||
_was_pumping = false
|
||
refresh_request.call_deferred()
|
||
# 锁期点击重放(T17 v3.1——玩家操作零丢失):最后一次锁期点击延迟一帧重入
|
||
# _on_board_action(此刻队列已空=锁已解,正常受理;重放入口由组合根注入)。
|
||
if pump_ended.is_valid():
|
||
pump_ended.call_deferred()
|
||
return
|
||
_was_pumping = true
|
||
_pace_wait -= delta
|
||
if _pace_wait > 0.0:
|
||
return
|
||
var entry: Dictionary[Variant, Variant] = _rows.pop_front()
|
||
_consume_row(entry)
|
||
var seg := String(entry.get("type", ""))
|
||
_pace_wait = 0.0 if UiKit.motion_scale < 1.0 else (PACE_SEGMENT_GAP if seg != _prev_segment else PACE_ROW_GAP)
|
||
_prev_segment = seg
|
||
|
||
|
||
# 行消费(排播队列的出队步 / 减动效快路共用):明细带入带+演出链+呈现刷新——与卡⑦前排位逐位一致
|
||
func _consume_row(row: Dictionary) -> void:
|
||
if row.has("__round_line"):
|
||
log_view.finish_settlement_round() # 上轮摘要行(明细带 pattern 3)随轮首分隔行落带
|
||
log_view.append_bb("[color=#e0b860]── 第 %d 轮 ──[/color]" % int(row["__round_line"]))
|
||
return
|
||
log_view.append_row(row)
|
||
stage.on_step_row_fx(row)
|
||
_play_cross_zone_fx(row) # 跨区因果演出(结算演出链批):开格之因 → 站桩之果
|
||
_play_settlement_mark(row) # 三轮 #3——逐条标出:Buff/Debuff 色环脉冲 → 伤害/治疗数字浮现
|
||
# 高光演出(战斗结算×3①② 占位):完美排雷横幅 / 标中旗加重弹道
|
||
if String(row.get("type", "")) == "highlight" and String(row.get("highlight", "")) != "skill_unlock":
|
||
board_zone.fx.play_perfect_sweep()
|
||
elif String(row.get("highlight", "")) == "flag_hit":
|
||
board_zone.fx.play_flag_hit_projectile(true)
|
||
# Boss 半血解锁技提示(迭代14④ T4——D8 呈现面:skill_unlock 行弹一次性技能名 toast,
|
||
# 轻量非演出零动画资产;行文本 =「XX 解锁了 YY」,只报技能名不报数值——规格=敌人系统 意图呈现节)
|
||
if String(row.get("highlight", "")) == "skill_unlock":
|
||
board_zone.toast.show_toast(String(row.get("display_name", "")), "info")
|
||
refresh_request.call()
|
||
|
||
|
||
# 逐条结算标出(三轮 #3——用户裁决按结算顺序演出:先 Buff/Debuff 特效、再基础伤害数字;
|
||
# 打中谁标谁、主角被打标主角;道具/奖励行逐条冒出)。目标解析失败兜底棋盘中心。
|
||
func _play_settlement_mark(row: Dictionary) -> void:
|
||
var mark_type := String(row.get("type", ""))
|
||
if mark_type != "effect" and mark_type != "damage" and mark_type != "heal":
|
||
return
|
||
var target := String(row.get("target", ""))
|
||
var center: Vector2
|
||
if target == "hero":
|
||
center = stage.hero_standee_center()
|
||
else:
|
||
var v = stage.enemy_standee_center(target) if target != "" and target != "all_enemies" else null
|
||
center = v if v != null else board_view.get_global_rect().get_center()
|
||
match mark_type:
|
||
"effect":
|
||
var col: Color = Color("7cc47c") if int(row.get("value", 0)) > 0 else Color("c47c7c")
|
||
settlement_fx.play_status_pulse(center, col)
|
||
"damage":
|
||
settlement_fx.play_damage_number(center, "-%d" % int(row.get("value", 0)),
|
||
Color("d9402a"), bool(row.get("crit", false)))
|
||
"heal":
|
||
settlement_fx.play_damage_number(center, "+%d" % int(row.get("value", 0)), Color("7cc47c"), false)
|
||
|
||
|
||
# 跨区因果演出(§Transitions 结算逐行兑现——动画密度终稿归战斗表现样张批):
|
||
# 伤害行 → ⚔ 弹道自棋盘飞向目标敌方站桩(crit 金档加重);治疗行 → ✚ 弹道飞向主角站桩;
|
||
# 命中反馈(闪白/血条递减/灰化)由站桩侧 on_step_row_fx/set_data 承接
|
||
func _play_cross_zone_fx(row: Dictionary) -> void:
|
||
var from_v: Vector2 = board_view.get_global_rect().get_center()
|
||
match String(row.get("type", "")):
|
||
"damage":
|
||
var target := String(row.get("target", ""))
|
||
var crit := bool(row.get("crit", false))
|
||
if target == "" or target == "hero":
|
||
# 主角受击弹道(迭代 6 T5 拆「敌→主角零反馈」早退):⚔ 危险红飞向主角站桩;
|
||
# crit 只加重字号不加金(金=收益/胜利语义位,不用于敌方对主角输出)
|
||
settlement_fx.play_projectile(from_v, stage.hero_standee_center(), "⚔",
|
||
UiKit.RED_MINE, crit)
|
||
return
|
||
var to_v = stage.enemy_standee_center(target)
|
||
if to_v != null:
|
||
settlement_fx.play_projectile(from_v, to_v, "⚔",
|
||
UiKit.GOLD if crit else UiKit.RED_MINE, crit)
|
||
"heal":
|
||
if String(row.get("target", "")) != "hero" and String(row.get("target", "")) != "":
|
||
return
|
||
settlement_fx.play_projectile(from_v, stage.hero_standee_center(), "✚", Color("7cc47c"))
|