P1-5/P2-7 组合根可测化+模态协议内聚(场景拆分后重估结论=抽取面收敛为模态编排域): - modal_flow.gd 新纯逻辑类: 依赖仅 ModalStack+查询 Callable(审计处方)——开合编排 (挂起兜底/排播排空/遮挡记账/开合同步)/棋盘输入锁谓词(三例外注入)/双形制角标谓词; V6 modal_flow_test 19 断言直接 new() 进 run_all(26→27 套)——测试抓出并修正 挂起兜底 divergent return 一处(原 main 语义=先结挂起后继续开本层不短路) - ModalStack 互斥域随层登记: register(m, tags) + TAG_NON_LOCKING/TAG_SCREEN_STATE 封闭词表 + has_open_excluding_tags 组查询;原 has_open_excluding/_any 调用点拼装退役 (main 五处判据迁移);main._modals=flow.stack(ui_struct _list 登记序断言缝保留) - P1-5 控制器构造收拢 context: curio 16 参→CurioFlowContext/camp 13 参→CampFlowContext (字段逐一同名迁移,控制器可独立实例化) 验收: 对拍三变体全同;冒烟 1079/0+run_all 27 套+probe click+render golden 全绿
90 lines
4.7 KiB
GDScript
90 lines
4.7 KiB
GDScript
class_name ModalFlow
|
||
extends RefCounted
|
||
# 模态编排纯逻辑类(迭代 27 T4——审计 P1-5/P2-7:组合根可测化抽取 + 模态互斥域内聚)。
|
||
# 依赖仅 ModalStack + 查询 Callable(审计处方原话)——零节点构建、零信号连接、零核心触碰
|
||
#(ADR-0001 同构:连接归组合根,本类只收注入)。可直接 new() 单测(V6)。
|
||
# 职责三件:
|
||
# ① 登记与开合编排(遮挡记账单口 / T17 演播后排窗挂起——原 main._open_modal 系逻辑随迁)
|
||
# ② 棋盘输入锁谓词(互斥域随层登记——原 main._input_locked 排除式拼装消亡)
|
||
# ③ 角标置灰谓词(状态/调试两屏同款守卫判据)
|
||
# 排除语义随层登记(ModalStack.register tags):debug_overlay=["non_locking"]、
|
||
# level_screen=["screen_state"],其余层零标签——原调用点排除式拼装面消亡(P2-7 修法)。
|
||
|
||
const ModalStackScript := preload("res://presentation/modal_stack.gd") # 非全局类(main 同款 preload 引用)
|
||
|
||
var stack = ModalStackScript.new()
|
||
|
||
# ---- 组合根注入面(查询 Callable 组——依赖仅 ModalStack + 查询 Callable 纪律载体) ----
|
||
var start_visible_get: Callable # () -> bool——开始层可见(非模态全屏态例外一)
|
||
var inter_visible_get: Callable # () -> bool——过场层可见(例外二)
|
||
var settlement_get: Callable # () -> Variant——当前战斗编排器(null=战斗缺位例外三)
|
||
var rows_empty_get: Callable # () -> bool——排播队列空(演播后排窗判据)
|
||
var flush_rows: Callable # 开层前排空排播(卡⑦——明细带恒完整)
|
||
var on_open_sync: Callable # 开侧同步钩子(状态角标+浮窗当局数据)
|
||
var on_close_sync: Callable # 关侧同步钩子
|
||
var replay_click: Callable # 演播完边沿无挂起时的锁期点击重放(main._replay_locked_click)
|
||
|
||
var _deferred: Control = null # 演播后开窗挂起(T17——排播放完再开)
|
||
|
||
|
||
func register(m: Control, tags: Array = []) -> void:
|
||
stack.register(m, tags)
|
||
|
||
|
||
func open(m: Control) -> void:
|
||
# 挂起兜底(T17 演播后排窗):其他路径(如回看)在播期排空队列会使演播完边沿不再触发——
|
||
# 此处先结挂起 modal 防永不兑现(m==挂起对象时跳过=本调用自身)。
|
||
if _deferred != null and m != _deferred:
|
||
var dm: Control = _deferred
|
||
_deferred = null
|
||
open(dm) # 原语义:先结挂起后继续开本层(不 return——两拍都走)
|
||
flush_rows.call() # 卡⑦——任何覆盖层开启前排空排播队列(明细带恒完整,回看/停点面不缺行)
|
||
stack.open(m)
|
||
on_open_sync.call()
|
||
|
||
|
||
func close(m: Control) -> void:
|
||
stack.close(m)
|
||
on_close_sync.call()
|
||
|
||
|
||
# 演播后排窗(T17 用户令「伤害过程演完才切结算窗口」):排播队列在播=挂起,演播完边沿
|
||
# (pump_ended 派发)再开——旧路径前置 flush 会把击杀轮的伤害/死亡演出同帧倒掉。
|
||
# 队列空=立即开(行为同旧路径)。
|
||
func open_after_playback(m: Control) -> void:
|
||
if rows_empty_get.call():
|
||
open(m)
|
||
return
|
||
_deferred = m
|
||
m.visible = false # 挂起含视觉(open_* 已置 visible=true——不压掉则窗在排播期照会上屏,延迟形同虚设)
|
||
|
||
|
||
# 演播完边沿派发(row_pacer.pump_ended 注入口):先开挂起 modal(胜利窗接管呈现),
|
||
# 后锁期点击重放——modal 开启后输入锁吞掉重放点击(战斗已收场,重放无意义)。
|
||
func pump_ended() -> void:
|
||
if _deferred != null:
|
||
var m: Control = _deferred
|
||
_deferred = null
|
||
open(m)
|
||
return
|
||
replay_click.call()
|
||
|
||
|
||
# 棋盘输入锁谓词(原 main._input_locked 随迁):模态互斥域(non_locking 层开态不计——迭代 18
|
||
# 卡⑦ T2 防线)+ 三例外(开始层/过场层非模态全屏态 + 战斗缺位棋盘输入无载体)。
|
||
func locks_input() -> bool:
|
||
return stack.has_open_excluding_tags([ModalStackScript.TAG_NON_LOCKING]) \
|
||
or bool(start_visible_get.call()) or bool(inter_visible_get.call()) or settlement_get.call() == null
|
||
|
||
|
||
# 角标置灰谓词·战斗屏形态(状态/调试两角标同判据):登记册上 non_locking 层外的任一层开着。
|
||
# (地图屏此态恒关——屏级互斥,与旧排除式 [debug] 逐位同值)
|
||
func badge_greyed_battle() -> bool:
|
||
return stack.has_open_excluding_tags([ModalStackScript.TAG_NON_LOCKING])
|
||
|
||
|
||
# 角标置灰谓词·地图屏形态(地图屏自身 screen_state 不计 + 调试浮窗 non_locking 不计——
|
||
# 与旧排除式 [level_screen, debug] 逐位同值)。
|
||
func badge_greyed_map() -> bool:
|
||
return stack.has_open_excluding_tags([ModalStackScript.TAG_NON_LOCKING, ModalStackScript.TAG_SCREEN_STATE])
|