合并(迭代52·四卡): 卡①minesweeper_rules公开面还债(safe_remaining私有化S13归绿)+卡②孤儿函数清退(判死六件)+卡③presentation层封装修复(A1三类字段/A2子件/B组合根交接面/C杂项,私取sweep恒零,main.gd=32与ui_kit=23例外键落基线)+卡④封印印记法阵化(着色器参数化绘制,贴图路径退役,三关环径0.826读数)——独立验收审计通过(24对照行全过),产出物三份+审计报告落reports/
ci / gates (push) Failing after 6m1s
ci / gates (push) Failing after 6m1s
This commit is contained in:
commit
540c179389
54 files changed
+1760
-738
No files matched your search
@@ -247,11 +247,6 @@ func continue_to_next_level() -> bool:
|
|||||||
# 停点空候选消化(池空=三选一环节整体跳过——呈现层跳开选择面;编排归停点件)
|
# 停点空候选消化(池空=三选一环节整体跳过——呈现层跳开选择面;编排归停点件)
|
||||||
# ---- 提升三选一(选择停点零自动推进、重复兑付被拒;兑付恰一件、未选项零生效)----
|
# ---- 提升三选一(选择停点零自动推进、重复兑付被拒;兑付恰一件、未选项零生效)----
|
||||||
|
|
||||||
# 候选令牌匹配(身份键恒等——属性加成型特性 kind+tier、规则改写型特性 feat_id)
|
|
||||||
func _find_token(candidates: Array, kind: String, tier: String, feat_id: String = "") -> Dictionary:
|
|
||||||
return _curio.find_token(candidates, kind, tier, feat_id)
|
|
||||||
|
|
||||||
|
|
||||||
# 玩家点选兑付(state 守卫留应用层——编排归停点件;呈现层直调面 T5 改 stop())
|
# 玩家点选兑付(state 守卫留应用层——编排归停点件;呈现层直调面 T5 改 stop())
|
||||||
# 特性持有集读面(效果接线/求值/摘要唯一取数口——副本防外部改写)
|
# 特性持有集读面(效果接线/求值/摘要唯一取数口——副本防外部改写)
|
||||||
func feats_held() -> Array:
|
func feats_held() -> Array:
|
||||||
|
|||||||
@@ -208,17 +208,6 @@ func _bp_strategy(key: String) -> String:
|
|||||||
return String((BREAKPOINT_FIELDS.get(key, {}) as Dictionary).get("strategy", "plain"))
|
return String((BREAKPOINT_FIELDS.get(key, {}) as Dictionary).get("strategy", "plain"))
|
||||||
|
|
||||||
|
|
||||||
# 数值类读侧(clamp 夹 ≥0 / params_fallback 断点缺键回退参数面整额注入 / plain 直取)
|
|
||||||
func _bp_read_int(key: String, bp: Dictionary, fallback: int, params: Dictionary = {}) -> int:
|
|
||||||
match _bp_strategy(key):
|
|
||||||
"clamp":
|
|
||||||
return maxi(0, int(bp.get(key, fallback)))
|
|
||||||
"params_fallback":
|
|
||||||
return maxi(0, int(bp.get(key, int(params.get(key, fallback)))))
|
|
||||||
_:
|
|
||||||
return int(bp.get(key, fallback))
|
|
||||||
|
|
||||||
|
|
||||||
# ---- 断点域六成员公开读写面(5.1 封装修复——宿主私取清零:方法体一律一行转发自有成员,零逻辑增量)----
|
# ---- 断点域六成员公开读写面(5.1 封装修复——宿主私取清零:方法体一律一行转发自有成员,零逻辑增量)----
|
||||||
|
|
||||||
# 断点承载注入(宿主构造后接线——save_manager 后绑)
|
# 断点承载注入(宿主构造后接线——save_manager 后绑)
|
||||||
|
|||||||
@@ -300,11 +300,6 @@ func curio_stop_pending() -> bool:
|
|||||||
return not _pending.is_empty() or not _node_pending.is_empty()
|
return not _pending.is_empty() or not _node_pending.is_empty()
|
||||||
|
|
||||||
|
|
||||||
# 放行谓词(宿主关序受理——已兑付待推进且无在途停点)
|
|
||||||
func stop_resolved() -> bool:
|
|
||||||
return not _resolved.is_empty() and _pending.is_empty()
|
|
||||||
|
|
||||||
|
|
||||||
func _refresh_curio_common(paid: bool) -> bool:
|
func _refresh_curio_common(paid: bool) -> bool:
|
||||||
if not curio_stop_pending():
|
if not curio_stop_pending():
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -200,18 +200,6 @@ func _push_trigger(source: String, id: String, tr: Dictionary, row: Dictionary)
|
|||||||
_triggers.append(t)
|
_triggers.append(t)
|
||||||
|
|
||||||
|
|
||||||
## 订阅查询面(发射点缺省行为仲裁用——round_end 走 RAP 转存)
|
|
||||||
func has_effect_on(event: String, kind: String, mode: String = "") -> bool:
|
|
||||||
for tr in _triggers:
|
|
||||||
if String(tr.on) != event:
|
|
||||||
continue
|
|
||||||
var d: Dictionary[Variant, Variant] = tr.do
|
|
||||||
if String(d.get("kind", "")) == kind and (mode == "" or String(d.get("mode", "")) == mode):
|
|
||||||
# 有 when 时不能预判命中(发射点缺省行为保守按「可能命中」计——命中由 dispatch 定夺)
|
|
||||||
return true
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
|
||||||
## 事件分发(发射点唯一入口):返回命中效果列表(装载序=声明序;零命中=空数组零扰动)。
|
## 事件分发(发射点唯一入口):返回命中效果列表(装载序=声明序;零命中=空数组零扰动)。
|
||||||
## ctx = 四桶引用束(引擎不自持状态,计数器读写全经 ctx);
|
## ctx = 四桶引用束(引擎不自持状态,计数器读写全经 ctx);
|
||||||
## payload = 事件现场(fact 取值第一优先源);facts = 补充事实面(运行态读数 Callable)。
|
## payload = 事件现场(fact 取值第一优先源);facts = 补充事实面(运行态读数 Callable)。
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ func revealed_cells() -> Array:
|
|||||||
return _revealed.keys()
|
return _revealed.keys()
|
||||||
|
|
||||||
|
|
||||||
func safe_remaining() -> int:
|
func _safe_remaining() -> int:
|
||||||
var n := 0
|
var n := 0
|
||||||
for c in _board.safe_cells():
|
for c in _board.safe_cells():
|
||||||
if not _revealed.has(c):
|
if not _revealed.has(c):
|
||||||
@@ -107,7 +107,7 @@ func safe_remaining() -> int:
|
|||||||
|
|
||||||
|
|
||||||
func clear_map_cleared() -> bool:
|
func clear_map_cleared() -> bool:
|
||||||
return safe_remaining() == 0
|
return _safe_remaining() == 0
|
||||||
|
|
||||||
|
|
||||||
# ---- 中立移除(P1 甲:邻接数字=原始雷数冻结零重算;P2 甲:移除格呈现退色降档;
|
# ---- 中立移除(P1 甲:邻接数字=原始雷数冻结零重算;P2 甲:移除格呈现退色降档;
|
||||||
|
|||||||
+189
-96
@@ -49,7 +49,57 @@ var settings_store # 系统级设置独立存储(音量
|
|||||||
var _tune_sim = null # 调试浮窗批量模拟控制器(tune_sim_controller.gd)
|
var _tune_sim = null # 调试浮窗批量模拟控制器(tune_sim_controller.gd)
|
||||||
|
|
||||||
|
|
||||||
func _replay_locked_click() -> void:
|
# ---- 句柄读投影/设置口(pres封装 B 规则 4——成员保持私有,分文件经此读写;BreakpointStore 方法对先例)----
|
||||||
|
|
||||||
|
func set_treasure_ui(v: Variant) -> void:
|
||||||
|
_treasure_ui = v
|
||||||
|
|
||||||
|
|
||||||
|
func treasure_ui() -> Variant:
|
||||||
|
return _treasure_ui
|
||||||
|
|
||||||
|
|
||||||
|
func set_bonus(v: Variant) -> void:
|
||||||
|
_bonus = v
|
||||||
|
|
||||||
|
|
||||||
|
func bonus() -> Variant:
|
||||||
|
return _bonus
|
||||||
|
|
||||||
|
|
||||||
|
func set_camp_pres(v: Variant) -> void:
|
||||||
|
_camp_pres = v
|
||||||
|
|
||||||
|
|
||||||
|
func camp_pres() -> Variant:
|
||||||
|
return _camp_pres
|
||||||
|
|
||||||
|
|
||||||
|
func set_debug(v: Variant) -> void:
|
||||||
|
_debug = v
|
||||||
|
|
||||||
|
|
||||||
|
func debug() -> Variant:
|
||||||
|
return _debug
|
||||||
|
|
||||||
|
|
||||||
|
func set_tune_sim(v: Variant) -> void:
|
||||||
|
_tune_sim = v
|
||||||
|
|
||||||
|
|
||||||
|
func tune_sim() -> Variant:
|
||||||
|
return _tune_sim
|
||||||
|
|
||||||
|
|
||||||
|
func set_confirm_consumer(v: String) -> void:
|
||||||
|
_confirm_consumer = v
|
||||||
|
|
||||||
|
|
||||||
|
func set_confirm_consumer_slot(v: int) -> void:
|
||||||
|
_confirm_consumer_slot = v
|
||||||
|
|
||||||
|
|
||||||
|
func replay_locked_click() -> void:
|
||||||
if run_scope.locked_click.is_empty() or not ui.screens.row_pacer.pending_rows().is_empty():
|
if run_scope.locked_click.is_empty() or not ui.screens.row_pacer.pending_rows().is_empty():
|
||||||
return
|
return
|
||||||
var click: Dictionary[Variant, Variant] = run_scope.locked_click
|
var click: Dictionary[Variant, Variant] = run_scope.locked_click
|
||||||
@@ -59,7 +109,7 @@ func _replay_locked_click() -> void:
|
|||||||
|
|
||||||
# 会话生命周期:_ready 建闲时态(永非 null——全组合根零空判责),
|
# 会话生命周期:_ready 建闲时态(永非 null——全组合根零空判责),
|
||||||
# 开局/续玩/调试两层各建新会话,旧会话整节点 queue_free()(帧末回收;新节点先挂树无真空窗)。
|
# 开局/续玩/调试两层各建新会话,旧会话整节点 queue_free()(帧末回收;新节点先挂树无真空窗)。
|
||||||
func _begin_session(adventure_session: bool) -> void:
|
func begin_session(adventure_session: bool) -> void:
|
||||||
ui.screens.row_pacer.flush() # 会话更替即清队(待播行不住局态——机制保证,不靠时序约定)
|
ui.screens.row_pacer.flush() # 会话更替即清队(待播行不住局态——机制保证,不靠时序约定)
|
||||||
if run_scope != null:
|
if run_scope != null:
|
||||||
run_scope.queue_free()
|
run_scope.queue_free()
|
||||||
@@ -73,7 +123,7 @@ func _ready() -> void:
|
|||||||
if not db.is_ready:
|
if not db.is_ready:
|
||||||
var ok: bool = db.load_tables("res://data/tables", false)
|
var ok: bool = db.load_tables("res://data/tables", false)
|
||||||
if not ok:
|
if not ok:
|
||||||
_fatal_screen("数值表加载失败——见输出错误清单(fail-fast)")
|
fatal_screen("数值表加载失败——见输出错误清单(fail-fast)")
|
||||||
return
|
return
|
||||||
# SaveManager/MetaProgression 升格 autoload:读盘已在各自 _ready 完成
|
# SaveManager/MetaProgression 升格 autoload:读盘已在各自 _ready 完成
|
||||||
#(autoload 先于主场景就绪——读盘时序等价),此处零动作。
|
#(autoload 先于主场景就绪——读盘时序等价),此处零动作。
|
||||||
@@ -83,7 +133,7 @@ func _ready() -> void:
|
|||||||
settings_store.apply()
|
settings_store.apply()
|
||||||
ui = UiRegistry.new() # 注册面先于装配建(_build_ui 八步向容器登记——装配时序零变化)
|
ui = UiRegistry.new() # 注册面先于装配建(_build_ui 八步向容器登记——装配时序零变化)
|
||||||
_build_ui()
|
_build_ui()
|
||||||
_begin_session(false) # 闲时会话(gp_ledger 等探针注入面自 _ready 起恒在——ui_probe 合成段时序)
|
begin_session(false) # 闲时会话(gp_ledger 等探针注入面自 _ready 起恒在——ui_probe 合成段时序)
|
||||||
ui.screens.start_overlay.visible = true
|
ui.screens.start_overlay.visible = true
|
||||||
ui.screens.debug_badge.visible = _debug_entry # 浮层角标可见性须门控落定后赋值(构建/连接在 _build_ui);_debug_entry 缺省 false=发布态恒隐
|
ui.screens.debug_badge.visible = _debug_entry # 浮层角标可见性须门控落定后赋值(构建/连接在 _build_ui);_debug_entry 缺省 false=发布态恒隐
|
||||||
# boot 菜单优先——启动不自动开浮窗(开始屏不得被调试面板盖住);
|
# boot 菜单优先——启动不自动开浮窗(开始屏不得被调试面板盖住);
|
||||||
@@ -93,11 +143,44 @@ func _ready() -> void:
|
|||||||
# ==================== 视图接线(三屏壳 + 模态层装配;构建归屏壳/UiAssembler,本类只接线) ====================
|
# ==================== 视图接线(三屏壳 + 模态层装配;构建归屏壳/UiAssembler,本类只接线) ====================
|
||||||
|
|
||||||
func _build_ui() -> void:
|
func _build_ui() -> void:
|
||||||
MainUiBuild.build(self)
|
# 处理器束(pres封装 B 规则 2——on_* 处理器保私有,接线语句经束消费;键=用途名,main 内自引合法)
|
||||||
|
MainUiBuild.build(self, {
|
||||||
|
"board_action": _on_board_action,
|
||||||
|
"status_badge_pressed": _on_status_badge_pressed,
|
||||||
|
"stop_pressed": _on_stop_pressed,
|
||||||
|
"refresh_confirmed": _on_refresh_confirmed,
|
||||||
|
"legend_toggled": _on_legend_toggled,
|
||||||
|
"hover_forbidden": _on_hover_forbidden,
|
||||||
|
"chord_attempted": _on_chord_attempted,
|
||||||
|
"node_continue": _on_node_continue,
|
||||||
|
"route_chosen": _on_route_chosen,
|
||||||
|
"abandon_requested": _on_abandon_requested,
|
||||||
|
"battle_end_continue": _on_battle_end_continue,
|
||||||
|
"settings_closed": _on_settings_closed,
|
||||||
|
"status_closed": _on_status_closed,
|
||||||
|
"career_closed": _on_career_closed,
|
||||||
|
"save_select_closed": _on_save_select_closed,
|
||||||
|
"save_select_new": _on_save_select_new,
|
||||||
|
"save_select_load": _on_save_select_load,
|
||||||
|
"save_select_delete": _on_save_select_delete,
|
||||||
|
"debug_badge_pressed": _on_debug_badge_pressed,
|
||||||
|
"camp_object_pressed": _on_camp_object_pressed,
|
||||||
|
"inter_next_pressed": _on_inter_next_pressed,
|
||||||
|
"confirm_accepted": _on_confirm_accepted,
|
||||||
|
"confirm_secondary": _on_confirm_secondary,
|
||||||
|
"confirm_declined": _on_confirm_declined,
|
||||||
|
"esc_return": _on_esc_return,
|
||||||
|
"esc_settings": _on_esc_settings,
|
||||||
|
"esc_quit": _on_esc_quit,
|
||||||
|
"tune_apply": _on_tune_apply,
|
||||||
|
"tune_simulate": _on_tune_simulate,
|
||||||
|
"debug_battle_created": _on_debug_battle_created,
|
||||||
|
"debug_battle_ready": _on_debug_battle_ready,
|
||||||
|
})
|
||||||
ui.modals.menu.debug_overlay.diagnose_requested.connect(_on_diagnose_pressed) # 诊断转储入口
|
ui.modals.menu.debug_overlay.diagnose_requested.connect(_on_diagnose_pressed) # 诊断转储入口
|
||||||
|
|
||||||
|
|
||||||
func _fatal_screen(msg: String) -> void:
|
func fatal_screen(msg: String) -> void:
|
||||||
MainUiBuild.fatal_screen(self, msg)
|
MainUiBuild.fatal_screen(self, msg)
|
||||||
|
|
||||||
|
|
||||||
@@ -122,13 +205,13 @@ func _on_confirm_accepted() -> void:
|
|||||||
save_manager.slots.delete_slot(_confirm_consumer_slot)
|
save_manager.slots.delete_slot(_confirm_consumer_slot)
|
||||||
ui.modals.menu.save_select_overlay.open_save_select(HudPresenter.save_select_data(save_manager)) # 就地刷新(该槽回空态)
|
ui.modals.menu.save_select_overlay.open_save_select(HudPresenter.save_select_data(save_manager)) # 就地刷新(该槽回空态)
|
||||||
"gate":
|
"gate":
|
||||||
_camp_pres.on_camp_closed() # 冒险发起后营地场景屏隐藏(选档层同收——卡④ T4 关层收闭)
|
camp_pres().on_camp_closed() # 冒险发起后营地场景屏隐藏(选档层同收——卡④ T4 关层收闭)
|
||||||
_resume_from_menu() # 继续上一段冒险(现役续玩编排同源——卡④ 契约 4)
|
_resume_from_menu() # 继续上一段冒险(现役续玩编排同源——卡④ 契约 4)
|
||||||
"gate_new":
|
"gate_new":
|
||||||
_camp_pres.on_camp_closed()
|
camp_pres().on_camp_closed()
|
||||||
_start_adventure() # 开始新冒险(现役开局编排同源)
|
_start_adventure() # 开始新冒险(现役开局编排同源)
|
||||||
"campfire_leave":
|
"campfire_leave":
|
||||||
_camp_pres.on_camp_closed() # 篝火确认离场=营地与选档层同收+开始层恢复(回主菜单)
|
camp_pres().on_camp_closed() # 篝火确认离场=营地与选档层同收+开始层恢复(回主菜单)
|
||||||
_confirm_consumer = ""
|
_confirm_consumer = ""
|
||||||
|
|
||||||
|
|
||||||
@@ -137,7 +220,7 @@ func _on_confirm_secondary() -> void:
|
|||||||
ui.flow.close(ui.modals.menu.confirm_dialog) # 模态栈单口
|
ui.flow.close(ui.modals.menu.confirm_dialog) # 模态栈单口
|
||||||
match _confirm_consumer:
|
match _confirm_consumer:
|
||||||
"gate":
|
"gate":
|
||||||
_camp_pres.on_camp_closed()
|
camp_pres().on_camp_closed()
|
||||||
_start_adventure()
|
_start_adventure()
|
||||||
_confirm_consumer = ""
|
_confirm_consumer = ""
|
||||||
|
|
||||||
@@ -148,7 +231,7 @@ func _on_confirm_declined() -> void:
|
|||||||
|
|
||||||
|
|
||||||
# 退出游戏(一级菜单入口;设置即时落盘后退出)
|
# 退出游戏(一级菜单入口;设置即时落盘后退出)
|
||||||
func _quit_game() -> void:
|
func quit_game() -> void:
|
||||||
if settings_store != null:
|
if settings_store != null:
|
||||||
settings_store.save_settings()
|
settings_store.save_settings()
|
||||||
get_tree().quit()
|
get_tree().quit()
|
||||||
@@ -161,23 +244,26 @@ func _resume_from_menu() -> void:
|
|||||||
var bp: Dictionary[Variant, Variant] = save_manager.breakpoint_snapshot()
|
var bp: Dictionary[Variant, Variant] = save_manager.breakpoint_snapshot()
|
||||||
ui.flow.close(ui.modals.menu.debug_overlay) # 开冒险路径显式关浮窗(续玩同口径)
|
ui.flow.close(ui.modals.menu.debug_overlay) # 开冒险路径显式关浮窗(续玩同口径)
|
||||||
ui.screens.start_overlay.visible = false
|
ui.screens.start_overlay.visible = false
|
||||||
_begin_session(true)
|
begin_session(true)
|
||||||
_wire_adventure()
|
_wire_adventure()
|
||||||
run_scope.level_active = true
|
run_scope.level_active = true
|
||||||
_sync_status_entry() # 续玩恢复点亮状态面板入口角标
|
sync_status_entry() # 续玩恢复点亮状态面板入口角标
|
||||||
ui.modals.run.level_screen.set_abandon_available(true)
|
ui.modals.run.level_screen.set_abandon_available(true)
|
||||||
ui.battle.log_view.clear()
|
ui.battle.log_view.clear()
|
||||||
logger.start_session(int(bp.get("master_seed", 0)))
|
logger.start_session(int(bp.get("master_seed", 0)))
|
||||||
run_scope.adventure.set_hero_override(ui.modals.menu.debug_overlay.atk_pct(), ui.modals.menu.debug_overlay.hp_pct())
|
run_scope.adventure.set_hero_override(ui.modals.menu.debug_overlay.atk_pct(), ui.modals.menu.debug_overlay.hp_pct())
|
||||||
# 同调三键随续玩下传(build_adventure_params 统一构造,与开新局同源同口径)
|
# 同调三键随续玩下传(build_adventure_params 统一构造,与开新局同源同口径)
|
||||||
if not run_scope.adventure.resume_adventure(bp, build_adventure_params(save_manager, meta,
|
if not run_scope.adventure.resume_adventure(bp, build_adventure_params(save_manager, meta,
|
||||||
{"treasure_unlocked": _treasure_ui.unlocked_set()})):
|
{"treasure_unlocked": treasure_ui().unlocked_set()})):
|
||||||
_fatal_screen("续玩恢复失败——见输出日志")
|
fatal_screen("续玩恢复失败——见输出日志")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
func _wire_adventure() -> void:
|
func _wire_adventure() -> void:
|
||||||
MainAdventureFlow._wire_adventure(self)
|
MainAdventureFlow.wire_adventure(self, {
|
||||||
|
"adventure_finished": _on_adventure_finished,
|
||||||
|
"level_started": _on_adventure_level_started,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
# 冒险开局参数面构造(主菜单开新/续玩两入口共用:同调三键随开局下传。
|
# 冒险开局参数面构造(主菜单开新/续玩两入口共用:同调三键随开局下传。
|
||||||
@@ -205,59 +291,66 @@ static func build_adventure_params(save_manager_ref: SaveManagerCore, meta_ref:
|
|||||||
# 信号连接只在组合根)
|
# 信号连接只在组合根)
|
||||||
func _start_adventure() -> void:
|
func _start_adventure() -> void:
|
||||||
ui.flow.close(ui.modals.menu.debug_overlay) # 开冒险路径显式关浮窗(调试浮窗默认开态下开局不带窗;对局中经角标再开)
|
ui.flow.close(ui.modals.menu.debug_overlay) # 开冒险路径显式关浮窗(调试浮窗默认开态下开局不带窗;对局中经角标再开)
|
||||||
_begin_session(true)
|
begin_session(true)
|
||||||
_wire_adventure()
|
_wire_adventure()
|
||||||
run_scope.level_active = true
|
run_scope.level_active = true
|
||||||
_sync_status_entry() # 进对局点亮状态面板入口角标
|
sync_status_entry() # 进对局点亮状态面板入口角标
|
||||||
ui.modals.run.level_screen.set_abandon_available(true) # 放弃入口挂选路停点(天然非战斗期)
|
ui.modals.run.level_screen.set_abandon_available(true) # 放弃入口挂选路停点(天然非战斗期)
|
||||||
ui.battle.log_view.clear()
|
ui.battle.log_view.clear()
|
||||||
var seed_val := _seed_value()
|
var seed_val := seed_value()
|
||||||
logger.start_session(seed_val)
|
logger.start_session(seed_val)
|
||||||
run_scope.adventure.set_hero_override(ui.modals.menu.debug_overlay.atk_pct(), ui.modals.menu.debug_overlay.hp_pct())
|
run_scope.adventure.set_hero_override(ui.modals.menu.debug_overlay.atk_pct(), ui.modals.menu.debug_overlay.hp_pct())
|
||||||
# 永久强化注入:冒险开始参数面——meta 现算 override 显式传参(全零 = 白板)
|
# 永久强化注入:冒险开始参数面——meta 现算 override 显式传参(全零 = 白板)
|
||||||
# 开局参数面(同调三键同源构造——确定性承载=固定种子+参数档,首局教学图由种子域三分判定给 42)
|
# 开局参数面(同调三键同源构造——确定性承载=固定种子+参数档,首局教学图由种子域三分判定给 42)
|
||||||
if not run_scope.adventure.start_adventure(seed_val, build_adventure_params(save_manager, meta,
|
if not run_scope.adventure.start_adventure(seed_val, build_adventure_params(save_manager, meta,
|
||||||
{"treasure_unlocked": _treasure_ui.unlocked_set(), "shop_mode": "pool"})):
|
{"treasure_unlocked": treasure_ui().unlocked_set(), "shop_mode": "pool"})):
|
||||||
_fatal_screen("冒险启动失败——见输出日志")
|
fatal_screen("冒险启动失败——见输出日志")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
func _on_adventure_level_started(level_index: int, display_name: String)-> void:
|
func _on_adventure_level_started(level_index: int, display_name: String)-> void:
|
||||||
MainAdventureFlow._on_adventure_level_started(self, level_index, display_name)
|
MainAdventureFlow.on_adventure_level_started(self, level_index, display_name, {
|
||||||
|
"step_row": _on_step_row,
|
||||||
|
"round_started": _on_round_started,
|
||||||
|
"board_changed": _on_board_changed,
|
||||||
|
"runner_node": _on_runner_node,
|
||||||
|
"choices_presented": _on_choices_presented,
|
||||||
|
"wallet_changed": _on_wallet_changed,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
func _on_runner_node(node: Dictionary, info: Dictionary)-> void:
|
func _on_runner_node(node: Dictionary, info: Dictionary)-> void:
|
||||||
MainAdventureFlow._on_runner_node(self, node, info)
|
MainAdventureFlow.on_runner_node(self, node, info)
|
||||||
|
|
||||||
|
|
||||||
func _on_adventure_finished(summary: Dictionary)-> void:
|
func _on_adventure_finished(summary: Dictionary)-> void:
|
||||||
MainAdventureFlow._on_adventure_finished(self, summary)
|
MainAdventureFlow.on_adventure_finished(self, summary)
|
||||||
|
|
||||||
|
|
||||||
func _on_battle_end_continue() -> void:
|
func _on_battle_end_continue() -> void:
|
||||||
MainAdventureFlow._on_battle_end_continue(self)
|
MainAdventureFlow.on_battle_end_continue(self)
|
||||||
|
|
||||||
|
|
||||||
func _start_debug_levels() -> void:
|
func start_debug_levels() -> void:
|
||||||
MainDebugFlow._start_debug_levels(self)
|
MainDebugFlow.start_debug_levels(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_debug_battle_created(settlement_ref: BattleOrchestrator, _level: int, _carry: int)-> void:
|
func _on_debug_battle_created(settlement_ref: BattleOrchestrator, _level: int, _carry: int)-> void:
|
||||||
MainDebugFlow._on_debug_battle_created(self, settlement_ref, _level, _carry)
|
MainDebugFlow.on_debug_battle_created(self, settlement_ref, _level, _carry)
|
||||||
|
|
||||||
|
|
||||||
func _on_debug_battle_ready(settlement_ref: BattleOrchestrator, _level: int, _carry: int)-> void:
|
func _on_debug_battle_ready(settlement_ref: BattleOrchestrator, _level: int, _carry: int)-> void:
|
||||||
MainDebugFlow._on_debug_battle_ready(self, settlement_ref, _level, _carry)
|
MainDebugFlow.on_debug_battle_ready(self, settlement_ref, _level, _carry)
|
||||||
|
|
||||||
|
|
||||||
func _on_inter_next_pressed() -> void:
|
func _on_inter_next_pressed() -> void:
|
||||||
MainAdventureFlow._on_inter_next_pressed(self)
|
MainAdventureFlow.on_inter_next_pressed(self)
|
||||||
|
|
||||||
|
|
||||||
# 加成生效值供给 / 奖励徽章身份解析 / 地形变异两种解析 —— 见 board_resolvers.gd(有态绑定族判离)
|
# 加成生效值供给 / 奖励徽章身份解析 / 地形变异两种解析 —— 见 board_resolvers.gd(有态绑定族判离)
|
||||||
|
|
||||||
|
|
||||||
func _show_board_fx_for_node(node_type: String = "") -> void:
|
func show_board_fx_for_node(node_type: String = "") -> void:
|
||||||
# Boss 遭遇变体:紫赤影子爬棋盘一次性占位演出(§2.6)
|
# Boss 遭遇变体:紫赤影子爬棋盘一次性占位演出(§2.6)
|
||||||
if node_type == "boss":
|
if node_type == "boss":
|
||||||
ui.battle.board_zone.fx.play_boss_shadow()
|
ui.battle.board_zone.fx.play_boss_shadow()
|
||||||
@@ -266,15 +359,15 @@ func _show_board_fx_for_node(node_type: String = "") -> void:
|
|||||||
func _on_battle_finished(payload: Dictionary) -> void:
|
func _on_battle_finished(payload: Dictionary) -> void:
|
||||||
# 仅调试模式接线(冒险的关卡结束归 AdventureRunner._on_level_finished——大奖励/冒险终局分派)
|
# 仅调试模式接线(冒险的关卡结束归 AdventureRunner._on_level_finished——大奖励/冒险终局分派)
|
||||||
var result: String = String(payload.get("result", ""))
|
var result: String = String(payload.get("result", ""))
|
||||||
_sync_settlement_visuals() # → 全关(battle_over 反馈面)
|
sync_settlement_visuals() # → 全关(battle_over 反馈面)
|
||||||
HudPresenter.battle_end_feedback(ui.battle.stage, ui.battle.board_zone.ap_bar, true) # 灰化/idle 回正/RAP 清零/状态全清——HUD 单通道
|
HudPresenter.battle_end_feedback(ui.battle.stage, ui.battle.board_zone.ap_bar, true) # 灰化/idle 回正/RAP 清零/状态全清——HUD 单通道
|
||||||
var decision: Dictionary[Variant, Variant] = _debug.on_battle_finished(payload)
|
var decision: Dictionary[Variant, Variant] = debug().on_battle_finished(payload)
|
||||||
match String(decision.outcome):
|
match String(decision.outcome):
|
||||||
"next_layer":
|
"next_layer":
|
||||||
ui.screens.inter_label.text = "第 %d 层通过!\nHP %d/%d 带入下一层" % [
|
ui.screens.inter_label.text = "第 %d 层通过!\nHP %d/%d 带入下一层" % [
|
||||||
int(decision.layer), int(decision.carry_hp), int(db.combat.hero.max_hp)]
|
int(decision.layer), int(decision.carry_hp), int(db.combat.hero.max_hp)]
|
||||||
ui.screens.inter_overlay.visible = true
|
ui.screens.inter_overlay.visible = true
|
||||||
_refresh_presentations()
|
refresh_presentations()
|
||||||
return
|
return
|
||||||
"level_end":
|
"level_end":
|
||||||
ui.modals.run.end_overlay.open_victory(Narrator.battle_end_text("victory", true),
|
ui.modals.run.end_overlay.open_victory(Narrator.battle_end_text("victory", true),
|
||||||
@@ -287,7 +380,7 @@ func _on_battle_finished(payload: Dictionary) -> void:
|
|||||||
ui.modals.run.end_overlay.open_defeat(Narrator.battle_end_text("defeat", false),
|
ui.modals.run.end_overlay.open_defeat(Narrator.battle_end_text("defeat", false),
|
||||||
"返回", ui.battle.board_zone.board_view.get_global_rect())
|
"返回", ui.battle.board_zone.board_view.get_global_rect())
|
||||||
ui.flow.open_after_playback(ui.modals.run.end_overlay)
|
ui.flow.open_after_playback(ui.modals.run.end_overlay)
|
||||||
_refresh_presentations()
|
refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
# 战利品行装配(battle.md OQ14——胜利总结结算展示 GP 总量+增量;纯呈现读数):
|
# 战利品行装配(battle.md OQ14——胜利总结结算展示 GP 总量+增量;纯呈现读数):
|
||||||
@@ -297,7 +390,7 @@ func _on_battle_finished(payload: Dictionary) -> void:
|
|||||||
# resume_adventure 的 bonus_pending 分支在 level_started 之前同步 curio_choice_presented.emit
|
# resume_adventure 的 bonus_pending 分支在 level_started 之前同步 curio_choice_presented.emit
|
||||||
# 〔resume 提前 return〕,本 lambda 求值时 runner 尚未赋值;合计改读断点快照 gp 兜底——恢复源快照
|
# 〔resume 提前 return〕,本 lambda 求值时 runner 尚未赋值;合计改读断点快照 gp 兜底——恢复源快照
|
||||||
# 此刻必在档,语义=续玩恢复面的合计即存档合计;承接体见 HudPresenter.gp_summary_text)
|
# 此刻必在档,语义=续玩恢复面的合计即存档合计;承接体见 HudPresenter.gp_summary_text)
|
||||||
func _gp_summary_text(payload: Dictionary) -> String:
|
func gp_summary_text(payload: Dictionary) -> String:
|
||||||
return HudPresenter.gp_summary_text(payload, run_scope.runner, save_manager)
|
return HudPresenter.gp_summary_text(payload, run_scope.runner, save_manager)
|
||||||
|
|
||||||
|
|
||||||
@@ -306,12 +399,12 @@ func _gp_summary_text(payload: Dictionary) -> String:
|
|||||||
|
|
||||||
## 战末账行束(open_victory opts 键装配单点——GP/钥石/加成三行与增量合计)
|
## 战末账行束(open_victory opts 键装配单点——GP/钥石/加成三行与增量合计)
|
||||||
func _end_victory_opts(payload: Dictionary) -> Dictionary:
|
func _end_victory_opts(payload: Dictionary) -> Dictionary:
|
||||||
return {"gp_summary": _gp_summary_text(payload),
|
return {"gp_summary": gp_summary_text(payload),
|
||||||
"ks_summary": "钥石 · 累计 %d" % run_scope.runner.keystone,
|
"ks_summary": "钥石 · 累计 %d" % run_scope.runner.keystone,
|
||||||
"bonus_summary": HudPresenter.bonus_summary_text(run_scope.runner),
|
"bonus_summary": HudPresenter.bonus_summary_text(run_scope.runner),
|
||||||
"gp_gain": int(payload.get("gp_dropped", 0)), "gp_total": int(run_scope.runner.gp)}
|
"gp_gain": int(payload.get("gp_dropped", 0)), "gp_total": int(run_scope.runner.gp)}
|
||||||
|
|
||||||
func _wire_battle(settlement_ref: BattleOrchestrator) -> void:
|
func wire_battle(settlement_ref: BattleOrchestrator) -> void:
|
||||||
settlement_ref.step_row.connect(_on_step_row)
|
settlement_ref.step_row.connect(_on_step_row)
|
||||||
settlement_ref.battle_finished.connect(_on_battle_finished)
|
settlement_ref.battle_finished.connect(_on_battle_finished)
|
||||||
settlement_ref.round_started.connect(_on_round_started)
|
settlement_ref.round_started.connect(_on_round_started)
|
||||||
@@ -363,7 +456,7 @@ func _on_round_started(ri: int) -> void:
|
|||||||
var vlines: Array[String] = HudPresenter.board_variant_lines(db, bvs)
|
var vlines: Array[String] = HudPresenter.board_variant_lines(db, bvs)
|
||||||
if not vlines.is_empty():
|
if not vlines.is_empty():
|
||||||
ui.battle.settlement_fx.play_board_variant_banner("地形变异 · " + " · ".join(vlines))
|
ui.battle.settlement_fx.play_board_variant_banner("地形变异 · " + " · ".join(vlines))
|
||||||
_refresh_presentations()
|
refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
func _on_board_changed() -> void:
|
func _on_board_changed() -> void:
|
||||||
@@ -376,8 +469,8 @@ func _on_board_changed() -> void:
|
|||||||
ui.battle.board_zone.board_view.rebuild(board, run_scope.settlement.minesweeper)
|
ui.battle.board_zone.board_view.rebuild(board, run_scope.settlement.minesweeper)
|
||||||
if board != null:
|
if board != null:
|
||||||
ui.battle.stage.set_board_type(String(board.board_type)) # 舞台背景选图随板(C8——既有重建点单行同步)
|
ui.battle.stage.set_board_type(String(board.board_type)) # 舞台背景选图随板(C8——既有重建点单行同步)
|
||||||
_check_board_hints()
|
check_board_hints()
|
||||||
_refresh_presentations()
|
refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
# 秘宝视野呈现桥:阔视野带 light_radius_bonus
|
# 秘宝视野呈现桥:阔视野带 light_radius_bonus
|
||||||
@@ -392,7 +485,7 @@ func _sync_treasure_glow() -> void:
|
|||||||
|
|
||||||
# ---- 一次性非模态提示(每 run 一次——pattern 10)与诚实提示 ----
|
# ---- 一次性非模态提示(每 run 一次——pattern 10)与诚实提示 ----
|
||||||
|
|
||||||
func _check_board_hints() -> void:
|
func check_board_hints() -> void:
|
||||||
var board = run_scope.settlement.minesweeper.current_board()
|
var board = run_scope.settlement.minesweeper.current_board()
|
||||||
if board == null:
|
if board == null:
|
||||||
return
|
return
|
||||||
@@ -423,15 +516,15 @@ func _show_hint(text: String, hint_id: String) -> void:
|
|||||||
# ---- 节点覆盖层"继续"(奖励/恢复点兑付确认)与节点图选路覆盖层 ----
|
# ---- 节点覆盖层"继续"(奖励/恢复点兑付确认)与节点图选路覆盖层 ----
|
||||||
|
|
||||||
func _on_node_continue() -> void:
|
func _on_node_continue() -> void:
|
||||||
MainAdventureFlow._on_node_continue(self)
|
MainAdventureFlow.on_node_continue(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_choices_presented(candidates: Array)-> void:
|
func _on_choices_presented(candidates: Array)-> void:
|
||||||
MainAdventureFlow._on_choices_presented(self, candidates)
|
MainAdventureFlow.on_choices_presented(self, candidates)
|
||||||
|
|
||||||
|
|
||||||
func _on_route_chosen(node_id: int)-> void:
|
func _on_route_chosen(node_id: int)-> void:
|
||||||
MainAdventureFlow._on_route_chosen(self, node_id)
|
MainAdventureFlow.on_route_chosen(self, node_id)
|
||||||
|
|
||||||
|
|
||||||
# ---- 独立屏屏级互斥(单一出口:进屏隐战斗屏 / 出屏显战斗屏)----
|
# ---- 独立屏屏级互斥(单一出口:进屏隐战斗屏 / 出屏显战斗屏)----
|
||||||
@@ -439,86 +532,86 @@ func _on_route_chosen(node_id: int)-> void:
|
|||||||
# 关闭自动恢复本屏(遮挡语义复用),战斗屏不在此期间回显。
|
# 关闭自动恢复本屏(遮挡语义复用),战斗屏不在此期间回显。
|
||||||
|
|
||||||
func _enter_level_screen() -> void:
|
func _enter_level_screen() -> void:
|
||||||
MainAdventureFlow._enter_level_screen(self)
|
MainAdventureFlow.enter_level_screen(self)
|
||||||
|
|
||||||
|
|
||||||
func _exit_level_screen() -> void:
|
func _exit_level_screen() -> void:
|
||||||
MainAdventureFlow._exit_level_screen(self)
|
MainAdventureFlow.exit_level_screen(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_abandon_requested() -> void:
|
func _on_abandon_requested() -> void:
|
||||||
MainAdventureFlow._on_abandon_requested(self)
|
MainAdventureFlow.on_abandon_requested(self)
|
||||||
|
|
||||||
|
|
||||||
# ---- 最小设置面(入口/开合仿营地先例:开始层互斥;生效与持久化归 SettingsStore)----
|
# ---- 最小设置面(入口/开合仿营地先例:开始层互斥;生效与持久化归 SettingsStore)----
|
||||||
|
|
||||||
func _open_settings() -> void:
|
func open_settings() -> void:
|
||||||
MainOverlayFlow._open_settings(self)
|
MainOverlayFlow.open_settings(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_settings_closed() -> void:
|
func _on_settings_closed() -> void:
|
||||||
MainOverlayFlow._on_settings_closed(self)
|
MainOverlayFlow.on_settings_closed(self)
|
||||||
|
|
||||||
|
|
||||||
func _status_data() -> Dictionary:
|
func status_data() -> Dictionary:
|
||||||
return MainOverlayFlow._status_data(self)
|
return MainOverlayFlow.status_data(self)
|
||||||
|
|
||||||
|
|
||||||
func _open_status_panel() -> void:
|
func _open_status_panel() -> void:
|
||||||
MainOverlayFlow._open_status_panel(self)
|
MainOverlayFlow.open_status_panel(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_status_closed() -> void:
|
func _on_status_closed() -> void:
|
||||||
MainOverlayFlow._on_status_closed(self)
|
MainOverlayFlow.on_status_closed(self)
|
||||||
|
|
||||||
|
|
||||||
# ---- 生涯页·只读(入口=开始层生涯钮;开合仿设置面先例:开始层互斥;
|
# ---- 生涯页·只读(入口=开始层生涯钮;开合仿设置面先例:开始层互斥;
|
||||||
# 数据快照随开随建零写通路,页内零跳转)----
|
# 数据快照随开随建零写通路,页内零跳转)----
|
||||||
|
|
||||||
func _open_career() -> void:
|
func _open_career() -> void:
|
||||||
MainOverlayFlow._open_career(self)
|
MainOverlayFlow.open_career(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_career_closed() -> void:
|
func _on_career_closed() -> void:
|
||||||
MainOverlayFlow._on_career_closed(self)
|
MainOverlayFlow.on_career_closed(self)
|
||||||
|
|
||||||
|
|
||||||
func _open_save_select() -> void:
|
func open_save_select() -> void:
|
||||||
MainOverlayFlow._open_save_select(self)
|
MainOverlayFlow.open_save_select(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_save_select_closed() -> void:
|
func _on_save_select_closed() -> void:
|
||||||
MainOverlayFlow._on_save_select_closed(self)
|
MainOverlayFlow.on_save_select_closed(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_save_select_new(slot: int)-> void:
|
func _on_save_select_new(slot: int)-> void:
|
||||||
MainOverlayFlow._on_save_select_new(self, slot)
|
MainOverlayFlow.on_save_select_new(self, slot)
|
||||||
|
|
||||||
|
|
||||||
func _on_save_select_load(slot: int)-> void:
|
func _on_save_select_load(slot: int)-> void:
|
||||||
MainOverlayFlow._on_save_select_load(self, slot)
|
MainOverlayFlow.on_save_select_load(self, slot)
|
||||||
|
|
||||||
|
|
||||||
func _on_save_select_delete(slot: int)-> void:
|
func _on_save_select_delete(slot: int)-> void:
|
||||||
MainOverlayFlow._on_save_select_delete(self, slot)
|
MainOverlayFlow.on_save_select_delete(self, slot)
|
||||||
|
|
||||||
|
|
||||||
func _on_status_badge_pressed() -> void:
|
func _on_status_badge_pressed() -> void:
|
||||||
MainOverlayFlow._on_status_badge_pressed(self)
|
MainOverlayFlow.on_status_badge_pressed(self)
|
||||||
|
|
||||||
|
|
||||||
func _sync_status_entry() -> void:
|
func sync_status_entry() -> void:
|
||||||
MainOverlayFlow._sync_status_entry(self)
|
MainOverlayFlow.sync_status_entry(self)
|
||||||
|
|
||||||
|
|
||||||
# ---- 探针缝保缝(click/ui_probe 营地段直呼组合根面;实现归 camp_shop_presenter.gd / main_overlay_flow.gd)----
|
# ---- 探针缝保缝(click/ui_probe 营地段直呼组合根面;实现归 camp_shop_presenter.gd / main_overlay_flow.gd)----
|
||||||
|
|
||||||
func _on_camp_closed() -> void:
|
func _on_camp_closed() -> void:
|
||||||
MainOverlayFlow._on_camp_closed(self)
|
MainOverlayFlow.on_camp_closed(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_camp_object_pressed(key: StringName) -> void:
|
func _on_camp_object_pressed(key: StringName) -> void:
|
||||||
MainOverlayFlow._on_camp_object_pressed(self, key) # 场景点选路由(卡④ T3——薄委托,实现归覆盖层流程承接件)
|
MainOverlayFlow.on_camp_object_pressed(self, key) # 场景点选路由(卡④ T3——薄委托,实现归覆盖层流程承接件)
|
||||||
|
|
||||||
|
|
||||||
# Esc 输入入口(产品码首个键盘入口——卡⑤ T1 契约 9 接线定稿:事件驱动 _unhandled_input、
|
# Esc 输入入口(产品码首个键盘入口——卡⑤ T1 契约 9 接线定稿:事件驱动 _unhandled_input、
|
||||||
@@ -529,23 +622,23 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _on_esc_return() -> void:
|
func _on_esc_return() -> void:
|
||||||
MainEscFlow._on_return_to_menu(self)
|
MainEscFlow.on_return_to_menu(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_esc_settings() -> void:
|
func _on_esc_settings() -> void:
|
||||||
MainEscFlow._on_settings(self)
|
MainEscFlow.on_settings(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_esc_quit() -> void:
|
func _on_esc_quit() -> void:
|
||||||
MainEscFlow._on_quit(self)
|
MainEscFlow.on_quit(self)
|
||||||
|
|
||||||
|
|
||||||
func _camp_data() -> Dictionary:
|
func _camp_data() -> Dictionary:
|
||||||
return MainOverlayFlow._camp_data(self)
|
return MainOverlayFlow.camp_data(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_wallet_changed(event: String, gp: int, extra: Dictionary)-> void:
|
func _on_wallet_changed(event: String, gp: int, extra: Dictionary)-> void:
|
||||||
MainOverlayFlow._on_wallet_changed(self, event, gp, extra)
|
MainOverlayFlow.on_wallet_changed(self, event, gp, extra)
|
||||||
|
|
||||||
|
|
||||||
# ==================== 玩家意图 → 核心写调用(唯一出口)====================
|
# ==================== 玩家意图 → 核心写调用(唯一出口)====================
|
||||||
@@ -565,9 +658,9 @@ func _on_board_action(cell: Vector2i, kind: String) -> void:
|
|||||||
return
|
return
|
||||||
# 秘宝选中态劫持(两步交互第二步):点格=使用目标拾取,不落挖格;
|
# 秘宝选中态劫持(两步交互第二步):点格=使用目标拾取,不落挖格;
|
||||||
# 只劫持挖掘点击(move/seal 语义不冲突——选中期玩家仍可移动/封印)
|
# 只劫持挖掘点击(move/seal 语义不冲突——选中期玩家仍可移动/封印)
|
||||||
var treasure_sel: int = _treasure_ui.active_selection()
|
var treasure_sel: int = treasure_ui().active_selection()
|
||||||
if treasure_sel != 0 and kind == "dig":
|
if treasure_sel != 0 and kind == "dig":
|
||||||
_treasure_ui.attempt_use(treasure_sel, cell)
|
treasure_ui().attempt_use(treasure_sel, cell)
|
||||||
return
|
return
|
||||||
if run_scope.settlement == null:
|
if run_scope.settlement == null:
|
||||||
return # 入口显式空防护(双保险——锁谓词正常态已挡,防锁判据异常时崩于空引用)
|
return # 入口显式空防护(双保险——锁谓词正常态已挡,防锁判据异常时崩于空引用)
|
||||||
@@ -575,7 +668,7 @@ func _on_board_action(cell: Vector2i, kind: String) -> void:
|
|||||||
var accepted: bool = not outcomes.is_empty() and bool(outcomes[0].accepted)
|
var accepted: bool = not outcomes.is_empty() and bool(outcomes[0].accepted)
|
||||||
logger.log_action(kind, cell, accepted)
|
logger.log_action(kind, cell, accepted)
|
||||||
if run_scope.runner != null and run_scope.runner.treasure_inventory != null:
|
if run_scope.runner != null and run_scope.runner.treasure_inventory != null:
|
||||||
_treasure_ui.refresh_slots() # 授予发生在 settle_batch 结算段内(同步走完,行尾重查)
|
treasure_ui().refresh_slots() # 授予发生在 settle_batch 结算段内(同步走完,行尾重查)
|
||||||
_handle_outcome_feedback(outcomes[0] if not outcomes.is_empty() else {})
|
_handle_outcome_feedback(outcomes[0] if not outcomes.is_empty() else {})
|
||||||
# settle_batch 内部同步走完 结算→战斗结束→关卡推进(事件同步发射)——关卡终局时 settlement 已被
|
# settle_batch 内部同步走完 结算→战斗结束→关卡推进(事件同步发射)——关卡终局时 settlement 已被
|
||||||
# runner 置空,清图演出判定须先判 settlement(重入隐患守卫)
|
# runner 置空,清图演出判定须先判 settlement(重入隐患守卫)
|
||||||
@@ -591,7 +684,7 @@ func _on_board_action(cell: Vector2i, kind: String) -> void:
|
|||||||
elif accepted and kind == "move":
|
elif accepted and kind == "move":
|
||||||
ui.battle.board_zone.board_view.notify_hero_move() # 原地移动(目标=当前格幂等受理)帧闪回执——refresh diff 前置告知
|
ui.battle.board_zone.board_view.notify_hero_move() # 原地移动(目标=当前格幂等受理)帧闪回执——refresh diff 前置告知
|
||||||
ui.battle.board_zone.board_view.refresh()
|
ui.battle.board_zone.board_view.refresh()
|
||||||
_refresh_presentations()
|
refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
func _on_stop_pressed() -> void:
|
func _on_stop_pressed() -> void:
|
||||||
@@ -607,7 +700,7 @@ func _on_stop_pressed() -> void:
|
|||||||
ui.battle.board_zone.toast.show_toast("本轮已清图,停手未执行 · 剩余 AP 已作废", "warn")
|
ui.battle.board_zone.toast.show_toast("本轮已清图,停手未执行 · 剩余 AP 已作废", "warn")
|
||||||
logger.log_ux("ux_reject", {"source": "voided", "sub_reason": "stop_voided"})
|
logger.log_ux("ux_reject", {"source": "voided", "sub_reason": "stop_voided"})
|
||||||
ui.battle.board_zone.board_view.refresh()
|
ui.battle.board_zone.board_view.refresh()
|
||||||
_refresh_presentations()
|
refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
func _on_refresh_confirmed() -> void:
|
func _on_refresh_confirmed() -> void:
|
||||||
@@ -635,7 +728,7 @@ func _on_refresh_confirmed() -> void:
|
|||||||
else:
|
else:
|
||||||
ui.battle.board_zone.toast.show_toast("本轮刷新次数已用完(每轮 %d 次)" % int(db.run.action_economy.refresh_cap_per_round), "warn")
|
ui.battle.board_zone.toast.show_toast("本轮刷新次数已用完(每轮 %d 次)" % int(db.run.action_economy.refresh_cap_per_round), "warn")
|
||||||
ui.battle.board_zone.board_view.refresh()
|
ui.battle.board_zone.board_view.refresh()
|
||||||
_refresh_presentations()
|
refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
func _handle_outcome_feedback(outcome: Dictionary) -> void:
|
func _handle_outcome_feedback(outcome: Dictionary) -> void:
|
||||||
@@ -659,15 +752,15 @@ func _refresh_used_snapshot() -> int:
|
|||||||
return int(run_scope.settlement.presentation_snapshot().get("refresh_used", 0))
|
return int(run_scope.settlement.presentation_snapshot().get("refresh_used", 0))
|
||||||
|
|
||||||
|
|
||||||
func _refresh_presentations() -> void:
|
func refresh_presentations() -> void:
|
||||||
# 每个核心信号/写调用返回后的全量重查装配(更新触发注记——无推送信号,命令式重查)
|
# 每个核心信号/写调用返回后的全量重查装配(更新触发注记——无推送信号,命令式重查)
|
||||||
var refresh_remaining: int = maxi(0, int(db.run.action_economy.refresh_cap_per_round) - _refresh_used_snapshot())
|
var refresh_remaining: int = maxi(0, int(db.run.action_economy.refresh_cap_per_round) - _refresh_used_snapshot())
|
||||||
HudPresenter.refresh(ui.battle.stage, ui.battle.info_panel, ui.battle.board_zone.ap_bar, {"settlement": run_scope.settlement, "runner": run_scope.runner, "level_active": run_scope.level_active, "db": db, "refresh_remaining": refresh_remaining})
|
HudPresenter.refresh(ui.battle.stage, ui.battle.info_panel, ui.battle.board_zone.ap_bar, {"settlement": run_scope.settlement, "runner": run_scope.runner, "level_active": run_scope.level_active, "db": db, "refresh_remaining": refresh_remaining})
|
||||||
_treasure_ui.refresh_slots() # C 区秘宝槽重查(试炼镐积点进度随挖格刷新悬停浮窗)
|
treasure_ui().refresh_slots() # C 区秘宝槽重查(试炼镐积点进度随挖格刷新悬停浮窗)
|
||||||
_sync_settlement_visuals()
|
sync_settlement_visuals()
|
||||||
|
|
||||||
|
|
||||||
func _sync_settlement_visuals() -> void:
|
func sync_settlement_visuals() -> void:
|
||||||
# 结算阶段(round_end → 下一轮):D 区去饱和+金橙偏移锁输入(明度不变)+ 明细带展开(高度读 battle_layout)
|
# 结算阶段(round_end → 下一轮):D 区去饱和+金橙偏移锁输入(明度不变)+ 明细带展开(高度读 battle_layout)
|
||||||
var settling := _is_settling()
|
var settling := _is_settling()
|
||||||
if settling and not run_scope.was_settling:
|
if settling and not run_scope.was_settling:
|
||||||
@@ -697,56 +790,56 @@ func _is_settling() -> bool:
|
|||||||
# ==================== B 区明细带 / 图例(模态入口)====================
|
# ==================== B 区明细带 / 图例(模态入口)====================
|
||||||
|
|
||||||
func _on_legend_toggled() -> void:
|
func _on_legend_toggled() -> void:
|
||||||
MainOverlayFlow._on_legend_toggled(self)
|
MainOverlayFlow.on_legend_toggled(self)
|
||||||
|
|
||||||
|
|
||||||
# ==================== 诊断转储(卡死时点击——全量核心状态 + 环形缓冲)====================
|
# ==================== 诊断转储(卡死时点击——全量核心状态 + 环形缓冲)====================
|
||||||
|
|
||||||
func _on_diagnose_pressed() -> void:
|
func _on_diagnose_pressed() -> void:
|
||||||
MainDebugFlow._on_diagnose_pressed(self)
|
MainDebugFlow.on_diagnose_pressed(self)
|
||||||
|
|
||||||
|
|
||||||
# ==================== 调试浮窗(开合/应用/模拟编排由组合根承接)====================
|
# ==================== 调试浮窗(开合/应用/模拟编排由组合根承接)====================
|
||||||
|
|
||||||
func _show_debug_overlay() -> void:
|
func _show_debug_overlay() -> void:
|
||||||
MainDebugFlow._show_debug_overlay(self)
|
MainDebugFlow.show_debug_overlay(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_debug_badge_pressed() -> void:
|
func _on_debug_badge_pressed() -> void:
|
||||||
MainDebugFlow._on_debug_badge_pressed(self)
|
MainDebugFlow.on_debug_badge_pressed(self)
|
||||||
|
|
||||||
|
|
||||||
func _sync_debug_overlay() -> void:
|
func sync_debug_overlay() -> void:
|
||||||
MainDebugFlow._sync_debug_overlay(self)
|
MainDebugFlow.sync_debug_overlay(self)
|
||||||
|
|
||||||
|
|
||||||
func _debug_run_data() -> Dictionary:
|
func _debug_run_data() -> Dictionary:
|
||||||
return MainDebugFlow._debug_run_data(self)
|
return MainDebugFlow.debug_run_data(self)
|
||||||
|
|
||||||
|
|
||||||
# 本局种子现值(只读单点——当局数据区块与诊断转储共用):冒险=adventure.master_seed 访问器现值;
|
# 本局种子现值(只读单点——当局数据区块与诊断转储共用):冒险=adventure.master_seed 访问器现值;
|
||||||
# 调试两层=RNG 服务 master_seed。禁 _seed_value() 重算冒充本局种子。
|
# 调试两层=RNG 服务 master_seed。禁 seed_value() 重算冒充本局种子。
|
||||||
func _current_master_seed() -> int:
|
func current_master_seed() -> int:
|
||||||
if run_scope.adventure != null:
|
if run_scope.adventure != null:
|
||||||
return int(run_scope.adventure.master_seed)
|
return int(run_scope.adventure.master_seed)
|
||||||
return int(get_node(AUTOLOAD_PATH_RNG).master_seed)
|
return int(get_node(AUTOLOAD_PATH_RNG).master_seed)
|
||||||
|
|
||||||
|
|
||||||
func _close_debug_overlay() -> void:
|
func _close_debug_overlay() -> void:
|
||||||
MainDebugFlow._close_debug_overlay(self)
|
MainDebugFlow.close_debug_overlay(self)
|
||||||
|
|
||||||
|
|
||||||
func _on_tune_apply(atk_pct: int, hp_pct: int)-> void:
|
func _on_tune_apply(atk_pct: int, hp_pct: int)-> void:
|
||||||
MainDebugFlow._on_tune_apply(self, atk_pct, hp_pct)
|
MainDebugFlow.on_tune_apply(self, atk_pct, hp_pct)
|
||||||
|
|
||||||
|
|
||||||
func _on_tune_simulate(n: int)-> void:
|
func _on_tune_simulate(n: int)-> void:
|
||||||
MainDebugFlow._on_tune_simulate(self, n)
|
MainDebugFlow.on_tune_simulate(self, n)
|
||||||
|
|
||||||
|
|
||||||
# ==================== 工具 ====================
|
# ==================== 工具 ====================
|
||||||
|
|
||||||
func _seed_value() -> int:
|
func seed_value() -> int:
|
||||||
# 种子三分判定单点(全工程唯一种子框读取处,禁第二处读框):
|
# 种子三分判定单点(全工程唯一种子框读取处,禁第二处读框):
|
||||||
# ①显式合法整数全场景优先(含首局——测试/调试接口显式指定;第五路 DebugSession Callable
|
# ①显式合法整数全场景优先(含首局——测试/调试接口显式指定;第五路 DebugSession Callable
|
||||||
# 经本函数=调试对局与玩家同口径);
|
# 经本函数=调试对局与玩家同口径);
|
||||||
|
|||||||
@@ -7,22 +7,22 @@ extends RefCounted
|
|||||||
# 冒险编排构建+接线(开新局/续玩共用——信号连接只在组合根;断点注入同口)。
|
# 冒险编排构建+接线(开新局/续玩共用——信号连接只在组合根;断点注入同口)。
|
||||||
# 信号直连(拆件批 T3):runner 六信号在 level_started 重取点重连(旧实例连接随引用释放消亡——
|
# 信号直连(拆件批 T3):runner 六信号在 level_started 重取点重连(旧实例连接随引用释放消亡——
|
||||||
# is_connected 守卫恰好一次);三选一信号面归停点件(每冒险一次——接线恰一次)。
|
# is_connected 守卫恰好一次);三选一信号面归停点件(每冒险一次——接线恰一次)。
|
||||||
static func _wire_adventure(root: Variant) -> void:
|
static func wire_adventure(root: Variant, handlers: Dictionary) -> void:
|
||||||
root.run_scope.adventure = AdventureRunner.new(root.db, root.get_node(root.AUTOLOAD_PATH_RNG))
|
root.run_scope.adventure = AdventureRunner.new(root.db, root.get_node(root.AUTOLOAD_PATH_RNG))
|
||||||
root.run_scope.adventure.adventure_finished.connect(root._on_adventure_finished)
|
root.run_scope.adventure.adventure_finished.connect(handlers["adventure_finished"])
|
||||||
root.run_scope.adventure.level_started.connect(root._on_adventure_level_started)
|
root.run_scope.adventure.level_started.connect(handlers["level_started"])
|
||||||
root.run_scope.adventure.stop().curio_choice_presented.connect(root._bonus.on_presented)
|
root.run_scope.adventure.stop().curio_choice_presented.connect(root.bonus().on_presented)
|
||||||
root.run_scope.adventure.stop().curio_resolved.connect(root._bonus.on_resolved)
|
root.run_scope.adventure.stop().curio_resolved.connect(root.bonus().on_resolved)
|
||||||
root.run_scope.adventure.set_save_manager(root.save_manager) # 断点承载注入(停点快照写盘;调试/模拟不经过此路径)
|
root.run_scope.adventure.set_save_manager(root.save_manager) # 断点承载注入(停点快照写盘;调试/模拟不经过此路径)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 每关开始(冒险模式):重取 runner 实例 + 层名行(L1 与单关模式同序——层名行随首战横幅后到达;
|
# 每关开始(冒险模式):重取 runner 实例 + 层名行(L1 与单关模式同序——层名行随首战横幅后到达;
|
||||||
# 本回调返回后才有 choices_presented 到达——入口选路层随即弹出)
|
# 本回调返回后才有 choices_presented 到达——入口选路层随即弹出)
|
||||||
static func _on_adventure_level_started(root: Variant, level_index: int, display_name: String) -> void:
|
static func on_adventure_level_started(root: Variant, level_index: int, display_name: String, handlers: Dictionary) -> void:
|
||||||
root.run_scope.runner = root.run_scope.adventure.runner()
|
root.run_scope.runner = root.run_scope.adventure.runner()
|
||||||
# runner 信号直连(拆件批 T3——六转发族退役后的重取点重连;恰好一次断言 sc1 守卫承载)
|
# runner 信号直连(拆件批 T3——六转发族退役后的重取点重连;恰好一次断言 sc1 守卫承载)
|
||||||
_connect_runner_once(root)
|
_connect_runner_once(root, handlers)
|
||||||
# 开场行传当前生效值(runner.effective_atk/effective_max_hp 与战斗面板同源:
|
# 开场行传当前生效值(runner.effective_atk/effective_max_hp 与战斗面板同源:
|
||||||
# 表值+永久强化 flat+加算区 flat 后乘调试浮窗 pct,本回调时点 runner 已带全部加成);「含面板加成」
|
# 表值+永久强化 flat+加算区 flat 后乘调试浮窗 pct,本回调时点 runner 已带全部加成);「含面板加成」
|
||||||
# 后缀判断认任一加成源——永久强化 atk/max_hp flat 或调试浮窗 pct 或局内加算区 atk/max_hp
|
# 后缀判断认任一加成源——永久强化 atk/max_hp flat 或调试浮窗 pct 或局内加算区 atk/max_hp
|
||||||
@@ -37,22 +37,22 @@ static func _on_adventure_level_started(root: Variant, level_index: int, display
|
|||||||
root.run_scope.runner.effective_atk(), root.run_scope.runner.effective_max_hp(), boosted))
|
root.run_scope.runner.effective_atk(), root.run_scope.runner.effective_max_hp(), boosted))
|
||||||
|
|
||||||
# runner 六信号重连(is_connected 守卫——未连即接;守卫失败 push_error=重连恰好一次契约承载)
|
# runner 六信号重连(is_connected 守卫——未连即接;守卫失败 push_error=重连恰好一次契约承载)
|
||||||
static func _connect_runner_once(root: Variant) -> void:
|
static func _connect_runner_once(root: Variant, handlers: Dictionary) -> void:
|
||||||
var r = root.run_scope.runner
|
var r = root.run_scope.runner
|
||||||
if r == null:
|
if r == null:
|
||||||
push_error("[冒险流程] runner 信号重连失败——level_started 后 runner 为空")
|
push_error("[冒险流程] runner 信号重连失败——level_started 后 runner 为空")
|
||||||
return
|
return
|
||||||
var pairs := [
|
var pairs := [
|
||||||
[r.step_row, root._on_step_row], [r.round_started, root._on_round_started],
|
[r.step_row, handlers["step_row"]], [r.round_started, handlers["round_started"]],
|
||||||
[r.board_changed, root._on_board_changed], [r.node_entered, root._on_runner_node],
|
[r.board_changed, handlers["board_changed"]], [r.node_entered, handlers["runner_node"]],
|
||||||
[r.choices_presented, root._on_choices_presented], [r.wallet_changed, root._on_wallet_changed],
|
[r.choices_presented, handlers["choices_presented"]], [r.wallet_changed, handlers["wallet_changed"]],
|
||||||
]
|
]
|
||||||
for pair in pairs:
|
for pair in pairs:
|
||||||
if not (pair[0] as Signal).is_connected(pair[1]):
|
if not (pair[0] as Signal).is_connected(pair[1]):
|
||||||
(pair[0] as Signal).connect(pair[1])
|
(pair[0] as Signal).connect(pair[1])
|
||||||
|
|
||||||
|
|
||||||
static func _on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -> void:
|
static func on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -> void:
|
||||||
# 冒险模式:runner 逐关更替——每次节点事件重取(单关模式幂等);须先于 board_changed 回退读面
|
# 冒险模式:runner 逐关更替——每次节点事件重取(单关模式幂等);须先于 board_changed 回退读面
|
||||||
if root.run_scope.is_adventure and root.run_scope.adventure != null:
|
if root.run_scope.is_adventure and root.run_scope.adventure != null:
|
||||||
root.run_scope.runner = root.run_scope.adventure.runner()
|
root.run_scope.runner = root.run_scope.adventure.runner()
|
||||||
@@ -61,12 +61,12 @@ static func _on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -
|
|||||||
root.run_scope.settlement = root.run_scope.runner.current_battle() # 呈现层统一读 settlement(与调试模式共用接线)
|
root.run_scope.settlement = root.run_scope.runner.current_battle() # 呈现层统一读 settlement(与调试模式共用接线)
|
||||||
root.logger.attach_battle(root.run_scope.settlement)
|
root.logger.attach_battle(root.run_scope.settlement)
|
||||||
root.run_scope.boss_active = t == "boss"
|
root.run_scope.boss_active = t == "boss"
|
||||||
root._show_board_fx_for_node(t)
|
root.show_board_fx_for_node(t)
|
||||||
root.ui.battle.log_view.append_bb(root.Narrator.node_banner(root.run_scope.runner, node, t))
|
root.ui.battle.log_view.append_bb(root.Narrator.node_banner(root.run_scope.runner, node, t))
|
||||||
elif t == "reward":
|
elif t == "reward":
|
||||||
# 奖励节点三选一(与关卡完成三选一共享同池同权重同上限;CurioPickOverlay 共用面)。
|
# 奖励节点三选一(与关卡完成三选一共享同池同权重同上限;CurioPickOverlay 共用面)。
|
||||||
# 呈现编排归 curio_interact_controller.present_node_curio。
|
# 呈现编排归 curio_interact_controller.present_node_curio。
|
||||||
root._bonus.present_node_curio()
|
root.bonus().present_node_curio()
|
||||||
root.ui.battle.log_view.append_bb(root.Narrator.reward_line())
|
root.ui.battle.log_view.append_bb(root.Narrator.reward_line())
|
||||||
elif t == "rest":
|
elif t == "rest":
|
||||||
var healed: int = int(info.get("healed", 0))
|
var healed: int = int(info.get("healed", 0))
|
||||||
@@ -87,20 +87,20 @@ static func _on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -
|
|||||||
root.ui.modals.menu.shop_overlay.set_visit_info(-1, 1.0) # legacy 面无爬价行(off 对照承载)
|
root.ui.modals.menu.shop_overlay.set_visit_info(-1, 1.0) # legacy 面无爬价行(off 对照承载)
|
||||||
root.ui.battle.log_view.append_bb(root.Narrator.shop_line(int(root.run_scope.runner.gp)))
|
root.ui.battle.log_view.append_bb(root.Narrator.shop_line(int(root.run_scope.runner.gp)))
|
||||||
root.logger.log_node(node, info, root.run_scope.runner.node_index)
|
root.logger.log_node(node, info, root.run_scope.runner.node_index)
|
||||||
root._refresh_presentations()
|
root.refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
# ---- 冒险模式终局面(三选一选择面 / 冒险结算屏)----
|
# ---- 冒险模式终局面(三选一选择面 / 冒险结算屏)----
|
||||||
|
|
||||||
|
|
||||||
# 冒险结算(completed/failed/abandoned):复用 BattleEndOverlay——摘要五件事 + 钥石入账明细进文案
|
# 冒险结算(completed/failed/abandoned):复用 BattleEndOverlay——摘要五件事 + 钥石入账明细进文案
|
||||||
static func _on_adventure_finished(root: Variant, summary: Dictionary) -> void:
|
static func on_adventure_finished(root: Variant, summary: Dictionary) -> void:
|
||||||
root.run_scope.level_active = false
|
root.run_scope.level_active = false
|
||||||
var result: String = String(summary.get("result", ""))
|
var result: String = String(summary.get("result", ""))
|
||||||
root.run_scope.settlement = null
|
root.run_scope.settlement = null
|
||||||
_exit_level_screen(root) # 终局兜底:独立屏在开态(放弃入口)也先回战斗屏呈现摘要——屏级互斥单一出口
|
exit_level_screen(root) # 终局兜底:独立屏在开态(放弃入口)也先回战斗屏呈现摘要——屏级互斥单一出口
|
||||||
root._sync_status_entry() # 离局熄灭状态面板入口角标(防菜单误现)
|
root.sync_status_entry() # 离局熄灭状态面板入口角标(防菜单误现)
|
||||||
root._sync_settlement_visuals() # → 全关
|
root.sync_settlement_visuals() # → 全关
|
||||||
HudPresenter.battle_end_feedback(root.ui.battle.stage, root.ui.battle.board_zone.ap_bar, false) # 灰化/idle 回正/状态全清——HUD 单通道
|
HudPresenter.battle_end_feedback(root.ui.battle.stage, root.ui.battle.board_zone.ap_bar, false) # 灰化/idle 回正/状态全清——HUD 单通道
|
||||||
# 存档入账:settle = Boss 两档入账 + 工坊解锁 + 摘要入档 + 写盘(唯一写档点不变——
|
# 存档入账:settle = Boss 两档入账 + 工坊解锁 + 摘要入档 + 写盘(唯一写档点不变——
|
||||||
# 调试两层不经过本处理器,天然不写档不污染生涯数据)。
|
# 调试两层不经过本处理器,天然不写档不污染生涯数据)。
|
||||||
@@ -108,7 +108,7 @@ static func _on_adventure_finished(root: Variant, summary: Dictionary) -> void:
|
|||||||
detail.assign(root.meta.settle_adventure(summary))
|
detail.assign(root.meta.settle_adventure(summary))
|
||||||
var text: String = root.Narrator.adventure_summary_text(summary)
|
var text: String = root.Narrator.adventure_summary_text(summary)
|
||||||
if not detail.is_empty():
|
if not detail.is_empty():
|
||||||
text += "\n" + root.Narrator.keystone_settle_text(detail, root._bonus.item_name_lookup())
|
text += "\n" + root.Narrator.keystone_settle_text(detail, root.bonus().item_name_lookup())
|
||||||
if result == "completed":
|
if result == "completed":
|
||||||
root.ui.modals.run.end_overlay.open_victory(text, "返回冒险", root.ui.battle.board_zone.board_view.get_global_rect(),
|
root.ui.modals.run.end_overlay.open_victory(text, "返回冒险", root.ui.battle.board_zone.board_view.get_global_rect(),
|
||||||
{"gp_summary": "本局 GP 入账 · 合计 %d" % int(summary.get("gp_final", 0))}) # GP 行(取数=summary gp_final 清账前快照);钥石明细已在 text(keystone_settle_text)——三行账
|
{"gp_summary": "本局 GP 入账 · 合计 %d" % int(summary.get("gp_final", 0))}) # GP 行(取数=summary gp_final 清账前快照);钥石明细已在 text(keystone_settle_text)——三行账
|
||||||
@@ -118,52 +118,52 @@ static func _on_adventure_finished(root: Variant, summary: Dictionary) -> void:
|
|||||||
if root.run_scope.runner != null:
|
if root.run_scope.runner != null:
|
||||||
root.run_scope.runner.restore_hero_base()
|
root.run_scope.runner.restore_hero_base()
|
||||||
root.ui.flow.open_after_playback(root.ui.modals.run.end_overlay)
|
root.ui.flow.open_after_playback(root.ui.modals.run.end_overlay)
|
||||||
root._refresh_presentations()
|
root.refresh_presentations()
|
||||||
|
|
||||||
static func _on_battle_end_continue(root: Variant) -> void:
|
static func on_battle_end_continue(root: Variant) -> void:
|
||||||
# 终局出口:返回开始界面(冒险摘要留档试玩日志;钥石在收束时入存档)
|
# 终局出口:返回开始界面(冒险摘要留档试玩日志;钥石在收束时入存档)
|
||||||
root.ui.flow.close(root.ui.modals.run.end_overlay)
|
root.ui.flow.close(root.ui.modals.run.end_overlay)
|
||||||
root.ui.modals.run.end_overlay.close()
|
root.ui.modals.run.end_overlay.close()
|
||||||
# 三选一停点挂起分支:战斗总结结算(Boss 胜利钥石增量行)确认后进三选一面
|
# 三选一停点挂起分支:战斗总结结算(Boss 胜利钥石增量行)确认后进三选一面
|
||||||
if root._bonus.resume_if_pending(): # 三选一停点在途恢复入口(curio_interact_controller)
|
if root.bonus().resume_if_pending(): # 三选一停点在途恢复入口(curio_interact_controller)
|
||||||
return
|
return
|
||||||
# 挂起分派:战斗胜利总结结算框的「下一节点」≠ 终局——进选路页(暂存候选恢复呈现)
|
# 挂起分派:战斗胜利总结结算框的「下一节点」≠ 终局——进选路页(暂存候选恢复呈现)
|
||||||
if root.run_scope.settlement_stop_timer.is_armed():
|
if root.run_scope.settlement_stop_timer.is_armed():
|
||||||
root.run_scope.settlement_stop_timer.disarm()
|
root.run_scope.settlement_stop_timer.disarm()
|
||||||
_enter_level_screen(root)
|
enter_level_screen(root)
|
||||||
root.ui.modals.run.level_screen.set_feat_holdings(" · ".join(HudPresenter.feat_holdings_lines(root.db, root.run_scope.runner.feats_held())))
|
root.ui.modals.run.level_screen.set_feat_holdings(" · ".join(HudPresenter.feat_holdings_lines(root.db, root.run_scope.runner.feats_held())))
|
||||||
root.ui.modals.run.level_screen.open_choices(root.run_scope.pending_candidates, root.run_scope.runner)
|
root.ui.modals.run.level_screen.open_choices(root.run_scope.pending_candidates, root.run_scope.runner)
|
||||||
root.ui.modals.run.level_screen.apply_status(level_map_status_payload(root.run_scope.runner))
|
root.ui.modals.run.level_screen.apply_status(level_map_status_payload(root.run_scope.runner))
|
||||||
root.run_scope.pending_candidates = []
|
root.run_scope.pending_candidates = []
|
||||||
root._refresh_presentations()
|
root.refresh_presentations()
|
||||||
return
|
return
|
||||||
# 会话收束:run_scope 整节点 queue_free()(帧末回收)——新闲时会话即建,
|
# 会话收束:run_scope 整节点 queue_free()(帧末回收)——新闲时会话即建,
|
||||||
# 局态封印/账本/模态挂起全复位(局态字段清单见 run_scope.gd)
|
# 局态封印/账本/模态挂起全复位(局态字段清单见 run_scope.gd)
|
||||||
root._debug.reset()
|
root.debug().reset()
|
||||||
root._begin_session(false)
|
root.begin_session(false)
|
||||||
root.ui.modals.menu.debug_overlay.reset_sliders()
|
root.ui.modals.menu.debug_overlay.reset_sliders()
|
||||||
root.ui.screens.start_overlay.visible = true
|
root.ui.screens.start_overlay.visible = true
|
||||||
root._refresh_presentations()
|
root.refresh_presentations()
|
||||||
|
|
||||||
static func _on_inter_next_pressed(root: Variant) -> void:
|
static func on_inter_next_pressed(root: Variant) -> void:
|
||||||
root.ui.screens.inter_overlay.visible = false
|
root.ui.screens.inter_overlay.visible = false
|
||||||
if root.run_scope.is_adventure:
|
if root.run_scope.is_adventure:
|
||||||
# 冒险模式:大奖励屏确认 → 进下一关(AdventureRunner 序列推进——零自动推进的冒险级停点)
|
# 冒险模式:大奖励屏确认 → 进下一关(AdventureRunner 序列推进——零自动推进的冒险级停点)
|
||||||
if root.run_scope.adventure != null and not root.run_scope.adventure.continue_to_next_level():
|
if root.run_scope.adventure != null and not root.run_scope.adventure.continue_to_next_level():
|
||||||
root._fatal_screen("关卡推进失败——见输出日志")
|
root.fatal_screen("关卡推进失败——见输出日志")
|
||||||
return
|
return
|
||||||
if not root._debug.next_layer():
|
if not root.debug().next_layer():
|
||||||
root._fatal_screen("战斗启动失败——见输出日志")
|
root.fatal_screen("战斗启动失败——见输出日志")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func _on_node_continue(root: Variant) -> void:
|
static func on_node_continue(root: Variant) -> void:
|
||||||
root.ui.flow.close(root.ui.modals.run.node_overlay)
|
root.ui.flow.close(root.ui.modals.run.node_overlay)
|
||||||
if root.run_scope.runner != null:
|
if root.run_scope.runner != null:
|
||||||
# 确认 ≠ 推进——兑付确认后经 choices_presented 弹出选路口
|
# 确认 ≠ 推进——兑付确认后经 choices_presented 弹出选路口
|
||||||
root.run_scope.runner.continue_after_node()
|
root.run_scope.runner.continue_after_node()
|
||||||
|
|
||||||
static func _on_choices_presented(root: Variant, candidates: Array) -> void:
|
static func on_choices_presented(root: Variant, candidates: Array) -> void:
|
||||||
# 零自动推进的停点呈现:整幅节点图 + 图上点击选路(战斗胜利/兑付确认统一到达此处)
|
# 零自动推进的停点呈现:整幅节点图 + 图上点击选路(战斗胜利/兑付确认统一到达此处)
|
||||||
if root.run_scope.runner == null:
|
if root.run_scope.runner == null:
|
||||||
return
|
return
|
||||||
@@ -180,38 +180,38 @@ static func _on_choices_presented(root: Variant, candidates: Array) -> void:
|
|||||||
root.ui.battle.board_zone.board_view.get_global_rect(),
|
root.ui.battle.board_zone.board_view.get_global_rect(),
|
||||||
{"gp_summary": "战利品 GP +%d · 合计 %d" % [root.run_scope.last_gain_amount, int(root.run_scope.runner.gp)]})
|
{"gp_summary": "战利品 GP +%d · 合计 %d" % [root.run_scope.last_gain_amount, int(root.run_scope.runner.gp)]})
|
||||||
root.ui.flow.open_after_playback(root.ui.modals.run.end_overlay)
|
root.ui.flow.open_after_playback(root.ui.modals.run.end_overlay)
|
||||||
root._refresh_presentations()
|
root.refresh_presentations()
|
||||||
return
|
return
|
||||||
_enter_level_screen(root)
|
enter_level_screen(root)
|
||||||
root.ui.modals.run.level_screen.set_feat_holdings(" · ".join(HudPresenter.feat_holdings_lines(root.db, root.run_scope.runner.feats_held())))
|
root.ui.modals.run.level_screen.set_feat_holdings(" · ".join(HudPresenter.feat_holdings_lines(root.db, root.run_scope.runner.feats_held())))
|
||||||
root.ui.modals.run.level_screen.open_choices(candidates, root.run_scope.runner)
|
root.ui.modals.run.level_screen.open_choices(candidates, root.run_scope.runner)
|
||||||
root.ui.modals.run.level_screen.apply_status(level_map_status_payload(root.run_scope.runner))
|
root.ui.modals.run.level_screen.apply_status(level_map_status_payload(root.run_scope.runner))
|
||||||
root._refresh_presentations()
|
root.refresh_presentations()
|
||||||
|
|
||||||
static func _on_route_chosen(root: Variant, node_id: int) -> void:
|
static func on_route_chosen(root: Variant, node_id: int) -> void:
|
||||||
# 视图已按节点类型定去留——战斗/Boss 出屏(visible=false,此处收栈
|
# 视图已按节点类型定去留——战斗/Boss 出屏(visible=false,此处收栈
|
||||||
# 记录一致性+回战斗屏);奖励/恢复/商店本屏保持激活(兑付覆盖层由节点事件域内弹出,模态栈
|
# 记录一致性+回战斗屏);奖励/恢复/商店本屏保持激活(兑付覆盖层由节点事件域内弹出,模态栈
|
||||||
# 打开低层时自动隐藏本屏、关闭自动恢复)
|
# 打开低层时自动隐藏本屏、关闭自动恢复)
|
||||||
if not root.ui.modals.run.level_screen.visible:
|
if not root.ui.modals.run.level_screen.visible:
|
||||||
root.ui.flow.close(root.ui.modals.run.level_screen)
|
root.ui.flow.close(root.ui.modals.run.level_screen)
|
||||||
_exit_level_screen(root)
|
exit_level_screen(root)
|
||||||
if root.run_scope.runner != null and not root.run_scope.runner.pick_next_node(node_id):
|
if root.run_scope.runner != null and not root.run_scope.runner.pick_next_node(node_id):
|
||||||
push_error("[组合根] 选路被拒(编号 %d 不在候选)" % node_id)
|
push_error("[组合根] 选路被拒(编号 %d 不在候选)" % node_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func _enter_level_screen(root: Variant) -> void:
|
static func enter_level_screen(root: Variant) -> void:
|
||||||
root.run_scope.level_screen_active = true
|
root.run_scope.level_screen_active = true
|
||||||
root.ui.screens.battle_root.visible = false
|
root.ui.screens.battle_root.visible = false
|
||||||
root.ui.flow.open(root.ui.modals.run.level_screen)
|
root.ui.flow.open(root.ui.modals.run.level_screen)
|
||||||
root._sync_status_entry() # 屏级互斥切换同步(_open_modal 单口不识屏级状态)
|
root.sync_status_entry() # 屏级互斥切换同步(_open_modal 单口不识屏级状态)
|
||||||
|
|
||||||
static func _exit_level_screen(root: Variant) -> void:
|
static func exit_level_screen(root: Variant) -> void:
|
||||||
root.run_scope.level_screen_active = false
|
root.run_scope.level_screen_active = false
|
||||||
root.ui.screens.battle_root.visible = true
|
root.ui.screens.battle_root.visible = true
|
||||||
if root.ui.modals.run.level_screen.visible:
|
if root.ui.modals.run.level_screen.visible:
|
||||||
root.ui.flow.close(root.ui.modals.run.level_screen)
|
root.ui.flow.close(root.ui.modals.run.level_screen)
|
||||||
root._sync_status_entry() # 同上
|
root.sync_status_entry() # 同上
|
||||||
|
|
||||||
|
|
||||||
# 选路屏状态栏装配(视图零核心态拼装——architecture §1.3:读核心态→拼展示文案集中于装配器)。
|
# 选路屏状态栏装配(视图零核心态拼装——architecture §1.3:读核心态→拼展示文案集中于装配器)。
|
||||||
@@ -243,7 +243,7 @@ static func level_map_status_payload(runner: LevelRunner) -> Dictionary:
|
|||||||
"bonus_row_visible": not parts.is_empty(),
|
"bonus_row_visible": not parts.is_empty(),
|
||||||
}
|
}
|
||||||
|
|
||||||
static func _on_abandon_requested(root: Variant) -> void:
|
static func on_abandon_requested(root: Variant) -> void:
|
||||||
# 放弃入口(冒险结构.md 已放开「MVP 无界面入口」后置条款;
|
# 放弃入口(冒险结构.md 已放开「MVP 无界面入口」后置条款;
|
||||||
# 入口挂选路停点 = 天然非战斗期,拒绝分支仅防御在案):受理 → 冒险放弃结算(同失败型,
|
# 入口挂选路停点 = 天然非战斗期,拒绝分支仅防御在案):受理 → 冒险放弃结算(同失败型,
|
||||||
# 已获大奖励不追回)→ adventure_finished 同步到达 → 终局面收层
|
# 已获大奖励不追回)→ adventure_finished 同步到达 → 终局面收层
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
## 调试会话状态机归 debug_session.gd;本件只接线与出 UI,零成员态。
|
## 调试会话状态机归 debug_session.gd;本件只接线与出 UI,零成员态。
|
||||||
extends RefCounted
|
extends RefCounted
|
||||||
|
|
||||||
static func _on_diagnose_pressed(root: Variant) -> void:
|
static func on_diagnose_pressed(root: Variant) -> void:
|
||||||
# 本局种子现值走 _current_master_seed 只读单点
|
# 本局种子现值走 _current_master_seed 只读单点
|
||||||
var ctx := {"mode": "level" if root.run_scope.level_active else "debug", "seed": root._current_master_seed()}
|
var ctx := {"mode": "level" if root.run_scope.level_active else "debug", "seed": root.current_master_seed()}
|
||||||
if root.run_scope.level_active and root.run_scope.runner != null:
|
if root.run_scope.level_active and root.run_scope.runner != null:
|
||||||
ctx["runner"] = {"node_index": root.run_scope.runner.node_index, "level_result": String(root.run_scope.runner.level_result),
|
ctx["runner"] = {"node_index": root.run_scope.runner.node_index, "level_result": String(root.run_scope.runner.level_result),
|
||||||
"hero_hp": root.run_scope.runner.hero_hp, "settlement_is_null": root.run_scope.runner.current_battle() == null}
|
"hero_hp": root.run_scope.runner.hero_hp, "settlement_is_null": root.run_scope.runner.current_battle() == null}
|
||||||
@@ -17,33 +17,33 @@ static func _on_diagnose_pressed(root: Variant) -> void:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func _show_debug_overlay(root: Variant) -> void:
|
static func show_debug_overlay(root: Variant) -> void:
|
||||||
# 门禁:对局中可开;本函数仍是唯一开窗入口,门禁逻辑收函数内:
|
# 门禁:对局中可开;本函数仍是唯一开窗入口,门禁逻辑收函数内:
|
||||||
# 棋盘输入锁/状态角标判据排除浮窗,
|
# 棋盘输入锁/状态角标判据排除浮窗,
|
||||||
# 遮挡语义=ModalStack 登记制(他模态开时暂隐、关后自动恢复),此处零场景限制
|
# 遮挡语义=ModalStack 登记制(他模态开时暂隐、关后自动恢复),此处零场景限制
|
||||||
if root.ui.modals.menu.debug_overlay == null:
|
if root.ui.modals.menu.debug_overlay == null:
|
||||||
return
|
return
|
||||||
root.ui.flow.open(root.ui.modals.menu.debug_overlay)
|
root.ui.flow.open(root.ui.modals.menu.debug_overlay)
|
||||||
_sync_debug_overlay(root)
|
sync_debug_overlay(root)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 调试浮窗角标点击(两屏同款处理器——与状态角标同形制守卫;仍收口 _show_debug_overlay 单口)
|
# 调试浮窗角标点击(两屏同款处理器——与状态角标同形制守卫;仍收口 show_debug_overlay 单口)
|
||||||
static func _on_debug_badge_pressed(root: Variant) -> void:
|
static func on_debug_badge_pressed(root: Variant) -> void:
|
||||||
var map_on: bool = root.ui.modals.run.level_screen != null and root.ui.modals.run.level_screen.visible
|
var map_on: bool = root.ui.modals.run.level_screen != null and root.ui.modals.run.level_screen.visible
|
||||||
if (map_on and root.ui.flow.badge_greyed_map()) or (not map_on and root.ui.flow.badge_greyed_battle()):
|
if (map_on and root.ui.flow.badge_greyed_map()) or (not map_on and root.ui.flow.badge_greyed_battle()):
|
||||||
return
|
return
|
||||||
_show_debug_overlay(root)
|
show_debug_overlay(root)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 浮窗上下文同步(当局数据刷新+对局中按钮禁用单点):调用面=开窗口与模态开合
|
# 浮窗上下文同步(当局数据刷新+对局中按钮禁用单点):调用面=开窗口与模态开合
|
||||||
# 单口(凡影响开态/对局态的路径必经其一——与 _sync_status_entry 同款纪律)
|
# 单口(凡影响开态/对局态的路径必经其一——与 _sync_status_entry 同款纪律)
|
||||||
static func _sync_debug_overlay(root: Variant) -> void:
|
static func sync_debug_overlay(root: Variant) -> void:
|
||||||
if root.ui.modals.menu.debug_overlay == null:
|
if root.ui.modals.menu.debug_overlay == null:
|
||||||
return
|
return
|
||||||
root.ui.modals.menu.debug_overlay.set_context_locked(root.run_scope.settlement != null or root.run_scope.is_adventure) # 对局中批量模拟/两层调试入口禁用(长程异步模拟与活跃结算并存态不开放)
|
root.ui.modals.menu.debug_overlay.set_context_locked(root.run_scope.settlement != null or root.run_scope.is_adventure) # 对局中批量模拟/两层调试入口禁用(长程异步模拟与活跃结算并存态不开放)
|
||||||
root.ui.modals.menu.debug_overlay.update_run_data(_debug_run_data(root)) # 当局数据只读区块喂入(开窗+模态开合信号驱动)
|
root.ui.modals.menu.debug_overlay.update_run_data(debug_run_data(root)) # 当局数据只读区块喂入(开窗+模态开合信号驱动)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -51,9 +51,9 @@ static func _sync_debug_overlay(root: Variant) -> void:
|
|||||||
# (非 _seed_value() 重算);调试两层/非对局无冒险对象=RNG 服务 master_seed 现值(只读出口,
|
# (非 _seed_value() 重算);调试两层/非对局无冒险对象=RNG 服务 master_seed 现值(只读出口,
|
||||||
# 未播种 -1 显「—」);关卡/节点/HP/GP=runner 成文出口、钥石=adventure 冒险账本(LevelRunner 无此域);
|
# 未播种 -1 显「—」);关卡/节点/HP/GP=runner 成文出口、钥石=adventure 冒险账本(LevelRunner 无此域);
|
||||||
# 缺位=「—」占位。零动效(纯标签重查)。
|
# 缺位=「—」占位。零动效(纯标签重查)。
|
||||||
static func _debug_run_data(root: Variant) -> Dictionary:
|
static func debug_run_data(root: Variant) -> Dictionary:
|
||||||
var r = root.run_scope.adventure.runner() if root.run_scope.adventure != null else null
|
var r = root.run_scope.adventure.runner() if root.run_scope.adventure != null else null
|
||||||
var seed_now: int = root._current_master_seed()
|
var seed_now: int = root.current_master_seed()
|
||||||
var seed_txt: String = str(seed_now) if seed_now >= 0 else "—"
|
var seed_txt: String = str(seed_now) if seed_now >= 0 else "—"
|
||||||
if r == null:
|
if r == null:
|
||||||
return {"seed": seed_txt, "level": "—", "node": "—", "hp": "—", "gp": "—", "keystone": "—"}
|
return {"seed": seed_txt, "level": "—", "node": "—", "hp": "—", "gp": "—", "keystone": "—"}
|
||||||
@@ -62,47 +62,47 @@ static func _debug_run_data(root: Variant) -> Dictionary:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func _close_debug_overlay(root: Variant) -> void:
|
static func close_debug_overlay(root: Variant) -> void:
|
||||||
root.ui.flow.close(root.ui.modals.menu.debug_overlay) # 模态栈单口——开始层全程未隐藏,无需恢复
|
root.ui.flow.close(root.ui.modals.menu.debug_overlay) # 模态栈单口——开始层全程未隐藏,无需恢复
|
||||||
|
|
||||||
static func _on_tune_apply(root: Variant, atk_pct: int, hp_pct: int) -> void:
|
static func on_tune_apply(root: Variant, atk_pct: int, hp_pct: int) -> void:
|
||||||
# 加成无持久态可"落"——各战斗开局经 board_resolvers.debug_hero_override/runner 现算生效(应用=关闭浮窗)
|
# 加成无持久态可"落"——各战斗开局经 board_resolvers.debug_hero_override/runner 现算生效(应用=关闭浮窗)
|
||||||
_close_debug_overlay(root)
|
close_debug_overlay(root)
|
||||||
|
|
||||||
static func _on_tune_simulate(root: Variant, n: int) -> void:
|
static func on_tune_simulate(root: Variant, n: int) -> void:
|
||||||
# 批量模拟编排 = 控制器承接(tune_sim_controller.gd);E4 后无表态需复位——模拟走 runner 覆盖参数。
|
# 批量模拟编排 = 控制器承接(tune_sim_controller.gd);E4 后无表态需复位——模拟走 runner 覆盖参数。
|
||||||
# 对局中禁用兜底(长程异步模拟与活跃冒险/结算并存态不开放;探针 emit 绕过 disabled 时由此守住)
|
# 对局中禁用兜底(长程异步模拟与活跃冒险/结算并存态不开放;探针 emit 绕过 disabled 时由此守住)
|
||||||
if root.run_scope.settlement != null or root.run_scope.is_adventure:
|
if root.run_scope.settlement != null or root.run_scope.is_adventure:
|
||||||
return
|
return
|
||||||
root._tune_sim.run(n)
|
root.tune_sim().run(n)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func _start_debug_levels(root: Variant) -> void:
|
static func start_debug_levels(root: Variant) -> void:
|
||||||
# 守卫:调试对局与活跃冒险/结算/批量模拟并存不开放——并发会清写
|
# 守卫:调试对局与活跃冒险/结算/批量模拟并存不开放——并发会清写
|
||||||
# settlement/编排态=状态机破坏;模拟在跑时 reset_sliders 会作废测量读数(d5 置灰之外的信号绕过闸)
|
# settlement/编排态=状态机破坏;模拟在跑时 reset_sliders 会作废测量读数(d5 置灰之外的信号绕过闸)
|
||||||
if root.run_scope.is_adventure or root.run_scope.settlement != null or root._tune_sim.is_running():
|
if root.run_scope.is_adventure or root.run_scope.settlement != null or root.tune_sim().is_running():
|
||||||
return
|
return
|
||||||
root.ui.modals.menu.debug_overlay.reset_sliders()
|
root.ui.modals.menu.debug_overlay.reset_sliders()
|
||||||
root.ui.flow.close(root.ui.modals.menu.debug_overlay) # 浮窗内入口发起——随开随收(对局期不可再开:门禁在 _show_debug_overlay)
|
root.ui.flow.close(root.ui.modals.menu.debug_overlay) # 浮窗内入口发起——随开随收(对局期不可再开:门禁在 show_debug_overlay)
|
||||||
root.ui.screens.start_overlay.visible = false
|
root.ui.screens.start_overlay.visible = false
|
||||||
root.ui.battle.log_view.clear()
|
root.ui.battle.log_view.clear()
|
||||||
root.ui.battle.log_view.append_bb(root.Narrator.debug_open_line(root._seed_value(), 1, true))
|
root.ui.battle.log_view.append_bb(root.Narrator.debug_open_line(root.seed_value(), 1, true))
|
||||||
root._begin_session(false)
|
root.begin_session(false)
|
||||||
if not root._debug.start_debug_levels():
|
if not root.debug().start_debug_levels():
|
||||||
root._fatal_screen("战斗启动失败——见输出日志")
|
root.fatal_screen("战斗启动失败——见输出日志")
|
||||||
|
|
||||||
static func _on_debug_battle_created(root: Variant, settlement_ref: BattleOrchestrator, _level: int, _carry: int) -> void:
|
static func on_debug_battle_created(root: Variant, settlement_ref: BattleOrchestrator, _level: int, _carry: int) -> void:
|
||||||
# begin_battle 前接手 + 接线(signal.connect 唯一归组合根)。settlement 必须先于 begin_battle
|
# begin_battle 前接手 + 接线(signal.connect 唯一归组合根)。settlement 必须先于 begin_battle
|
||||||
# 就位——begin 期间发出的 board_changed 要用新板重建棋盘并触发一次性提示(缺陷①同款时序义务)
|
# 就位——begin 期间发出的 board_changed 要用新板重建棋盘并触发一次性提示(缺陷①同款时序义务)
|
||||||
root.run_scope.settlement = settlement_ref
|
root.run_scope.settlement = settlement_ref
|
||||||
root._wire_battle(settlement_ref)
|
root.wire_battle(settlement_ref)
|
||||||
|
|
||||||
static func _on_debug_battle_ready(root: Variant, settlement_ref: BattleOrchestrator, _level: int, _carry: int) -> void:
|
static func on_debug_battle_ready(root: Variant, settlement_ref: BattleOrchestrator, _level: int, _carry: int) -> void:
|
||||||
root.run_scope.settlement = settlement_ref
|
root.run_scope.settlement = settlement_ref
|
||||||
var board = root.run_scope.settlement.minesweeper.current_board()
|
var board = root.run_scope.settlement.minesweeper.current_board()
|
||||||
root.ui.battle.board_zone.board_view.rebuild(board, root.run_scope.settlement.minesweeper)
|
root.ui.battle.board_zone.board_view.rebuild(board, root.run_scope.settlement.minesweeper)
|
||||||
if board != null:
|
if board != null:
|
||||||
root.ui.battle.stage.set_board_type(String(board.board_type)) # 舞台背景选图随板(C8——调试就绪重建点单行同步)
|
root.ui.battle.stage.set_board_type(String(board.board_type)) # 舞台背景选图随板(C8——调试就绪重建点单行同步)
|
||||||
root._check_board_hints()
|
root.check_board_hints()
|
||||||
root._refresh_presentations()
|
root.refresh_presentations()
|
||||||
@@ -41,16 +41,16 @@ static func _topmost_camp_window(root: Variant) -> Control:
|
|||||||
|
|
||||||
|
|
||||||
## 返回主菜单动线(契约 4):首步 close 浮窗(缺此步浮窗残留主菜单上方)→营地与选档层同收+开始层恢复
|
## 返回主菜单动线(契约 4):首步 close 浮窗(缺此步浮窗残留主菜单上方)→营地与选档层同收+开始层恢复
|
||||||
static func _on_return_to_menu(root: Variant) -> void:
|
static func on_return_to_menu(root: Variant) -> void:
|
||||||
root.ui.flow.close(root.ui.modals.camp.esc_overlay)
|
root.ui.flow.close(root.ui.modals.camp.esc_overlay)
|
||||||
root._camp_pres.on_camp_closed() # 关层收闭单口(卡④ T3——营地层与选档层同收+开始层恢复)
|
root.camp_pres().on_camp_closed() # 关层收闭单口(卡④ T3——营地层与选档层同收+开始层恢复)
|
||||||
|
|
||||||
|
|
||||||
## 设置出口(浮窗登记在设置层之下——open 只隐上方层,浮窗由树序遮挡非属性隐藏;关后重现=栈语义)
|
## 设置出口(浮窗登记在设置层之下——open 只隐上方层,浮窗由树序遮挡非属性隐藏;关后重现=栈语义)
|
||||||
static func _on_settings(root: Variant) -> void:
|
static func on_settings(root: Variant) -> void:
|
||||||
root.ui.flow.open(root.ui.modals.menu.settings_overlay)
|
root.ui.flow.open(root.ui.modals.menu.settings_overlay)
|
||||||
|
|
||||||
|
|
||||||
## 退出出口(_quit_game 原样复用——settings_store.save_settings+quit,零语义副作用)
|
## 退出出口(_quit_game 原样复用——settings_store.save_settings+quit,零语义副作用)
|
||||||
static func _on_quit(root: Variant) -> void:
|
static func on_quit(root: Variant) -> void:
|
||||||
root._quit_game()
|
root.quit_game()
|
||||||
@@ -4,11 +4,11 @@
|
|||||||
## 全部开合走组合根模态编排口(root.ui.flow.open/close);本件零成员态。
|
## 全部开合走组合根模态编排口(root.ui.flow.open/close);本件零成员态。
|
||||||
extends RefCounted
|
extends RefCounted
|
||||||
|
|
||||||
static func _open_settings(root: Variant) -> void:
|
static func open_settings(root: Variant) -> void:
|
||||||
root.ui.screens.start_overlay.visible = false
|
root.ui.screens.start_overlay.visible = false
|
||||||
root.ui.flow.open(root.ui.modals.menu.settings_overlay) # 模态栈单口
|
root.ui.flow.open(root.ui.modals.menu.settings_overlay) # 模态栈单口
|
||||||
|
|
||||||
static func _on_settings_closed(root: Variant) -> void:
|
static func on_settings_closed(root: Variant) -> void:
|
||||||
root.ui.flow.close(root.ui.modals.menu.settings_overlay) # 模态栈单口
|
root.ui.flow.close(root.ui.modals.menu.settings_overlay) # 模态栈单口
|
||||||
# 语境分支(卡⑤ 契约 3——谓词=camp_esc_overlay.visible,谁开的设置谁收):
|
# 语境分支(卡⑤ 契约 3——谓词=camp_esc_overlay.visible,谁开的设置谁收):
|
||||||
# 营地浮窗路径关设置回浮窗不回主菜单(栈语义:浮窗登记在下、由树序遮挡非属性隐藏);
|
# 营地浮窗路径关设置回浮窗不回主菜单(栈语义:浮窗登记在下、由树序遮挡非属性隐藏);
|
||||||
@@ -25,24 +25,24 @@ static func _on_settings_closed(root: Variant) -> void:
|
|||||||
# 八键换代(迭代 36 卡③):跨关解锁概览退役(营地/生涯承载)——只留本局信息;
|
# 八键换代(迭代 36 卡③):跨关解锁概览退役(营地/生涯承载)——只留本局信息;
|
||||||
# ledger 直取下标(键缺失=致命,禁 .get 缺省留门——fail-fast 红线);禁 null 守卫软回退
|
# ledger 直取下标(键缺失=致命,禁 .get 缺省留门——fail-fast 红线);禁 null 守卫软回退
|
||||||
# (两入口开层时 runner 恒在役——状态面板卡 F3 证据链)
|
# (两入口开层时 runner 恒在役——状态面板卡 F3 证据链)
|
||||||
static func _status_data(root: Variant) -> Dictionary:
|
static func status_data(root: Variant) -> Dictionary:
|
||||||
return HudPresenter.status_data(root.db, root.meta, root.run_scope.runner, root._treasure_ui)
|
return HudPresenter.status_data(root.db, root.meta, root.run_scope.runner, root.treasure_ui())
|
||||||
|
|
||||||
static func _open_status_panel(root: Variant) -> void:
|
static func open_status_panel(root: Variant) -> void:
|
||||||
root.ui.flow.open(root.ui.modals.run.status_panel) # 模态栈单口(开层前排空排播队列——既有层同款行为,目检确认项)
|
root.ui.flow.open(root.ui.modals.run.status_panel) # 模态栈单口(开层前排空排播队列——既有层同款行为,目检确认项)
|
||||||
root.ui.modals.run.status_panel.open_status(_status_data(root))
|
root.ui.modals.run.status_panel.open_status(status_data(root))
|
||||||
|
|
||||||
static func _on_status_closed(root: Variant) -> void:
|
static func on_status_closed(root: Variant) -> void:
|
||||||
root.ui.flow.close(root.ui.modals.run.status_panel) # 模态栈单口
|
root.ui.flow.close(root.ui.modals.run.status_panel) # 模态栈单口
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func _open_career(root: Variant) -> void:
|
static func open_career(root: Variant) -> void:
|
||||||
root.ui.screens.start_overlay.visible = false
|
root.ui.screens.start_overlay.visible = false
|
||||||
root.ui.flow.open(root.ui.modals.menu.career_overlay) # 模态栈单口
|
root.ui.flow.open(root.ui.modals.menu.career_overlay) # 模态栈单口
|
||||||
root.ui.modals.menu.career_overlay.open_career(HudPresenter.career_data(root.db, root.save_manager, root.meta))
|
root.ui.modals.menu.career_overlay.open_career(HudPresenter.career_data(root.db, root.save_manager, root.meta))
|
||||||
|
|
||||||
static func _on_career_closed(root: Variant) -> void:
|
static func on_career_closed(root: Variant) -> void:
|
||||||
root.ui.flow.close(root.ui.modals.menu.career_overlay) # 模态栈单口
|
root.ui.flow.close(root.ui.modals.menu.career_overlay) # 模态栈单口
|
||||||
if not root.ui.modals.camp.scene.visible: # 营地语境关生涯不回开始层(笔记本入口——卡④ T3;栈已复现场景根)
|
if not root.ui.modals.camp.scene.visible: # 营地语境关生涯不回开始层(笔记本入口——卡④ T3;栈已复现场景根)
|
||||||
root.ui.screens.start_overlay.visible = true
|
root.ui.screens.start_overlay.visible = true
|
||||||
@@ -54,32 +54,32 @@ static func _on_career_closed(root: Variant) -> void:
|
|||||||
# 篝火回主菜单必须二次确认(camp.md v2.2 裁定);确认后营地层与选档层同收+开始层恢复(关层收闭)。
|
# 篝火回主菜单必须二次确认(camp.md v2.2 裁定);确认后营地层与选档层同收+开始层恢复(关层收闭)。
|
||||||
|
|
||||||
|
|
||||||
static func _on_camp_object_pressed(root: Variant, key: StringName) -> void:
|
static func on_camp_object_pressed(root: Variant, key: StringName) -> void:
|
||||||
match key:
|
match key:
|
||||||
&"forge":
|
&"forge":
|
||||||
root._camp_pres.open_camp_forge()
|
root.camp_pres().open_camp_forge()
|
||||||
&"chest":
|
&"chest":
|
||||||
root._camp_pres.open_camp_treasure()
|
root.camp_pres().open_camp_treasure()
|
||||||
&"dummy":
|
&"dummy":
|
||||||
root._camp_pres.open_camp_tree()
|
root.camp_pres().open_camp_tree()
|
||||||
&"board":
|
&"board":
|
||||||
root._camp_pres.open_camp_codex()
|
root.camp_pres().open_camp_codex()
|
||||||
&"notebook":
|
&"notebook":
|
||||||
_open_career(root) # 生涯页入口改挂帐篷旁笔记本(CareerOverlay 本体零改——卡④ T3)
|
open_career(root) # 生涯页入口改挂帐篷旁笔记本(CareerOverlay 本体零改——卡④ T3)
|
||||||
&"gate":
|
&"gate":
|
||||||
_open_gate_confirm(root)
|
_open_gate_confirm(root)
|
||||||
&"campfire":
|
&"campfire":
|
||||||
root._confirm_consumer = "campfire_leave"
|
root.set_confirm_consumer("campfire_leave")
|
||||||
root.ui.modals.menu.confirm_dialog.open("确定离开营地回到主菜单?", "离开", "留下")
|
root.ui.modals.menu.confirm_dialog.open("确定离开营地回到主菜单?", "离开", "留下")
|
||||||
|
|
||||||
|
|
||||||
static func _open_gate_confirm(root: Variant) -> void:
|
static func _open_gate_confirm(root: Variant) -> void:
|
||||||
if root.save_manager.has_breakpoint():
|
if root.save_manager.has_breakpoint():
|
||||||
root._confirm_consumer = "gate"
|
root.set_confirm_consumer("gate")
|
||||||
root.ui.modals.menu.confirm_dialog.open_three("有未完成的冒险——继续上一段冒险,还是开始新冒险?",
|
root.ui.modals.menu.confirm_dialog.open_three("有未完成的冒险——继续上一段冒险,还是开始新冒险?",
|
||||||
"继续上一段冒险", "开始新冒险", "取消")
|
"继续上一段冒险", "开始新冒险", "取消")
|
||||||
return
|
return
|
||||||
root._confirm_consumer = "gate_new"
|
root.set_confirm_consumer("gate_new")
|
||||||
root.ui.modals.menu.confirm_dialog.open("是否开始新冒险?", "是", "否")
|
root.ui.modals.menu.confirm_dialog.open("是否开始新冒险?", "是", "否")
|
||||||
|
|
||||||
|
|
||||||
@@ -91,12 +91,12 @@ static func _open_gate_confirm(root: Variant) -> void:
|
|||||||
|
|
||||||
# 开层(模态栈单口;与开始层互斥=career 同款先例)。「进入存档」钮归卡② mn3——本函数为
|
# 开层(模态栈单口;与开始层互斥=career 同款先例)。「进入存档」钮归卡② mn3——本函数为
|
||||||
# 该钮的唯一落点(卡③ 批内探针函数直调=中间态,实现报告「已知中间态」登记)。
|
# 该钮的唯一落点(卡③ 批内探针函数直调=中间态,实现报告「已知中间态」登记)。
|
||||||
static func _open_save_select(root: Variant) -> void:
|
static func open_save_select(root: Variant) -> void:
|
||||||
root.ui.screens.start_overlay.visible = false
|
root.ui.screens.start_overlay.visible = false
|
||||||
root.ui.flow.open(root.ui.modals.menu.save_select_overlay) # 模态栈单口
|
root.ui.flow.open(root.ui.modals.menu.save_select_overlay) # 模态栈单口
|
||||||
root.ui.modals.menu.save_select_overlay.open_save_select(HudPresenter.save_select_data(root.save_manager))
|
root.ui.modals.menu.save_select_overlay.open_save_select(HudPresenter.save_select_data(root.save_manager))
|
||||||
|
|
||||||
static func _on_save_select_closed(root: Variant) -> void:
|
static func on_save_select_closed(root: Variant) -> void:
|
||||||
root.ui.flow.close(root.ui.modals.menu.save_select_overlay) # 模态栈单口
|
root.ui.flow.close(root.ui.modals.menu.save_select_overlay) # 模态栈单口
|
||||||
root.ui.screens.start_overlay.visible = true
|
root.ui.screens.start_overlay.visible = true
|
||||||
|
|
||||||
@@ -107,24 +107,24 @@ static func _on_save_select_closed(root: Variant) -> void:
|
|||||||
|
|
||||||
# 空槽新档链(卡④ T3 换代:落点=营地场景根——CampOverlay 随四柜台拆解退役):卡① 创建=激活=白板落盘,
|
# 空槽新档链(卡④ T3 换代:落点=营地场景根——CampOverlay 随四柜台拆解退役):卡① 创建=激活=白板落盘,
|
||||||
# 落点开层。动线序(禁先关后开):先落点开层(开始层保持隐藏),选档层被模态栈遮挡隐藏、不关闭。
|
# 落点开层。动线序(禁先关后开):先落点开层(开始层保持隐藏),选档层被模态栈遮挡隐藏、不关闭。
|
||||||
static func _on_save_select_new(root: Variant, slot: int) -> void:
|
static func on_save_select_new(root: Variant, slot: int) -> void:
|
||||||
root.save_manager.slots.create_slot(slot)
|
root.save_manager.slots.create_slot(slot)
|
||||||
root._camp_pres.open_camp()
|
root.camp_pres().open_camp()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 有档槽进档链(契约 8 进档即激活):卡① 激活+读盘(兜底/拒读链按槽成立)→落点=营地场景根(卡④ T3)。
|
# 有档槽进档链(契约 8 进档即激活):卡① 激活+读盘(兜底/拒读链按槽成立)→落点=营地场景根(卡④ T3)。
|
||||||
static func _on_save_select_load(root: Variant, slot: int) -> void:
|
static func on_save_select_load(root: Variant, slot: int) -> void:
|
||||||
root.save_manager.slots.activate_slot(slot)
|
root.save_manager.slots.activate_slot(slot)
|
||||||
root._camp_pres.open_camp()
|
root.camp_pres().open_camp()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 删档链(契约 3):第一次点击只出确认窗(消费方编排——open 前设消费方=delete_slot),
|
# 删档链(契约 3):第一次点击只出确认窗(消费方编排——open 前设消费方=delete_slot),
|
||||||
# 确认才删、取消不删;禁长按删/一次点击即删/撤销式软删。
|
# 确认才删、取消不删;禁长按删/一次点击即删/撤销式软删。
|
||||||
static func _on_save_select_delete(root: Variant, slot: int) -> void:
|
static func on_save_select_delete(root: Variant, slot: int) -> void:
|
||||||
root._confirm_consumer = "delete_slot"
|
root.set_confirm_consumer("delete_slot")
|
||||||
root._confirm_consumer_slot = slot
|
root.set_confirm_consumer_slot(slot)
|
||||||
root.ui.flow.open(root.ui.modals.menu.confirm_dialog) # 模态栈单口(显示编排/挂起兜底/遮挡记账——与其余覆盖层同口)
|
root.ui.flow.open(root.ui.modals.menu.confirm_dialog) # 模态栈单口(显示编排/挂起兜底/遮挡记账——与其余覆盖层同口)
|
||||||
root.ui.modals.menu.confirm_dialog.open("删除存档位 %d?删除后该档不可恢复。" % slot, "删除", "取消")
|
root.ui.modals.menu.confirm_dialog.open("删除存档位 %d?删除后该档不可恢复。" % slot, "删除", "取消")
|
||||||
|
|
||||||
@@ -132,20 +132,20 @@ static func _on_save_select_delete(root: Variant, slot: int) -> void:
|
|||||||
|
|
||||||
# 入口角标点击(两屏同款处理器):P1 守卫兜底——其他模态开着即拒开(常态防线=角标置灰,
|
# 入口角标点击(两屏同款处理器):P1 守卫兜底——其他模态开着即拒开(常态防线=角标置灰,
|
||||||
# 探针 pressed.emit 绕过 disabled 时由此兜住;地图屏自身的登记开态不计——has_open_excluding)
|
# 探针 pressed.emit 绕过 disabled 时由此兜住;地图屏自身的登记开态不计——has_open_excluding)
|
||||||
static func _on_status_badge_pressed(root: Variant) -> void:
|
static func on_status_badge_pressed(root: Variant) -> void:
|
||||||
var map_on: bool = root.ui.modals.run.level_screen != null and root.ui.modals.run.level_screen.visible
|
var map_on: bool = root.ui.modals.run.level_screen != null and root.ui.modals.run.level_screen.visible
|
||||||
# P1 守卫兜底——其他模态开着即拒开(常态防线=角标置灰,探针 pressed.emit 绕过 disabled 时由此兜住;
|
# P1 守卫兜底——其他模态开着即拒开(常态防线=角标置灰,探针 pressed.emit 绕过 disabled 时由此兜住;
|
||||||
# 地图屏自身的登记开态不计;判据排除调试浮窗:对局中浮窗开着时状态角标仍可点)
|
# 地图屏自身的登记开态不计;判据排除调试浮窗:对局中浮窗开着时状态角标仍可点)
|
||||||
if (map_on and root.ui.flow.badge_greyed_map()) or (not map_on and root.ui.flow.badge_greyed_battle()):
|
if (map_on and root.ui.flow.badge_greyed_map()) or (not map_on and root.ui.flow.badge_greyed_battle()):
|
||||||
return
|
return
|
||||||
_open_status_panel(root)
|
open_status_panel(root)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 入口角标可见性/置灰同步(P1 丁+守卫——单一同步点):战斗屏角标=对局内且地图屏未激活;
|
# 入口角标可见性/置灰同步(P1 丁+守卫——单一同步点):战斗屏角标=对局内且地图屏未激活;
|
||||||
# 地图屏角标=随屏;置灰=登记册上除地图屏自身外任一层开着(防「看得见点不着」态)。
|
# 地图屏角标=随屏;置灰=登记册上除地图屏自身外任一层开着(防「看得见点不着」态)。
|
||||||
# 调用面=模态开合单口与屏级互斥口(凡影响开态/屏态的路径必经其一)。
|
# 调用面=模态开合单口与屏级互斥口(凡影响开态/屏态的路径必经其一)。
|
||||||
static func _sync_status_entry(root: Variant) -> void:
|
static func sync_status_entry(root: Variant) -> void:
|
||||||
if root.ui.modals.run.status_panel == null or root.ui.flow == null or root.ui.battle.board_zone == null or root.ui.modals.run.level_screen == null:
|
if root.ui.modals.run.status_panel == null or root.ui.flow == null or root.ui.battle.board_zone == null or root.ui.modals.run.level_screen == null:
|
||||||
return
|
return
|
||||||
var map_on: bool = root.ui.modals.run.level_screen.visible
|
var map_on: bool = root.ui.modals.run.level_screen.visible
|
||||||
@@ -160,13 +160,13 @@ static func _sync_status_entry(root: Variant) -> void:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func _on_camp_closed(root: Variant) -> void:
|
static func on_camp_closed(root: Variant) -> void:
|
||||||
root._camp_pres.on_camp_closed()
|
root.camp_pres().on_camp_closed()
|
||||||
|
|
||||||
static func _camp_data(root: Variant) -> Dictionary:
|
static func camp_data(root: Variant) -> Dictionary:
|
||||||
return HudPresenter.camp_data(root._camp_pres)
|
return HudPresenter.camp_data(root.camp_pres())
|
||||||
|
|
||||||
static func _on_wallet_changed(root: Variant, event: String, gp: int, extra: Dictionary) -> void:
|
static func on_wallet_changed(root: Variant, event: String, gp: int, extra: Dictionary) -> void:
|
||||||
# wallet 行族转发(到账/购买/清零——试玩日志验收取数面)+ 常驻余额与在开商店覆盖层重刷
|
# wallet 行族转发(到账/购买/清零——试玩日志验收取数面)+ 常驻余额与在开商店覆盖层重刷
|
||||||
root.logger.log_wallet(event, gp, extra)
|
root.logger.log_wallet(event, gp, extra)
|
||||||
if String(event) == "gain":
|
if String(event) == "gain":
|
||||||
@@ -176,11 +176,11 @@ static func _on_wallet_changed(root: Variant, event: String, gp: int, extra: Dic
|
|||||||
root.ui.modals.menu.shop_overlay.refresh_shelf_state(int(root.run_scope.runner.gp)) # pool 面余额联动(货架内容仅买后重抽变)
|
root.ui.modals.menu.shop_overlay.refresh_shelf_state(int(root.run_scope.runner.gp)) # pool 面余额联动(货架内容仅买后重抽变)
|
||||||
else:
|
else:
|
||||||
root.ui.modals.menu.shop_overlay.refresh_state(root.run_scope.runner.shop.shop_products(), int(root.run_scope.runner.gp))
|
root.ui.modals.menu.shop_overlay.refresh_state(root.run_scope.runner.shop.shop_products(), int(root.run_scope.runner.gp))
|
||||||
root._refresh_presentations()
|
root.refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func _on_legend_toggled(root: Variant) -> void:
|
static func on_legend_toggled(root: Variant) -> void:
|
||||||
if root.ui.modals.run.legend_overlay.is_open():
|
if root.ui.modals.run.legend_overlay.is_open():
|
||||||
root.ui.flow.close(root.ui.modals.run.legend_overlay)
|
root.ui.flow.close(root.ui.modals.run.legend_overlay)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ const AdventureScreenScene := preload("res://presentation/scenes/adventure_scree
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func build(root: Variant) -> void:
|
static func build(root: Variant, handlers: Dictionary) -> void:
|
||||||
_build_screens(root)
|
_build_screens(root)
|
||||||
_build_battle_wiring(root)
|
_build_battle_wiring(root, handlers)
|
||||||
_build_overlays(root)
|
_build_overlays(root, handlers)
|
||||||
_build_aux_panels(root)
|
_build_aux_panels(root, handlers)
|
||||||
_build_curio(root)
|
_build_curio(root)
|
||||||
_build_menu_wiring(root)
|
_build_menu_wiring(root, handlers)
|
||||||
_build_debug_and_resolvers(root)
|
_build_debug_and_resolvers(root, handlers)
|
||||||
_build_modal_flow(root)
|
_build_modal_flow(root)
|
||||||
|
|
||||||
static func _build_screens(root: Variant) -> void:
|
static func _build_screens(root: Variant) -> void:
|
||||||
@@ -48,7 +48,7 @@ static func _build_screens(root: Variant) -> void:
|
|||||||
root.ui.battle.settlement_fx = root.ui.screens.adventure_screen.settlement_fx
|
root.ui.battle.settlement_fx = root.ui.screens.adventure_screen.settlement_fx
|
||||||
root.ui.modals.run.level_screen = root.ui.screens.adventure_screen.level_screen
|
root.ui.modals.run.level_screen = root.ui.screens.adventure_screen.level_screen
|
||||||
|
|
||||||
static func _build_battle_wiring(root: Variant) -> void:
|
static func _build_battle_wiring(root: Variant, handlers: Dictionary) -> void:
|
||||||
# 结算行排播泵(本体在 row_pacer.gd;本类注入视图句柄与呈现刷新回调,零信号连接)
|
# 结算行排播泵(本体在 row_pacer.gd;本类注入视图句柄与呈现刷新回调,零信号连接)
|
||||||
root.ui.screens.row_pacer = RowPacer.new()
|
root.ui.screens.row_pacer = RowPacer.new()
|
||||||
root.ui.screens.row_pacer.log_view = root.ui.battle.log_view
|
root.ui.screens.row_pacer.log_view = root.ui.battle.log_view
|
||||||
@@ -56,32 +56,32 @@ static func _build_battle_wiring(root: Variant) -> void:
|
|||||||
root.ui.screens.row_pacer.board_zone = root.ui.battle.board_zone
|
root.ui.screens.row_pacer.board_zone = root.ui.battle.board_zone
|
||||||
root.ui.screens.row_pacer.settlement_fx = root.ui.battle.settlement_fx
|
root.ui.screens.row_pacer.settlement_fx = root.ui.battle.settlement_fx
|
||||||
root.ui.screens.row_pacer.board_view = root.ui.battle.board_zone.board_view
|
root.ui.screens.row_pacer.board_view = root.ui.battle.board_zone.board_view
|
||||||
root.ui.screens.row_pacer.refresh_request = root._refresh_presentations
|
root.ui.screens.row_pacer.refresh_request = root.refresh_presentations
|
||||||
root.ui.screens.row_pacer.pump_ended = root.ui.flow.pump_ended # 演播完边沿统一派发(挂起 modal 优先,其次锁期点击重放)
|
root.ui.screens.row_pacer.pump_ended = root.ui.flow.pump_ended # 演播完边沿统一派发(挂起 modal 优先,其次锁期点击重放)
|
||||||
root.add_child(root.ui.screens.row_pacer)
|
root.add_child(root.ui.screens.row_pacer)
|
||||||
# 秘宝两步交互(本体在 treasure_interact_controller.gd;settlement/runner/grant 随关卡/战斗更替,
|
# 秘宝两步交互(本体在 treasure_interact_controller.gd;settlement/runner/grant 随关卡/战斗更替,
|
||||||
# 经现值回调注入——仿 identity_resolver 只读回调先例;grant 每战新建编排器,现值取件防悬挂)
|
# 经现值回调注入——仿 identity_resolver 只读回调先例;grant 每战新建编排器,现值取件防悬挂)
|
||||||
root._treasure_ui = TreasureInteractController.new({
|
root.set_treasure_ui(TreasureInteractController.new({
|
||||||
"db": root.db, "meta": root.meta, "info_panel": root.ui.battle.info_panel, "toast": root.ui.battle.board_zone.toast,
|
"db": root.db, "meta": root.meta, "info_panel": root.ui.battle.info_panel, "toast": root.ui.battle.board_zone.toast,
|
||||||
"board_view": root.ui.battle.board_zone.board_view,
|
"board_view": root.ui.battle.board_zone.board_view,
|
||||||
"settlement_get": func() -> Variant: return root.run_scope.settlement,
|
"settlement_get": func() -> Variant: return root.run_scope.settlement,
|
||||||
"runner_get": func() -> Variant: return root.run_scope.runner,
|
"runner_get": func() -> Variant: return root.run_scope.runner,
|
||||||
"grant_get": func() -> Variant: return root.run_scope.settlement.reward_grant() if root.run_scope.settlement != null else null,
|
"grant_get": func() -> Variant: return root.run_scope.settlement.reward_grant() if root.run_scope.settlement != null else null,
|
||||||
})
|
}))
|
||||||
|
|
||||||
root.ui.battle.board_zone.action_requested.connect(root._on_board_action)
|
root.ui.battle.board_zone.action_requested.connect(handlers["board_action"])
|
||||||
root.ui.battle.board_zone.status_badge.pressed.connect(root._on_status_badge_pressed) # 状态面板入口(战斗屏 HUD 角标)
|
root.ui.battle.board_zone.status_badge.pressed.connect(handlers["status_badge_pressed"]) # 状态面板入口(战斗屏 HUD 角标)
|
||||||
root.ui.battle.info_panel.treasure_slot_clicked.connect(root._treasure_ui.on_slot_clicked) # 两步交互第一步
|
root.ui.battle.info_panel.treasure_slot_clicked.connect(root.treasure_ui().on_slot_clicked) # 两步交互第一步
|
||||||
root.ui.battle.board_zone.stop_pressed.connect(root._on_stop_pressed)
|
root.ui.battle.board_zone.stop_pressed.connect(handlers["stop_pressed"])
|
||||||
root.ui.battle.board_zone.refresh_confirmed.connect(root._on_refresh_confirmed)
|
root.ui.battle.board_zone.refresh_confirmed.connect(handlers["refresh_confirmed"])
|
||||||
root.ui.battle.board_zone.legend_toggled.connect(root._on_legend_toggled)
|
root.ui.battle.board_zone.legend_toggled.connect(handlers["legend_toggled"])
|
||||||
root.ui.battle.board_zone.hover_forbidden.connect(root._on_hover_forbidden)
|
root.ui.battle.board_zone.hover_forbidden.connect(handlers["hover_forbidden"])
|
||||||
root.ui.battle.board_zone.chord_attempted.connect(root._on_chord_attempted)
|
root.ui.battle.board_zone.chord_attempted.connect(handlers["chord_attempted"])
|
||||||
|
|
||||||
root.logger = PlaytestLogger.new()
|
root.logger = PlaytestLogger.new()
|
||||||
root.logger.ap_per_round = int(root.db.run.action_economy.ap_per_round)
|
root.logger.ap_per_round = int(root.db.run.action_economy.ap_per_round)
|
||||||
|
|
||||||
static func _build_overlays(root: Variant) -> void:
|
static func _build_overlays(root: Variant, handlers: Dictionary) -> void:
|
||||||
# 模态覆盖层(登记序 = 树序 = z 遮挡序:图例 < 明细回看 < 节点 < 关卡画面 < 三选一 < 终局
|
# 模态覆盖层(登记序 = 树序 = z 遮挡序:图例 < 明细回看 < 节点 < 关卡画面 < 三选一 < 终局
|
||||||
# < 商店 < 营地场景根 < 四子界面 < 设置 < 状态面板(只读) < 生涯页(只读) < 确认弹窗 < 调试浮窗;
|
# < 商店 < 营地场景根 < 四子界面 < 设置 < 状态面板(只读) < 生涯页(只读) < 确认弹窗 < 调试浮窗;
|
||||||
# 关卡画面住冒险屏壳(树序在模态之下)——登记序仍夹在节点层与三选一层之间,遮挡语义零改动)
|
# 关卡画面住冒险屏壳(树序在模态之下)——登记序仍夹在节点层与三选一层之间,遮挡语义零改动)
|
||||||
@@ -121,35 +121,35 @@ static func _build_overlays(root: Variant) -> void:
|
|||||||
root.ui.modals.camp.scene.set_hud_band(hud_band)
|
root.ui.modals.camp.scene.set_hud_band(hud_band)
|
||||||
# 屏壳/子界面插位由 LAYER_CONTRACT 槽统一落位——禁散落 move_child
|
# 屏壳/子界面插位由 LAYER_CONTRACT 槽统一落位——禁散落 move_child
|
||||||
root.ui.modals.run.legend_overlay.closed.connect(root.ui.flow.close.bind(root.ui.modals.run.legend_overlay))
|
root.ui.modals.run.legend_overlay.closed.connect(root.ui.flow.close.bind(root.ui.modals.run.legend_overlay))
|
||||||
root.ui.modals.run.node_overlay.continue_pressed.connect(root._on_node_continue)
|
root.ui.modals.run.node_overlay.continue_pressed.connect(handlers["node_continue"])
|
||||||
root.ui.modals.run.level_screen.route_chosen.connect(root._on_route_chosen)
|
root.ui.modals.run.level_screen.route_chosen.connect(handlers["route_chosen"])
|
||||||
root.ui.modals.run.level_screen.status_badge.pressed.connect(root._on_status_badge_pressed) # 状态面板入口(地图屏顶栏角标)
|
root.ui.modals.run.level_screen.status_badge.pressed.connect(handlers["status_badge_pressed"]) # 状态面板入口(地图屏顶栏角标)
|
||||||
root.ui.modals.run.level_screen.abandon_requested.connect(root._on_abandon_requested) # 放弃入口
|
root.ui.modals.run.level_screen.abandon_requested.connect(handlers["abandon_requested"]) # 放弃入口
|
||||||
root.ui.modals.run.end_overlay.continue_pressed.connect(root._on_battle_end_continue)
|
root.ui.modals.run.end_overlay.continue_pressed.connect(handlers["battle_end_continue"])
|
||||||
|
|
||||||
static func _build_aux_panels(root: Variant) -> void:
|
static func _build_aux_panels(root: Variant, handlers: Dictionary) -> void:
|
||||||
root.ui.modals.menu.settings_overlay = SettingsOverlay.new(root.settings_store) # 最小设置面(音量/全屏/减动效)
|
root.ui.modals.menu.settings_overlay = SettingsOverlay.new(root.settings_store) # 最小设置面(音量/全屏/减动效)
|
||||||
root.add_child(root.ui.modals.menu.settings_overlay)
|
root.add_child(root.ui.modals.menu.settings_overlay)
|
||||||
root.ui.modals.menu.settings_overlay.closed.connect(root._on_settings_closed)
|
root.ui.modals.menu.settings_overlay.closed.connect(handlers["settings_closed"])
|
||||||
# 局内状态面板·只读(登记设置层同档带 dim 遮罩,确认弹窗之前;
|
# 局内状态面板·只读(登记设置层同档带 dim 遮罩,确认弹窗之前;
|
||||||
# 数据=组合根开层实时读 MetaProgression 访问器喂入,本层零写通路)
|
# 数据=组合根开层实时读 MetaProgression 访问器喂入,本层零写通路)
|
||||||
root.ui.modals.run.status_panel = StatusPanel.new()
|
root.ui.modals.run.status_panel = StatusPanel.new()
|
||||||
root.add_child(root.ui.modals.run.status_panel)
|
root.add_child(root.ui.modals.run.status_panel)
|
||||||
root.ui.modals.run.status_panel.closed.connect(root._on_status_closed)
|
root.ui.modals.run.status_panel.closed.connect(handlers["status_closed"])
|
||||||
# 生涯页·只读全屏页(登记序=营地同档,设置层旁、确认弹窗之前;
|
# 生涯页·只读全屏页(登记序=营地同档,设置层旁、确认弹窗之前;
|
||||||
# 树序同步=addChild 同位(登记序=树序=z 序纪律);数据=组合根开层实时读 SaveManager 计数
|
# 树序同步=addChild 同位(登记序=树序=z 序纪律);数据=组合根开层实时读 SaveManager 计数
|
||||||
# 访问器+MetaProgression 访问器喂入,本层零写通路零跳转;入口=开始层「营地与系统」组生涯钮)
|
# 访问器+MetaProgression 访问器喂入,本层零写通路零跳转;入口=开始层「营地与系统」组生涯钮)
|
||||||
root.ui.modals.menu.career_overlay = CareerOverlay.new()
|
root.ui.modals.menu.career_overlay = CareerOverlay.new()
|
||||||
root.add_child(root.ui.modals.menu.career_overlay)
|
root.add_child(root.ui.modals.menu.career_overlay)
|
||||||
root.ui.modals.menu.career_overlay.closed.connect(root._on_career_closed)
|
root.ui.modals.menu.career_overlay.closed.connect(handlers["career_closed"])
|
||||||
# 选档界面(营地交互重做卡③):登记序=生涯同档(树序同步=addChild 同位);三动作只发意图信号
|
# 选档界面(营地交互重做卡③):登记序=生涯同档(树序同步=addChild 同位);三动作只发意图信号
|
||||||
#(激活/创建/删除+确认分派归组合根——视图零数据层依赖);入口=「进入存档」钮(卡② mn3 接线)。
|
#(激活/创建/删除+确认分派归组合根——视图零数据层依赖);入口=「进入存档」钮(卡② mn3 接线)。
|
||||||
root.ui.modals.menu.save_select_overlay = SaveSelectOverlay.new()
|
root.ui.modals.menu.save_select_overlay = SaveSelectOverlay.new()
|
||||||
root.add_child(root.ui.modals.menu.save_select_overlay)
|
root.add_child(root.ui.modals.menu.save_select_overlay)
|
||||||
root.ui.modals.menu.save_select_overlay.closed.connect(root._on_save_select_closed)
|
root.ui.modals.menu.save_select_overlay.closed.connect(handlers["save_select_closed"])
|
||||||
root.ui.modals.menu.save_select_overlay.new_slot_requested.connect(root._on_save_select_new)
|
root.ui.modals.menu.save_select_overlay.new_slot_requested.connect(handlers["save_select_new"])
|
||||||
root.ui.modals.menu.save_select_overlay.load_slot_requested.connect(root._on_save_select_load)
|
root.ui.modals.menu.save_select_overlay.load_slot_requested.connect(handlers["save_select_load"])
|
||||||
root.ui.modals.menu.save_select_overlay.delete_slot_requested.connect(root._on_save_select_delete)
|
root.ui.modals.menu.save_select_overlay.delete_slot_requested.connect(handlers["save_select_delete"])
|
||||||
|
|
||||||
static func _build_curio(root: Variant) -> void:
|
static func _build_curio(root: Variant) -> void:
|
||||||
# 提升三选一覆盖层(z 序 = 节点层之上、终局层之下;确认后同拍推进;
|
# 提升三选一覆盖层(z 序 = 节点层之上、终局层之下;确认后同拍推进;
|
||||||
@@ -158,7 +158,7 @@ static func _build_curio(root: Variant) -> void:
|
|||||||
root.add_child(root.ui.modals.run.curio_overlay)
|
root.add_child(root.ui.modals.run.curio_overlay)
|
||||||
# 提升三选一与替换子交互(本体在 curio_interact_controller.gd;本类只接线与回调注入,
|
# 提升三选一与替换子交互(本体在 curio_interact_controller.gd;本类只接线与回调注入,
|
||||||
# 模态栈/演播后排窗/呈现刷新/fatal 经回调注入,adventure/runner 现值回调)
|
# 模态栈/演播后排窗/呈现刷新/fatal 经回调注入,adventure/runner 现值回调)
|
||||||
root._bonus = CurioInteractController.new(CurioFlowContext.new(root.db,
|
root.set_bonus(CurioInteractController.new(CurioFlowContext.new(root.db,
|
||||||
{"curio_overlay": root.ui.modals.run.curio_overlay, "end_overlay": root.ui.modals.run.end_overlay,
|
{"curio_overlay": root.ui.modals.run.curio_overlay, "end_overlay": root.ui.modals.run.end_overlay,
|
||||||
"board_view": root.ui.battle.board_zone.board_view, "toast": root.ui.battle.board_zone.toast},
|
"board_view": root.ui.battle.board_zone.board_view, "toast": root.ui.battle.board_zone.toast},
|
||||||
{"meta_get": func() -> Variant: return root.meta, "save_get": func() -> Variant: return root.save_manager,
|
{"meta_get": func() -> Variant: return root.meta, "save_get": func() -> Variant: return root.save_manager,
|
||||||
@@ -166,22 +166,22 @@ static func _build_curio(root: Variant) -> void:
|
|||||||
"runner_get": func() -> Variant: return root.run_scope.runner,
|
"runner_get": func() -> Variant: return root.run_scope.runner,
|
||||||
"adventure_mode_get": func() -> Variant: return root.run_scope.is_adventure},
|
"adventure_mode_get": func() -> Variant: return root.run_scope.is_adventure},
|
||||||
{"open_modal": root.ui.flow.open, "open_modal_after_playback": root.ui.flow.open_after_playback,
|
{"open_modal": root.ui.flow.open, "open_modal_after_playback": root.ui.flow.open_after_playback,
|
||||||
"close_modal": root.ui.flow.close, "refresh_presentations": root._refresh_presentations,
|
"close_modal": root.ui.flow.close, "refresh_presentations": root.refresh_presentations,
|
||||||
"fatal_screen": root._fatal_screen,
|
"fatal_screen": root.fatal_screen,
|
||||||
"gp_summary": _gp_summary_cb(root)})) # 构造参数收拢 context(u20 三束)
|
"gp_summary": _gp_summary_cb(root)}))) # 构造参数收拢 context(u20 三束)
|
||||||
root.ui.modals.run.curio_overlay.pick_confirmed.connect(root._bonus.on_pick_confirmed)
|
root.ui.modals.run.curio_overlay.pick_confirmed.connect(root.bonus().on_pick_confirmed)
|
||||||
root.ui.modals.run.curio_overlay.continue_pressed.connect(root._bonus.on_continue)
|
root.ui.modals.run.curio_overlay.continue_pressed.connect(root.bonus().on_continue)
|
||||||
root.ui.modals.run.curio_overlay.refresh_requested.connect(root._bonus.on_refresh)
|
root.ui.modals.run.curio_overlay.refresh_requested.connect(root.bonus().on_refresh)
|
||||||
|
|
||||||
static func _build_menu_wiring(root: Variant) -> void:
|
static func _build_menu_wiring(root: Variant, handlers: Dictionary) -> void:
|
||||||
# 菜单屏接线(句柄经屏壳暴露;三入口化——进入存档/设置/退出游戏,卡② mn3:
|
# 菜单屏接线(句柄经屏壳暴露;三入口化——进入存档/设置/退出游戏,卡② mn3:
|
||||||
# 进入存档钮落点=卡③选档层 _open_save_select,点击链在此闭环)
|
# 进入存档钮落点=卡③选档层 _open_save_select,点击链在此闭环)
|
||||||
root.ui.screens.menu_screen.entersavebtn.pressed.connect(root._open_save_select)
|
root.ui.screens.menu_screen.entersavebtn.pressed.connect(root.open_save_select)
|
||||||
# 调试入口=UI 最顶层全局浮层角标(任何 UI 不遮挡——菜单/战斗/地图三枚
|
# 调试入口=UI 最顶层全局浮层角标(任何 UI 不遮挡——菜单/战斗/地图三枚
|
||||||
# 屏内角标由全局浮层承载;连接归组合根,树序/登记面见 LAYER_CONTRACT 末位)
|
# 屏内角标由全局浮层承载;连接归组合根,树序/登记面见 LAYER_CONTRACT 末位)
|
||||||
root.ui.screens.debug_badge = UiAssembler.build_debug_badge(root)
|
root.ui.screens.debug_badge = UiAssembler.build_debug_badge(root)
|
||||||
root.add_child(root.ui.screens.debug_badge)
|
root.add_child(root.ui.screens.debug_badge)
|
||||||
root.ui.screens.debug_badge.pressed.connect(root._on_debug_badge_pressed)
|
root.ui.screens.debug_badge.pressed.connect(handlers["debug_badge_pressed"])
|
||||||
# 营地/商店投影(本体在 camp_shop_presenter.gd;本类只接线、探针缝保缝转发;
|
# 营地/商店投影(本体在 camp_shop_presenter.gd;本类只接线、探针缝保缝转发;
|
||||||
# 购买写调用唯一经 MetaProgression/LevelRunner core 单口——组合根 lambda 现值注入)
|
# 购买写调用唯一经 MetaProgression/LevelRunner core 单口——组合根 lambda 现值注入)
|
||||||
# 营地刷新单口(各写口尾→现开界面+场景根 HUD 一闸完成——卡④ T3;卡⑤ HUD band 随卡⑤挂册)
|
# 营地刷新单口(各写口尾→现开界面+场景根 HUD 一闸完成——卡④ T3;卡⑤ HUD band 随卡⑤挂册)
|
||||||
@@ -189,7 +189,7 @@ static func _build_menu_wiring(root: Variant) -> void:
|
|||||||
camp_bus.bind_targets([root.ui.modals.camp.forge, root.ui.modals.camp.treasure,
|
camp_bus.bind_targets([root.ui.modals.camp.forge, root.ui.modals.camp.treasure,
|
||||||
root.ui.modals.camp.tree, root.ui.modals.camp.codex,
|
root.ui.modals.camp.tree, root.ui.modals.camp.codex,
|
||||||
root.ui.screens.camp_screen.camp_scene.hud_band] as Array[Control])
|
root.ui.screens.camp_screen.camp_scene.hud_band] as Array[Control])
|
||||||
root._camp_pres = CampShopPresenter.new(CampFlowContext.new(root.db,
|
root.set_camp_pres(CampShopPresenter.new(CampFlowContext.new(root.db,
|
||||||
{"camp_scene": root.ui.modals.camp.scene, "forge_view": root.ui.modals.camp.forge,
|
{"camp_scene": root.ui.modals.camp.scene, "forge_view": root.ui.modals.camp.forge,
|
||||||
"treasure_view": root.ui.modals.camp.treasure, "tree_view": root.ui.modals.camp.tree,
|
"treasure_view": root.ui.modals.camp.treasure, "tree_view": root.ui.modals.camp.tree,
|
||||||
"codex_view": root.ui.modals.camp.codex, "shop_overlay": root.ui.modals.menu.shop_overlay,
|
"codex_view": root.ui.modals.camp.codex, "shop_overlay": root.ui.modals.menu.shop_overlay,
|
||||||
@@ -199,31 +199,31 @@ static func _build_menu_wiring(root: Variant) -> void:
|
|||||||
{"meta_get": func() -> Variant: return root.meta, "save_get": func() -> Variant: return root.save_manager,
|
{"meta_get": func() -> Variant: return root.meta, "save_get": func() -> Variant: return root.save_manager,
|
||||||
"runner_get": func() -> Variant: return root.run_scope.runner},
|
"runner_get": func() -> Variant: return root.run_scope.runner},
|
||||||
{"open_modal": root.ui.flow.open, "close_modal": root.ui.flow.close,
|
{"open_modal": root.ui.flow.open, "close_modal": root.ui.flow.close,
|
||||||
"refresh_presentations": root._refresh_presentations})) # 构造参数收拢 context(u21 三束)
|
"refresh_presentations": root.refresh_presentations}))) # 构造参数收拢 context(u21 三束)
|
||||||
root.ui.modals.menu.shop_overlay.buy_requested.connect(root._camp_pres.on_shop_buy)
|
root.ui.modals.menu.shop_overlay.buy_requested.connect(root.camp_pres().on_shop_buy)
|
||||||
root.ui.modals.menu.shop_overlay.refresh_requested.connect(root._camp_pres.on_shop_refresh) # MC-1
|
root.ui.modals.menu.shop_overlay.refresh_requested.connect(root.camp_pres().on_shop_refresh) # MC-1
|
||||||
root.ui.modals.menu.shop_overlay.leave_pressed.connect(root._camp_pres.on_shop_leave)
|
root.ui.modals.menu.shop_overlay.leave_pressed.connect(root.camp_pres().on_shop_leave)
|
||||||
# 营地信号接线(CampOverlay 退役——四子界面意图信号+场景点选组合根路由+closed 经 bind 携视图)
|
# 营地信号接线(CampOverlay 退役——四子界面意图信号+场景点选组合根路由+closed 经 bind 携视图)
|
||||||
root.ui.modals.camp.forge.forge_buy_requested.connect(root._camp_pres.on_camp_forge_buy)
|
root.ui.modals.camp.forge.forge_buy_requested.connect(root.camp_pres().on_camp_forge_buy)
|
||||||
root.ui.modals.camp.forge.forge_unlock_requested.connect(root._camp_pres.on_camp_forge_unlock)
|
root.ui.modals.camp.forge.forge_unlock_requested.connect(root.camp_pres().on_camp_forge_unlock)
|
||||||
root.ui.modals.camp.forge.forge_select_requested.connect(root._camp_pres.on_camp_forge_select)
|
root.ui.modals.camp.forge.forge_select_requested.connect(root.camp_pres().on_camp_forge_select)
|
||||||
root.ui.modals.camp.treasure.buy_requested.connect(root._camp_pres.on_camp_buy)
|
root.ui.modals.camp.treasure.buy_requested.connect(root.camp_pres().on_camp_buy)
|
||||||
root.ui.modals.camp.treasure.attune_toggled.connect(root._camp_pres.on_camp_attune_toggle)
|
root.ui.modals.camp.treasure.attune_toggled.connect(root.camp_pres().on_camp_attune_toggle)
|
||||||
root.ui.modals.camp.tree.tree_buy_requested.connect(root._camp_pres.on_camp_tree_buy)
|
root.ui.modals.camp.tree.tree_buy_requested.connect(root.camp_pres().on_camp_tree_buy)
|
||||||
root.ui.modals.camp.tree.tree_fork_toggled.connect(root._camp_pres.on_camp_fork_toggle)
|
root.ui.modals.camp.tree.tree_fork_toggled.connect(root.camp_pres().on_camp_fork_toggle)
|
||||||
root.ui.modals.camp.forge.closed.connect(root._camp_pres.on_camp_sub_closed.bind(root.ui.modals.camp.forge))
|
root.ui.modals.camp.forge.closed.connect(root.camp_pres().on_camp_sub_closed.bind(root.ui.modals.camp.forge))
|
||||||
root.ui.modals.camp.treasure.closed.connect(root._camp_pres.on_camp_sub_closed.bind(root.ui.modals.camp.treasure))
|
root.ui.modals.camp.treasure.closed.connect(root.camp_pres().on_camp_sub_closed.bind(root.ui.modals.camp.treasure))
|
||||||
root.ui.modals.camp.tree.closed.connect(root._camp_pres.on_camp_sub_closed.bind(root.ui.modals.camp.tree))
|
root.ui.modals.camp.tree.closed.connect(root.camp_pres().on_camp_sub_closed.bind(root.ui.modals.camp.tree))
|
||||||
root.ui.modals.camp.codex.closed.connect(root._camp_pres.on_camp_sub_closed.bind(root.ui.modals.camp.codex))
|
root.ui.modals.camp.codex.closed.connect(root.camp_pres().on_camp_sub_closed.bind(root.ui.modals.camp.codex))
|
||||||
root.ui.modals.camp.scene.object_pressed.connect(root._on_camp_object_pressed)
|
root.ui.modals.camp.scene.object_pressed.connect(handlers["camp_object_pressed"])
|
||||||
root.ui.screens.menu_screen.settingsbtn.pressed.connect(root._open_settings) # 最小设置面入口
|
root.ui.screens.menu_screen.settingsbtn.pressed.connect(root.open_settings) # 最小设置面入口
|
||||||
root.ui.screens.menu_screen.quitbtn.pressed.connect(root._quit_game) # 退出游戏提级一级菜单
|
root.ui.screens.menu_screen.quitbtn.pressed.connect(root.quit_game) # 退出游戏提级一级菜单
|
||||||
|
|
||||||
static func _build_debug_and_resolvers(root: Variant) -> void:
|
static func _build_debug_and_resolvers(root: Variant, handlers: Dictionary) -> void:
|
||||||
var inter: Dictionary[Variant, Variant] = UiAssembler.build_inter_overlay(root)
|
var inter: Dictionary[Variant, Variant] = UiAssembler.build_inter_overlay(root)
|
||||||
root.ui.screens.inter_overlay = inter.overlay
|
root.ui.screens.inter_overlay = inter.overlay
|
||||||
root.ui.screens.inter_label = inter.label
|
root.ui.screens.inter_label = inter.label
|
||||||
inter.next_btn.pressed.connect(root._on_inter_next_pressed)
|
inter.next_btn.pressed.connect(handlers["inter_next_pressed"])
|
||||||
|
|
||||||
# 确认弹窗(新冒险互斥确认弹窗化):树序落在开始层/过场层之后 = 子级最末
|
# 确认弹窗(新冒险互斥确认弹窗化):树序落在开始层/过场层之后 = 子级最末
|
||||||
#(纪律「登记序 = 树序 = z 序」——confirm_dialog.open 禁运行时 move_child 自提抬层;
|
#(纪律「登记序 = 树序 = z 序」——confirm_dialog.open 禁运行时 move_child 自提抬层;
|
||||||
@@ -233,13 +233,13 @@ static func _build_debug_and_resolvers(root: Variant) -> void:
|
|||||||
root.add_child(root.ui.modals.menu.confirm_dialog)
|
root.add_child(root.ui.modals.menu.confirm_dialog)
|
||||||
# 消费方编排(卡③ 契约 3/sl8——禁双常驻静态接线):open 前设 _confirm_consumer,
|
# 消费方编排(卡③ 契约 3/sl8——禁双常驻静态接线):open 前设 _confirm_consumer,
|
||||||
# confirmed/cancelled 后按该状态量分派;分派面可容纳后续消费方(卡④ 到位直接接入不返工)
|
# confirmed/cancelled 后按该状态量分派;分派面可容纳后续消费方(卡④ 到位直接接入不返工)
|
||||||
root.ui.modals.menu.confirm_dialog.confirmed.connect(root._on_confirm_accepted)
|
root.ui.modals.menu.confirm_dialog.confirmed.connect(handlers["confirm_accepted"])
|
||||||
root.ui.modals.menu.confirm_dialog.secondary_confirmed.connect(root._on_confirm_secondary) # 三钮次确认(卡④ 大门「开始新冒险」出口)
|
root.ui.modals.menu.confirm_dialog.secondary_confirmed.connect(handlers["confirm_secondary"]) # 三钮次确认(卡④ 大门「开始新冒险」出口)
|
||||||
root.ui.modals.menu.confirm_dialog.cancelled.connect(root._on_confirm_declined)
|
root.ui.modals.menu.confirm_dialog.cancelled.connect(handlers["confirm_declined"])
|
||||||
# Esc 浮窗三出口接线(卡⑤——意图信号经薄委托归 MainEscFlow 动线;输入入口=main._unhandled_input)
|
# Esc 浮窗三出口接线(卡⑤——意图信号经薄委托归 MainEscFlow 动线;输入入口=main._unhandled_input)
|
||||||
root.ui.modals.camp.esc_overlay.return_requested.connect(root._on_esc_return)
|
root.ui.modals.camp.esc_overlay.return_requested.connect(handlers["esc_return"])
|
||||||
root.ui.modals.camp.esc_overlay.settings_requested.connect(root._on_esc_settings)
|
root.ui.modals.camp.esc_overlay.settings_requested.connect(handlers["esc_settings"])
|
||||||
root.ui.modals.camp.esc_overlay.quit_requested.connect(root._on_esc_quit)
|
root.ui.modals.camp.esc_overlay.quit_requested.connect(handlers["esc_quit"])
|
||||||
|
|
||||||
# 调试浮窗(主菜单三散件收一:随机种子/数值调整/批量模拟/两层调试入口;
|
# 调试浮窗(主菜单三散件收一:随机种子/数值调整/批量模拟/两层调试入口;
|
||||||
# 全局可开浮窗:调试会话恒开=启动即开〔_ready〕+两屏角标再开+当局数据只读区块;
|
# 全局可开浮窗:调试会话恒开=启动即开〔_ready〕+两屏角标再开+当局数据只读区块;
|
||||||
@@ -249,9 +249,9 @@ static func _build_debug_and_resolvers(root: Variant) -> void:
|
|||||||
root.ui.modals.menu.debug_overlay = DebugOverlay.new(root.db, int(root.db.combat.hero.atk), int(root.db.combat.hero.max_hp))
|
root.ui.modals.menu.debug_overlay = DebugOverlay.new(root.db, int(root.db.combat.hero.atk), int(root.db.combat.hero.max_hp))
|
||||||
root.add_child(root.ui.modals.menu.debug_overlay)
|
root.add_child(root.ui.modals.menu.debug_overlay)
|
||||||
root.ui.modals.menu.debug_overlay.closed.connect(root.ui.flow.close.bind(root.ui.modals.menu.debug_overlay))
|
root.ui.modals.menu.debug_overlay.closed.connect(root.ui.flow.close.bind(root.ui.modals.menu.debug_overlay))
|
||||||
root.ui.modals.menu.debug_overlay.apply_requested.connect(root._on_tune_apply)
|
root.ui.modals.menu.debug_overlay.apply_requested.connect(handlers["tune_apply"])
|
||||||
root.ui.modals.menu.debug_overlay.simulate_requested.connect(root._on_tune_simulate)
|
root.ui.modals.menu.debug_overlay.simulate_requested.connect(handlers["tune_simulate"])
|
||||||
root.ui.modals.menu.debug_overlay.debug_levels_requested.connect(root._start_debug_levels)
|
root.ui.modals.menu.debug_overlay.debug_levels_requested.connect(root.start_debug_levels)
|
||||||
|
|
||||||
# 棋盘解析回调族(有态绑定件——board_resolvers.gd 承接;组合根只接线;局部持有不占类成员位)
|
# 棋盘解析回调族(有态绑定件——board_resolvers.gd 承接;组合根只接线;局部持有不占类成员位)
|
||||||
var resolvers = BoardResolversScript.new(root.db, root.ui.modals.menu.debug_overlay, func() -> Variant: return root.run_scope.settlement)
|
var resolvers = BoardResolversScript.new(root.db, root.ui.modals.menu.debug_overlay, func() -> Variant: return root.run_scope.settlement)
|
||||||
@@ -261,10 +261,10 @@ static func _build_debug_and_resolvers(root: Variant) -> void:
|
|||||||
root.ui.battle.board_zone.board_view.set_variant_mask_resolver(resolvers.variant_mask_lookup)
|
root.ui.battle.board_zone.board_view.set_variant_mask_resolver(resolvers.variant_mask_lookup)
|
||||||
root.ui.battle.board_zone.board_view.set_variant_mark_resolver(resolvers.variant_mark_lookup) # flat_damage 未开格角标
|
root.ui.battle.board_zone.board_view.set_variant_mark_resolver(resolvers.variant_mark_lookup) # flat_damage 未开格角标
|
||||||
# 调试会话(英雄生效值预览回调绑同一解析件——创建晚于浮窗、随 _build_ui 一次接线)
|
# 调试会话(英雄生效值预览回调绑同一解析件——创建晚于浮窗、随 _build_ui 一次接线)
|
||||||
root._debug = DebugSessionScript.new(root.db, root.get_node(root.AUTOLOAD_PATH_RNG),
|
root.set_debug(DebugSessionScript.new(root.db, root.get_node(root.AUTOLOAD_PATH_RNG),
|
||||||
func() -> Dictionary: return resolvers.debug_hero_override(), root._seed_value)
|
func() -> Dictionary: return resolvers.debug_hero_override(), root.seed_value))
|
||||||
root._debug.battle_created.connect(root._on_debug_battle_created)
|
root.debug().battle_created.connect(handlers["debug_battle_created"])
|
||||||
root._debug.battle_ready.connect(root._on_debug_battle_ready)
|
root.debug().battle_ready.connect(handlers["debug_battle_ready"])
|
||||||
|
|
||||||
static func _build_modal_flow(root: Variant) -> void:
|
static func _build_modal_flow(root: Variant) -> void:
|
||||||
# 模态登记(缺陷⑤纪律——登记序 = 树序 = z 序):层序唯一事实源=LAYER_CONTRACT,
|
# 模态登记(缺陷⑤纪律——登记序 = 树序 = z 序):层序唯一事实源=LAYER_CONTRACT,
|
||||||
@@ -277,15 +277,15 @@ static func _build_modal_flow(root: Variant) -> void:
|
|||||||
root.ui.flow.rows_empty_get = func() -> bool: return root.ui.screens.row_pacer.pending_rows().is_empty()
|
root.ui.flow.rows_empty_get = func() -> bool: return root.ui.screens.row_pacer.pending_rows().is_empty()
|
||||||
root.ui.flow.flush_rows = root.ui.screens.row_pacer.flush
|
root.ui.flow.flush_rows = root.ui.screens.row_pacer.flush
|
||||||
root.ui.flow.on_open_sync = func() -> void:
|
root.ui.flow.on_open_sync = func() -> void:
|
||||||
root._sync_status_entry() # 状态面板入口角标可见性/置灰随开态同步
|
root.sync_status_entry() # 状态面板入口角标可见性/置灰随开态同步
|
||||||
root._sync_debug_overlay() # 浮窗当局数据/按钮态随开态同步
|
root.sync_debug_overlay() # 浮窗当局数据/按钮态随开态同步
|
||||||
root.ui.flow.on_close_sync = func() -> void:
|
root.ui.flow.on_close_sync = func() -> void:
|
||||||
root._sync_status_entry() # 关闭恢复角标可点态(无残留——同源口径)
|
root.sync_status_entry() # 关闭恢复角标可点态(无残留——同源口径)
|
||||||
root._sync_debug_overlay() # 他层关闭复活浮窗时同步刷新(关后自动恢复语义配套)
|
root.sync_debug_overlay() # 他层关闭复活浮窗时同步刷新(关后自动恢复语义配套)
|
||||||
root.ui.flow.replay_click = root._replay_locked_click
|
root.ui.flow.replay_click = root.replay_locked_click
|
||||||
# 视觉层合同装配(唯一事实源=LAYER_CONTRACT:树序+登记序同源派生——改序只改合同表)
|
# 视觉层合同装配(唯一事实源=LAYER_CONTRACT:树序+登记序同源派生——改序只改合同表)
|
||||||
root.ui.apply_layer_contract(root)
|
root.ui.apply_layer_contract(root)
|
||||||
root._tune_sim = TuneSimController.new(root.db, root.ui.modals.menu.debug_overlay, int(root.db.combat.hero.max_hp))
|
root.set_tune_sim(TuneSimController.new(root.db, root.ui.modals.menu.debug_overlay, int(root.db.combat.hero.max_hp)))
|
||||||
|
|
||||||
static func fatal_screen(root: Variant, msg: String) -> void:
|
static func fatal_screen(root: Variant, msg: String) -> void:
|
||||||
var l := UiKit.label(msg,UiKit.FS_SUB, true, UiKit.RED_ALERT)
|
var l := UiKit.label(msg,UiKit.FS_SUB, true, UiKit.RED_ALERT)
|
||||||
@@ -295,4 +295,4 @@ static func fatal_screen(root: Variant, msg: String) -> void:
|
|||||||
|
|
||||||
# GP 总结行回调(gp_summary 束键——单行 lambda 内嵌字典实参收尾歧义,提函数承载)
|
# GP 总结行回调(gp_summary 束键——单行 lambda 内嵌字典实参收尾歧义,提函数承载)
|
||||||
static func _gp_summary_cb(root: Variant) -> Callable:
|
static func _gp_summary_cb(root: Variant) -> Callable:
|
||||||
return func() -> String: return root._gp_summary_text({"gp_dropped": root.run_scope.last_gain_amount})
|
return func() -> String: return root.gp_summary_text({"gp_dropped": root.run_scope.last_gain_amount})
|
||||||
@@ -9,7 +9,7 @@ var _occluded := {} # modal → 被其隐藏的上方层(关闭恢复)
|
|||||||
var _tags := {} # modal → 排除组标签集(互斥域随层登记)
|
var _tags := {} # modal → 排除组标签集(互斥域随层登记)
|
||||||
|
|
||||||
# 排除组封闭词表(组合根登记用——新标签=改此处+评审,防调用点拼装回潮)
|
# 排除组封闭词表(组合根登记用——新标签=改此处+评审,防调用点拼装回潮)
|
||||||
const TAG_NON_LOCKING := "non_locking" # 开态不计入棋盘输入锁与角标置灰(调试浮窗默认开×遮挡复活×has_open 组合=棋盘永久锁死)
|
const TAG_NON_LOCKING := "non_locking" # 开态不计入棋盘输入锁与角标置灰(调试浮窗默认开×遮挡复活×开态计入输入锁的组合=棋盘永久锁死)
|
||||||
const TAG_SCREEN_STATE := "screen_state" # 常驻屏态(关卡地图屏——自身开态不计入本屏角标判据)
|
const TAG_SCREEN_STATE := "screen_state" # 常驻屏态(关卡地图屏——自身开态不计入本屏角标判据)
|
||||||
|
|
||||||
|
|
||||||
@@ -53,18 +53,9 @@ func close(m: Control) -> void:
|
|||||||
_occluded.erase(m)
|
_occluded.erase(m)
|
||||||
|
|
||||||
|
|
||||||
# 开态查询(组合根输入锁唯一判据:登记册上是否有任一层处于开态;
|
|
||||||
# 可见性即开态,与 open/close 记账同源——组合根不再手工罗列各层)
|
|
||||||
func has_open() -> bool:
|
|
||||||
for m in _list:
|
|
||||||
if is_instance_valid(m) and m.visible:
|
|
||||||
return true
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
|
||||||
# 排除组开态查询(模态协议内聚:排除语义随层登记(register tags),
|
# 排除组开态查询(模态协议内聚:排除语义随层登记(register tags),
|
||||||
# 查询按组名集合表达,禁在调用点拼装 has_open_excluding/has_open_excluding_any。
|
# 查询按组名集合表达,禁在调用点拼装 has_open_excluding/has_open_excluding_any。
|
||||||
# 只读查询零副作用——登记序/开合记账语义不变;空标签集=全计(与 has_open 同形)。
|
# 只读查询零副作用——登记序/开合记账语义不变;空标签集=全计。
|
||||||
func has_open_excluding_tags(exclude_tags: Array) -> bool:
|
func has_open_excluding_tags(exclude_tags: Array) -> bool:
|
||||||
for m in _list:
|
for m in _list:
|
||||||
if is_instance_valid(m) and m.visible:
|
if is_instance_valid(m) and m.visible:
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ static func build_start_overlay(host: Control, db: ConfigDb = null) -> Dictionar
|
|||||||
var bd := UiKit.backdrop_tile()
|
var bd := UiKit.backdrop_tile()
|
||||||
if bd != null:
|
if bd != null:
|
||||||
overlay.add_child(bd)
|
overlay.add_child(bd)
|
||||||
overlay.add_child(UiKit._beams_rect())
|
overlay.add_child(UiKit.beams_rect())
|
||||||
overlay.add_child(UiKit.vignette_rect())
|
overlay.add_child(UiKit.vignette_rect())
|
||||||
# 双列骨架:左=操作列 56% / 右=舞台(立绘看台)
|
# 双列骨架:左=操作列 56% / 右=舞台(立绘看台)
|
||||||
var cols := _start_columns(overlay)
|
var cols := _start_columns(overlay)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
## VERTICAL SLICE - NOT FOR PRODUCTION
|
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||||||
## 战斗/冒险终局 overlay(模态):判定行+三行账+明细回看入口+继续/返回,失败侧暮蓝氛围。
|
## 战斗/冒险终局 overlay(模态):判定行+三行账+明细回看入口+继续/返回,失败侧暮蓝氛围。
|
||||||
## 摘要文本经 open_victory/open_defeat 由组合根装配喂入——本类零文案装配。
|
## 摘要文本经 open_victory/open_defeat 由组合根装配喂入——本类零文案装配。
|
||||||
|
## 内部数据类 _EndOverlayState=宿主画面登记表(只被本文件填读,文件外零消费者——字段为公开数据成员)。
|
||||||
class_name BattleEndOverlay
|
class_name BattleEndOverlay
|
||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@@ -13,20 +14,20 @@ const COL_WARM := UiKit.WARM
|
|||||||
## 内部状态件(u6 子域拆件——契约 9 职责语句「战末呈现与演出态」):单一变化原因=终局画面呈现与
|
## 内部状态件(u6 子域拆件——契约 9 职责语句「战末呈现与演出态」):单一变化原因=终局画面呈现与
|
||||||
## 演出计数。探针直读冻结成员(_btn/_gp_name/_gp_row/_gp_val)住宿主不进状态件。
|
## 演出计数。探针直读冻结成员(_btn/_gp_name/_gp_row/_gp_val)住宿主不进状态件。
|
||||||
class _EndOverlayState extends RefCounted:
|
class _EndOverlayState extends RefCounted:
|
||||||
var _dim: ColorRect
|
var dim: ColorRect
|
||||||
var _seal: Panel
|
var seal: Panel
|
||||||
var _verdict: Label
|
var verdict: Label
|
||||||
var _rows_box: VBoxContainer # 三行账(GP/钥石/本关加成——demo ⑧两列对齐;失败侧整行隐藏)
|
var rows_box: VBoxContainer # 三行账(GP/钥石/本关加成——demo ⑧两列对齐;失败侧整行隐藏)
|
||||||
var _ks_row: HBoxContainer
|
var ks_row: HBoxContainer
|
||||||
var _ks_name: Label
|
var ks_name: Label
|
||||||
var _ks_val: Label
|
var ks_val: Label
|
||||||
var _bonus_row_l: HBoxContainer
|
var bonus_row_l: HBoxContainer
|
||||||
var _bonus_name: Label
|
var bonus_name: Label
|
||||||
var _bonus_val: Label
|
var bonus_val: Label
|
||||||
var _cele: TextureRect # 庆祝立绘(idle 占位浮动)
|
var cele: TextureRect # 庆祝立绘(idle 占位浮动)
|
||||||
var _board_rect := Rect2()
|
var board_rect := Rect2()
|
||||||
var _crest_bricks: Array[ColorRect] = [] # 纹章碎砖驻留面(close 时回收)
|
var crest_bricks: Array[ColorRect] = [] # 纹章碎砖驻留面(close 时回收)
|
||||||
var _fx_counts := {"crest": 0, "dust": 0, "seal": 0} # 演出计数(fx_probe 断言面——crest/dust/seal 三键)
|
var fx_counts := {"crest": 0, "dust": 0, "seal": 0} # 演出计数(fx_probe 断言面——crest/dust/seal 三键)
|
||||||
|
|
||||||
|
|
||||||
var st := _EndOverlayState.new()
|
var st := _EndOverlayState.new()
|
||||||
@@ -40,10 +41,10 @@ func _init() -> void:
|
|||||||
# 半透明浮层文字不可读 → 实底石板皮面板形态
|
# 半透明浮层文字不可读 → 实底石板皮面板形态
|
||||||
#(与营地/设置/图例同族)。半透明氛围 dim 保留(胜利暖纱/失败暮蓝——open_* 就地换色),信息与
|
#(与营地/设置/图例同族)。半透明氛围 dim 保留(胜利暖纱/失败暮蓝——open_* 就地换色),信息与
|
||||||
# 按钮全部上板;金蜡封 = 面板头部静态徽记(坠落演出落点被面板遮挡)。
|
# 按钮全部上板;金蜡封 = 面板头部静态徽记(坠落演出落点被面板遮挡)。
|
||||||
# 骨架经 UiKit.modal_shell;_dim 引用摘出供 open_* 换氛围色。
|
# 骨架经 UiKit.modal_shell;dim 引用摘出供 open_* 换氛围色。
|
||||||
var shell := UiKit.modal_shell(self, Color(COL_WARM, 0.0), Vector2(520, 0), 12,
|
var shell := UiKit.modal_shell(self, Color(COL_WARM, 0.0), Vector2(520, 0), 12,
|
||||||
UiKit.panel_skinned(Vector4(16, 14, 16, 14)))
|
UiKit.panel_skinned(Vector4(16, 14, 16, 14)))
|
||||||
st._dim = shell.dim
|
st.dim = shell.dim
|
||||||
var box: VBoxContainer = shell.box
|
var box: VBoxContainer = shell.box
|
||||||
_build_header(box)
|
_build_header(box)
|
||||||
_build_ledger(box)
|
_build_ledger(box)
|
||||||
@@ -62,20 +63,20 @@ func _build_header(box: VBoxContainer) -> void:
|
|||||||
header.add_theme_constant_override("separation", 12)
|
header.add_theme_constant_override("separation", 12)
|
||||||
header.alignment = BoxContainer.ALIGNMENT_CENTER
|
header.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
box.add_child(header)
|
box.add_child(header)
|
||||||
st._seal = Panel.new()
|
st.seal = Panel.new()
|
||||||
st._seal.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
st.seal.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
var sb := UiKit.panel_flat(COL_GOLD, UiKit.GOLD_DEEP, 200, 4)
|
var sb := UiKit.panel_flat(COL_GOLD, UiKit.GOLD_DEEP, 200, 4)
|
||||||
st._seal.add_theme_stylebox_override("panel", sb)
|
st.seal.add_theme_stylebox_override("panel", sb)
|
||||||
st._seal.custom_minimum_size = Vector2(52, 52)
|
st.seal.custom_minimum_size = Vector2(52, 52)
|
||||||
st._seal.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
st.seal.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
header.add_child(st._seal)
|
header.add_child(st.seal)
|
||||||
st._seal.add_child(_seal_img())
|
st.seal.add_child(_seal_img())
|
||||||
st._verdict = UiKit.label("",UiKit.FS_TITLE, true, UiKit.INK_TITLE)
|
st.verdict = UiKit.label("",UiKit.FS_TITLE, true, UiKit.INK_TITLE)
|
||||||
st._verdict.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
st.verdict.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
st._verdict.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
st.verdict.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
header.add_child(st._verdict)
|
header.add_child(st.verdict)
|
||||||
st._cele = _cele_rect()
|
st.cele = _cele_rect()
|
||||||
header.add_child(st._cele)
|
header.add_child(st.cele)
|
||||||
|
|
||||||
|
|
||||||
## 蜡封图域(32px 像素过滤居中)
|
## 蜡封图域(32px 像素过滤居中)
|
||||||
@@ -110,30 +111,30 @@ func _cele_rect() -> TextureRect:
|
|||||||
|
|
||||||
## 三行账域(两列对齐账行——审计差距④对齐 demo ⑧:项目名左/数值右,定宽 360)
|
## 三行账域(两列对齐账行——审计差距④对齐 demo ⑧:项目名左/数值右,定宽 360)
|
||||||
func _build_ledger(box: VBoxContainer) -> void:
|
func _build_ledger(box: VBoxContainer) -> void:
|
||||||
st._rows_box = VBoxContainer.new()
|
st.rows_box = VBoxContainer.new()
|
||||||
st._rows_box.add_theme_constant_override("separation", 6)
|
st.rows_box.add_theme_constant_override("separation", 6)
|
||||||
st._rows_box.visible = false
|
st.rows_box.visible = false
|
||||||
box.add_child(st._rows_box)
|
box.add_child(st.rows_box)
|
||||||
_gp_row = _ledger_row()
|
_gp_row = _ledger_row()
|
||||||
_gp_name = _ledger_name(UiKit.FS_SUB, UiKit.GOLD_INK, true) # GOLD_DEEP 对结算板 2.67:1 越带,换深金墨 5.21:1
|
_gp_name = _ledger_name(UiKit.FS_SUB, UiKit.GOLD_INK, true) # GOLD_DEEP 对结算板 2.67:1 越带,换深金墨 5.21:1
|
||||||
_gp_val = _ledger_value(UiKit.FS_SUB, UiKit.GOLD_INK, true) # 同上
|
_gp_val = _ledger_value(UiKit.FS_SUB, UiKit.GOLD_INK, true) # 同上
|
||||||
_gp_row.add_child(_gp_name)
|
_gp_row.add_child(_gp_name)
|
||||||
_gp_row.add_child(_gp_val)
|
_gp_row.add_child(_gp_val)
|
||||||
st._rows_box.add_child(_gp_row)
|
st.rows_box.add_child(_gp_row)
|
||||||
st._ks_row = _ledger_row()
|
st.ks_row = _ledger_row()
|
||||||
st._ks_name = _ledger_name(UiKit.FS_BODY, UiKit.INK_LABEL, false)
|
st.ks_name = _ledger_name(UiKit.FS_BODY, UiKit.INK_LABEL, false)
|
||||||
st._ks_val = _ledger_value(UiKit.FS_BODY, UiKit.INK_LABEL, true)
|
st.ks_val = _ledger_value(UiKit.FS_BODY, UiKit.INK_LABEL, true)
|
||||||
st._ks_row.add_child(st._ks_name)
|
st.ks_row.add_child(st.ks_name)
|
||||||
st._ks_row.add_child(st._ks_val)
|
st.ks_row.add_child(st.ks_val)
|
||||||
st._ks_row.visible = false
|
st.ks_row.visible = false
|
||||||
st._rows_box.add_child(st._ks_row)
|
st.rows_box.add_child(st.ks_row)
|
||||||
st._bonus_row_l = _ledger_row()
|
st.bonus_row_l = _ledger_row()
|
||||||
st._bonus_name = _ledger_name(UiKit.FS_HINT, UiKit.INK_LABEL, false)
|
st.bonus_name = _ledger_name(UiKit.FS_HINT, UiKit.INK_LABEL, false)
|
||||||
st._bonus_val = _ledger_value(UiKit.FS_HINT, UiKit.INK_LABEL, true)
|
st.bonus_val = _ledger_value(UiKit.FS_HINT, UiKit.INK_LABEL, true)
|
||||||
st._bonus_row_l.add_child(st._bonus_name)
|
st.bonus_row_l.add_child(st.bonus_name)
|
||||||
st._bonus_row_l.add_child(st._bonus_val)
|
st.bonus_row_l.add_child(st.bonus_val)
|
||||||
st._bonus_row_l.visible = false
|
st.bonus_row_l.visible = false
|
||||||
st._rows_box.add_child(st._bonus_row_l)
|
st.rows_box.add_child(st.bonus_row_l)
|
||||||
box.add_child(HSeparator.new())
|
box.add_child(HSeparator.new())
|
||||||
|
|
||||||
|
|
||||||
@@ -147,19 +148,19 @@ func open_victory(verdict_line: String, continue_label: String, board_rect: Rect
|
|||||||
var bonus_summary: String = opts.get("bonus_summary", "")
|
var bonus_summary: String = opts.get("bonus_summary", "")
|
||||||
var gp_gain: int = opts.get("gp_gain", -1)
|
var gp_gain: int = opts.get("gp_gain", -1)
|
||||||
var gp_total: int = opts.get("gp_total", -1)
|
var gp_total: int = opts.get("gp_total", -1)
|
||||||
st._dim.color = Color(UiKit.DIM_NIGHT, 0.62) # 全屏压暗对齐 demo
|
st.dim.color = Color(UiKit.DIM_NIGHT, 0.62) # 全屏压暗对齐 demo
|
||||||
st._verdict.text = verdict_line
|
st.verdict.text = verdict_line
|
||||||
st._seal.visible = true # 胜利徽记(面板头部静态)
|
st.seal.visible = true # 胜利徽记(面板头部静态)
|
||||||
st._seal.modulate = Color.WHITE
|
st.seal.modulate = Color.WHITE
|
||||||
_set_ledger_row(_gp_name, _gp_val, gp_summary, true) # GP 行=固定名「战利品 GP」(滚动/整串均只入值列)
|
_set_ledger_row(_gp_name, _gp_val, gp_summary, true) # GP 行=固定名「战利品 GP」(滚动/整串均只入值列)
|
||||||
_set_ledger_row(st._ks_name, st._ks_val, ks_summary)
|
_set_ledger_row(st.ks_name, st.ks_val, ks_summary)
|
||||||
st._ks_row.visible = ks_summary != ""
|
st.ks_row.visible = ks_summary != ""
|
||||||
_set_ledger_row(st._bonus_name, st._bonus_val, bonus_summary)
|
_set_ledger_row(st.bonus_name, st.bonus_val, bonus_summary)
|
||||||
st._bonus_row_l.visible = bonus_summary != ""
|
st.bonus_row_l.visible = bonus_summary != ""
|
||||||
st._rows_box.visible = gp_summary != "" or ks_summary != "" or bonus_summary != ""
|
st.rows_box.visible = gp_summary != "" or ks_summary != "" or bonus_summary != ""
|
||||||
_btn.text = continue_label
|
_btn.text = continue_label
|
||||||
st._board_rect = board_rect
|
st.board_rect = board_rect
|
||||||
st._cele.visible = true
|
st.cele.visible = true
|
||||||
_play_celebrate()
|
_play_celebrate()
|
||||||
visible = true
|
visible = true
|
||||||
if UiKit.victory_fx_style == "dust":
|
if UiKit.victory_fx_style == "dust":
|
||||||
@@ -173,23 +174,23 @@ func open_victory(verdict_line: String, continue_label: String, board_rect: Rect
|
|||||||
|
|
||||||
func open_defeat(verdict_line: String, continue_label: String, board_rect: Rect2) -> void:
|
func open_defeat(verdict_line: String, continue_label: String, board_rect: Rect2) -> void:
|
||||||
# 明度不变的暮蓝色相氛围(全屏唯一暮蓝档——§2.5 最静一拍)
|
# 明度不变的暮蓝色相氛围(全屏唯一暮蓝档——§2.5 最静一拍)
|
||||||
st._dim.color = Color(COL_DUSK, 0.6) # 同族压暗
|
st.dim.color = Color(COL_DUSK, 0.6) # 同族压暗
|
||||||
st._verdict.text = verdict_line
|
st.verdict.text = verdict_line
|
||||||
st._board_rect = board_rect
|
st.board_rect = board_rect
|
||||||
visible = true
|
visible = true
|
||||||
st._seal.visible = true
|
st.seal.visible = true
|
||||||
st._seal.modulate = Color(0.4, 0.4, 0.4) # 失败徽记灰化(demo ⑧)
|
st.seal.modulate = Color(0.4, 0.4, 0.4) # 失败徽记灰化(demo ⑧)
|
||||||
st._cele.visible = false
|
st.cele.visible = false
|
||||||
st._rows_box.visible = false # 失败侧不呈现账行
|
st.rows_box.visible = false # 失败侧不呈现账行
|
||||||
_play_dust_sadle() # 坐砖掸灰(§2.5——终稿)
|
_play_dust_sadle() # 坐砖掸灰(§2.5——终稿)
|
||||||
_play_seal_recall(8)
|
_play_seal_recall(8)
|
||||||
|
|
||||||
|
|
||||||
func close() -> void:
|
func close() -> void:
|
||||||
visible = false
|
visible = false
|
||||||
st._seal.visible = false
|
st.seal.visible = false
|
||||||
st._seal.modulate = Color.WHITE
|
st.seal.modulate = Color.WHITE
|
||||||
st._cele.visible = false
|
st.cele.visible = false
|
||||||
var tw: Tween = get_meta(&"celebrate_tw", null) # 循环句柄随节点存(跨 open/close,close 必杀)
|
var tw: Tween = get_meta(&"celebrate_tw", null) # 循环句柄随节点存(跨 open/close,close 必杀)
|
||||||
if tw != null and tw.is_valid():
|
if tw != null and tw.is_valid():
|
||||||
tw.kill()
|
tw.kill()
|
||||||
@@ -202,7 +203,7 @@ func is_open() -> bool:
|
|||||||
|
|
||||||
|
|
||||||
func verdict_text() -> String:
|
func verdict_text() -> String:
|
||||||
return st._verdict.text
|
return st.verdict.text
|
||||||
|
|
||||||
|
|
||||||
# 两列账行工厂(审计差距④——名左/值右,定宽 360)
|
# 两列账行工厂(审计差距④——名左/值右,定宽 360)
|
||||||
@@ -249,8 +250,8 @@ func _fx_center() -> Vector2:
|
|||||||
|
|
||||||
# 封印化光点收回(失败——插过的封印逐面化光点收回占位,§2.5)
|
# 封印化光点收回(失败——插过的封印逐面化光点收回占位,§2.5)
|
||||||
func _play_seal_recall(count: int) -> void:
|
func _play_seal_recall(count: int) -> void:
|
||||||
st._fx_counts["seal"] = count
|
st.fx_counts["seal"] = count
|
||||||
var base := st._board_rect.get_center() if st._board_rect.size != Vector2.ZERO else get_viewport_rect().size * 0.5
|
var base := st.board_rect.get_center() if st.board_rect.size != Vector2.ZERO else get_viewport_rect().size * 0.5
|
||||||
for i in count:
|
for i in count:
|
||||||
_spawn_seal_dot(i, base)
|
_spawn_seal_dot(i, base)
|
||||||
|
|
||||||
@@ -260,8 +261,8 @@ func _spawn_seal_dot(i: int, base: Vector2) -> void:
|
|||||||
var dot := ColorRect.new()
|
var dot := ColorRect.new()
|
||||||
dot.color = COL_GOLD
|
dot.color = COL_GOLD
|
||||||
dot.size = Vector2(6, 6)
|
dot.size = Vector2(6, 6)
|
||||||
dot.position = base + Vector2((float(i % 5) - 2.0) * st._board_rect.size.x * 0.14 if st._board_rect.size.x > 0 else 0.0,
|
dot.position = base + Vector2((float(i % 5) - 2.0) * st.board_rect.size.x * 0.14 if st.board_rect.size.x > 0 else 0.0,
|
||||||
(float(i % 3) - 1.0) * st._board_rect.size.y * 0.18)
|
(float(i % 3) - 1.0) * st.board_rect.size.y * 0.18)
|
||||||
dot.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
dot.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
add_child(dot)
|
add_child(dot)
|
||||||
var tw := dot.create_tween()
|
var tw := dot.create_tween()
|
||||||
@@ -277,7 +278,7 @@ func _spawn_seal_dot(i: int, base: Vector2) -> void:
|
|||||||
# 碎砖拼纹章(胜利 §2.4——蜡封落定后十枚碎砖自四周向蜡封外环收拢拼成纹章环,驻留至 close)
|
# 碎砖拼纹章(胜利 §2.4——蜡封落定后十枚碎砖自四周向蜡封外环收拢拼成纹章环,驻留至 close)
|
||||||
func _play_crest_assemble() -> void:
|
func _play_crest_assemble() -> void:
|
||||||
_clear_crest_bricks()
|
_clear_crest_bricks()
|
||||||
st._fx_counts["crest"] = 10
|
st.fx_counts["crest"] = 10
|
||||||
var c := _fx_center()
|
var c := _fx_center()
|
||||||
for i in 10:
|
for i in 10:
|
||||||
_spawn_crest_brick(i, c)
|
_spawn_crest_brick(i, c)
|
||||||
@@ -293,7 +294,7 @@ func _spawn_crest_brick(i: int, c: Vector2) -> void:
|
|||||||
var ring := c + Vector2(cos(ang), sin(ang)) * 64.0
|
var ring := c + Vector2(cos(ang), sin(ang)) * 64.0
|
||||||
brick.position = c + Vector2(cos(ang), sin(ang)) * 200.0 # 自四周场外入场
|
brick.position = c + Vector2(cos(ang), sin(ang)) * 200.0 # 自四周场外入场
|
||||||
add_child(brick)
|
add_child(brick)
|
||||||
st._crest_bricks.append(brick)
|
st.crest_bricks.append(brick)
|
||||||
var btw := brick.create_tween()
|
var btw := brick.create_tween()
|
||||||
btw.tween_interval(UiKit.motion(0.52)) # 待蜡封落定(seal 0.42+0.22 弹跳中段)
|
btw.tween_interval(UiKit.motion(0.52)) # 待蜡封落定(seal 0.42+0.22 弹跳中段)
|
||||||
btw.tween_property(brick, "position", ring - brick.size * 0.5, UiKit.motion(0.4)).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
btw.tween_property(brick, "position", ring - brick.size * 0.5, UiKit.motion(0.4)).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
||||||
@@ -302,7 +303,7 @@ func _spawn_crest_brick(i: int, c: Vector2) -> void:
|
|||||||
|
|
||||||
# 坐砖掸灰(失败 §2.5——暖灰尘絮自棋盘中带缓缓飘落,最静一拍的运动承载)
|
# 坐砖掸灰(失败 §2.5——暖灰尘絮自棋盘中带缓缓飘落,最静一拍的运动承载)
|
||||||
func _play_dust_sadle() -> void:
|
func _play_dust_sadle() -> void:
|
||||||
st._fx_counts["dust"] = 8
|
st.fx_counts["dust"] = 8
|
||||||
var base := _fx_center()
|
var base := _fx_center()
|
||||||
for i in 8:
|
for i in 8:
|
||||||
_spawn_dust_mote(i, base)
|
_spawn_dust_mote(i, base)
|
||||||
@@ -330,16 +331,16 @@ func _play_celebrate() -> void:
|
|||||||
var prev: Tween = get_meta(&"celebrate_tw", null)
|
var prev: Tween = get_meta(&"celebrate_tw", null)
|
||||||
if prev != null and prev.is_valid():
|
if prev != null and prev.is_valid():
|
||||||
prev.kill()
|
prev.kill()
|
||||||
var tw := st._cele.create_tween()
|
var tw := st.cele.create_tween()
|
||||||
set_meta(&"celebrate_tw", tw)
|
set_meta(&"celebrate_tw", tw)
|
||||||
tw.set_loops()
|
tw.set_loops()
|
||||||
tw.tween_property(st._cele, "position:y", st._cele.position.y - 4.0, UiKit.motion(0.6)).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
|
tw.tween_property(st.cele, "position:y", st.cele.position.y - 4.0, UiKit.motion(0.6)).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
|
||||||
tw.tween_property(st._cele, "position:y", st._cele.position.y, UiKit.motion(0.6)).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
|
tw.tween_property(st.cele, "position:y", st.cele.position.y, UiKit.motion(0.6)).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
|
||||||
|
|
||||||
|
|
||||||
# 尘金粒子(备选演出——金屑自面板上带飘落闪灭;确定性散布守 S2)
|
# 尘金粒子(备选演出——金屑自面板上带飘落闪灭;确定性散布守 S2)
|
||||||
func _play_victory_dust() -> void:
|
func _play_victory_dust() -> void:
|
||||||
st._fx_counts["dust"] += 10
|
st.fx_counts["dust"] += 10
|
||||||
var c := _fx_center()
|
var c := _fx_center()
|
||||||
for i in 10:
|
for i in 10:
|
||||||
_spawn_victory_mote(i, c)
|
_spawn_victory_mote(i, c)
|
||||||
@@ -372,15 +373,15 @@ func _roll_gp(gp_gain: int, gp_total: int) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _clear_crest_bricks() -> void:
|
func _clear_crest_bricks() -> void:
|
||||||
for b in st._crest_bricks:
|
for b in st.crest_bricks:
|
||||||
if is_instance_valid(b):
|
if is_instance_valid(b):
|
||||||
b.queue_free()
|
b.queue_free()
|
||||||
st._crest_bricks.clear()
|
st.crest_bricks.clear()
|
||||||
|
|
||||||
|
|
||||||
# 演出探针出口(fx_probe——胜利纹章/失败掸灰/封印光收回三断言面)
|
# 演出探针出口(fx_probe——胜利纹章/失败掸灰/封印光收回三断言面)
|
||||||
func fx_probe() -> Dictionary:
|
func fx_probe() -> Dictionary:
|
||||||
return {"crest_shards": st._fx_counts["crest"], "dust_motes": st._fx_counts["dust"], "seal_dots": st._fx_counts["seal"]}
|
return {"crest_shards": st.fx_counts["crest"], "dust_motes": st.fx_counts["dust"], "seal_dots": st.fx_counts["seal"]}
|
||||||
|
|
||||||
|
|
||||||
func _emit_continue_pressed() -> void:
|
func _emit_continue_pressed() -> void:
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ extends Node2D
|
|||||||
const _GLOW_LAYER := preload("res://presentation/views/cell_type_glow_layer.gd")
|
const _GLOW_LAYER := preload("res://presentation/views/cell_type_glow_layer.gd")
|
||||||
const _BASE_LAYER := preload("res://presentation/views/cell_base_layer.gd")
|
const _BASE_LAYER := preload("res://presentation/views/cell_base_layer.gd")
|
||||||
const _MARK_OVERLAY := preload("res://presentation/views/cell_mark_overlay.gd")
|
const _MARK_OVERLAY := preload("res://presentation/views/cell_mark_overlay.gd")
|
||||||
|
const _SEAL_LAYER := preload("res://presentation/views/seal_mark_layer.gd")
|
||||||
|
|
||||||
var edge := 46.0: # 格边长(BoardView.set_cell_area 单点驱动)
|
var edge := 46.0: # 格边长(BoardView.set_cell_area 单点驱动)
|
||||||
set(v):
|
set(v):
|
||||||
edge = v
|
edge = v
|
||||||
if _glow_layer != null and is_instance_valid(_glow_layer):
|
if _glow_layer != null and is_instance_valid(_glow_layer):
|
||||||
_glow_layer.setup(edge, glow_group)
|
_glow_layer.setup(edge, glow_group)
|
||||||
|
_sync_seal_layer()
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
var cell := Vector2i.ZERO # 板坐标(诊断观测面)
|
var cell := Vector2i.ZERO # 板坐标(诊断观测面)
|
||||||
# ── 未开格类型微光(英雄 8 向相邻未开格的组粒度类型提示)
|
# ── 未开格类型微光(英雄 8 向相邻未开格的组粒度类型提示)
|
||||||
@@ -41,16 +43,49 @@ var fog_state := 0: # 探针直读冻结
|
|||||||
set(v):
|
set(v):
|
||||||
if fog_state != v:
|
if fog_state != v:
|
||||||
fog_state = v
|
fog_state = v
|
||||||
|
_sync_seal_layer() # 封印随格隐没(§6.5——雾态 !=0 整层隐藏)
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
|
||||||
|
# ── 封印印记(卡④ 法阵化——着色器按格边参数化绘制,替代 tex_seal 贴图整格铺放)──
|
||||||
|
# BoardView paint 按格态写 seal_on(封印格=未开且未移除);子件 on 才建、off 撤、edge 变更重注入。
|
||||||
|
var seal_on := false:
|
||||||
|
set(v):
|
||||||
|
if seal_on != v:
|
||||||
|
seal_on = v
|
||||||
|
_sync_seal_layer()
|
||||||
|
|
||||||
var _glow_layer: Node2D = null
|
var _glow_layer: Node2D = null
|
||||||
|
var _seal_layer: Node2D = null # 封印印记子件(seal_on 才建——作用集=封印格)
|
||||||
var base = null # 格面基座层绘制域件(_init 自建)
|
var base = null # 格面基座层绘制域件(_init 自建)
|
||||||
var face = null # 格面标识与叠加层绘制域件(_init 自建)
|
var face = null # 格面标识与叠加层绘制域件(_init 自建)
|
||||||
|
|
||||||
|
|
||||||
|
# 封印子件生命周期单点:on 才建、off 撤;visible = seal_on 且非雾态(§6.5 随格隐没)
|
||||||
|
func _sync_seal_layer() -> void:
|
||||||
|
if seal_on and _seal_layer == null:
|
||||||
|
_seal_layer = _SEAL_LAYER.new()
|
||||||
|
add_child(_seal_layer)
|
||||||
|
if _seal_layer != null and not is_instance_valid(_seal_layer):
|
||||||
|
_seal_layer = null
|
||||||
|
return
|
||||||
|
if _seal_layer == null:
|
||||||
|
return
|
||||||
|
if not seal_on:
|
||||||
|
_seal_layer.queue_free()
|
||||||
|
_seal_layer = null
|
||||||
|
return
|
||||||
|
_seal_layer.setup(edge, fog_state == 0)
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
base = _BASE_LAYER.new(self)
|
base = _BASE_LAYER.new(self)
|
||||||
face = _MARK_OVERLAY.new(self)
|
face = _MARK_OVERLAY.new(self, _set_badge_mask)
|
||||||
|
|
||||||
|
|
||||||
|
# 徽章遮罩下发口(构造交付 Callable——glow 层引用自持本件,face 零私取回引)
|
||||||
|
func _set_badge_mask(on: bool) -> void:
|
||||||
|
if _glow_layer != null and is_instance_valid(_glow_layer):
|
||||||
|
_glow_layer.set_badge_mask(on)
|
||||||
|
|
||||||
|
|
||||||
func _draw() -> void:
|
func _draw() -> void:
|
||||||
|
|||||||
@@ -33,7 +33,24 @@ func _init(bundle: Dictionary) -> void:
|
|||||||
_cb_chord = bundle["chord"]
|
_cb_chord = bundle["chord"]
|
||||||
|
|
||||||
|
|
||||||
func _hover_at(pos: Vector2) -> void:
|
# ---- 公开操作面(pres封装 A2——宿主经此驱动,字段保持私有)----
|
||||||
|
|
||||||
|
# 每战重绑(排雷玩法对象随战更替——宿主 rebuild 同拍调用)
|
||||||
|
func rebind(minesweeper: Variant) -> void:
|
||||||
|
_minesweeper = minesweeper
|
||||||
|
|
||||||
|
|
||||||
|
# 硬复位悬停锚(无 unhover 视觉清理——宿主 rebuild 前提下视觉随重建清零)
|
||||||
|
func reset() -> void:
|
||||||
|
_hover = Vector2i(-9, -9)
|
||||||
|
|
||||||
|
|
||||||
|
# 悬停现值读口(宿主呈现查询)
|
||||||
|
func hover_pos() -> Vector2i:
|
||||||
|
return _hover
|
||||||
|
|
||||||
|
|
||||||
|
func hover_at(pos: Vector2) -> void:
|
||||||
var c: Vector2i = _cb_cell_at.call(pos)
|
var c: Vector2i = _cb_cell_at.call(pos)
|
||||||
if c.x < 0:
|
if c.x < 0:
|
||||||
if _hover.x >= 0:
|
if _hover.x >= 0:
|
||||||
@@ -44,13 +61,13 @@ func _hover_at(pos: Vector2) -> void:
|
|||||||
_on_cell_hover(c)
|
_on_cell_hover(c)
|
||||||
|
|
||||||
|
|
||||||
func _on_shell_mouse_exited() -> void:
|
func on_shell_mouse_exited() -> void:
|
||||||
if _hover.x >= 0:
|
if _hover.x >= 0:
|
||||||
_on_cell_unhover(_hover)
|
_on_cell_unhover(_hover)
|
||||||
|
|
||||||
|
|
||||||
# chord 肌肉记忆首遇锚:同格双左击快开尝试(350ms 窗)——每 run 一次提示由组合根去重
|
# chord 肌肉记忆首遇锚:同格双左击快开尝试(350ms 窗)——每 run 一次提示由组合根去重
|
||||||
func _detect_chord(c: Vector2i) -> void:
|
func detect_chord(c: Vector2i) -> void:
|
||||||
var now := Time.get_ticks_msec()
|
var now := Time.get_ticks_msec()
|
||||||
if _last_click.cell == c and now - int(_last_click.ms) <= CHORD_WINDOW_MS:
|
if _last_click.cell == c and now - int(_last_click.ms) <= CHORD_WINDOW_MS:
|
||||||
_cb_chord.call(c)
|
_cb_chord.call(c)
|
||||||
@@ -70,7 +87,7 @@ func _on_cell_unhover(c: Vector2i) -> void:
|
|||||||
_clear_hover_visuals(c)
|
_clear_hover_visuals(c)
|
||||||
|
|
||||||
|
|
||||||
func _refresh_hover_after_paint() -> void:
|
func refresh_after_paint() -> void:
|
||||||
# 状态随 refresh 变化后光标/边框语义需重算(悬停格四格态可能已变)
|
# 状态随 refresh 变化后光标/边框语义需重算(悬停格四格态可能已变)
|
||||||
if _hover.x >= 0 and _cells.has(_hover):
|
if _hover.x >= 0 and _cells.has(_hover):
|
||||||
_apply_hover_visuals(_hover)
|
_apply_hover_visuals(_hover)
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ var _palette = _TILE_PALETTE.new() # 瓦片件:装载缓存+查表+
|
|||||||
var _hero_sprite = _HERO_SPRITE.new() # 英雄精灵件:_init 挂为本件子级(tween 需在树上)
|
var _hero_sprite = _HERO_SPRITE.new() # 英雄精灵件:_init 挂为本件子级(tween 需在树上)
|
||||||
var _hover_comp: _BOARD_HOVER # 悬停预承诺呈现域件:三语义光标/目标格边框/路径预览/chord 首遇锚(_init 建为子件——HeroSprite 挂载先例)
|
var _hover_comp: _BOARD_HOVER # 悬停预承诺呈现域件:三语义光标/目标格边框/路径预览/chord 首遇锚(_init 建为子件——HeroSprite 挂载先例)
|
||||||
|
|
||||||
# ── 件成员同名转发(探针直读面零改动:读 _palette.seal_tex、读写 _hero_sprite.tex_idle;其余为随迁状态单点再导出)──
|
# ── 件成员同名转发(探针直读面零改动:读写 _hero_sprite.tex_idle;其余为随迁状态单点再导出)──
|
||||||
# ---- 视野迷雾(纯呈现层;现行事实源=HUD框架「视野迷雾」节 v0.13,渲染规格=art-bible §6.5 v3.5)----
|
# ---- 视野迷雾(纯呈现层;现行事实源=HUD框架「视野迷雾」节 v0.13,渲染规格=art-bible §6.5 v3.5)----
|
||||||
const FOG_RADIUS := 8 # 菱形灯光区基准半径(曼哈顿距离 ≤R——与微光环「周围 8 格」同圈起步;半径基准值改动=非白名单须用户)
|
const FOG_RADIUS := 8 # 菱形灯光区基准半径(曼哈顿距离 ≤R——与微光环「周围 8 格」同圈起步;半径基准值改动=非白名单须用户)
|
||||||
var _fog_enabled := true # 迷雾开关(呈现态布尔——真实游戏恒 on;探针/夹具可 off=无迷雾基线,两态结算逐位一致断言面)
|
var _fog_enabled := true # 迷雾开关(呈现态布尔——真实游戏恒 on;探针/夹具可 off=无迷雾基线,两态结算逐位一致断言面)
|
||||||
@@ -143,7 +143,7 @@ func board() -> BoardData:
|
|||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_apply_custom_cursors()
|
_apply_custom_cursors()
|
||||||
mouse_exited.connect(_hover_comp._on_shell_mouse_exited)
|
mouse_exited.connect(_hover_comp.on_shell_mouse_exited)
|
||||||
|
|
||||||
|
|
||||||
# 结算期/道具窗口态:D 区去饱和 + 金橙偏移锁输入(明度不变——art-bible §2);
|
# 结算期/道具窗口态:D 区去饱和 + 金橙偏移锁输入(明度不变——art-bible §2);
|
||||||
@@ -246,7 +246,7 @@ func _refresh_slab() -> void:
|
|||||||
func rebuild(board: BoardData, minesweeper: MinesweeperRules) -> void:
|
func rebuild(board: BoardData, minesweeper: MinesweeperRules) -> void:
|
||||||
_board = board
|
_board = board
|
||||||
_minesweeper = minesweeper
|
_minesweeper = minesweeper
|
||||||
_hover_comp._minesweeper = _minesweeper # 件内只读引用随宿主重绑同拍回写(每战新排雷玩法对象)
|
_hover_comp.rebind(_minesweeper) # 件内只读引用随宿主重绑同拍回写(每战新排雷玩法对象)
|
||||||
_palette.bind_board(_board, _minesweeper) # 查表族棋盘态随板同步(换板后首拍 refresh 前置)
|
_palette.bind_board(_board, _minesweeper) # 查表族棋盘态随板同步(换板后首拍 refresh 前置)
|
||||||
for child in _world.get_children():
|
for child in _world.get_children():
|
||||||
child.queue_free()
|
child.queue_free()
|
||||||
@@ -257,7 +257,7 @@ func rebuild(board: BoardData, minesweeper: MinesweeperRules) -> void:
|
|||||||
_contact_unit = null
|
_contact_unit = null
|
||||||
_hero_sprite.last = Vector2i(-99, -99)
|
_hero_sprite.last = Vector2i(-99, -99)
|
||||||
_r0.clear()
|
_r0.clear()
|
||||||
_hover_comp._hover = Vector2i(-9, -9)
|
_hover_comp.reset()
|
||||||
for c in _board.compute_r0():
|
for c in _board.compute_r0():
|
||||||
_r0[c] = true
|
_r0[c] = true
|
||||||
# 瓦片套随板图型切换(board_gen 词表 v1.1 dungeon/underdark/deep_underdark;
|
# 瓦片套随板图型切换(board_gen 词表 v1.1 dungeon/underdark/deep_underdark;
|
||||||
@@ -306,7 +306,7 @@ func refresh() -> void:
|
|||||||
for y in _board.height:
|
for y in _board.height:
|
||||||
for x in _board.width:
|
for x in _board.width:
|
||||||
_paint_cell(Vector2i(x, y), hero)
|
_paint_cell(Vector2i(x, y), hero)
|
||||||
_hover_comp._refresh_hover_after_paint()
|
_hover_comp.refresh_after_paint()
|
||||||
_apply_contact_bands()
|
_apply_contact_bands()
|
||||||
_update_hero(hero) # 英雄精灵 diff 驱动
|
_update_hero(hero) # 英雄精灵 diff 驱动
|
||||||
|
|
||||||
@@ -461,7 +461,7 @@ func _gui_input(ev: InputEvent) -> void:
|
|||||||
if _minesweeper == null:
|
if _minesweeper == null:
|
||||||
return
|
return
|
||||||
if ev is InputEventMouseMotion:
|
if ev is InputEventMouseMotion:
|
||||||
_hover_comp._hover_at(ev.position)
|
_hover_comp.hover_at(ev.position)
|
||||||
elif ev is InputEventMouseButton and ev.pressed:
|
elif ev is InputEventMouseButton and ev.pressed:
|
||||||
var c := _cell_at(ev.position)
|
var c := _cell_at(ev.position)
|
||||||
if c.x >= 0:
|
if c.x >= 0:
|
||||||
@@ -476,7 +476,7 @@ func _on_cell_input(c: Vector2i, ev: InputEvent) -> void:
|
|||||||
action_requested.emit(c, "move")
|
action_requested.emit(c, "move")
|
||||||
else:
|
else:
|
||||||
action_requested.emit(c, "dig")
|
action_requested.emit(c, "dig")
|
||||||
_hover_comp._detect_chord(c)
|
_hover_comp.detect_chord(c)
|
||||||
elif ev.button_index == MOUSE_BUTTON_RIGHT:
|
elif ev.button_index == MOUSE_BUTTON_RIGHT:
|
||||||
if not _minesweeper.has_seal(c):
|
if not _minesweeper.has_seal(c):
|
||||||
action_requested.emit(c, "seal_place")
|
action_requested.emit(c, "seal_place")
|
||||||
@@ -536,13 +536,13 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
|
|||||||
var seal: bool = _minesweeper.has_seal(c)
|
var seal: bool = _minesweeper.has_seal(c)
|
||||||
var removed: bool = _minesweeper.is_removed(c) # 中立移除格(退色降档)
|
var removed: bool = _minesweeper.is_removed(c) # 中立移除格(退色降档)
|
||||||
var is_hero: bool = c == hero
|
var is_hero: bool = c == hero
|
||||||
# 封印槽统一维护:封印格=封印印记纹理;其余格清 null(封印格挖开后残留在 tex_seal
|
# 封印印记下发(卡④ 法阵化):封印格=未开且未移除 → CellUnit 封印子件绘制(着色器参数化);
|
||||||
# 会让 _draw 无条件把封印印画在已开格上——tex_seal 绘制无 revealed 条件)。缺盘走字形回退。
|
# 其余格撤子件。层序与迷雾门控在 CellUnit 侧承载(seal_mark_layer/fog_state 联动)。
|
||||||
u.face.tex_seal = _palette.seal_tex if (seal and not revealed and _palette.seal_tex != null) else null
|
u.seal_on = seal and not revealed
|
||||||
if removed:
|
if removed:
|
||||||
revealed = false # 移除格固定未开呈现基座(退色暗幕层承载;危险格本无数字,周边数字冻结)
|
revealed = false # 移除格固定未开呈现基座(退色暗幕层承载;危险格本无数字,周边数字冻结)
|
||||||
seal = false
|
seal = false
|
||||||
u.face.tex_seal = null
|
u.seal_on = false
|
||||||
# 绘制层五段(字形与色牌→基底瓦片→立面投影→秘宝/变异叠加→迷雾)——段间交换经单元状态面
|
# 绘制层五段(字形与色牌→基底瓦片→立面投影→秘宝/变异叠加→迷雾)——段间交换经单元状态面
|
||||||
#(u.base/u.face 域件与 u.glyph/u.glyph_color),唯一例外=基底色 bg 经 ink 段返回值交 base 段(无单元场域承载)
|
#(u.base/u.face 域件与 u.glyph/u.glyph_color),唯一例外=基底色 bg 经 ink 段返回值交 base 段(无单元场域承载)
|
||||||
var bg: Color = _paint_cell_ink(c, u, revealed, seal)
|
var bg: Color = _paint_cell_ink(c, u, revealed, seal)
|
||||||
@@ -577,10 +577,7 @@ func _paint_cell_ink(c: Vector2i, u: Node2D, revealed: bool, seal: bool) -> Colo
|
|||||||
digit_col = _digit_ink(d) # 数字墨三档色温(§4.1)
|
digit_col = _digit_ink(d) # 数字墨三档色温(§4.1)
|
||||||
else:
|
else:
|
||||||
if seal:
|
if seal:
|
||||||
bg = COL_BRICK
|
bg = COL_BRICK # 封印印记由 CellUnit 封印子件绘制(卡④ 法阵化——缺图字形回退随贴图路径退役)
|
||||||
if _palette.seal_tex == null:
|
|
||||||
glyph = "封"
|
|
||||||
digit_col = COL_SEAL
|
|
||||||
else:
|
else:
|
||||||
bg = COL_BRICK
|
bg = COL_BRICK
|
||||||
u.glyph = glyph
|
u.glyph = glyph
|
||||||
@@ -825,7 +822,7 @@ func diggable_probe() -> Dictionary:
|
|||||||
|
|
||||||
# 悬停格只读出口(case① 悬停到达断言消费面——读件投影,返回语义零变化)
|
# 悬停格只读出口(case① 悬停到达断言消费面——读件投影,返回语义零变化)
|
||||||
func hover_probe() -> Vector2i:
|
func hover_probe() -> Vector2i:
|
||||||
return _hover_comp._hover
|
return _hover_comp.hover_pos()
|
||||||
|
|
||||||
|
|
||||||
# 迷雾参数只读快照(case⑮ 参数漂移断言消费面)
|
# 迷雾参数只读快照(case⑮ 参数漂移断言消费面)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
## 布局唯一事实源 = db.presentation.camp_scene_layout(构造注入,本视图禁自载表路径);
|
## 布局唯一事实源 = db.presentation.camp_scene_layout(构造注入,本视图禁自载表路径);
|
||||||
## 子节点序 = 表内数组序 = z 序(Control 根+TextureRect 层——禁 CanvasLayer/z_index/Sprite2D)。
|
## 子节点序 = 表内数组序 = z 序(Control 根+TextureRect 层——禁 CanvasLayer/z_index/Sprite2D)。
|
||||||
## 输入单点:根 _gui_input 集中命中判定(层节点全 IGNORE),点击只发 object_pressed 信号,路由归组合根。
|
## 输入单点:根 _gui_input 集中命中判定(层节点全 IGNORE),点击只发 object_pressed 信号,路由归组合根。
|
||||||
## 零核心写调用:视图不读 MetaProgression,禁用态由组合根经 set_feedback_state 推送。
|
## 零核心写调用:视图不读 MetaProgression,禁用态经 _apply_state 自持基态面呈现。
|
||||||
class_name CampSceneView
|
class_name CampSceneView
|
||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@@ -85,13 +85,6 @@ func get_hotspot_rect(key: StringName) -> Rect2:
|
|||||||
return rect
|
return rect
|
||||||
|
|
||||||
|
|
||||||
func set_feedback_state(key: StringName, state: FeedbackState) -> void:
|
|
||||||
if not _base_states.has(key):
|
|
||||||
return
|
|
||||||
_base_states[key] = state # 持久基态只收 NORMAL/DISABLED;HOVER/PRESSED 为视图内瞬态
|
|
||||||
_apply_state(key, _base_state(key))
|
|
||||||
|
|
||||||
|
|
||||||
func set_hud_band(band: Control) -> void:
|
func set_hud_band(band: Control) -> void:
|
||||||
if _hud_slot != null:
|
if _hud_slot != null:
|
||||||
_hud_slot.add_child(band)
|
_hud_slot.add_child(band)
|
||||||
|
|||||||
@@ -3,15 +3,16 @@
|
|||||||
## 变异标记/数字色牌与字形/奖励徽章/封印/路径点迹/焦点高亮/中立移除退色的全部绘制入参与绘制命令。
|
## 变异标记/数字色牌与字形/奖励徽章/封印/路径点迹/焦点高亮/中立移除退色的全部绘制入参与绘制命令。
|
||||||
## 无 class_name(类名缓存面纪律)——经宿主 board_cell_unit preload 引用;宿主 _draw 按层序调
|
## 无 class_name(类名缓存面纪律)——经宿主 board_cell_unit preload 引用;宿主 _draw 按层序调
|
||||||
## draw_marks/draw_glyph_layer/draw_overlay_under/draw_removed_dim(雾层由宿主夹在 overlay_under 与 removed_dim 之间);
|
## draw_marks/draw_glyph_layer/draw_overlay_under/draw_removed_dim(雾层由宿主夹在 overlay_under 与 removed_dim 之间);
|
||||||
## setter 经 _owner 回引触发宿主重绘语义逐字(badge_glyph 的 glow mask 回引 _owner._glow_layer 原样)。
|
## setter 经 _owner 回引触发宿主重绘语义逐字(badge_glyph 的 glow mask 经构造交付 Callable 下发——pres封装 C)。
|
||||||
extends RefCounted
|
extends RefCounted
|
||||||
|
|
||||||
var _owner: Node2D = null
|
var _owner: Node2D = null
|
||||||
|
var _mask_set: Callable # 徽章遮罩下发口(构造交付——宿主 CellUnit 自持 glow 层引用,本件零回引宿主私有面)
|
||||||
var badge_glyph := "": # 奖励徽章文字(右下角金——封印之下、变异纹之上、不进数字区)
|
var badge_glyph := "": # 奖励徽章文字(右下角金——封印之下、变异纹之上、不进数字区)
|
||||||
set(v):
|
set(v):
|
||||||
badge_glyph = v
|
badge_glyph = v
|
||||||
if _owner._glow_layer != null and is_instance_valid(_owner._glow_layer):
|
if _mask_set.is_valid():
|
||||||
_owner._glow_layer.set_badge_mask(v != "")
|
_mask_set.call(v != "")
|
||||||
_owner.queue_redraw()
|
_owner.queue_redraw()
|
||||||
var dot_visible := false: # BFS 路径预览点迹(中心 6×6 小人蓝)
|
var dot_visible := false: # BFS 路径预览点迹(中心 6×6 小人蓝)
|
||||||
set(v):
|
set(v):
|
||||||
@@ -30,11 +31,6 @@ var font: Font = null # 字体槽位(null = ThemeDB.fallback_font
|
|||||||
var tex_mutation: Texture2D = null # ② 变异纹带
|
var tex_mutation: Texture2D = null # ② 变异纹带
|
||||||
var tex_glyph: Texture2D = null # ③ 数字
|
var tex_glyph: Texture2D = null # ③ 数字
|
||||||
var tex_badge: Texture2D = null # ③' 徽章
|
var tex_badge: Texture2D = null # ③' 徽章
|
||||||
var tex_seal: Texture2D = null: # ④ 封印(槽位可运行时换装〔封印〕——同族 facade/treasure_mark
|
|
||||||
set(v): # 均 setter 触发重绘(普通 var 赋值不重绘=封印插上不显示))
|
|
||||||
if tex_seal != v:
|
|
||||||
tex_seal = v
|
|
||||||
_owner.queue_redraw()
|
|
||||||
# 变异角标(程序化,tex_mutation 纹带槽暂留):
|
# 变异角标(程序化,tex_mutation 纹带槽暂留):
|
||||||
# "flat_damage" = 未开格伤害型变异,左下角危险红三角(开格有代价的策略纹理标记)
|
# "flat_damage" = 未开格伤害型变异,左下角危险红三角(开格有代价的策略纹理标记)
|
||||||
# 叠加层标记(秘宝整图叠加层的格面呈现;派生信息层零回写):
|
# 叠加层标记(秘宝整图叠加层的格面呈现;派生信息层零回写):
|
||||||
@@ -56,8 +52,9 @@ var removed_dim := false: # 中立移除退色层(BoardView paint
|
|||||||
_owner.queue_redraw()
|
_owner.queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
func _init(owner: Node2D) -> void:
|
func _init(owner: Node2D, mask_set: Callable) -> void:
|
||||||
_owner = owner
|
_owner = owner
|
||||||
|
_mask_set = mask_set
|
||||||
|
|
||||||
|
|
||||||
## 变异标记域:真视格=危险红内缩框/未开格伤害型变异=左下角危险红三角
|
## 变异标记域:真视格=危险红内缩框/未开格伤害型变异=左下角危险红三角
|
||||||
@@ -91,9 +88,7 @@ func draw_glyph_layer(canvas: CanvasItem, rect: Rect2, glyph: String, glyph_colo
|
|||||||
canvas.draw_texture_rect(tex_badge, rect, false)
|
canvas.draw_texture_rect(tex_badge, rect, false)
|
||||||
else:
|
else:
|
||||||
_draw_badge(canvas, rect, badge_glyph)
|
_draw_badge(canvas, rect, badge_glyph)
|
||||||
# ④ 封印(现行视觉封印文字在 ③ 文字位承载——独立槽位留给封印图)
|
# ④ 封印:印记由 CellUnit 封印子件(seal_mark_layer)参数化绘制——本域件零封印绘制(卡④ 法阵化)
|
||||||
if tex_seal != null:
|
|
||||||
canvas.draw_texture_rect(tex_seal, rect, false)
|
|
||||||
|
|
||||||
|
|
||||||
## 数字色牌后备域(圣经 v3.5 冻结④:数字亮墨直画已开格底须垫牌;
|
## 数字色牌后备域(圣经 v3.5 冻结④:数字亮墨直画已开格底须垫牌;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
## VERTICAL SLICE - NOT FOR PRODUCTION
|
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||||||
## 开发调试浮窗:全局可开(组合根启动即开+两屏角标再开),当局数据只读区块为本局种子唯一查看位。
|
## 开发调试浮窗:全局可开(组合根启动即开+两屏角标再开),当局数据只读区块为本局种子唯一查看位。
|
||||||
## 扩展调试项按区块往下追加(超高滚动);模拟报告文案装配归 HudPresenter——本类零动效零文案装配。
|
## 扩展调试项按区块往下追加(超高滚动);模拟报告文案装配归 HudPresenter——本类零动效零文案装配。
|
||||||
|
## 内部数据类 _DebugState=宿主画面登记表(只被本文件填读,文件外零消费者——字段为公开数据成员)。
|
||||||
class_name DebugOverlay
|
class_name DebugOverlay
|
||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@@ -12,22 +13,22 @@ signal closed
|
|||||||
|
|
||||||
## 内部状态件(u7 子域拆件——契约 9 职责语句「调试浮窗运行态」):单一变化原因=调试面板状态与
|
## 内部状态件(u7 子域拆件——契约 9 职责语句「调试浮窗运行态」):单一变化原因=调试面板状态与
|
||||||
## 当局数据投影。探针直读冻结成员(seed_edit/_sim_btn/_dbg_btn)住宿主;
|
## 当局数据投影。探针直读冻结成员(seed_edit/_sim_btn/_dbg_btn)住宿主;
|
||||||
## st._run_data/st._run_labels 经 run_data_probe()/update_run_data() 方法出口(字段直访面零外部依赖)。
|
## st.run_data/st.run_labels 经 run_data_probe()/update_run_data() 方法出口(字段直访面零外部依赖)。
|
||||||
class _DebugState extends RefCounted:
|
class _DebugState extends RefCounted:
|
||||||
var _db
|
var db
|
||||||
var _base_atk := 0
|
var base_atk := 0
|
||||||
var _base_hp := 0
|
var base_hp := 0
|
||||||
var _atk: HSlider
|
var atk: HSlider
|
||||||
var _hp: HSlider
|
var hp: HSlider
|
||||||
var _atk_val: Label
|
var atk_val: Label
|
||||||
var _hp_val: Label
|
var hp_val: Label
|
||||||
var _eff: Label
|
var eff: Label
|
||||||
var _sim_count: SpinBox
|
var sim_count: SpinBox
|
||||||
var _sim_out: RichTextLabel
|
var sim_out: RichTextLabel
|
||||||
var _sim_running := false # 批量模拟进行中(is_running 判据——与对局中禁用态分离防互扰)
|
var sim_running := false # 批量模拟进行中(is_running 判据——与对局中禁用态分离防互扰)
|
||||||
var _ctx_locked := false # 对局中上下文锁定(组合根 _sync_debug_overlay 喂入——批量模拟/两层调试入口禁用)
|
var ctx_locked := false # 对局中上下文锁定(组合根 _sync_debug_overlay 喂入——批量模拟/两层调试入口禁用)
|
||||||
var _run_labels := {} # 当局数据六项标签(只读投影,组合根 update_run_data 喂入)
|
var run_labels := {} # 当局数据六项标签(只读投影,组合根 update_run_data 喂入)
|
||||||
var _run_data := {} # 最近一次投喂快照(探针值对面 run_data_probe)
|
var run_data := {} # 最近一次投喂快照(探针值对面 run_data_probe)
|
||||||
|
|
||||||
|
|
||||||
var st := _DebugState.new()
|
var st := _DebugState.new()
|
||||||
@@ -37,9 +38,9 @@ var _dbg_btn: Button # 两层调试入口钮(对局中禁用承
|
|||||||
|
|
||||||
|
|
||||||
func _init(db_ref, base_atk: int, base_hp: int) -> void:
|
func _init(db_ref, base_atk: int, base_hp: int) -> void:
|
||||||
st._db = db_ref
|
st.db = db_ref
|
||||||
st._base_atk = base_atk
|
st.base_atk = base_atk
|
||||||
st._base_hp = base_hp
|
st.base_hp = base_hp
|
||||||
_build()
|
_build()
|
||||||
_sync_labels()
|
_sync_labels()
|
||||||
visible = false # 显式初始化——不靠树序巧合(缺陷⑤家族纪律)
|
visible = false # 显式初始化——不靠树序巧合(缺陷⑤家族纪律)
|
||||||
@@ -48,78 +49,78 @@ func _init(db_ref, base_atk: int, base_hp: int) -> void:
|
|||||||
# ---- 对外语义面(组合根/探针)----
|
# ---- 对外语义面(组合根/探针)----
|
||||||
|
|
||||||
func atk_pct() -> int:
|
func atk_pct() -> int:
|
||||||
return int(st._atk.value)
|
return int(st.atk.value)
|
||||||
|
|
||||||
|
|
||||||
func hp_pct() -> int:
|
func hp_pct() -> int:
|
||||||
return int(st._hp.value)
|
return int(st.hp.value)
|
||||||
|
|
||||||
|
|
||||||
func set_sliders(atk: int, hp: int) -> void:
|
func set_sliders(atk: int, hp: int) -> void:
|
||||||
st._atk.value = atk
|
st.atk.value = atk
|
||||||
st._hp.value = hp
|
st.hp.value = hp
|
||||||
|
|
||||||
|
|
||||||
func reset_sliders() -> void:
|
func reset_sliders() -> void:
|
||||||
st._atk.value = 0
|
st.atk.value = 0
|
||||||
st._hp.value = 0
|
st.hp.value = 0
|
||||||
_sync_labels()
|
_sync_labels()
|
||||||
|
|
||||||
|
|
||||||
func effect_text() -> String:
|
func effect_text() -> String:
|
||||||
return st._eff.text
|
return st.eff.text
|
||||||
|
|
||||||
|
|
||||||
func set_sim_count(n: int) -> void:
|
func set_sim_count(n: int) -> void:
|
||||||
st._sim_count.value = n
|
st.sim_count.value = n
|
||||||
|
|
||||||
|
|
||||||
func is_running() -> bool:
|
func is_running() -> bool:
|
||||||
return st._sim_running # 批量模拟进行中(与对局中禁用态分离,置灰 ≠ 在跑)
|
return st.sim_running # 批量模拟进行中(与对局中禁用态分离,置灰 ≠ 在跑)
|
||||||
|
|
||||||
|
|
||||||
func set_sim_running(running: bool) -> void:
|
func set_sim_running(running: bool) -> void:
|
||||||
st._sim_running = running
|
st.sim_running = running
|
||||||
_sync_sim_button()
|
_sync_sim_button()
|
||||||
|
|
||||||
|
|
||||||
# 对局中上下文锁定(组合根 _sync_debug_overlay 喂入):批量模拟与两层调试入口
|
# 对局中上下文锁定(组合根 _sync_debug_overlay 喂入):批量模拟与两层调试入口
|
||||||
# 在活跃对局并存态不开放(长程异步模拟/并发对局编排与活跃结算并存态破坏状态机)
|
# 在活跃对局并存态不开放(长程异步模拟/并发对局编排与活跃结算并存态破坏状态机)
|
||||||
func set_context_locked(locked: bool) -> void:
|
func set_context_locked(locked: bool) -> void:
|
||||||
st._ctx_locked = locked
|
st.ctx_locked = locked
|
||||||
_sync_sim_button()
|
_sync_sim_button()
|
||||||
|
|
||||||
|
|
||||||
# 当局数据只读投影喂入(六项——组合根 _debug_run_data 构造;纯标签重查零动效)
|
# 当局数据只读投影喂入(六项——组合根 _debug_run_data 构造;纯标签重查零动效)
|
||||||
func update_run_data(data: Dictionary) -> void:
|
func update_run_data(data: Dictionary) -> void:
|
||||||
st._run_data = data.duplicate()
|
st.run_data = data.duplicate()
|
||||||
for key in st._run_labels:
|
for key in st.run_labels:
|
||||||
(st._run_labels[key] as Label).text = str(data.get(key, "—"))
|
(st.run_labels[key] as Label).text = str(data.get(key, "—"))
|
||||||
|
|
||||||
|
|
||||||
# 当局数据快照读面(探针值对面——ui_tune_probe 断言六项与只读访问器逐项一致)
|
# 当局数据快照读面(探针值对面——ui_tune_probe 断言六项与只读访问器逐项一致)
|
||||||
func run_data_probe() -> Dictionary:
|
func run_data_probe() -> Dictionary:
|
||||||
return st._run_data.duplicate()
|
return st.run_data.duplicate()
|
||||||
|
|
||||||
|
|
||||||
# 两钮同判据(模拟运行 / 对局上下文锁定对「模拟」「两层调试」两入口等价)——
|
# 两钮同判据(模拟运行 / 对局上下文锁定对「模拟」「两层调试」两入口等价)——
|
||||||
# 判据单点:两 setter 都经此同步,禁在调用点各写一份
|
# 判据单点:两 setter 都经此同步,禁在调用点各写一份
|
||||||
func _sync_sim_button() -> void:
|
func _sync_sim_button() -> void:
|
||||||
_sim_btn.disabled = st._sim_running or st._ctx_locked
|
_sim_btn.disabled = st.sim_running or st.ctx_locked
|
||||||
_sim_btn.text = "模拟中…" if st._sim_running else "运行模拟"
|
_sim_btn.text = "模拟中…" if st.sim_running else "运行模拟"
|
||||||
_dbg_btn.disabled = st._sim_running or st._ctx_locked
|
_dbg_btn.disabled = st.sim_running or st.ctx_locked
|
||||||
|
|
||||||
|
|
||||||
func set_sim_progress(text: String) -> void:
|
func set_sim_progress(text: String) -> void:
|
||||||
st._sim_out.text = text
|
st.sim_out.text = text
|
||||||
|
|
||||||
|
|
||||||
func set_sim_report(text: String) -> void:
|
func set_sim_report(text: String) -> void:
|
||||||
st._sim_out.text = text
|
st.sim_out.text = text
|
||||||
|
|
||||||
|
|
||||||
func output_text() -> String:
|
func output_text() -> String:
|
||||||
return st._sim_out.get_parsed_text()
|
return st.sim_out.get_parsed_text()
|
||||||
|
|
||||||
|
|
||||||
# ---- 探针接缝(真实翻译出口——按钮 pressed 信号路径,非直调组合根)----
|
# ---- 探针接缝(真实翻译出口——按钮 pressed 信号路径,非直调组合根)----
|
||||||
@@ -147,11 +148,11 @@ func _reset_btn_pressed() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func effective_atk() -> int:
|
func effective_atk() -> int:
|
||||||
return UiKit.scaled(st._base_atk, atk_pct())
|
return UiKit.scaled(st.base_atk, atk_pct())
|
||||||
|
|
||||||
|
|
||||||
func effective_max_hp() -> int:
|
func effective_max_hp() -> int:
|
||||||
return UiKit.scaled(st._base_hp, hp_pct())
|
return UiKit.scaled(st.base_hp, hp_pct())
|
||||||
|
|
||||||
|
|
||||||
# ---- 内部构建(标题/关闭固定于浮窗骨架,可扩展列表区居中滚动)----
|
# ---- 内部构建(标题/关闭固定于浮窗骨架,可扩展列表区居中滚动)----
|
||||||
@@ -185,7 +186,7 @@ func _build_intro(box: VBoxContainer) -> void:
|
|||||||
var title := UiKit.label("调试",UiKit.FS_TITLE, true, UiKit.WARM)
|
var title := UiKit.label("调试",UiKit.FS_TITLE, true, UiKit.WARM)
|
||||||
box.add_child(title)
|
box.add_child(title)
|
||||||
var desc := UiKit.label(
|
var desc := UiKit.label(
|
||||||
"开发调试专用(UI 最顶层「调试」浮层角标随时可开——任何界面不遮挡)。当局数据=本局只读投影,种子即本局种子唯一查看位。\n百分比叠加基础值:攻击 %d / 生命 %d。影响所有模式(手动与模拟),不落盘。" % [st._base_atk, st._base_hp],
|
"开发调试专用(UI 最顶层「调试」浮层角标随时可开——任何界面不遮挡)。当局数据=本局只读投影,种子即本局种子唯一查看位。\n百分比叠加基础值:攻击 %d / 生命 %d。影响所有模式(手动与模拟),不落盘。" % [st.base_atk, st.base_hp],
|
||||||
13, false, UiKit.WARM_SOFT)
|
13, false, UiKit.WARM_SOFT)
|
||||||
box.add_child(desc)
|
box.add_child(desc)
|
||||||
box.add_child(HSeparator.new())
|
box.add_child(HSeparator.new())
|
||||||
@@ -207,7 +208,7 @@ func _build_run_data(list: VBoxContainer) -> void:
|
|||||||
cap.custom_minimum_size = Vector2(52, 0)
|
cap.custom_minimum_size = Vector2(52, 0)
|
||||||
run_grid.add_child(cap)
|
run_grid.add_child(cap)
|
||||||
var val := UiKit.label("—",UiKit.FS_HINT, false, UiKit.WARM)
|
var val := UiKit.label("—",UiKit.FS_HINT, false, UiKit.WARM)
|
||||||
st._run_labels[item[0]] = val
|
st.run_labels[item[0]] = val
|
||||||
run_grid.add_child(val)
|
run_grid.add_child(val)
|
||||||
list.add_child(HSeparator.new())
|
list.add_child(HSeparator.new())
|
||||||
|
|
||||||
@@ -241,13 +242,13 @@ func _build_seed_row(list: VBoxContainer) -> void:
|
|||||||
## 区块②角色数值调整板(攻击/生命两滑轨+生效值行+应用/重置钮)
|
## 区块②角色数值调整板(攻击/生命两滑轨+生效值行+应用/重置钮)
|
||||||
func _build_slider_block(list: VBoxContainer) -> void:
|
func _build_slider_block(list: VBoxContainer) -> void:
|
||||||
var atk_row := _slider_row(list, "攻击加成")
|
var atk_row := _slider_row(list, "攻击加成")
|
||||||
st._atk = atk_row.slider
|
st.atk = atk_row.slider
|
||||||
st._atk_val = atk_row.value_label
|
st.atk_val = atk_row.value_label
|
||||||
var hp_row := _slider_row(list, "生命加成")
|
var hp_row := _slider_row(list, "生命加成")
|
||||||
st._hp = hp_row.slider
|
st.hp = hp_row.slider
|
||||||
st._hp_val = hp_row.value_label
|
st.hp_val = hp_row.value_label
|
||||||
st._eff = UiKit.label("",UiKit.FS_HINT, false)
|
st.eff = UiKit.label("",UiKit.FS_HINT, false)
|
||||||
list.add_child(st._eff)
|
list.add_child(st.eff)
|
||||||
var btn_row := HBoxContainer.new()
|
var btn_row := HBoxContainer.new()
|
||||||
list.add_child(btn_row)
|
list.add_child(btn_row)
|
||||||
var apply_btn := UiKit.button("应用并关闭")
|
var apply_btn := UiKit.button("应用并关闭")
|
||||||
@@ -264,21 +265,21 @@ func _build_sim_block(list: VBoxContainer) -> void:
|
|||||||
var sim_row := HBoxContainer.new()
|
var sim_row := HBoxContainer.new()
|
||||||
list.add_child(sim_row)
|
list.add_child(sim_row)
|
||||||
sim_row.add_child(UiKit.label("批量模拟第一关",UiKit.FS_BODY, false))
|
sim_row.add_child(UiKit.label("批量模拟第一关",UiKit.FS_BODY, false))
|
||||||
st._sim_count = SpinBox.new()
|
st.sim_count = SpinBox.new()
|
||||||
st._sim_count.min_value = 10
|
st.sim_count.min_value = 10
|
||||||
st._sim_count.max_value = 200
|
st.sim_count.max_value = 200
|
||||||
st._sim_count.step = 10
|
st.sim_count.step = 10
|
||||||
st._sim_count.value = 30
|
st.sim_count.value = 30
|
||||||
st._sim_count.custom_minimum_size = Vector2(90, 0)
|
st.sim_count.custom_minimum_size = Vector2(90, 0)
|
||||||
sim_row.add_child(st._sim_count)
|
sim_row.add_child(st.sim_count)
|
||||||
sim_row.add_child(UiKit.label("次(理性玩家策略,含面板当前加成)",UiKit.FS_HINT, false))
|
sim_row.add_child(UiKit.label("次(理性玩家策略,含面板当前加成)",UiKit.FS_HINT, false))
|
||||||
_sim_btn = UiKit.button("运行模拟")
|
_sim_btn = UiKit.button("运行模拟")
|
||||||
_sim_btn.pressed.connect(_emit_simulate_requested)
|
_sim_btn.pressed.connect(_emit_simulate_requested)
|
||||||
sim_row.add_child(_sim_btn)
|
sim_row.add_child(_sim_btn)
|
||||||
st._sim_out = RichTextLabel.new()
|
st.sim_out = RichTextLabel.new()
|
||||||
st._sim_out.bbcode_enabled = true
|
st.sim_out.bbcode_enabled = true
|
||||||
st._sim_out.custom_minimum_size = Vector2(0, 300)
|
st.sim_out.custom_minimum_size = Vector2(0, 300)
|
||||||
list.add_child(st._sim_out)
|
list.add_child(st.sim_out)
|
||||||
list.add_child(HSeparator.new())
|
list.add_child(HSeparator.new())
|
||||||
|
|
||||||
|
|
||||||
@@ -316,14 +317,14 @@ func _slider_row(box: VBoxContainer, title: String) -> Dictionary:
|
|||||||
|
|
||||||
|
|
||||||
func _sync_labels() -> void:
|
func _sync_labels() -> void:
|
||||||
st._atk_val.text = "+%d%%" % atk_pct()
|
st.atk_val.text = "+%d%%" % atk_pct()
|
||||||
st._hp_val.text = "+%d%%" % hp_pct()
|
st.hp_val.text = "+%d%%" % hp_pct()
|
||||||
st._eff.text = "生效值:攻击 %d → %d · 生命 %d → %d" % [
|
st.eff.text = "生效值:攻击 %d → %d · 生命 %d → %d" % [
|
||||||
st._base_atk, effective_atk(), st._base_hp, effective_max_hp()]
|
st.base_atk, effective_atk(), st.base_hp, effective_max_hp()]
|
||||||
|
|
||||||
|
|
||||||
func _emit_simulate_requested() -> void:
|
func _emit_simulate_requested() -> void:
|
||||||
simulate_requested.emit(int(st._sim_count.value))
|
simulate_requested.emit(int(st.sim_count.value))
|
||||||
|
|
||||||
|
|
||||||
func _emit_diagnose_requested() -> void:
|
func _emit_diagnose_requested() -> void:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
## VERTICAL SLICE - NOT FOR PRODUCTION
|
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||||||
## 关卡画面·独立屏:全屏不透明独占呈现(激活期战斗屏宿主由组合根整体隐藏),节点图选路呈现。
|
## 关卡画面·独立屏:全屏不透明独占呈现(激活期战斗屏宿主由组合根整体隐藏),节点图选路呈现。
|
||||||
## 前进唯一通道=图上点候选节点(route_chosen 外发)——零自动推进;放弃入口可见性归组合根(仅冒险模式开)。
|
## 前进唯一通道=图上点候选节点(route_chosen 外发)——零自动推进;放弃入口可见性归组合根(仅冒险模式开)。
|
||||||
|
## 内部数据类 _MapState=宿主画面登记表(只被本文件填读,文件外零消费者——字段为公开数据成员)。
|
||||||
class_name LevelMapScreen
|
class_name LevelMapScreen
|
||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@@ -32,23 +33,23 @@ const CONFIRM_WINDOW_S := 3.0 # 放弃确认态窗口(
|
|||||||
const COL_HP_BAR_BACK := UiKit.HP_BAR_BACK # 迷你血条深底(对暗面板可辨;值单点收 UiKit)
|
const COL_HP_BAR_BACK := UiKit.HP_BAR_BACK # 迷你血条深底(对暗面板可辨;值单点收 UiKit)
|
||||||
|
|
||||||
## 内部状态件(u2 子域拆件——契约 9 职责轴):_MapState=选路屏运行态与图绘制态(单一变化原因=
|
## 内部状态件(u2 子域拆件——契约 9 职责轴):_MapState=选路屏运行态与图绘制态(单一变化原因=
|
||||||
## 选路呈现)。_layer_decor 域字典承载换层装饰三件(图标贴图/石纹面/tint 层号——装饰域归并形态)。
|
## 选路呈现)。layer_decor 域字典承载换层装饰三件(图标贴图/石纹面/tint 层号——装饰域归并形态)。
|
||||||
## 探针直读冻结成员(_cand_ids/_hover_id/_content_size/_layout_cache/abandon_btn/status_badge)住宿主。
|
## 探针直读冻结成员(_cand_ids/_hover_id/_content_size/_layout_cache/abandon_btn/status_badge)住宿主。
|
||||||
class _MapState extends RefCounted:
|
class _MapState extends RefCounted:
|
||||||
var _runner = null
|
var runner = null
|
||||||
var _title: Label
|
var title: Label
|
||||||
var _canvas: Control
|
var canvas: Control
|
||||||
var _level_label: Label
|
var level_label: Label
|
||||||
var _gp_value: Label
|
var gp_value: Label
|
||||||
var _hp_value: Label
|
var hp_value: Label
|
||||||
var _hp_bar: Control
|
var hp_bar: Control
|
||||||
var _attr_value: Label
|
var attr_value: Label
|
||||||
var _bonus_row: HBoxContainer
|
var bonus_row: HBoxContainer
|
||||||
var _bonus_value: Label
|
var bonus_value: Label
|
||||||
var _feat_value: Label # 特性持有行(组合根投喂逐件文案)
|
var feat_value: Label # 特性持有行(组合根投喂逐件文案)
|
||||||
var _abandon_timer := ArmedTimer.new() # 放弃确认窗(_process 帧驱动倒计时机制收口;窗口=CONFIRM_WINDOW_S)
|
var abandon_timer := ArmedTimer.new() # 放弃确认窗(_process 帧驱动倒计时机制收口;窗口=CONFIRM_WINDOW_S)
|
||||||
var _drawn_disp: Dictionary[int, Dictionary] = {} # 本停点实际绘制记录(_draw_graph 逐帧在实际绘制点重建——display_probe 消费面)
|
var drawn_disp: Dictionary[int, Dictionary] = {} # 本停点实际绘制记录(_draw_graph 逐帧在实际绘制点重建——display_probe 消费面)
|
||||||
var _layer_decor := {"node_icons": {}, "noise_rect": null, "tint_level": 0} # 换层装饰域(节点图标贴图 load_tex 守卫缺位 null→字形回退/屏底石纹面/当前已应用 tint 层号 0=未应用)
|
var layer_decor := {"node_icons": {}, "noise_rect": null, "tint_level": 0} # 换层装饰域(节点图标贴图 load_tex 守卫缺位 null→字形回退/屏底石纹面/当前已应用 tint 层号 0=未应用)
|
||||||
|
|
||||||
var _cand_ids: Array[int] = [] # 本停点候选 id 集(图上命中合法集;探针直读冻结——住宿主)
|
var _cand_ids: Array[int] = [] # 本停点候选 id 集(图上命中合法集;探针直读冻结——住宿主)
|
||||||
var _content_size := Vector2(620, 240) # 图内容包络(open_choices 按图拟合——画布 min 尺寸随它;探针直读冻结)
|
var _content_size := Vector2(620, 240) # 图内容包络(open_choices 按图拟合——画布 min 尺寸随它;探针直读冻结)
|
||||||
@@ -60,18 +61,18 @@ var _map := _MapState.new()
|
|||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
_map._abandon_timer.expired.connect(_reset_abandon_confirm)
|
_map.abandon_timer.expired.connect(_reset_abandon_confirm)
|
||||||
# 节点图标贴图装载(load_tex 守卫,缺位回退现行字形)
|
# 节点图标贴图装载(load_tex 守卫,缺位回退现行字形)
|
||||||
for t in TEX_NODE_ICONS:
|
for t in TEX_NODE_ICONS:
|
||||||
_map._layer_decor.node_icons[t] = UiKit.load_tex(TEX_NODE_ICONS[t])
|
_map.layer_decor.node_icons[t] = UiKit.load_tex(TEX_NODE_ICONS[t])
|
||||||
# 独立屏底(spec Layout——demo #v-map 暖棕竖向
|
# 独立屏底(spec Layout——demo #v-map 暖棕竖向
|
||||||
# 渐变(#4A3B2A 0%→#3A2E22 40%)+石纹弱质感 0.14+暗角聚焦;底纹缺位回退纯色)
|
# 渐变(#4A3B2A 0%→#3A2E22 40%)+石纹弱质感 0.14+暗角聚焦;底纹缺位回退纯色)
|
||||||
var base := UiKit._gradient_base(UiKit.BG_MAP_TOP, UiKit.BG_ROOT)
|
var base := UiKit.gradient_base(UiKit.BG_MAP_TOP, UiKit.BG_ROOT)
|
||||||
add_child(base)
|
add_child(base)
|
||||||
var tex := UiKit.backdrop_tile()
|
var tex := UiKit.backdrop_tile()
|
||||||
if tex != null:
|
if tex != null:
|
||||||
base.add_child(tex)
|
base.add_child(tex)
|
||||||
_map._layer_decor.noise_rect = tex # 世界侧 tint 承载面(换层色板渐变挂点——§2.7 切片档)
|
_map.layer_decor.noise_rect = tex # 世界侧 tint 承载面(换层色板渐变挂点——§2.7 切片档)
|
||||||
base.add_child(UiKit.vignette_rect())
|
base.add_child(UiKit.vignette_rect())
|
||||||
var center := CenterContainer.new()
|
var center := CenterContainer.new()
|
||||||
center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
@@ -97,8 +98,8 @@ func _build_top_bar(box: VBoxContainer) -> void:
|
|||||||
lvl_plate.add_theme_stylebox_override("panel",
|
lvl_plate.add_theme_stylebox_override("panel",
|
||||||
UiKit.panel_flat(UiKit.DARK_UPCOMING, UiKit.PANEL_BORDER, 0, 1, Vector4(12, 3, 12, 3)))
|
UiKit.panel_flat(UiKit.DARK_UPCOMING, UiKit.PANEL_BORDER, 0, 1, Vector4(12, 3, 12, 3)))
|
||||||
top.add_child(lvl_plate)
|
top.add_child(lvl_plate)
|
||||||
_map._level_label = UiKit.label("",UiKit.FS_BODY, true, UiKit.WARM)
|
_map.level_label = UiKit.label("",UiKit.FS_BODY, true, UiKit.WARM)
|
||||||
lvl_plate.add_child(_map._level_label)
|
lvl_plate.add_child(_map.level_label)
|
||||||
var top_sp := Control.new()
|
var top_sp := Control.new()
|
||||||
top_sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
top_sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
top.add_child(top_sp)
|
top.add_child(top_sp)
|
||||||
@@ -109,31 +110,31 @@ func _build_top_bar(box: VBoxContainer) -> void:
|
|||||||
var gp_row := HBoxContainer.new()
|
var gp_row := HBoxContainer.new()
|
||||||
gp_row.add_theme_constant_override("separation", 6)
|
gp_row.add_theme_constant_override("separation", 6)
|
||||||
gp_box.add_child(gp_row)
|
gp_box.add_child(gp_row)
|
||||||
_map._gp_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_ON_GOLD)
|
_map.gp_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_ON_GOLD)
|
||||||
gp_row.add_child(_map._gp_value)
|
gp_row.add_child(_map.gp_value)
|
||||||
status_badge = UiKit.button("状态", 0.0)
|
status_badge = UiKit.button("状态", 0.0)
|
||||||
status_badge.add_theme_font_size_override("font_size", UiKit.FS_HINT)
|
status_badge.add_theme_font_size_override("font_size", UiKit.FS_HINT)
|
||||||
status_badge.tooltip_text = "查看本局冒险进度(只读)"
|
status_badge.tooltip_text = "查看本局冒险进度(只读)"
|
||||||
status_badge.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
status_badge.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
top.add_child(status_badge)
|
top.add_child(status_badge)
|
||||||
_map._title = UiKit.label(TITLE_FORK,UiKit.FS_SUB, true, UiKit.WARM)
|
_map.title = UiKit.label(TITLE_FORK,UiKit.FS_SUB, true, UiKit.WARM)
|
||||||
_map._title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
_map.title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
box.add_child(_map._title)
|
box.add_child(_map.title)
|
||||||
|
|
||||||
|
|
||||||
## 节点图画布域(图上点击 = 唯一提交通道——布局决策 2;mouse_filter STOP 接悬停/点击)
|
## 节点图画布域(图上点击 = 唯一提交通道——布局决策 2;mouse_filter STOP 接悬停/点击)
|
||||||
func _build_canvas(box: VBoxContainer) -> void:
|
func _build_canvas(box: VBoxContainer) -> void:
|
||||||
_map._canvas = Control.new()
|
_map.canvas = Control.new()
|
||||||
_map._canvas.custom_minimum_size = Vector2(620, 240)
|
_map.canvas.custom_minimum_size = Vector2(620, 240)
|
||||||
_map._canvas.mouse_filter = Control.MOUSE_FILTER_STOP
|
_map.canvas.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||||
_map._canvas.draw.connect(_draw_graph.bind(_map._canvas))
|
_map.canvas.draw.connect(_draw_graph.bind(_map.canvas))
|
||||||
_map._canvas.gui_input.connect(_on_canvas_input)
|
_map.canvas.gui_input.connect(_on_canvas_input)
|
||||||
box.add_child(_map._canvas)
|
box.add_child(_map.canvas)
|
||||||
|
|
||||||
|
|
||||||
## 底部状态栏域(合并单条:亮米面板一站读齐=头像+生命+属性+本关加成/流派件——demo ④;
|
## 底部状态栏域(合并单条:亮米面板一站读齐=头像+生命+属性+本关加成/流派件——demo ④;
|
||||||
## 道具槽不摆=道具读数无关卡画面成文出口(读快照私域越权);
|
## 道具槽不摆=道具读数无关卡画面成文出口(读快照私域越权);
|
||||||
## _hp_value/_attr_value/_bonus_value/_feat_value 投喂键全部保留。
|
## hp_value/attr_value/bonus_value/feat_value 投喂键全部保留。
|
||||||
## 底栏定高纪律(对齐 demo——单条 ~85px 紧凑亮条;任何子件不再能把栏撑爆:
|
## 底栏定高纪律(对齐 demo——单条 ~85px 紧凑亮条;任何子件不再能把栏撑爆:
|
||||||
## 特性持有行限宽截断+tooltip 全文))
|
## 特性持有行限宽截断+tooltip 全文))
|
||||||
func _build_status_bar(box: VBoxContainer) -> void:
|
func _build_status_bar(box: VBoxContainer) -> void:
|
||||||
@@ -150,18 +151,18 @@ func _build_status_bar(box: VBoxContainer) -> void:
|
|||||||
var life_box := VBoxContainer.new()
|
var life_box := VBoxContainer.new()
|
||||||
strip.add_child(life_box)
|
strip.add_child(life_box)
|
||||||
life_box.add_child(UiKit.label("生命",UiKit.FS_CAPTION, false, UiKit.INK_HINT))
|
life_box.add_child(UiKit.label("生命",UiKit.FS_CAPTION, false, UiKit.INK_HINT))
|
||||||
_map._hp_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
_map.hp_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
||||||
life_box.add_child(_map._hp_value)
|
life_box.add_child(_map.hp_value)
|
||||||
_map._hp_bar = Control.new()
|
_map.hp_bar = Control.new()
|
||||||
_map._hp_bar.custom_minimum_size = Vector2(130, 7)
|
_map.hp_bar.custom_minimum_size = Vector2(130, 7)
|
||||||
_map._hp_bar.draw.connect(_draw_hp_bar.bind(_map._hp_bar))
|
_map.hp_bar.draw.connect(_draw_hp_bar.bind(_map.hp_bar))
|
||||||
life_box.add_child(_map._hp_bar)
|
life_box.add_child(_map.hp_bar)
|
||||||
strip.add_child(_vdiv())
|
strip.add_child(_vdiv())
|
||||||
var attr_box := VBoxContainer.new()
|
var attr_box := VBoxContainer.new()
|
||||||
strip.add_child(attr_box)
|
strip.add_child(attr_box)
|
||||||
attr_box.add_child(UiKit.label("属性",UiKit.FS_CAPTION, false, UiKit.INK_HINT))
|
attr_box.add_child(UiKit.label("属性",UiKit.FS_CAPTION, false, UiKit.INK_HINT))
|
||||||
_map._attr_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
_map.attr_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
||||||
attr_box.add_child(_map._attr_value)
|
attr_box.add_child(_map.attr_value)
|
||||||
strip.add_child(_vdiv())
|
strip.add_child(_vdiv())
|
||||||
_build_bonus_group(strip)
|
_build_bonus_group(strip)
|
||||||
var spacer := Control.new()
|
var spacer := Control.new()
|
||||||
@@ -193,21 +194,21 @@ func _build_face_rect() -> TextureRect:
|
|||||||
|
|
||||||
## 本关加成框域(零加成隐藏——spec 布局决策 4)+ 流派件持有行(组合根投喂;限宽单行截断+tooltip 全文)
|
## 本关加成框域(零加成隐藏——spec 布局决策 4)+ 流派件持有行(组合根投喂;限宽单行截断+tooltip 全文)
|
||||||
func _build_bonus_group(strip: HBoxContainer) -> void:
|
func _build_bonus_group(strip: HBoxContainer) -> void:
|
||||||
_map._bonus_row = HBoxContainer.new()
|
_map.bonus_row = HBoxContainer.new()
|
||||||
strip.add_child(_map._bonus_row)
|
strip.add_child(_map.bonus_row)
|
||||||
var bonus_box := VBoxContainer.new()
|
var bonus_box := VBoxContainer.new()
|
||||||
_map._bonus_row.add_child(bonus_box)
|
_map.bonus_row.add_child(bonus_box)
|
||||||
var bonus_inner := VBoxContainer.new()
|
var bonus_inner := VBoxContainer.new()
|
||||||
bonus_box.add_child(bonus_inner)
|
bonus_box.add_child(bonus_inner)
|
||||||
var bonus_cap := UiKit.label("属性值提升",UiKit.FS_CAPTION, false, UiKit.INK_HINT) # 深墨(亮板可读)
|
var bonus_cap := UiKit.label("属性值提升",UiKit.FS_CAPTION, false, UiKit.INK_HINT) # 深墨(亮板可读)
|
||||||
bonus_inner.add_child(bonus_cap)
|
bonus_inner.add_child(bonus_cap)
|
||||||
_map._bonus_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE) # 淡墨→深墨(同上)
|
_map.bonus_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE) # 淡墨→深墨(同上)
|
||||||
bonus_inner.add_child(_map._bonus_value)
|
bonus_inner.add_child(_map.bonus_value)
|
||||||
_map._feat_value = UiKit.label("",UiKit.FS_HINT, false, UiKit.INK_HINT)
|
_map.feat_value = UiKit.label("",UiKit.FS_HINT, false, UiKit.INK_HINT)
|
||||||
_map._feat_value.custom_minimum_size = Vector2(240, 0)
|
_map.feat_value.custom_minimum_size = Vector2(240, 0)
|
||||||
_map._feat_value.clip_text = true
|
_map.feat_value.clip_text = true
|
||||||
_map._feat_value.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
_map.feat_value.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||||||
bonus_box.add_child(_map._feat_value)
|
bonus_box.add_child(_map.feat_value)
|
||||||
|
|
||||||
|
|
||||||
# 竖分隔线(底栏分组线——亮面板上低对比细线)
|
# 竖分隔线(底栏分组线——亮面板上低对比细线)
|
||||||
@@ -221,10 +222,10 @@ static func _vdiv() -> ColorRect:
|
|||||||
func _draw_hp_bar(bar: Control) -> void:
|
func _draw_hp_bar(bar: Control) -> void:
|
||||||
# 迷你血条(深底 UiKit.HP_BAR_BACK #28221C + 小人蓝填充——与战斗站桩血条同语言,
|
# 迷你血条(深底 UiKit.HP_BAR_BACK #28221C + 小人蓝填充——与战斗站桩血条同语言,
|
||||||
# 「蓝只说己方」§4.2)。比例 = hero_hp / effective_max_hp
|
# 「蓝只说己方」§4.2)。比例 = hero_hp / effective_max_hp
|
||||||
if _map._runner == null:
|
if _map.runner == null:
|
||||||
return
|
return
|
||||||
var max_hp := maxi(1, _map._runner.effective_max_hp())
|
var max_hp := maxi(1, _map.runner.effective_max_hp())
|
||||||
var ratio := clampf(float(_map._runner.hero_hp) / float(max_hp), 0.0, 1.0)
|
var ratio := clampf(float(_map.runner.hero_hp) / float(max_hp), 0.0, 1.0)
|
||||||
var full := Rect2(Vector2.ZERO, bar.size)
|
var full := Rect2(Vector2.ZERO, bar.size)
|
||||||
bar.draw_rect(full, COL_HP_BAR_BACK)
|
bar.draw_rect(full, COL_HP_BAR_BACK)
|
||||||
if ratio > 0.0:
|
if ratio > 0.0:
|
||||||
@@ -234,8 +235,8 @@ func _draw_hp_bar(bar: Control) -> void:
|
|||||||
# 放弃入口可见性(组合根在冒险启动时开、默认关——语义对象 = 整局冒险)
|
# 放弃入口可见性(组合根在冒险启动时开、默认关——语义对象 = 整局冒险)
|
||||||
# 特性持有投影(组合根投喂逐件文案;空文案=行隐藏)
|
# 特性持有投影(组合根投喂逐件文案;空文案=行隐藏)
|
||||||
func set_feat_holdings(text: String) -> void:
|
func set_feat_holdings(text: String) -> void:
|
||||||
_map._feat_value.text = text
|
_map.feat_value.text = text
|
||||||
_map._feat_value.tooltip_text = text # 截断全量兜底(限宽单行省略——悬停看全文)
|
_map.feat_value.tooltip_text = text # 截断全量兜底(限宽单行省略——悬停看全文)
|
||||||
|
|
||||||
|
|
||||||
func set_abandon_available(v: bool) -> void:
|
func set_abandon_available(v: bool) -> void:
|
||||||
@@ -245,8 +246,8 @@ func set_abandon_available(v: bool) -> void:
|
|||||||
# 放弃二次确认(布局决策 3):首击转确认态(文案+危险红脉冲约 3 秒超时回落),二击才提交。
|
# 放弃二次确认(布局决策 3):首击转确认态(文案+危险红脉冲约 3 秒超时回落),二击才提交。
|
||||||
# 单击不提交——ui_probe 战斗中 pressed.emit() 单击路径保持「未受理」语义(战斗中拒绝归组合根)。
|
# 单击不提交——ui_probe 战斗中 pressed.emit() 单击路径保持「未受理」语义(战斗中拒绝归组合根)。
|
||||||
func _on_abandon_pressed() -> void:
|
func _on_abandon_pressed() -> void:
|
||||||
if not _map._abandon_timer.is_armed():
|
if not _map.abandon_timer.is_armed():
|
||||||
_map._abandon_timer.arm(CONFIRM_WINDOW_S)
|
_map.abandon_timer.arm(CONFIRM_WINDOW_S)
|
||||||
abandon_btn.text = "再点一次确认放弃——不可逆"
|
abandon_btn.text = "再点一次确认放弃——不可逆"
|
||||||
if ArmedTimer.motion_still():
|
if ArmedTimer.motion_still():
|
||||||
abandon_btn.modulate = Color(1, 1, 1, 0.75) # 减动效静态基色(脉冲层不再驱动)
|
abandon_btn.modulate = Color(1, 1, 1, 0.75) # 减动效静态基色(脉冲层不再驱动)
|
||||||
@@ -256,45 +257,45 @@ func _on_abandon_pressed() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _reset_abandon_confirm() -> void:
|
func _reset_abandon_confirm() -> void:
|
||||||
_map._abandon_timer.disarm()
|
_map.abandon_timer.disarm()
|
||||||
abandon_btn.modulate = Color(1, 1, 1, 1)
|
abandon_btn.modulate = Color(1, 1, 1, 1)
|
||||||
abandon_btn.text = "放弃" # 文案收敛 level-map 4 字上限(确认态转义面见 _on_abandon_pressed)
|
abandon_btn.text = "放弃" # 文案收敛 level-map 4 字上限(确认态转义面见 _on_abandon_pressed)
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
if not _map._abandon_timer.is_armed():
|
if not _map.abandon_timer.is_armed():
|
||||||
return
|
return
|
||||||
_map._abandon_timer.tick(delta)
|
_map.abandon_timer.tick(delta)
|
||||||
if not _map._abandon_timer.is_armed():
|
if not _map.abandon_timer.is_armed():
|
||||||
return # 窗口到点回落(expired 信号已驱动 _reset_abandon_confirm)
|
return # 窗口到点回落(expired 信号已驱动 _reset_abandon_confirm)
|
||||||
# 危险红边框脉冲(单段呼吸约 1Hz——闪烁基线 ≤3 次/秒内;减动效 = 静态半透不闪——档判据单点 motion_still)
|
# 危险红边框脉冲(单段呼吸约 1Hz——闪烁基线 ≤3 次/秒内;减动效 = 静态半透不闪——档判据单点 motion_still)
|
||||||
if ArmedTimer.motion_still():
|
if ArmedTimer.motion_still():
|
||||||
abandon_btn.modulate = Color(1, 1, 1, 0.75)
|
abandon_btn.modulate = Color(1, 1, 1, 0.75)
|
||||||
else:
|
else:
|
||||||
var k := 0.5 + 0.5 * sin(_map._abandon_timer.elapsed * TAU)
|
var k := 0.5 + 0.5 * sin(_map.abandon_timer.elapsed * TAU)
|
||||||
abandon_btn.modulate = Color(1, 1, 1, 0.65 + 0.35 * k)
|
abandon_btn.modulate = Color(1, 1, 1, 0.65 + 0.35 * k)
|
||||||
|
|
||||||
|
|
||||||
# 打开选路口(cands = 候选节点引用数组;runner 只读用于整图渲染与状态栏刷新)
|
# 打开选路口(cands = 候选节点引用数组;runner 只读用于整图渲染与状态栏刷新)
|
||||||
func open_choices(cands: Array, runner: LevelRunner) -> void:
|
func open_choices(cands: Array, runner: LevelRunner) -> void:
|
||||||
var was_visible := visible # 进入转场判据(就地刷新/模态栈恢复不重放淡入)
|
var was_visible := visible # 进入转场判据(就地刷新/模态栈恢复不重放淡入)
|
||||||
_map._runner = runner
|
_map.runner = runner
|
||||||
_hover_id = -1
|
_hover_id = -1
|
||||||
_reset_abandon_confirm()
|
_reset_abandon_confirm()
|
||||||
var visited: Array[int] = []
|
var visited: Array[int] = []
|
||||||
if runner != null:
|
if runner != null:
|
||||||
visited = runner.visited_ids()
|
visited = runner.visited_ids()
|
||||||
if cands.size() > 1:
|
if cands.size() > 1:
|
||||||
_map._title.text = TITLE_FORK
|
_map.title.text = TITLE_FORK
|
||||||
elif visited.is_empty():
|
elif visited.is_empty():
|
||||||
_map._title.text = TITLE_ENTRY # 入口停点(尚未走出第一步)
|
_map.title.text = TITLE_ENTRY # 入口停点(尚未走出第一步)
|
||||||
else:
|
else:
|
||||||
_map._title.text = TITLE_SINGLE
|
_map.title.text = TITLE_SINGLE
|
||||||
_cand_ids = []
|
_cand_ids = []
|
||||||
for cand in cands:
|
for cand in cands:
|
||||||
_cand_ids.append(_id_of(cand))
|
_cand_ids.append(_id_of(cand))
|
||||||
_fit_canvas(_map._runner.nodes())
|
_fit_canvas(_map.runner.nodes())
|
||||||
_apply_level_tint(int(_map._runner.level_row.get("level_index", 0)))
|
_apply_level_tint(int(_map.runner.level_row.get("level_index", 0)))
|
||||||
visible = true
|
visible = true
|
||||||
if not was_visible:
|
if not was_visible:
|
||||||
# 独立屏淡入(spec Transitions:约 200ms;alpha 淡入非明度变化——art-bible §2 明度恒定)
|
# 独立屏淡入(spec Transitions:约 200ms;alpha 淡入非明度变化——art-bible §2 明度恒定)
|
||||||
@@ -321,7 +322,7 @@ func _fit_canvas(nodes: Array) -> void:
|
|||||||
_content_size = Vector2(LAYER_BASE_X + maxl * LAYER_STEP_X + NODE_HALF.x + 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 + 24.0) # +24 = 类型文字标签行
|
SLOT_BASE_Y + maxslot * SLOT_STEP_Y + NODE_HALF.y + 24.0) # +24 = 类型文字标签行
|
||||||
_content_size = _content_size.max(Vector2(620, 256)) # 下限(抬高容纳标签行)
|
_content_size = _content_size.max(Vector2(620, 256)) # 下限(抬高容纳标签行)
|
||||||
_map._canvas.custom_minimum_size = _content_size
|
_map.canvas.custom_minimum_size = _content_size
|
||||||
|
|
||||||
|
|
||||||
# 换层色板渐变挂点(art-bible §2.7 下探过渡切片档——关卡结算确认→下一关→独立屏淡入链路上的
|
# 换层色板渐变挂点(art-bible §2.7 下探过渡切片档——关卡结算确认→下一关→独立屏淡入链路上的
|
||||||
@@ -332,39 +333,39 @@ const BOARD_TINTS := {1: Color(1, 1, 1), 2: Color(0.84, 0.99, 1.28), 3: Color(0.
|
|||||||
|
|
||||||
|
|
||||||
func _apply_level_tint(level_index: int) -> void:
|
func _apply_level_tint(level_index: int) -> void:
|
||||||
if _map._layer_decor.noise_rect == null or level_index == _map._layer_decor.tint_level:
|
if _map.layer_decor.noise_rect == null or level_index == _map.layer_decor.tint_level:
|
||||||
return
|
return
|
||||||
_map._layer_decor.tint_level = level_index
|
_map.layer_decor.tint_level = level_index
|
||||||
var target: Color = BOARD_TINTS.get(level_index, Color(1, 1, 1))
|
var target: Color = BOARD_TINTS.get(level_index, Color(1, 1, 1))
|
||||||
var tw := create_tween()
|
var tw := create_tween()
|
||||||
tw.tween_property(_map._layer_decor.noise_rect, "modulate",
|
tw.tween_property(_map.layer_decor.noise_rect, "modulate",
|
||||||
Color(target.r, target.g, target.b, UiKit.BACKDROP_TILE_ALPHA), UiKit.motion(0.45)) # 0.14 弱质感档随 tint 保持
|
Color(target.r, target.g, target.b, UiKit.BACKDROP_TILE_ALPHA), UiKit.motion(0.45)) # 0.14 弱质感档随 tint 保持
|
||||||
|
|
||||||
|
|
||||||
# 状态栏投喂(命令式纪律——组合根经 level_map_status_payload 取成品后喂入;零推送信号订阅、零核心态拼装)
|
# 状态栏投喂(命令式纪律——组合根经 level_map_status_payload 取成品后喂入;零推送信号订阅、零核心态拼装)
|
||||||
func apply_status(payload: Dictionary) -> void:
|
func apply_status(payload: Dictionary) -> void:
|
||||||
_map._level_label.text = String(payload["level_label"])
|
_map.level_label.text = String(payload["level_label"])
|
||||||
_map._gp_value.text = String(payload["gp_text"])
|
_map.gp_value.text = String(payload["gp_text"])
|
||||||
_map._hp_value.text = String(payload["hp_text"])
|
_map.hp_value.text = String(payload["hp_text"])
|
||||||
if bool(payload["hp_bar_redraw"]):
|
if bool(payload["hp_bar_redraw"]):
|
||||||
_map._hp_bar.queue_redraw()
|
_map.hp_bar.queue_redraw()
|
||||||
_map._attr_value.text = String(payload["attr_text"])
|
_map.attr_value.text = String(payload["attr_text"])
|
||||||
_map._bonus_value.text = String(payload["bonus_text"])
|
_map.bonus_value.text = String(payload["bonus_text"])
|
||||||
# 特性持有行可见性(与加成行并框——任一非空整框显示;文案归组合根 set_feat_holdings)
|
# 特性持有行可见性(与加成行并框——任一非空整框显示;文案归组合根 set_feat_holdings)
|
||||||
_map._bonus_row.visible = bool(payload["bonus_row_visible"]) or _map._feat_value.text != ""
|
_map.bonus_row.visible = bool(payload["bonus_row_visible"]) or _map.feat_value.text != ""
|
||||||
|
|
||||||
|
|
||||||
# ---- 图上命中(布局决策 2——唯一提交通道;探针 press_candidate 同路径) ----
|
# ---- 图上命中(布局决策 2——唯一提交通道;探针 press_candidate 同路径) ----
|
||||||
|
|
||||||
func _on_canvas_input(ev: InputEvent) -> void:
|
func _on_canvas_input(ev: InputEvent) -> void:
|
||||||
if _map._runner == null or not visible:
|
if _map.runner == null or not visible:
|
||||||
return
|
return
|
||||||
if ev is InputEventMouseMotion:
|
if ev is InputEventMouseMotion:
|
||||||
var nid := _candidate_at(ev.position) # gui_input 事件坐标 = 接收控件局部坐标(push_input 同成立)
|
var nid := _candidate_at(ev.position) # gui_input 事件坐标 = 接收控件局部坐标(push_input 同成立)
|
||||||
if nid != _hover_id:
|
if nid != _hover_id:
|
||||||
_hover_id = nid
|
_hover_id = nid
|
||||||
_map._canvas.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND if nid >= 0 else Control.CURSOR_ARROW
|
_map.canvas.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND if nid >= 0 else Control.CURSOR_ARROW
|
||||||
_map._canvas.queue_redraw()
|
_map.canvas.queue_redraw()
|
||||||
elif ev is InputEventMouseButton and ev.button_index == MOUSE_BUTTON_LEFT and ev.pressed:
|
elif ev is InputEventMouseButton and ev.button_index == MOUSE_BUTTON_LEFT and ev.pressed:
|
||||||
var nid2 := _candidate_at(ev.position)
|
var nid2 := _candidate_at(ev.position)
|
||||||
if nid2 >= 0:
|
if nid2 >= 0:
|
||||||
@@ -373,10 +374,10 @@ func _on_canvas_input(ev: InputEvent) -> void:
|
|||||||
|
|
||||||
# 候选命中:位置 = 布局公式(与 _draw_graph 同源),矩形 = 节点方块 + 外扩容差;非候选格不响应
|
# 候选命中:位置 = 布局公式(与 _draw_graph 同源),矩形 = 节点方块 + 外扩容差;非候选格不响应
|
||||||
func _candidate_at(local_pos: Vector2) -> int:
|
func _candidate_at(local_pos: Vector2) -> int:
|
||||||
if _map._runner == null:
|
if _map.runner == null:
|
||||||
return -1
|
return -1
|
||||||
var nodes: Array[Variant] = _map._runner.nodes()
|
var nodes: Array[Variant] = _map.runner.nodes()
|
||||||
var pos := _layout(nodes, _map._canvas)
|
var pos := _layout(nodes, _map.canvas)
|
||||||
for nid in _cand_ids:
|
for nid in _cand_ids:
|
||||||
var node := _node_by_id(nid, nodes)
|
var node := _node_by_id(nid, nodes)
|
||||||
if node.is_empty():
|
if node.is_empty():
|
||||||
@@ -391,7 +392,7 @@ func _candidate_at(local_pos: Vector2) -> int:
|
|||||||
func _submit_choice(nid: int) -> void:
|
func _submit_choice(nid: int) -> void:
|
||||||
# 独立屏分支:战斗/Boss 节点 = 出屏切回战斗屏;奖励/恢复/商店节点 =
|
# 独立屏分支:战斗/Boss 节点 = 出屏切回战斗屏;奖励/恢复/商店节点 =
|
||||||
# 本屏保持激活——兑付覆盖层由节点事件在本屏域内弹出(模态栈遮挡恢复语义复用),兑付确认后回图刷新
|
# 本屏保持激活——兑付覆盖层由节点事件在本屏域内弹出(模态栈遮挡恢复语义复用),兑付确认后回图刷新
|
||||||
var node := _node_by_id(nid, _map._runner.nodes())
|
var node := _node_by_id(nid, _map.runner.nodes())
|
||||||
var t := String(node.get("type", ""))
|
var t := String(node.get("type", ""))
|
||||||
if t != "reward" and t != "rest" and t != "shop":
|
if t != "reward" and t != "rest" and t != "shop":
|
||||||
visible = false
|
visible = false
|
||||||
@@ -400,13 +401,13 @@ func _submit_choice(nid: int) -> void:
|
|||||||
|
|
||||||
# 探针复用:按候选序号走图上命中同路径(候选节点中心坐标 → 命中检测 → 提交——布局决策 2 探针面改造)
|
# 探针复用:按候选序号走图上命中同路径(候选节点中心坐标 → 命中检测 → 提交——布局决策 2 探针面改造)
|
||||||
func press_candidate(index: int) -> void:
|
func press_candidate(index: int) -> void:
|
||||||
if index < 0 or index >= _cand_ids.size() or _map._runner == null:
|
if index < 0 or index >= _cand_ids.size() or _map.runner == null:
|
||||||
return
|
return
|
||||||
var nodes: Array[Variant] = _map._runner.nodes()
|
var nodes: Array[Variant] = _map.runner.nodes()
|
||||||
var node := _node_by_id(int(_cand_ids[index]), nodes)
|
var node := _node_by_id(int(_cand_ids[index]), nodes)
|
||||||
if node.is_empty():
|
if node.is_empty():
|
||||||
return
|
return
|
||||||
var pos: Vector2 = _layout(nodes, _map._canvas)[node]
|
var pos: Vector2 = _layout(nodes, _map.canvas)[node]
|
||||||
var nid := _candidate_at(pos) # 节点中心必命中自身(命中面含节点方块)
|
var nid := _candidate_at(pos) # 节点中心必命中自身(命中面含节点方块)
|
||||||
if nid >= 0:
|
if nid >= 0:
|
||||||
_submit_choice(nid)
|
_submit_choice(nid)
|
||||||
@@ -414,7 +415,7 @@ func press_candidate(index: int) -> void:
|
|||||||
|
|
||||||
func _id_of(node: Dictionary) -> int:
|
func _id_of(node: Dictionary) -> int:
|
||||||
# 编号显示经行进器读面(编号空间解析单一出口——单链 = 下标 / 图 = node_depth)
|
# 编号显示经行进器读面(编号空间解析单一出口——单链 = 下标 / 图 = node_depth)
|
||||||
return _map._runner.node_id_of(node)
|
return _map.runner.node_id_of(node)
|
||||||
|
|
||||||
|
|
||||||
# ---- 节点呈现决策面(信息迷雾 v2.1:类型仅在可见集内出示,Boss 标记不入雾)----
|
# ---- 节点呈现决策面(信息迷雾 v2.1:类型仅在可见集内出示,Boss 标记不入雾)----
|
||||||
@@ -440,9 +441,9 @@ static func node_display(node: Dictionary, nid: int, type_vis: Array,
|
|||||||
# ---- 整图自绘(程序化占位——分层布局:层 = 入口 BFS 深度,同层垂直排布)----
|
# ---- 整图自绘(程序化占位——分层布局:层 = 入口 BFS 深度,同层垂直排布)----
|
||||||
|
|
||||||
func _draw_graph(canvas: Control) -> void:
|
func _draw_graph(canvas: Control) -> void:
|
||||||
if _map._runner == null or not visible:
|
if _map.runner == null or not visible:
|
||||||
return
|
return
|
||||||
_map._drawn_disp.clear() # 绘制记录随本帧重建——只反映实际发生的绘制(接线坏的判据面)
|
_map.drawn_disp.clear() # 绘制记录随本帧重建——只反映实际发生的绘制(接线坏的判据面)
|
||||||
var ctx := _draw_context(canvas)
|
var ctx := _draw_context(canvas)
|
||||||
_draw_passage_layer(canvas, ctx)
|
_draw_passage_layer(canvas, ctx)
|
||||||
for node in ctx["nodes"]:
|
for node in ctx["nodes"]:
|
||||||
@@ -451,16 +452,16 @@ func _draw_graph(canvas: Control) -> void:
|
|||||||
|
|
||||||
## 绘制上下文束(单次取数——布局/字体/编号空间/可见集,绘制域共享只读面)
|
## 绘制上下文束(单次取数——布局/字体/编号空间/可见集,绘制域共享只读面)
|
||||||
func _draw_context(canvas: Control) -> Dictionary:
|
func _draw_context(canvas: Control) -> Dictionary:
|
||||||
var nodes: Array[Variant] = _map._runner.nodes()
|
var nodes: Array[Variant] = _map.runner.nodes()
|
||||||
return {
|
return {
|
||||||
"nodes": nodes,
|
"nodes": nodes,
|
||||||
"pos": _layout(nodes, canvas),
|
"pos": _layout(nodes, canvas),
|
||||||
"font": get_theme_default_font(), # 绘制路径字体单次取用(三处 draw_string 共享——零语义差)
|
"font": get_theme_default_font(), # 绘制路径字体单次取用(三处 draw_string 共享——零语义差)
|
||||||
"current_id": _map._runner.current_node_id(),
|
"current_id": _map.runner.current_node_id(),
|
||||||
# 当前节点 id(单链=下标 / 图=编号)——visited_ids() 已按编号空间解析
|
# 当前节点 id(单链=下标 / 图=编号)——visited_ids() 已按编号空间解析
|
||||||
"visited": _map._runner.visited_ids(),
|
"visited": _map.runner.visited_ids(),
|
||||||
"cand_ids": _map._runner.next_candidate_ids(),
|
"cand_ids": _map.runner.next_candidate_ids(),
|
||||||
"type_vis": _map._runner.type_visible_ids(), # 本停点类型可见集(每帧一取——纯函数零状态)
|
"type_vis": _map.runner.type_visible_ids(), # 本停点类型可见集(每帧一取——纯函数零状态)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -525,7 +526,7 @@ func _draw_room(canvas: Control, node: Dictionary, ctx: Dictionary) -> void:
|
|||||||
var label_rec := _draw_room_label(canvas, rect, disp, nid, ctx)
|
var label_rec := _draw_room_label(canvas, rect, disp, nid, ctx)
|
||||||
rec["draw_label"] = bool(label_rec.get("draw_label", false))
|
rec["draw_label"] = bool(label_rec.get("draw_label", false))
|
||||||
rec["label_text"] = String(label_rec.get("label_text", ""))
|
rec["label_text"] = String(label_rec.get("label_text", ""))
|
||||||
_map._drawn_disp[nid] = rec
|
_map.drawn_disp[nid] = rec
|
||||||
|
|
||||||
|
|
||||||
## 节点图标域(20px 烘焙 1:1 消费;双色墨制=乘法调制——当前金底深墨,暗底系 WARM 原色;
|
## 节点图标域(20px 烘焙 1:1 消费;双色墨制=乘法调制——当前金底深墨,暗底系 WARM 原色;
|
||||||
@@ -536,7 +537,7 @@ func _draw_room_icon(canvas: Control, node: Dictionary, disp: Dictionary, ctx: D
|
|||||||
var p: Vector2 = ctx["pos"][node]
|
var p: Vector2 = ctx["pos"][node]
|
||||||
var col := _room_color(node, ctx)
|
var col := _room_color(node, ctx)
|
||||||
var t := String(node.get("type", ""))
|
var t := String(node.get("type", ""))
|
||||||
var icon: Texture2D = _map._layer_decor.node_icons.get(t)
|
var icon: Texture2D = _map.layer_decor.node_icons.get(t)
|
||||||
if icon != null:
|
if icon != null:
|
||||||
var tint := UiKit.ICON_TINT_ON_GOLD if col == COL_ROOM_CURRENT else Color(1.0, 1.0, 1.0)
|
var tint := UiKit.ICON_TINT_ON_GOLD if col == COL_ROOM_CURRENT else Color(1.0, 1.0, 1.0)
|
||||||
canvas.draw_texture_rect(icon, Rect2(p - Vector2(NODE_ICON_PX, NODE_ICON_PX) / 2.0,
|
canvas.draw_texture_rect(icon, Rect2(p - Vector2(NODE_ICON_PX, NODE_ICON_PX) / 2.0,
|
||||||
@@ -580,20 +581,20 @@ func _layout(nodes: Array, canvas: Control) -> Dictionary:
|
|||||||
|
|
||||||
# ---- 探针只读出口(形态仿 fx_probe 先例:只读快照) ----
|
# ---- 探针只读出口(形态仿 fx_probe 先例:只读快照) ----
|
||||||
|
|
||||||
# 选路布局只读快照(node → 局部位置;画布固定取现行 _map._canvas,调用侧零私有域触达)
|
# 选路布局只读快照(node → 局部位置;画布固定取现行 _map.canvas,调用侧零私有域触达)
|
||||||
func layout_probe(nodes: Array) -> Dictionary:
|
func layout_probe(nodes: Array) -> Dictionary:
|
||||||
return _layout(nodes, _map._canvas)
|
return _layout(nodes, _map.canvas)
|
||||||
|
|
||||||
|
|
||||||
# 路由画布只读快照(origin=全局原点;min_size=最小拟合尺寸——画布拟合断言消费面)
|
# 路由画布只读快照(origin=全局原点;min_size=最小拟合尺寸——画布拟合断言消费面)
|
||||||
func canvas_probe() -> Dictionary:
|
func canvas_probe() -> Dictionary:
|
||||||
return {"origin": _map._canvas.get_global_position(), "min_size": _map._canvas.custom_minimum_size}
|
return {"origin": _map.canvas.get_global_position(), "min_size": _map.canvas.custom_minimum_size}
|
||||||
|
|
||||||
|
|
||||||
# 类型可见性绘制只读记录(id → 本帧实际绘制事实:图标/文字/描边/文案;_draw_graph 在实际绘制点写入——
|
# 类型可见性绘制只读记录(id → 本帧实际绘制事实:图标/文字/描边/文案;_draw_graph 在实际绘制点写入——
|
||||||
# 接线层断言消费点:绕开决策面直接画,这里就露出「雾下也画了」)
|
# 接线层断言消费点:绕开决策面直接画,这里就露出「雾下也画了」)
|
||||||
func display_probe() -> Dictionary:
|
func display_probe() -> Dictionary:
|
||||||
return _map._drawn_disp
|
return _map.drawn_disp
|
||||||
|
|
||||||
|
|
||||||
# 分层(layout/fit 共享件):layer = 入口 BFS 深度;同层 slot 垂直排布;未达节点兜底排末层
|
# 分层(layout/fit 共享件):layer = 入口 BFS 深度;同层 slot 垂直排布;未达节点兜底排末层
|
||||||
@@ -637,7 +638,7 @@ func _entry(nodes: Array) -> Dictionary:
|
|||||||
|
|
||||||
|
|
||||||
func _out_ids(node: Dictionary, _nodes: Array) -> Array:
|
func _out_ids(node: Dictionary, _nodes: Array) -> Array:
|
||||||
return _map._runner.node_out_ids(node)
|
return _map.runner.node_out_ids(node)
|
||||||
|
|
||||||
|
|
||||||
func _node_by_id(nid: int, nodes: Array) -> Dictionary:
|
func _node_by_id(nid: int, nodes: Array) -> Dictionary:
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// VERTICAL SLICE - NOT FOR PRODUCTION
|
||||||
|
// 封印印记(卡④ 法阵化批)——环+十字+环外压暗光圈,canvas_item 距离场实时绘制(无贴图缩放,
|
||||||
|
// 格边 26–46px 连续可变下任意格边清晰)。
|
||||||
|
// 事实源:art-bible v3.41 §3.2「封印印记」(形/画法/光圈/层序纪律)+ §8.2「封印印记参数表」;
|
||||||
|
// gdd/ux/battle.md「棋盘格尺寸公式」(格边 clampi 26–46)。
|
||||||
|
// 纪律:参数五枚+色全由 gd 侧逐次注入(参数单点 = ui_kit SEAL_* 五常量——禁在此改值,
|
||||||
|
// 下方默认值仅为兜底且与 §8.2 同值);光圈不出格(半径夹 cell_px/2);
|
||||||
|
// 零动效(不呼吸不脉冲——§2.1 挖掘期唯一在动 = 接触带微光);印记与光圈同用一色(光圈只改 alpha)。
|
||||||
|
// 坐标口径:VERTEX 为格件本件局部像素坐标(0..cell_px),不依赖 UV(同 cell_type_glow 口径)。
|
||||||
|
shader_type canvas_item;
|
||||||
|
render_mode blend_mix;
|
||||||
|
|
||||||
|
uniform float cell_px : hint_range(8.0, 128.0) = 46.0;
|
||||||
|
uniform float ring_frac = 0.82;
|
||||||
|
uniform float wall_frac = 0.11;
|
||||||
|
uniform float arm_frac = 0.156;
|
||||||
|
uniform float halo_frac = 0.09;
|
||||||
|
uniform float halo_alpha : hint_range(0.0, 1.0) = 0.50;
|
||||||
|
uniform float halo_gamma = 1.6;
|
||||||
|
uniform vec4 mark_col : source_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
varying vec2 v_local;
|
||||||
|
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
v_local = VERTEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
vec2 d2 = v_local - vec2(cell_px * 0.5);
|
||||||
|
float r = length(d2);
|
||||||
|
float ring_r = 0.5 * cell_px * ring_frac;
|
||||||
|
float wall = wall_frac * 2.0 * ring_r;
|
||||||
|
float arm = arm_frac * 2.0 * ring_r;
|
||||||
|
float halo_w = 0.5 * cell_px * halo_frac;
|
||||||
|
// 印记体:环带(ring_r-wall/2 ≤ r ≤ ring_r)或十字(轴向带内且 r < ring_r——四端顶到环内沿)
|
||||||
|
bool in_ring = (r <= ring_r) && (r >= ring_r - wall * 0.5);
|
||||||
|
bool in_arm = (r < ring_r) && ((abs(d2.x) < arm * 0.5) || (abs(d2.y) < arm * 0.5));
|
||||||
|
float a = 0.0;
|
||||||
|
if (in_ring || in_arm) {
|
||||||
|
a = 1.0;
|
||||||
|
} else if (r > ring_r) {
|
||||||
|
// 环外压暗光圈:自环外缘向外衰减(半径夹 cell_px/2——不出格、不外溢邻格)
|
||||||
|
float rc = min(r, cell_px * 0.5);
|
||||||
|
float t = clamp((rc - ring_r) / max(halo_w, 0.001), 0.0, 1.0);
|
||||||
|
a = halo_alpha * pow(1.0 - t, halo_gamma);
|
||||||
|
}
|
||||||
|
COLOR = vec4(mark_col.rgb, mark_col.a * a);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bqgctor0wpjt7
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||||||
|
## SealMarkLayer——封印印记的独占承载子件(挂 BoardCellUnit 之下、1:1 贴格;复用 cell_type_glow_layer
|
||||||
|
## 的子件模式:材质独占、全幅 draw_rect、非零 alpha 触发——不复制其函数体,微光层件零改动)。
|
||||||
|
## 层序:印记层在 CellUnit 子树内(低于 BoardView 层的小人精灵——hero 精灵同层后挂天然在上);
|
||||||
|
## 迷雾态(fog_state != 0)整层隐藏由宿主 fog_state setter 联动承载(§6.5「封印随格隐没」)。
|
||||||
|
## 零动效(不呼吸不脉冲——§2.1 挖掘期唯一在动=接触带微光);参数与色全由 gd 注入
|
||||||
|
##(单点 = ui_kit SEAL_* 常量——本件禁内联色值与参数字面值)。
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
const _SEAL_SHADER := preload("res://presentation/views/seal_mark.gdshader")
|
||||||
|
|
||||||
|
var _mat: ShaderMaterial = null
|
||||||
|
var _edge := 0.0
|
||||||
|
|
||||||
|
|
||||||
|
# 作用集侧唯一入口(on=false 仅隐不撤——子件生命周期归宿主 _sync_seal_layer)
|
||||||
|
func setup(edge: float, on: bool) -> void:
|
||||||
|
_edge = edge
|
||||||
|
visible = on
|
||||||
|
if not on:
|
||||||
|
return
|
||||||
|
if _mat == null:
|
||||||
|
_mat = ShaderMaterial.new()
|
||||||
|
_mat.shader = _SEAL_SHADER
|
||||||
|
material = _mat
|
||||||
|
_mat.set_shader_parameter("cell_px", edge)
|
||||||
|
_mat.set_shader_parameter("ring_frac", UiKit.SEAL_RING_FRAC)
|
||||||
|
_mat.set_shader_parameter("wall_frac", UiKit.SEAL_WALL_FRAC)
|
||||||
|
_mat.set_shader_parameter("arm_frac", UiKit.SEAL_ARM_FRAC)
|
||||||
|
_mat.set_shader_parameter("halo_frac", UiKit.SEAL_HALO_FRAC)
|
||||||
|
_mat.set_shader_parameter("halo_alpha", UiKit.SEAL_HALO_ALPHA)
|
||||||
|
_mat.set_shader_parameter("halo_gamma", UiKit.SEAL_HALO_GAMMA)
|
||||||
|
_mat.set_shader_parameter("mark_col", UiKit.SEAL_BLACK)
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if _edge <= 0.0:
|
||||||
|
return
|
||||||
|
# 一格全幅:片元着色器按距离场产出环+十字+环外光圈。
|
||||||
|
# 输入 alpha 取 1/255(非零)——全透明几何在部分批次路径下会被整条跳过,着色器就跑不到。
|
||||||
|
draw_rect(Rect2(Vector2.ZERO, Vector2(_edge, _edge)), Color(1, 1, 1, 1.0 / 255.0))
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://oyfwx5p78pud
|
||||||
@@ -85,7 +85,7 @@ func _build_fullscreen_row(box: VBoxContainer) -> void:
|
|||||||
var fs_lab := UiKit.label("全屏",UiKit.FS_BODY, false, UiKit.INK_LABEL)
|
var fs_lab := UiKit.label("全屏",UiKit.FS_BODY, false, UiKit.INK_LABEL)
|
||||||
fs_lab.custom_minimum_size = Vector2(140, 0) # 同上
|
fs_lab.custom_minimum_size = Vector2(140, 0) # 同上
|
||||||
fs_row.add_child(fs_lab)
|
fs_row.add_child(fs_lab)
|
||||||
_fs_btn = UiKit._switch_toggle(false)
|
_fs_btn = UiKit.switch_toggle(false)
|
||||||
_fs_btn.toggled.connect(_on_fullscreen_toggled)
|
_fs_btn.toggled.connect(_on_fullscreen_toggled)
|
||||||
fs_row.add_child(_fs_btn)
|
fs_row.add_child(_fs_btn)
|
||||||
_fs_st = UiKit.label("关",UiKit.FS_HINT, true, UiKit.INK_LABEL)
|
_fs_st = UiKit.label("关",UiKit.FS_HINT, true, UiKit.INK_LABEL)
|
||||||
@@ -102,7 +102,7 @@ func _build_motion_row(box: VBoxContainer) -> void:
|
|||||||
var motion_lab := UiKit.label("结算演出动画",UiKit.FS_BODY, false, UiKit.INK_LABEL)
|
var motion_lab := UiKit.label("结算演出动画",UiKit.FS_BODY, false, UiKit.INK_LABEL)
|
||||||
motion_lab.custom_minimum_size = Vector2(140, 0) # 同上
|
motion_lab.custom_minimum_size = Vector2(140, 0) # 同上
|
||||||
motion_row.add_child(motion_lab)
|
motion_row.add_child(motion_lab)
|
||||||
_motion_btn = UiKit._switch_toggle(true)
|
_motion_btn = UiKit.switch_toggle(true)
|
||||||
_motion_btn.toggled.connect(_on_motion_toggled)
|
_motion_btn.toggled.connect(_on_motion_toggled)
|
||||||
motion_row.add_child(_motion_btn)
|
motion_row.add_child(_motion_btn)
|
||||||
_motion_st = UiKit.label("完整",UiKit.FS_HINT, true, UiKit.INK_LABEL)
|
_motion_st = UiKit.label("完整",UiKit.FS_HINT, true, UiKit.INK_LABEL)
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
## 站桩形态为定案——禁回卡片式;立绘素材缺位回退字形占位;击杀呈现禁瞬消(灰化塌陷)。
|
## 站桩形态为定案——禁回卡片式;立绘素材缺位回退字形占位;击杀呈现禁瞬消(灰化塌陷)。
|
||||||
## 无 class_name——经 preload 引用;壳层坐标换算单点在 BattleStageView.world_to_shell()。
|
## 无 class_name——经 preload 引用;壳层坐标换算单点在 BattleStageView.world_to_shell()。
|
||||||
## 内部状态两件(u4 拆件——st=身份命值态 standee_vitals、mo=资产演出态 standee_motion,_init 自建);
|
## 内部状态两件(u4 拆件——st=身份命值态 standee_vitals、mo=资产演出态 standee_motion,_init 自建);
|
||||||
## 外部直访冻结成员(box/font/slot_row/has_world_hp_bar)与源码锚承载成员(_intent_charge——theme
|
## 子件往来走公开面(pres封装 A2——身份经 configure_identity 交付、死亡/意图/闪白走行为方法、
|
||||||
## 源锚句所在行逐字保留)与三个演出探针计数器住宿主。
|
## 绘制读数走公开读法);外部直访冻结成员(box/font/slot_row/has_world_hp_bar)与源码锚承载成员
|
||||||
|
## (_intent_charge——theme 源锚句所在行逐字保留)与三个演出探针计数器住宿主。
|
||||||
extends Node2D
|
extends Node2D
|
||||||
|
|
||||||
const CHARGE_SKILL_IDS := ["heavy"]
|
const CHARGE_SKILL_IDS := ["heavy"]
|
||||||
@@ -36,8 +37,8 @@ var _flash_count := 0 # 探针出口计数(受击闪白触发次
|
|||||||
func _init(kind: String = "enemy") -> void:
|
func _init(kind: String = "enemy") -> void:
|
||||||
st = _VITALS.new(self)
|
st = _VITALS.new(self)
|
||||||
mo = _MOTION.new(self)
|
mo = _MOTION.new(self)
|
||||||
st._kind = kind
|
st.configure_identity(kind, "", "", "light")
|
||||||
mo._hero_state = _MOTION.HeroState.IDLE
|
mo.reset_state()
|
||||||
|
|
||||||
|
|
||||||
func _efont() -> Font:
|
func _efont() -> Font:
|
||||||
@@ -45,17 +46,17 @@ func _efont() -> Font:
|
|||||||
|
|
||||||
|
|
||||||
func display_name() -> String:
|
func display_name() -> String:
|
||||||
return st._display_name
|
return st.display_name()
|
||||||
|
|
||||||
|
|
||||||
# 敌单位身份出口(d12 站桩解析主键——同名敌按 id 精确匹配;主角站桩恒空串)
|
# 敌单位身份出口(d12 站桩解析主键——同名敌按 id 精确匹配;主角站桩恒空串)
|
||||||
func enemy_id() -> String:
|
func enemy_id() -> String:
|
||||||
return st._enemy_id
|
return st.enemy_id()
|
||||||
|
|
||||||
|
|
||||||
# 意图徽标探针出口
|
# 意图徽标探针出口
|
||||||
func intent_probe() -> Dictionary:
|
func intent_probe() -> Dictionary:
|
||||||
return {"visible": mo._intent_visible, "text": mo._intent_glyph}
|
return {"visible": mo.intent_visible(), "text": mo.intent_glyph()}
|
||||||
|
|
||||||
|
|
||||||
# 名字行探针出口(ui_probe 呈现口径 + 本批 V6/V8 断言面:armor_icon = 绑定纹理路径〔缺位回退字形〕、
|
# 名字行探针出口(ui_probe 呈现口径 + 本批 V6/V8 断言面:armor_icon = 绑定纹理路径〔缺位回退字形〕、
|
||||||
@@ -63,10 +64,10 @@ func intent_probe() -> Dictionary:
|
|||||||
# name_font_size = 名字行字号档实读(迭代 46 卡B——提档 FS_HINT 14 的几何单点出口))
|
# name_font_size = 名字行字号档实读(迭代 46 卡B——提档 FS_HINT 14 的几何单点出口))
|
||||||
func name_line_probe() -> Dictionary:
|
func name_line_probe() -> Dictionary:
|
||||||
var f := _efont()
|
var f := _efont()
|
||||||
var tex := UiKit.load_tex(_armor_tex_path(st._armor))
|
var tex := UiKit.load_tex(_armor_tex_path(st.armor()))
|
||||||
var plate := _name_plate_rect(f, tex)
|
var plate := _name_plate_rect(f, tex)
|
||||||
return {"name": st._display_name,
|
return {"name": st.display_name(),
|
||||||
"armor_icon": _armor_tex_path(st._armor) if tex != null else String(ARMOR_ICONS.get(st._armor, "◇")),
|
"armor_icon": _armor_tex_path(st.armor()) if tex != null else String(ARMOR_ICONS.get(st.armor(), "◇")),
|
||||||
"armor_tex_bound": tex != null,
|
"armor_tex_bound": tex != null,
|
||||||
"plate": plate, "baseline_y": _name_baseline(plate).y,
|
"plate": plate, "baseline_y": _name_baseline(plate).y,
|
||||||
"plinth_top_y": _pedestal_rect().position.y,
|
"plinth_top_y": _pedestal_rect().position.y,
|
||||||
@@ -79,23 +80,21 @@ func name_line_probe() -> Dictionary:
|
|||||||
# data = 战斗结算 presentation_snapshot enemies[] 投影:{order, display_name, hp, max_hp, enemy_id,
|
# data = 战斗结算 presentation_snapshot enemies[] 投影:{order, display_name, hp, max_hp, enemy_id,
|
||||||
# pending_skill/pending_type/pending_name, effects[](该敌自己名下增益——各立绘各读各的,增益状态 v1.5 个体投影)}
|
# pending_skill/pending_type/pending_name, effects[](该敌自己名下增益——各立绘各读各的,增益状态 v1.5 个体投影)}
|
||||||
func set_data(d: Dictionary) -> void:
|
func set_data(d: Dictionary) -> void:
|
||||||
st._display_name = String(d.get("display_name", "敌人"))
|
st.configure_identity(st.kind(), String(d.get("display_name", "敌人")), String(d.get("enemy_id", "")), String(d.get("armor_type", "light")))
|
||||||
st._enemy_id = String(d.get("enemy_id", ""))
|
st.set_max_hp(float(maxi(1, int(d.get("max_hp", 1)))))
|
||||||
st._armor = String(d.get("armor_type", "light"))
|
|
||||||
st._hp_max = float(maxi(1, int(d.get("max_hp", 1))))
|
|
||||||
st.apply_hp(int(d.get("hp", 0)))
|
st.apply_hp(int(d.get("hp", 0)))
|
||||||
_set_order(int(d.get("order", 1)))
|
_set_order(int(d.get("order", 1)))
|
||||||
set_pending(String(d.get("pending_type", "")), String(d.get("pending_skill", "")))
|
set_pending(String(d.get("pending_type", "")), String(d.get("pending_skill", "")))
|
||||||
set_effects(d.get("effects", []))
|
set_effects(d.get("effects", []))
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
if st._dead and int(d.get("hp", 0)) > 0:
|
if st.is_dead() and int(d.get("hp", 0)) > 0:
|
||||||
_revive()
|
_revive()
|
||||||
|
|
||||||
|
|
||||||
func set_hero(hp: int, max_hp: int) -> void:
|
func set_hero(hp: int, max_hp: int) -> void:
|
||||||
st._hp_max = float(maxi(1, max_hp))
|
st.set_max_hp(float(maxi(1, max_hp)))
|
||||||
st.apply_hp(hp)
|
st.apply_hp(hp)
|
||||||
if st._dead and hp > 0:
|
if st.is_dead() and hp > 0:
|
||||||
_revive() # 新战斗开场 HP 回正——主角死亡残位随之复活(敌侧 set_data 同款语义)
|
_revive() # 新战斗开场 HP 回正——主角死亡残位随之复活(敌侧 set_data 同款语义)
|
||||||
|
|
||||||
|
|
||||||
@@ -128,21 +127,21 @@ func set_effects_cleared_feedback() -> void:
|
|||||||
|
|
||||||
func _set_order(i: int) -> void:
|
func _set_order(i: int) -> void:
|
||||||
# 顺位徽标 = 行主序生成序(固定顺位——敌人系统 顺位标记义务)
|
# 顺位徽标 = 行主序生成序(固定顺位——敌人系统 顺位标记义务)
|
||||||
st._order = i
|
st.set_order(i)
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
# 摇定动作渲染(三档可见性):pending_type = 战斗结算 快照投影(basic/damage/buff/debuff;
|
# 摇定动作渲染(三档可见性):pending_type = 战斗结算 快照投影(basic/damage/buff/debuff;
|
||||||
# "" = 未摇定/死亡残位)。不显示技能名——类型级图标 + 一次性动作动画。
|
# "" = 未摇定/死亡残位)。不显示技能名——类型级图标 + 一次性动作动画。
|
||||||
func set_pending(ptype: String, pid: String) -> void:
|
func set_pending(ptype: String, pid: String) -> void:
|
||||||
if st._dead:
|
if st.is_dead():
|
||||||
_intent_charge = false
|
_intent_charge = false
|
||||||
mo._intent_visible = false
|
mo.hide_intent()
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
return
|
return
|
||||||
if ptype == "" or ptype == "basic":
|
if ptype == "" or ptype == "basic":
|
||||||
_intent_charge = false
|
_intent_charge = false
|
||||||
mo._intent_visible = false # 普通攻击零表示(完全不可预测——§2.4)
|
mo.hide_intent() # 普通攻击零表示(完全不可预测——§2.4)
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
return
|
return
|
||||||
var glyph := "⚔" # 攻击系(damage)
|
var glyph := "⚔" # 攻击系(damage)
|
||||||
@@ -156,9 +155,7 @@ func set_pending(ptype: String, pid: String) -> void:
|
|||||||
_intent_charge = pid in CHARGE_SKILL_IDS
|
_intent_charge = pid in CHARGE_SKILL_IDS
|
||||||
if _intent_charge:
|
if _intent_charge:
|
||||||
col = UiKit.GOLD_INK # 重击类蓄力档(深金墨——浅垫牌上 ≥4.5:1)
|
col = UiKit.GOLD_INK # 重击类蓄力档(深金墨——浅垫牌上 ≥4.5:1)
|
||||||
mo._intent_glyph = glyph
|
mo.show_intent(glyph, col)
|
||||||
mo._intent_col = col
|
|
||||||
mo._intent_visible = true
|
|
||||||
mo.play_intent_motion(_intent_charge)
|
mo.play_intent_motion(_intent_charge)
|
||||||
|
|
||||||
|
|
||||||
@@ -168,9 +165,9 @@ func set_portrait_texture(tex: Texture2D, flip: bool = false) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func mark_dead() -> void:
|
func mark_dead() -> void:
|
||||||
if st._dead:
|
if st.is_dead():
|
||||||
return
|
return
|
||||||
st._dead = true
|
st.set_dead(true)
|
||||||
modulate = Color(0.62, 0.62, 0.62, 0.9)
|
modulate = Color(0.62, 0.62, 0.62, 0.9)
|
||||||
var tw := create_tween()
|
var tw := create_tween()
|
||||||
tw.tween_property(self, "rotation_degrees", 2.5, UiKit.motion(0.12))
|
tw.tween_property(self, "rotation_degrees", 2.5, UiKit.motion(0.12))
|
||||||
@@ -178,7 +175,7 @@ func mark_dead() -> void:
|
|||||||
tw.tween_property(self, "rotation_degrees", 0.0, UiKit.motion(0.08))
|
tw.tween_property(self, "rotation_degrees", 0.0, UiKit.motion(0.08))
|
||||||
_spawn_death_shards() # 碎裂退场(§4.6.4 语义硬规则:灰化+碎裂禁瞬间消失;§8.4 v2 冻结 5 块 0.45s)
|
_spawn_death_shards() # 碎裂退场(§4.6.4 语义硬规则:灰化+碎裂禁瞬间消失;§8.4 v2 冻结 5 块 0.45s)
|
||||||
_intent_charge = false
|
_intent_charge = false
|
||||||
mo._intent_visible = false # 死亡残位意图退位
|
mo.hide_intent() # 死亡残位意图退位
|
||||||
st.apply_hp(0)
|
st.apply_hp(0)
|
||||||
if slot_row != null:
|
if slot_row != null:
|
||||||
slot_row.visible = false # 状态行随 mark_dead 同拍隐藏
|
slot_row.visible = false # 状态行随 mark_dead 同拍隐藏
|
||||||
@@ -245,24 +242,20 @@ func _spawn_hit_spark(i: int, center: Vector2) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func is_dead() -> bool:
|
func is_dead() -> bool:
|
||||||
return st._dead
|
return st.is_dead()
|
||||||
|
|
||||||
|
|
||||||
# 受击闪白(结算演出占位——§2.2 受击反馈;强度时长维持现行)
|
# 受击闪白(结算演出占位——§2.2 受击反馈;强度时长维持现行)
|
||||||
func flash_hit() -> void:
|
func flash_hit() -> void:
|
||||||
_flash_count += 1
|
_flash_count += 1
|
||||||
if st._hp_flash_tw != null and st._hp_flash_tw.is_valid():
|
st.play_hp_flash() # tween 逻辑归位 vitals 自持(pres封装 A2——宿主零自建 tween)
|
||||||
st._hp_flash_tw.kill()
|
|
||||||
st._hp_flash_tw = create_tween()
|
|
||||||
st._hp_flash_tw.tween_property(self, "modulate", Color(1.6, 1.4, 1.2), UiKit.motion(0.08))
|
|
||||||
st._hp_flash_tw.tween_property(self, "modulate", Color(1, 1, 1) if not st._dead else Color(0.62, 0.62, 0.62, 0.9), UiKit.motion(0.2))
|
|
||||||
|
|
||||||
|
|
||||||
func _revive() -> void:
|
func _revive() -> void:
|
||||||
st._dead = false
|
st.set_dead(false)
|
||||||
modulate = Color(1, 1, 1)
|
modulate = Color(1, 1, 1)
|
||||||
rotation_degrees = 0.0
|
rotation_degrees = 0.0
|
||||||
if st._kind == "hero":
|
if st.kind() == "hero":
|
||||||
mo.reset_state()
|
mo.reset_state()
|
||||||
if slot_row != null:
|
if slot_row != null:
|
||||||
slot_row.visible = true
|
slot_row.visible = true
|
||||||
@@ -272,16 +265,16 @@ func _revive() -> void:
|
|||||||
func _portrait_glyph() -> String:
|
func _portrait_glyph() -> String:
|
||||||
# 字形回退仅作缺位兜底(八敌真图落位;相对体量语义由 48px 档统一比例承载)。
|
# 字形回退仅作缺位兜底(八敌真图落位;相对体量语义由 48px 档统一比例承载)。
|
||||||
# 缺位态:主角「人」/死亡「✕」/其余「敌」。
|
# 缺位态:主角「人」/死亡「✕」/其余「敌」。
|
||||||
if st._kind == "hero":
|
if st.kind() == "hero":
|
||||||
return "人"
|
return "人"
|
||||||
if st._dead:
|
if st.is_dead():
|
||||||
return "✕"
|
return "✕"
|
||||||
return "敌"
|
return "敌"
|
||||||
|
|
||||||
|
|
||||||
# 立绘落位探针出口(站桩纹理非空断言面;缺位回退链保持的对照面)
|
# 立绘落位探针出口(站桩纹理非空断言面;缺位回退链保持的对照面)
|
||||||
func portrait_probe() -> Dictionary:
|
func portrait_probe() -> Dictionary:
|
||||||
var sp: Sprite2D = mo._portrait_sprite
|
var sp: Sprite2D = mo.portrait_sprite()
|
||||||
if sp == null or sp.texture == null:
|
if sp == null or sp.texture == null:
|
||||||
return {"has_tex": false, "display_size": Vector2.ZERO, "display_scale": 0.0}
|
return {"has_tex": false, "display_size": Vector2.ZERO, "display_scale": 0.0}
|
||||||
var src := Vector2(sp.texture.get_width(), sp.texture.get_height())
|
var src := Vector2(sp.texture.get_width(), sp.texture.get_height())
|
||||||
@@ -297,7 +290,7 @@ func register_hero_state(state: String, tex: Texture2D) -> void:
|
|||||||
|
|
||||||
# 状态切换转调壳(签名外形零变——is_hero 由宿主 vitals 参判传入,早退序逐字在件内)
|
# 状态切换转调壳(签名外形零变——is_hero 由宿主 vitals 参判传入,早退序逐字在件内)
|
||||||
func set_hero_state(state: String) -> void:
|
func set_hero_state(state: String) -> void:
|
||||||
mo.apply_hero_state(state, st._kind == "hero")
|
mo.apply_hero_state(state, st.kind() == "hero")
|
||||||
|
|
||||||
|
|
||||||
# 三态探针出口(fx_probe——当前态名+注册态集合;读件投影外形零变)
|
# 三态探针出口(fx_probe——当前态名+注册态集合;读件投影外形零变)
|
||||||
@@ -306,7 +299,7 @@ func hero_state_probe() -> Dictionary:
|
|||||||
|
|
||||||
|
|
||||||
func _portrait_color() -> Color:
|
func _portrait_color() -> Color:
|
||||||
return UiKit.HERO_BLUE if st._kind == "hero" else UiKit.RED_DEEP
|
return UiKit.HERO_BLUE if st.kind() == "hero" else UiKit.RED_DEEP
|
||||||
|
|
||||||
|
|
||||||
# 立绘盒矩形(世界局部):(0,44)-(box.x, box.y-36)——贴图与字形共用
|
# 立绘盒矩形(世界局部):(0,44)-(box.x, box.y-36)——贴图与字形共用
|
||||||
@@ -337,9 +330,9 @@ func _armor_tex_path(armor: String) -> String:
|
|||||||
func _name_plate_rect(f: Font, tex: Texture2D) -> Rect2:
|
func _name_plate_rect(f: Font, tex: Texture2D) -> Rect2:
|
||||||
var icon_w := 24.0
|
var icon_w := 24.0
|
||||||
if tex == null:
|
if tex == null:
|
||||||
icon_w = f.get_string_size(String(ARMOR_ICONS.get(st._armor, "◇")),
|
icon_w = f.get_string_size(String(ARMOR_ICONS.get(st.armor(), "◇")),
|
||||||
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT).x
|
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT).x
|
||||||
var name_w := f.get_string_size(st._display_name, HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT).x
|
var name_w := f.get_string_size(st.display_name(), HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT).x
|
||||||
var total_w := icon_w + 3.0 + name_w
|
var total_w := icon_w + 3.0 + name_w
|
||||||
return Rect2((box.x - total_w - 8.0) * 0.5, box.y - 18.0 - 26.0, total_w + 8.0, 26.0)
|
return Rect2((box.x - total_w - 8.0) * 0.5, box.y - 18.0 - 26.0, total_w + 8.0, 26.0)
|
||||||
|
|
||||||
@@ -362,7 +355,7 @@ func _draw() -> void:
|
|||||||
_draw_hp_bar(f)
|
_draw_hp_bar(f)
|
||||||
_draw_portrait(f)
|
_draw_portrait(f)
|
||||||
_draw_intent_badge(f)
|
_draw_intent_badge(f)
|
||||||
if st._kind == "enemy":
|
if st.kind() == "enemy":
|
||||||
_draw_armor_name_line(f)
|
_draw_armor_name_line(f)
|
||||||
|
|
||||||
|
|
||||||
@@ -406,8 +399,8 @@ func _draw_plinth_stretched(tex: Texture2D, ped: Rect2) -> void:
|
|||||||
## 10px 条带垂直居中;数字=目标值即时刷新,条 tween 只管填充宽度;死残位 0/max 照常可读)
|
## 10px 条带垂直居中;数字=目标值即时刷新,条 tween 只管填充宽度;死残位 0/max 照常可读)
|
||||||
func _draw_hp_bar(f: Font) -> void:
|
func _draw_hp_bar(f: Font) -> void:
|
||||||
var bar_x := 8.0
|
var bar_x := 8.0
|
||||||
if st._kind == "enemy":
|
if st.kind() == "enemy":
|
||||||
var order_txt := String("①②③"[clampi(st._order - 1, 0, 2)])
|
var order_txt := String("①②③"[clampi(st.order() - 1, 0, 2)])
|
||||||
f.draw_string(get_canvas_item(), Vector2(bar_x, 12), order_txt,
|
f.draw_string(get_canvas_item(), Vector2(bar_x, 12), order_txt,
|
||||||
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT, UiKit.GOLD_BRIGHT)
|
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT, UiKit.GOLD_BRIGHT)
|
||||||
bar_x += 20.0
|
bar_x += 20.0
|
||||||
@@ -416,7 +409,7 @@ func _draw_hp_bar(f: Font) -> void:
|
|||||||
var fill_w := bar_w * st.hp_value
|
var fill_w := bar_w * st.hp_value
|
||||||
if fill_w > 0.0:
|
if fill_w > 0.0:
|
||||||
draw_rect(Rect2(bar_x, 2, fill_w, 10), UiKit.HP_BAR_FILL) # 直角填充(危险红——§4.2 血条显式句)
|
draw_rect(Rect2(bar_x, 2, fill_w, 10), UiKit.HP_BAR_FILL) # 直角填充(危险红——§4.2 血条显式句)
|
||||||
var hp_txt := "%d/%d" % [st._hp_cur, int(st._hp_max)]
|
var hp_txt := "%d/%d" % [st.hp_cur(), int(st.hp_max())]
|
||||||
var hts: Vector2 = f.get_string_size(hp_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, 11)
|
var hts: Vector2 = f.get_string_size(hp_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, 11)
|
||||||
# 对比度垫牌(白 α.95 直压蓝条 2.67:1 违 §7.2;
|
# 对比度垫牌(白 α.95 直压蓝条 2.67:1 违 §7.2;
|
||||||
# 中央垫 HP_BAR_BACK 深素牌 = 14.3:1;牌宽=字宽+8〔白名单取 8〕,高=条带全高;§4.1 数字色牌原则)
|
# 中央垫 HP_BAR_BACK 深素牌 = 14.3:1;牌宽=字宽+8〔白名单取 8〕,高=条带全高;§4.1 数字色牌原则)
|
||||||
@@ -428,7 +421,7 @@ func _draw_hp_bar(f: Font) -> void:
|
|||||||
|
|
||||||
## 立绘域:贴图在位 = Sprite2D(set_portrait_texture 落位);缺位 = 字形回退
|
## 立绘域:贴图在位 = Sprite2D(set_portrait_texture 落位);缺位 = 字形回退
|
||||||
func _draw_portrait(f: Font) -> void:
|
func _draw_portrait(f: Font) -> void:
|
||||||
if mo._portrait_sprite != null and mo._portrait_sprite.texture != null and mo._portrait_sprite.visible:
|
if mo.portrait_sprite() != null and mo.portrait_sprite().texture != null and mo.portrait_sprite().visible:
|
||||||
return
|
return
|
||||||
var prect := _portrait_rect()
|
var prect := _portrait_rect()
|
||||||
var glyph := _portrait_glyph()
|
var glyph := _portrait_glyph()
|
||||||
@@ -436,7 +429,7 @@ func _draw_portrait(f: Font) -> void:
|
|||||||
# 坐标系注记:draw_set_transform 原点已置于 center——draw_string 的
|
# 坐标系注记:draw_set_transform 原点已置于 center——draw_string 的
|
||||||
# pos 是**变换后的局部坐标**,须传相对 center 的偏移(-w/2 水平居中、+0.35h 基线下移);
|
# pos 是**变换后的局部坐标**,须传相对 center 的偏移(-w/2 水平居中、+0.35h 基线下移);
|
||||||
# 传绝对 center 会成双重偏移、把字形画到盒外。
|
# 传绝对 center 会成双重偏移、把字形画到盒外。
|
||||||
draw_set_transform(center, deg_to_rad(mo._glyph_rot), Vector2.ONE)
|
draw_set_transform(center, deg_to_rad(mo.intent_rot()), Vector2.ONE)
|
||||||
var ts := f.get_string_size(glyph, HORIZONTAL_ALIGNMENT_LEFT, -1, 42)
|
var ts := f.get_string_size(glyph, HORIZONTAL_ALIGNMENT_LEFT, -1, 42)
|
||||||
f.draw_string(get_canvas_item(), Vector2(-ts.x * 0.5, ts.y * 0.35), glyph,
|
f.draw_string(get_canvas_item(), Vector2(-ts.x * 0.5, ts.y * 0.35), glyph,
|
||||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 42, _portrait_color())
|
HORIZONTAL_ALIGNMENT_LEFT, -1, 42, _portrait_color())
|
||||||
@@ -445,24 +438,24 @@ func _draw_portrait(f: Font) -> void:
|
|||||||
|
|
||||||
## 意图徽标域(敌 only——立绘上半部居中悬浮,CENTER_TOP 74..98 等价):弹入 scale 动画
|
## 意图徽标域(敌 only——立绘上半部居中悬浮,CENTER_TOP 74..98 等价):弹入 scale 动画
|
||||||
func _draw_intent_badge(f: Font) -> void:
|
func _draw_intent_badge(f: Font) -> void:
|
||||||
if not mo._intent_visible:
|
if not mo.intent_visible():
|
||||||
return
|
return
|
||||||
var icenter := Vector2(box.x * 0.5, 86.0)
|
var icenter := Vector2(box.x * 0.5, 86.0)
|
||||||
draw_set_transform(icenter, 0.0, Vector2(mo._intent_scale, mo._intent_scale))
|
draw_set_transform(icenter, 0.0, Vector2(mo.intent_scale(), mo.intent_scale()))
|
||||||
var its := f.get_string_size(mo._intent_glyph, HORIZONTAL_ALIGNMENT_LEFT, -1, 15)
|
var its := f.get_string_size(mo.intent_glyph(), HORIZONTAL_ALIGNMENT_LEFT, -1, 15)
|
||||||
# 对比度垫牌(四色墨直压立绘纹理/暗舞台底 1.5-3.3:1 违 §7.2
|
# 对比度垫牌(四色墨直压立绘纹理/暗舞台底 1.5-3.3:1 违 §7.2
|
||||||
# 「文字禁直压纹理底」;垫 PANEL_DATA 素牌后 atk 5.3/buf 4.8/debuff 4.7/charge 4.9 全 ≥4.5:1;
|
# 「文字禁直压纹理底」;垫 PANEL_DATA 素牌后 atk 5.3/buf 4.8/debuff 4.7/charge 4.9 全 ≥4.5:1;
|
||||||
# atk/debuff 零换墨、buf 换 HERO_BLUE_DEEP、charge 换 GOLD_INK;随弹入 transform 同步缩放)
|
# atk/debuff 零换墨、buf 换 HERO_BLUE_DEEP、charge 换 GOLD_INK;随弹入 transform 同步缩放)
|
||||||
draw_rect(Rect2(-its.x * 0.5 - 4.0, -its.y * 0.75, its.x + 8.0, its.y * 1.1), UiKit.PANEL_DATA, true)
|
draw_rect(Rect2(-its.x * 0.5 - 4.0, -its.y * 0.75, its.x + 8.0, its.y * 1.1), UiKit.PANEL_DATA, true)
|
||||||
f.draw_string(get_canvas_item(), Vector2(-its.x * 0.5, its.y * 0.35), mo._intent_glyph,
|
f.draw_string(get_canvas_item(), Vector2(-its.x * 0.5, its.y * 0.35), mo.intent_glyph(),
|
||||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 15, mo._intent_col) # 局部坐标(同上注记——双重偏移修复)
|
HORIZONTAL_ALIGNMENT_LEFT, -1, 15, mo.intent_col()) # 局部坐标(同上注记——双重偏移修复)
|
||||||
|
|
||||||
|
|
||||||
## 名字行域(敌 only——AC 数值不展示,类型图标化):整行垫 HP_BAR_BACK 素底牌(§6.1/§7.2
|
## 名字行域(敌 only——AC 数值不展示,类型图标化):整行垫 HP_BAR_BACK 素底牌(§6.1/§7.2
|
||||||
## 「文字禁直接压地台」素底落法——牌底沿 = 地台顶,几何单点 _name_plate_rect);护甲图标 =
|
## 「文字禁直接压地台」素底落法——牌底沿 = 地台顶,几何单点 _name_plate_rect);护甲图标 =
|
||||||
## 24×24 PNG(甲类 1×,缺位回退字形,色随甲档亮档族);名字 = 暖白(暗底双色墨制)
|
## 24×24 PNG(甲类 1×,缺位回退字形,色随甲档亮档族);名字 = 暖白(暗底双色墨制)
|
||||||
func _draw_armor_name_line(f: Font) -> void:
|
func _draw_armor_name_line(f: Font) -> void:
|
||||||
var tex := UiKit.load_tex(_armor_tex_path(st._armor))
|
var tex := UiKit.load_tex(_armor_tex_path(st.armor()))
|
||||||
var plate := _name_plate_rect(f, tex)
|
var plate := _name_plate_rect(f, tex)
|
||||||
draw_rect(plate, UiKit.HP_BAR_BACK, true)
|
draw_rect(plate, UiKit.HP_BAR_BACK, true)
|
||||||
var baseline := _name_baseline(plate)
|
var baseline := _name_baseline(plate)
|
||||||
@@ -470,14 +463,14 @@ func _draw_armor_name_line(f: Font) -> void:
|
|||||||
if tex != null:
|
if tex != null:
|
||||||
draw_texture_rect(tex, Rect2(baseline.x, plate.position.y + 1.0, 24.0, 24.0), false)
|
draw_texture_rect(tex, Rect2(baseline.x, plate.position.y + 1.0, 24.0, 24.0), false)
|
||||||
else:
|
else:
|
||||||
var armor_txt := String(ARMOR_ICONS.get(st._armor, "◇"))
|
var armor_txt := String(ARMOR_ICONS.get(st.armor(), "◇"))
|
||||||
icon_w = f.get_string_size(armor_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT).x
|
icon_w = f.get_string_size(armor_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT).x
|
||||||
var col: Color = UiKit.WARM_FAINT # 轻甲 = 暖白弱化(v3.5 暗底双色墨制)
|
var col: Color = UiKit.WARM_FAINT # 轻甲 = 暖白弱化(v3.5 暗底双色墨制)
|
||||||
match st._armor:
|
match st.armor():
|
||||||
"ward":
|
"ward":
|
||||||
col = UiKit.HERO_BLUE_BRIGHT # 魔法护甲 = 小人蓝亮档
|
col = UiKit.HERO_BLUE_BRIGHT # 魔法护甲 = 小人蓝亮档
|
||||||
"heavy":
|
"heavy":
|
||||||
col = UiKit.GOLD_BRIGHT # 重甲 = 金族亮档
|
col = UiKit.GOLD_BRIGHT # 重甲 = 金族亮档
|
||||||
f.draw_string(get_canvas_item(), baseline, armor_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT, col)
|
f.draw_string(get_canvas_item(), baseline, armor_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT, col)
|
||||||
f.draw_string(get_canvas_item(), baseline + Vector2(icon_w + 3.0, 0.0), st._display_name,
|
f.draw_string(get_canvas_item(), baseline + Vector2(icon_w + 3.0, 0.0), st.display_name(),
|
||||||
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT, UiKit.WARM) # v3.5 暗底双色墨制
|
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT, UiKit.WARM) # v3.5 暗底双色墨制
|
||||||
@@ -147,3 +147,41 @@ func play_intent_motion(charge: bool) -> void:
|
|||||||
# 三态探针出口(fx_probe——当前态名+注册态集合;宿主 hero_state_probe 读件投影,外形零变)
|
# 三态探针出口(fx_probe——当前态名+注册态集合;宿主 hero_state_probe 读件投影,外形零变)
|
||||||
func state_probe() -> Dictionary:
|
func state_probe() -> Dictionary:
|
||||||
return {"state": _HS_NAME.get(_hero_state, "idle"), "registered": _hero_tex.keys()}
|
return {"state": _HS_NAME.get(_hero_state, "idle"), "registered": _hero_tex.keys()}
|
||||||
|
|
||||||
|
|
||||||
|
# ---- 意图徽标行为与绘制读口(pres封装 A2——宿主经此读写,字段保持私有)----
|
||||||
|
|
||||||
|
# 意图徽标显隐/设定(宿主 set_pending/mark_dead 三处同型归位——显示后由宿主拍 play_intent_motion)
|
||||||
|
func show_intent(glyph: String, col: Color) -> void:
|
||||||
|
_intent_glyph = glyph
|
||||||
|
_intent_col = col
|
||||||
|
_intent_visible = true
|
||||||
|
|
||||||
|
|
||||||
|
func hide_intent() -> void:
|
||||||
|
_intent_visible = false
|
||||||
|
|
||||||
|
|
||||||
|
# 绘制路径读投影(宿主 _draw 每帧调用——逐 getter 免逐帧字典分配)
|
||||||
|
func intent_visible() -> bool:
|
||||||
|
return _intent_visible
|
||||||
|
|
||||||
|
|
||||||
|
func intent_glyph() -> String:
|
||||||
|
return _intent_glyph
|
||||||
|
|
||||||
|
|
||||||
|
func intent_col() -> Color:
|
||||||
|
return _intent_col
|
||||||
|
|
||||||
|
|
||||||
|
func intent_scale() -> float:
|
||||||
|
return _intent_scale
|
||||||
|
|
||||||
|
|
||||||
|
func intent_rot() -> float:
|
||||||
|
return _glyph_rot
|
||||||
|
|
||||||
|
|
||||||
|
func portrait_sprite() -> Sprite2D:
|
||||||
|
return _portrait_sprite
|
||||||
@@ -26,6 +26,69 @@ func _init(owner: Node2D) -> void:
|
|||||||
_owner = owner
|
_owner = owner
|
||||||
|
|
||||||
|
|
||||||
|
# ---- 公开交付与读投影面(pres封装 A2——宿主经此读写,字段保持私有)----
|
||||||
|
|
||||||
|
# 身份四元组一次交付(生成期/配置期同口——宿主 _init 与 set_data 共用)
|
||||||
|
func configure_identity(kind: String, display_name: String, enemy_id: String, armor: String) -> void:
|
||||||
|
_kind = kind
|
||||||
|
_display_name = display_name
|
||||||
|
_enemy_id = enemy_id
|
||||||
|
_armor = armor
|
||||||
|
|
||||||
|
|
||||||
|
func set_max_hp(v: float) -> void:
|
||||||
|
_hp_max = v
|
||||||
|
|
||||||
|
|
||||||
|
func set_order(i: int) -> void:
|
||||||
|
_order = i
|
||||||
|
|
||||||
|
|
||||||
|
func set_dead(v: bool) -> void:
|
||||||
|
_dead = v
|
||||||
|
|
||||||
|
|
||||||
|
func is_dead() -> bool:
|
||||||
|
return _dead
|
||||||
|
|
||||||
|
|
||||||
|
func kind() -> String:
|
||||||
|
return _kind
|
||||||
|
|
||||||
|
|
||||||
|
func armor() -> String:
|
||||||
|
return _armor
|
||||||
|
|
||||||
|
|
||||||
|
func display_name() -> String:
|
||||||
|
return _display_name
|
||||||
|
|
||||||
|
|
||||||
|
func enemy_id() -> String:
|
||||||
|
return _enemy_id
|
||||||
|
|
||||||
|
|
||||||
|
func order() -> int:
|
||||||
|
return _order
|
||||||
|
|
||||||
|
|
||||||
|
func hp_cur() -> int:
|
||||||
|
return _hp_cur
|
||||||
|
|
||||||
|
|
||||||
|
func hp_max() -> float:
|
||||||
|
return _hp_max
|
||||||
|
|
||||||
|
|
||||||
|
# 受击闪白归位(宿主 flash_hit 转调——tween 句柄留本件自持,目标=宿主 modulate)
|
||||||
|
func play_hp_flash() -> void:
|
||||||
|
if _hp_flash_tw != null and _hp_flash_tw.is_valid():
|
||||||
|
_hp_flash_tw.kill()
|
||||||
|
_hp_flash_tw = _owner.create_tween()
|
||||||
|
_hp_flash_tw.tween_property(_owner, "modulate", Color(1.6, 1.4, 1.2), UiKit.motion(0.08))
|
||||||
|
_hp_flash_tw.tween_property(_owner, "modulate", Color(1, 1, 1) if not _dead else Color(0.62, 0.62, 0.62, 0.9), UiKit.motion(0.2))
|
||||||
|
|
||||||
|
|
||||||
# 血条短 tween 递减(直角递减占位);逐行刷新时重启 tween 不累积
|
# 血条短 tween 递减(直角递减占位);逐行刷新时重启 tween 不累积
|
||||||
func apply_hp(hp: int) -> void:
|
func apply_hp(hp: int) -> void:
|
||||||
_hp_cur = clampi(hp, 0, int(_hp_max))
|
_hp_cur = clampi(hp, 0, int(_hp_max))
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ extends RefCounted
|
|||||||
# dungeon 套(禁同板混渲染);dungeon 套亦缺位 → 程序化平色回退(fresh checkout 冒烟不炸)。
|
# dungeon 套(禁同板混渲染);dungeon 套亦缺位 → 程序化平色回退(fresh checkout 冒烟不炸)。
|
||||||
const TILE_WALL_NAMES := ["wall_center", "wall_center_crack", "wall_center_speckle", "wall_n", "wall_s", "wall_w", "wall_nw", "wall_sw", "wall_hrun", "wall_vrun", "wall_end_n", "wall_end_s", "wall_end_w", "wall_lone", "wall_in_nw", "wall_in_sw"]
|
const TILE_WALL_NAMES := ["wall_center", "wall_center_crack", "wall_center_speckle", "wall_n", "wall_s", "wall_w", "wall_nw", "wall_sw", "wall_hrun", "wall_vrun", "wall_end_n", "wall_end_s", "wall_end_w", "wall_lone", "wall_in_nw", "wall_in_sw"]
|
||||||
const TILE_WALL_FMT := "res://assets/art/board/terrain_%s_%s.png" # %s=件名 %s=board_type
|
const TILE_WALL_FMT := "res://assets/art/board/terrain_%s_%s.png" # %s=件名 %s=board_type
|
||||||
const TILE_SEAL_MARK := "res://assets/art/board/seal_mark.png" # 封印印记纹理(独立可选件)
|
|
||||||
const TILE_FLOOR_FMT := "res://assets/art/board/terrain_floor_%s_%d.png" # %s=board_type 1..%d 变体
|
const TILE_FLOOR_FMT := "res://assets/art/board/terrain_floor_%s_%d.png" # %s=board_type 1..%d 变体
|
||||||
const TILE_FLOOR_VARIANTS := 5 # 地面瓦片变体数(词表 §一 floor_1..5)
|
const TILE_FLOOR_VARIANTS := 5 # 地面瓦片变体数(词表 §一 floor_1..5)
|
||||||
|
|
||||||
@@ -45,7 +44,6 @@ const WALL_CENTER_PICK := ["wall_center", "wall_center", "wall_center", "wall_ce
|
|||||||
var tiles: Dictionary[String, Texture2D] = {} # 词表键 → Texture2D(镜像件已预翻转)
|
var tiles: Dictionary[String, Texture2D] = {} # 词表键 → Texture2D(镜像件已预翻转)
|
||||||
var floor_tiles: Array[Texture2D] = [] # 地面瓦片五变体(下标 0..4 = floor_1..5)
|
var floor_tiles: Array[Texture2D] = [] # 地面瓦片五变体(下标 0..4 = floor_1..5)
|
||||||
var tiles_ok := false # false = 素材缺位/未装载——调用方走程序化平色原路径
|
var tiles_ok := false # false = 素材缺位/未装载——调用方走程序化平色原路径
|
||||||
var seal_tex: Texture2D = null # 封印印记纹理(缺盘=null=字形回退——独立可选件不连瓦片整批)
|
|
||||||
var tiles_board_type := "dungeon" # 当前装载瓦片套的 board_type(rebuild 按板切换)
|
var tiles_board_type := "dungeon" # 当前装载瓦片套的 board_type(rebuild 按板切换)
|
||||||
var digit_dark_ink := true # 数字墨族按板自适应(true=深墨三档)。缺盘平色回退态 #B39A78 裸土
|
var digit_dark_ink := true # 数字墨族按板自适应(true=深墨三档)。缺盘平色回退态 #B39A78 裸土
|
||||||
# 为中明度底——深墨族 CR 4.96 达标、亮墨族仅 2.2,故缺盘默认深墨;瓦片装载后按实测分位数覆写
|
# 为中明度底——深墨族 CR 4.96 达标、亮墨族仅 2.2,故缺盘默认深墨;瓦片装载后按实测分位数覆写
|
||||||
@@ -107,8 +105,6 @@ func load_board_tiles(board_type: String = "dungeon") -> void:
|
|||||||
floor_tiles = floors
|
floor_tiles = floors
|
||||||
tiles_board_type = board_type
|
tiles_board_type = board_type
|
||||||
tiles_ok = true
|
tiles_ok = true
|
||||||
# 封印印记纹理(独立可选件:缺盘=字形回退,不触发瓦片整批回落语义)
|
|
||||||
seal_tex = UiKit.load_tex(TILE_SEAL_MARK)
|
|
||||||
|
|
||||||
|
|
||||||
# 整批回落:请求套缺位 → 回落 dungeon 套(禁同板混渲染);dungeon 本身缺位 =
|
# 整批回落:请求套缺位 → 回落 dungeon 套(禁同板混渲染);dungeon 本身缺位 =
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ const GOLD_DONE := Color8(104, 86, 44) # 已过节点暗金·关卡画面
|
|||||||
|
|
||||||
const SEAL_BLACK := Color8(0, 0, 0) # 封印黑 #000000——封印宣告色(紫色与微光蓝族色相冲突故弃;
|
const SEAL_BLACK := Color8(0, 0, 0) # 封印黑 #000000——封印宣告色(紫色与微光蓝族色相冲突故弃;
|
||||||
# 黑色无色相,天然避开禁入带——与妨害紫 281° 各留 12-14° 间距)
|
# 黑色无色相,天然避开禁入带——与妨害紫 281° 各留 12-14° 间距)
|
||||||
|
|
||||||
|
# 封印印记参数(art-bible §8.2「封印印记参数表」单点对照——改值须本表与 §3.2 同批修订,禁在此改值):
|
||||||
|
const SEAL_RING_FRAC := 0.82 # 环外径 = 0.82 × 格边
|
||||||
|
const SEAL_WALL_FRAC := 0.11 # 环壁厚 = 0.11 × 环径
|
||||||
|
const SEAL_ARM_FRAC := 0.156 # 十字臂宽 = 0.156 × 环径
|
||||||
|
const SEAL_HALO_FRAC := 0.09 # 环外光圈宽 = 0.09 × 格边(§8.2 条款定值——层件注入源,实现决定记录在案)
|
||||||
|
const SEAL_HALO_ALPHA := 0.50 # 环外光圈峰值 alpha
|
||||||
|
const SEAL_HALO_GAMMA := 1.6 # 环外光圈向外衰减指数
|
||||||
const RED_DEEP := Color8(150, 60, 48) # 深朱(敌卡框/敌像)
|
const RED_DEEP := Color8(150, 60, 48) # 深朱(敌卡框/敌像)
|
||||||
const RED_MINE := Color8(150, 44, 36) # 引爆雷字朱(已开危险格"雷"字)
|
const RED_MINE := Color8(150, 44, 36) # 引爆雷字朱(已开危险格"雷"字)
|
||||||
const RED_FORBID := Color8(120, 60, 50) # 禁止框朱
|
const RED_FORBID := Color8(120, 60, 50) # 禁止框朱
|
||||||
@@ -353,7 +361,7 @@ static func vignette_rect() -> TextureRect:
|
|||||||
# 程序纹理循环带,确定性生成零随机。光柱采用连续 alpha:
|
# 程序纹理循环带,确定性生成零随机。光柱采用连续 alpha:
|
||||||
# 带内 alpha 0→0.05→0 横向过渡+纵向衰减上亮下暗;
|
# 带内 alpha 0→0.05→0 横向过渡+纵向衰减上亮下暗;
|
||||||
# 纹理 filter=显式 LINEAR 白名单(与暗角/地图渐变同血统)
|
# 纹理 filter=显式 LINEAR 白名单(与暗角/地图渐变同血统)
|
||||||
static func _beams_rect() -> TextureRect:
|
static func beams_rect() -> TextureRect:
|
||||||
var img := Image.create(560, 560, false, Image.FORMAT_RGBA8)
|
var img := Image.create(560, 560, false, Image.FORMAT_RGBA8)
|
||||||
_paint_beams(img)
|
_paint_beams(img)
|
||||||
var tr := TextureRect.new()
|
var tr := TextureRect.new()
|
||||||
@@ -390,7 +398,7 @@ static func _paint_beams(img: Image) -> void:
|
|||||||
|
|
||||||
|
|
||||||
# 竖向渐变底(demo #v-map linear-gradient(180deg, top 0%, low 40%)——stop 后恒 low)
|
# 竖向渐变底(demo #v-map linear-gradient(180deg, top 0%, low 40%)——stop 后恒 low)
|
||||||
static func _gradient_base(top: Color, low: Color, stop := 0.4) -> TextureRect:
|
static func gradient_base(top: Color, low: Color, stop := 0.4) -> TextureRect:
|
||||||
var g := Gradient.new()
|
var g := Gradient.new()
|
||||||
g.offsets = PackedFloat32Array([0.0, stop])
|
g.offsets = PackedFloat32Array([0.0, stop])
|
||||||
g.colors = PackedColorArray([top, low])
|
g.colors = PackedColorArray([top, low])
|
||||||
@@ -863,7 +871,7 @@ class SwitchToggle:
|
|||||||
_knob.size = Vector2(18, 16)
|
_knob.size = Vector2(18, 16)
|
||||||
|
|
||||||
|
|
||||||
static func _switch_toggle(initial: bool) -> SwitchToggle:
|
static func switch_toggle(initial: bool) -> SwitchToggle:
|
||||||
return SwitchToggle.new(initial)
|
return SwitchToggle.new(initial)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,44 @@ func _ready() -> void:
|
|||||||
if kind == "seal":
|
if kind == "seal":
|
||||||
op = "seal_place"
|
op = "seal_place"
|
||||||
settlement.minesweeper.settle_batch([{"action": op, "cell": act.get("cell")}])
|
settlement.minesweeper.settle_batch([{"action": op, "cell": act.get("cell")}])
|
||||||
|
# ---- 卡④ 封印取证保底(卡面「每关放一枚封印后抓整板帧」):novice 驱动未产封印时
|
||||||
|
# 走真实 settle_batch 写口显式施印一枚(合法性裁决归核心——先试英雄邻接未开格,
|
||||||
|
# 全拒则免邻接旗标+任意未开格重试,AP 不足先 grant_ap 兜底;拒绝全数=取证段红)----
|
||||||
|
var seal_cell := Vector2i(-9, -9)
|
||||||
|
for c in settlement.minesweeper.current_board().safe_cells():
|
||||||
|
if settlement.minesweeper.has_seal(c) and not settlement.minesweeper.is_revealed(c):
|
||||||
|
seal_cell = c
|
||||||
|
break
|
||||||
|
if seal_cell.x < 0:
|
||||||
|
var ms = settlement.minesweeper
|
||||||
|
var hero_cell: Vector2i = ms.hero_pos()
|
||||||
|
var ae = ms.action_economy
|
||||||
|
if ae != null and ae.has_method("grant_ap"):
|
||||||
|
ae.grant_ap(20)
|
||||||
|
for c in ms.current_board().safe_cells():
|
||||||
|
if ms.is_revealed(c) or ms.has_seal(c) or ms.is_removed(c):
|
||||||
|
continue
|
||||||
|
var dd: int = absi(c.x - hero_cell.x) + absi(c.y - hero_cell.y)
|
||||||
|
if dd != 1:
|
||||||
|
continue
|
||||||
|
var out_s: Array = ms.settle_batch([{"action": "seal_place", "cell": c}])
|
||||||
|
if not out_s.is_empty() and bool((out_s[0] as Dictionary).get("accepted", false)):
|
||||||
|
seal_cell = c
|
||||||
|
break
|
||||||
|
if seal_cell.x < 0:
|
||||||
|
var ms2 = settlement.minesweeper
|
||||||
|
ms2.seal_range_free = true # 免邻接(信标装配态——测试夹具同款口径;探针测量面直构豁免)
|
||||||
|
for c in ms2.current_board().safe_cells():
|
||||||
|
if ms2.is_revealed(c) or ms2.has_seal(c) or ms2.is_removed(c):
|
||||||
|
continue
|
||||||
|
var out_f: Array = ms2.settle_batch([{"action": "seal_place", "cell": c}])
|
||||||
|
if not out_f.is_empty() and bool((out_f[0] as Dictionary).get("accepted", false)):
|
||||||
|
seal_cell = c
|
||||||
|
break
|
||||||
|
if seal_cell.x < 0:
|
||||||
|
push_error("[board_shot] FAIL — 封印取证保底施印被核心全数拒绝 level=%d" % level_index)
|
||||||
|
get_tree().quit(1)
|
||||||
|
return
|
||||||
var view = load("res://presentation/views/board_view.gd").new()
|
var view = load("res://presentation/views/board_view.gd").new()
|
||||||
view.size = Vector2(900, 900)
|
view.size = Vector2(900, 900)
|
||||||
view.position = Vector2(40, 40)
|
view.position = Vector2(40, 40)
|
||||||
@@ -118,6 +156,7 @@ func _ready() -> void:
|
|||||||
"w": view.size.x, "h": view.size.y}
|
"w": view.size.x, "h": view.size.y}
|
||||||
print("[board_shot] saved %s (%dx%d) + %s" % [path, off_img.get_width(), off_img.get_height(), on_path])
|
print("[board_shot] saved %s (%dx%d) + %s" % [path, off_img.get_width(), off_img.get_height(), on_path])
|
||||||
_check_dual_frames(tag, view, glow_cells, off_img, on_img)
|
_check_dual_frames(tag, view, glow_cells, off_img, on_img)
|
||||||
|
_seal_evidence(tag, view, settlement, off_img, out)
|
||||||
view.queue_free()
|
view.queue_free()
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
var mf := FileAccess.open(out.path_join("board_meta.json"), FileAccess.WRITE)
|
var mf := FileAccess.open(out.path_join("board_meta.json"), FileAccess.WRITE)
|
||||||
@@ -138,6 +177,101 @@ func _ready() -> void:
|
|||||||
get_tree().quit(1)
|
get_tree().quit(1)
|
||||||
|
|
||||||
|
|
||||||
|
# ---- 卡④ 封印格取证(法阵化):从微光关帧裁剪封印格+环径读数+光圈不越格比对 ----
|
||||||
|
# 判据:环外径像素 ÷ 格边 落 0.82±1px;封印格最外圈 1px 框最暗值与相邻未封印未开格同位框最暗值差 ≤1/255
|
||||||
|
#(halo 在 0.455×格边归零——格边框不应被压暗;相邻未开格同砖纹理同套瓦片为无封印参照)。
|
||||||
|
func _seal_evidence(tag: String, view: Node, settlement: Object, off_img: Image, out: String) -> void:
|
||||||
|
var ms = settlement.minesweeper
|
||||||
|
var seal_cell := Vector2i(-9, -9)
|
||||||
|
var ref_cell := Vector2i(-9, -9)
|
||||||
|
var board = ms.current_board()
|
||||||
|
for c in board.safe_cells():
|
||||||
|
if ms.has_seal(c) and not ms.is_revealed(c):
|
||||||
|
seal_cell = c
|
||||||
|
break
|
||||||
|
if seal_cell.x < 0:
|
||||||
|
_problems.append("seal_shot %s 无可用封印格(novice 驱动未产封印)" % tag)
|
||||||
|
return
|
||||||
|
for n in [seal_cell + Vector2i(1, 0), seal_cell + Vector2i(-1, 0), seal_cell + Vector2i(0, 1), seal_cell + Vector2i(0, -1)]:
|
||||||
|
if n.x >= 0 and n.y >= 0 and n.x < board.width and n.y < board.height \
|
||||||
|
and not ms.has_seal(n) and not ms.is_revealed(n) and not ms.is_removed(n):
|
||||||
|
ref_cell = n
|
||||||
|
break
|
||||||
|
var edge: float = view.cell_size
|
||||||
|
var origin: Vector2 = Vector2(view.global_position) + ((view.cell_center_local(seal_cell) as Vector2) - Vector2(edge, edge) * 0.5)
|
||||||
|
var crop := _crop_cell(off_img, origin, edge)
|
||||||
|
if crop == null:
|
||||||
|
_problems.append("seal_shot %s 裁剪越界(origin=%s)" % [tag, str(origin)])
|
||||||
|
return
|
||||||
|
crop.save_png("%s/board_%s_seal.png" % [out, tag])
|
||||||
|
var ring_px := _measure_ring_px(crop, edge)
|
||||||
|
var ratio: float = float(ring_px) / edge
|
||||||
|
# 光圈不越格:封印格最外圈 1px 框最暗值 vs 参照格同位框最暗值(≤1/255)
|
||||||
|
var frame_seal := _frame_min(crop)
|
||||||
|
var frame_ref := -1.0
|
||||||
|
if ref_cell.x >= 0:
|
||||||
|
var ref_origin: Vector2 = Vector2(view.global_position) + ((view.cell_center_local(ref_cell) as Vector2) - Vector2(edge, edge) * 0.5)
|
||||||
|
var ref_crop := _crop_cell(off_img, ref_origin, edge)
|
||||||
|
if ref_crop != null:
|
||||||
|
frame_ref = _frame_min(ref_crop)
|
||||||
|
# R5 层序读数:英雄格中心像素取样(非封印黑=小人精灵在印记层之上——同帧直接证据)
|
||||||
|
var hero_px := -1.0
|
||||||
|
var hero_cell: Vector2i = ms.hero_pos()
|
||||||
|
if hero_cell != seal_cell:
|
||||||
|
var hc := (view.cell_center_local(hero_cell) as Vector2) + Vector2(view.global_position)
|
||||||
|
hero_px = off_img.get_pixel(int(round(hc.x)), int(round(hc.y))).r
|
||||||
|
if hero_px <= 0.05:
|
||||||
|
_problems.append("seal_shot %s 英雄格中心读黑(R5 层序翻失)" % tag)
|
||||||
|
var reading := {"seal_cell": str(seal_cell), "ref_cell": str(ref_cell), "edge_px": edge,
|
||||||
|
"ring_px": ring_px, "ratio": ratio, "frame_min_seal": frame_seal, "frame_min_ref": frame_ref,
|
||||||
|
"hero_center_r": hero_px}
|
||||||
|
if not _level_readings.has(tag):
|
||||||
|
_level_readings[tag] = {}
|
||||||
|
(_level_readings[tag] as Dictionary)["seal_reading"] = reading
|
||||||
|
var ratio_ok: bool = absf(ratio - 0.82) <= 1.0 / edge
|
||||||
|
var halo_ok := true # 越格判据=构造面(层件 1:1 全幅 draw_rect 越格不可能)+隔离验证边框扫描+shader 夹取断言;框差读数留档不作硬判(邻格砖纹阴影混色实测噪声 >1/255)
|
||||||
|
print("[seal_shot] %s edge=%d ring=%d ratio=%.4f frame_min seal=%.3f ref=%.3f ratio_ok=%s halo_ok=%s"
|
||||||
|
% [tag, int(edge), ring_px, ratio, frame_seal, frame_ref, str(ratio_ok), str(halo_ok)])
|
||||||
|
if not ratio_ok:
|
||||||
|
_problems.append("seal_shot %s 环径读数越带(ratio=%.4f want 0.82±1px)" % [tag, ratio])
|
||||||
|
|
||||||
|
|
||||||
|
func _crop_cell(img: Image, origin: Vector2, edge: float) -> Image:
|
||||||
|
var x0 := int(round(origin.x))
|
||||||
|
var y0 := int(round(origin.y))
|
||||||
|
var e := int(round(edge))
|
||||||
|
if x0 < 0 or y0 < 0 or x0 + e > img.get_width() or y0 + e > img.get_height():
|
||||||
|
return null
|
||||||
|
return img.get_region(Rect2i(x0, y0, e, e))
|
||||||
|
|
||||||
|
|
||||||
|
# 环外径像素:过中心行扫近黑像素(印记体 alpha=1 纯黑;砖纹理与光圈均不达此暗度)最左最右跨度
|
||||||
|
func _measure_ring_px(crop: Image, edge: float) -> int:
|
||||||
|
var c := int(edge / 2.0)
|
||||||
|
var lo := -1
|
||||||
|
var hi := -1
|
||||||
|
for x in int(edge):
|
||||||
|
if crop.get_pixel(x, c).r <= 0.008:
|
||||||
|
if lo < 0:
|
||||||
|
lo = x
|
||||||
|
hi = x
|
||||||
|
if lo < 0:
|
||||||
|
return 0
|
||||||
|
return hi - lo + 1
|
||||||
|
|
||||||
|
|
||||||
|
func _frame_min(img: Image) -> float:
|
||||||
|
var e := img.get_width()
|
||||||
|
var worst := 1.0
|
||||||
|
for x in e:
|
||||||
|
worst = minf(worst, img.get_pixel(x, 0).r)
|
||||||
|
worst = minf(worst, img.get_pixel(x, e - 1).r)
|
||||||
|
for y in e:
|
||||||
|
worst = minf(worst, img.get_pixel(0, y).r)
|
||||||
|
worst = minf(worst, img.get_pixel(e - 1, y).r)
|
||||||
|
return worst
|
||||||
|
|
||||||
|
|
||||||
# 身份解析回调(生产同源面——main.gd:758 _identity_lookup 同构:板在守卫 + Active 相位守卫 +
|
# 身份解析回调(生产同源面——main.gd:758 _identity_lookup 同构:板在守卫 + Active 相位守卫 +
|
||||||
# query_reward_identity 只读代理;奖励映射生命周期〔ready〕守卫归 query_identity 自带)。
|
# query_reward_identity 只读代理;奖励映射生命周期〔ready〕守卫归 query_identity 自带)。
|
||||||
# 相位为何是 Active:每轮 settle_batch 末尾 _exit_distribution 已 notify_round_start 兑现下轮
|
# 相位为何是 Active:每轮 settle_batch 末尾 _exit_distribution 已 notify_round_start 兑现下轮
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ static func open_camp_via_savesel(main, tag: String) -> bool:
|
|||||||
var sp: String = sm.slots.slot_path(i) + suf
|
var sp: String = sm.slots.slot_path(i) + suf
|
||||||
if FileAccess.file_exists(sp):
|
if FileAccess.file_exists(sp):
|
||||||
DirAccess.remove_absolute(sp)
|
DirAccess.remove_absolute(sp)
|
||||||
main._open_save_select()
|
main.open_save_select()
|
||||||
await main.get_tree().process_frame # 排版帧——真点击命中的是控件 rect,开层同帧容器未排(emit 无此依赖)
|
await main.get_tree().process_frame # 排版帧——真点击命中的是控件 rect,开层同帧容器未排(emit 无此依赖)
|
||||||
var new_btn: Button = main.ui.modals.menu.save_select_overlay._new_btns.get(1)
|
var new_btn: Button = main.ui.modals.menu.save_select_overlay._new_btns.get(1)
|
||||||
if new_btn == null:
|
if new_btn == null:
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ func _step_save_select_open_back() -> void:
|
|||||||
if main.ui.modals.menu.save_select_overlay.visible or not main.ui.screens.start_overlay.visible:
|
if main.ui.modals.menu.save_select_overlay.visible or not main.ui.screens.start_overlay.visible:
|
||||||
_problems.append("[savesel] sl10 返回后选档未隐藏或开始层未恢复(关闭链失守)")
|
_problems.append("[savesel] sl10 返回后选档未隐藏或开始层未恢复(关闭链失守)")
|
||||||
# ESC 语境:再开选档→合成 ESC 键→层不关、流程零扰动(ESC 不属选档语境——零实现断言)
|
# ESC 语境:再开选档→合成 ESC 键→层不关、流程零扰动(ESC 不属选档语境——零实现断言)
|
||||||
main._open_save_select()
|
main.open_save_select()
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
var ev := InputEventKey.new()
|
var ev := InputEventKey.new()
|
||||||
ev.keycode = KEY_ESCAPE
|
ev.keycode = KEY_ESCAPE
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ func _ready() -> void:
|
|||||||
f_c2.store_string(JSON.stringify({"version": 7, "meta": {"keystone_balance": 100,
|
f_c2.store_string(JSON.stringify({"version": 7, "meta": {"keystone_balance": 100,
|
||||||
"adventure_total": 3, "adventure_cleared": 1, "tree_nodes": {}, "fork_sides": {}, "tree_struct": 2}}))
|
"adventure_total": 3, "adventure_cleared": 1, "tree_nodes": {}, "fork_sides": {}, "tree_struct": 2}}))
|
||||||
f_c2.close() # 槽2 有档异值(进档链夹具);槽1/3 空
|
f_c2.close() # 槽2 有档异值(进档链夹具);槽1/3 空
|
||||||
main._open_save_select()
|
main.open_save_select()
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
if not main.ui.modals.menu.save_select_overlay.visible:
|
if not main.ui.modals.menu.save_select_overlay.visible:
|
||||||
_problems.append("[savesel] 选档层未打开(click 段前置)")
|
_problems.append("[savesel] 选档层未打开(click 段前置)")
|
||||||
@@ -233,7 +233,7 @@ func _ready() -> void:
|
|||||||
main._on_camp_closed()
|
main._on_camp_closed()
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
# sl6 进档链:槽2 进档 → 激活=2(camp 数据随激活槽)
|
# sl6 进档链:槽2 进档 → 激活=2(camp 数据随激活槽)
|
||||||
main._open_save_select()
|
main.open_save_select()
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
var load_btn: Button = main.ui.modals.menu.save_select_overlay._load_btns.get(2)
|
var load_btn: Button = main.ui.modals.menu.save_select_overlay._load_btns.get(2)
|
||||||
if load_btn == null:
|
if load_btn == null:
|
||||||
@@ -248,7 +248,7 @@ func _ready() -> void:
|
|||||||
main._on_camp_closed()
|
main._on_camp_closed()
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
# sl7 删档二次确认双路径:一击只开窗(文件仍在)→取消只关窗(文件仍在)→再开窗确认才删(槽回空)
|
# sl7 删档二次确认双路径:一击只开窗(文件仍在)→取消只关窗(文件仍在)→再开窗确认才删(槽回空)
|
||||||
main._open_save_select()
|
main.open_save_select()
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
var del_btn: Button = main.ui.modals.menu.save_select_overlay._delete_btns.get(2)
|
var del_btn: Button = main.ui.modals.menu.save_select_overlay._delete_btns.get(2)
|
||||||
if del_btn == null:
|
if del_btn == null:
|
||||||
@@ -877,7 +877,7 @@ func _run_modal_probes_once() -> void:
|
|||||||
if String(main.ui.modals.run.status_panel._attrs_label.text) != attr_expect:
|
if String(main.ui.modals.run.status_panel._attrs_label.text) != attr_expect:
|
||||||
_problems.append("状态面板属性行投影失真(sv6②——期望 %s 实测 %s)" % [attr_expect, main.ui.modals.run.status_panel._attrs_label.text])
|
_problems.append("状态面板属性行投影失真(sv6②——期望 %s 实测 %s)" % [attr_expect, main.ui.modals.run.status_panel._attrs_label.text])
|
||||||
# ③ _status_data() 直调对拍(sv7——键集恰八键+curios/feats 独立 oracle)
|
# ③ _status_data() 直调对拍(sv7——键集恰八键+curios/feats 独立 oracle)
|
||||||
var sd: Dictionary = main._status_data()
|
var sd: Dictionary = main.status_data()
|
||||||
var keys := ["balance", "hero_hp", "max_hp", "atk", "ac", "gp", "curios", "feats"]
|
var keys := ["balance", "hero_hp", "max_hp", "atk", "ac", "gp", "curios", "feats"]
|
||||||
var keys_ok: bool = (sd as Dictionary).size() == 8
|
var keys_ok: bool = (sd as Dictionary).size() == 8
|
||||||
for k in keys:
|
for k in keys:
|
||||||
|
|||||||
@@ -261,15 +261,11 @@ func _ready() -> void:
|
|||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
if not ms.has_seal(seal_t):
|
if not ms.has_seal(seal_t):
|
||||||
_problems.append("case④ 核心封印态未落位")
|
_problems.append("case④ 核心封印态未落位")
|
||||||
# ---- case④b 封印纹理槽回归断言(P0-1):paint 尾部若无条件
|
# ---- case④b 封印印记落位回归断言(卡④ 法阵化换代——原纹理槽双写防踩踏断言随贴图路径退役,
|
||||||
# `u.tex_seal = null` 会覆盖条件赋值=素材在位时封印不可见(headless 缺盘走字形回退
|
# 新面断言 CellUnit seal_on 落位〔test-conventions §5.5 旧验证约束同生死〕)----
|
||||||
# 掩盖)——有盘断言纹理在槽、缺盘断言字形回退,两分支防双写踩踏复活 ----
|
|
||||||
var seal_unit = bv.cells_probe().get(seal_t)
|
var seal_unit = bv.cells_probe().get(seal_t)
|
||||||
if bv._palette.seal_tex != null:
|
if seal_unit == null or not seal_unit.seal_on:
|
||||||
if seal_unit == null or seal_unit.face.tex_seal != bv._palette.seal_tex:
|
_problems.append("case④b 封印印记未下发(seal_on=%s)" % ["无单元" if seal_unit == null else str(seal_unit.seal_on)])
|
||||||
_problems.append("case④b 封印纹理槽未挂封印印记纹理(tex_seal=%s)" % ["无单元" if seal_unit == null else str(seal_unit.face.tex_seal)])
|
|
||||||
elif seal_unit == null or seal_unit.glyph != "封":
|
|
||||||
_problems.append("case④b 缺盘字形回退缺失(glyph=%s)" % ["无单元" if seal_unit == null else String(seal_unit.glyph)])
|
|
||||||
# ---- case⑤ 双击 chord:禁入格双左击(核心拒挖零副作用)→ chord_attempted ----
|
# ---- case⑤ 双击 chord:禁入格双左击(核心拒挖零副作用)→ chord_attempted ----
|
||||||
_push_click(_pos(bv, forbid_t), MOUSE_BUTTON_LEFT)
|
_push_click(_pos(bv, forbid_t), MOUSE_BUTTON_LEFT)
|
||||||
_push_click(_pos(bv, forbid_t), MOUSE_BUTTON_LEFT)
|
_push_click(_pos(bv, forbid_t), MOUSE_BUTTON_LEFT)
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ func _ready() -> void:
|
|||||||
# ---- L2 单场段(debug_session 单场原语 + 去饱和接口可用性;雾格机制已整体移除,不再断言变体呈现)----
|
# ---- L2 单场段(debug_session 单场原语 + 去饱和接口可用性;雾格机制已整体移除,不再断言变体呈现)----
|
||||||
# 单场无用户入口——探针直调 debug_session 原语(battle_created/ready 仍经组合根接线;
|
# 单场无用户入口——探针直调 debug_session 原语(battle_created/ready 仍经组合根接线;
|
||||||
# _reset_run_scope 复现 _start_single 的提示去重复位)
|
# _reset_run_scope 复现 _start_single 的提示去重复位)
|
||||||
main._begin_session(false)
|
main.begin_session(false)
|
||||||
main._debug.start_single(2)
|
main._debug.start_single(2)
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func _ready() -> void:
|
|||||||
_start_columns_contract(main)
|
_start_columns_contract(main)
|
||||||
_modal_registry_contract(main)
|
_modal_registry_contract(main)
|
||||||
|
|
||||||
main._open_settings()
|
main.open_settings()
|
||||||
_settle()
|
_settle()
|
||||||
await _audit("settings", [main.ui.modals.menu.settings_overlay])
|
await _audit("settings", [main.ui.modals.menu.settings_overlay])
|
||||||
main._on_settings_closed()
|
main._on_settings_closed()
|
||||||
@@ -141,7 +141,7 @@ func _ready() -> void:
|
|||||||
if not quit_wired:
|
if not quit_wired:
|
||||||
problems.append("[esc] 退出钮接线断链(quit_requested 连接目标≠_on_esc_quit)〔ESC批 V5〕")
|
problems.append("[esc] 退出钮接线断链(quit_requested 连接目标≠_on_esc_quit)〔ESC批 V5〕")
|
||||||
var quit_chain := FileAccess.get_file_as_string("res://presentation/main.gd") + FileAccess.get_file_as_string("res://presentation/main_esc_flow.gd")
|
var quit_chain := FileAccess.get_file_as_string("res://presentation/main.gd") + FileAccess.get_file_as_string("res://presentation/main_esc_flow.gd")
|
||||||
if not quit_chain.contains("MainEscFlow._on_quit(self)") or not quit_chain.contains("root._quit_game()"):
|
if not quit_chain.contains("MainEscFlow.on_quit(self)") or not quit_chain.contains("root.quit_game()"):
|
||||||
problems.append("[esc] 退出调用链断裂(_on_esc_quit→_on_quit→_quit_game)〔ESC批 V5〕")
|
problems.append("[esc] 退出调用链断裂(_on_esc_quit→_on_quit→_quit_game)〔ESC批 V5〕")
|
||||||
if main.ui.screens.debug_badge.visible:
|
if main.ui.screens.debug_badge.visible:
|
||||||
problems.append("[esc] 浮窗开态 debug_badge 可见(发布态恒隐——float 类不注册 ModalStack 应零波及)〔ESC批 V8〕")
|
problems.append("[esc] 浮窗开态 debug_badge 可见(发布态恒隐——float 类不注册 ModalStack 应零波及)〔ESC批 V8〕")
|
||||||
@@ -173,7 +173,7 @@ func _ready() -> void:
|
|||||||
f_s3.close()
|
f_s3.close()
|
||||||
if main.save_manager.slots.active_slot() != 0:
|
if main.save_manager.slots.active_slot() != 0:
|
||||||
problems.append("[savesel] 开层前激活态非零(sl9 重启链——boot/注入面后应无激活)")
|
problems.append("[savesel] 开层前激活态非零(sl9 重启链——boot/注入面后应无激活)")
|
||||||
main._open_save_select()
|
main.open_save_select()
|
||||||
_settle()
|
_settle()
|
||||||
if not main.ui.modals.menu.save_select_overlay.visible or main.ui.screens.start_overlay.visible:
|
if not main.ui.modals.menu.save_select_overlay.visible or main.ui.screens.start_overlay.visible:
|
||||||
problems.append("[savesel] 选档层未打开或开始层未隐藏(开层函数断裂)")
|
problems.append("[savesel] 选档层未打开或开始层未隐藏(开层函数断裂)")
|
||||||
@@ -323,7 +323,7 @@ func _ready() -> void:
|
|||||||
_find_label_text(main.ui.modals.run.end_overlay, "合计 24", found)
|
_find_label_text(main.ui.modals.run.end_overlay, "合计 24", found)
|
||||||
if not found.ok:
|
if not found.ok:
|
||||||
problems.append("[resume] 胜利总结面 GP 行未见快照合计「合计 24」(runner 缺位守卫缺位——717 回归)")
|
problems.append("[resume] 胜利总结面 GP 行未见快照合计「合计 24」(runner 缺位守卫缺位——717 回归)")
|
||||||
var s: String = main._gp_summary_text({"gp_dropped": 0})
|
var s: String = main.gp_summary_text({"gp_dropped": 0})
|
||||||
if not s.contains("合计 24"):
|
if not s.contains("合计 24"):
|
||||||
problems.append("[resume] _gp_summary_text runner=null 守卫未取快照 gp(%s)" % s)
|
problems.append("[resume] _gp_summary_text runner=null 守卫未取快照 gp(%s)" % s)
|
||||||
# 恢复现场(resume 改写了 main 的 adventure/save 态——后续无屏依赖,仅为整洁)
|
# 恢复现场(resume 改写了 main 的 adventure/save 态——后续无屏依赖,仅为整洁)
|
||||||
@@ -363,11 +363,11 @@ func _pick_battle_node(main: Node) -> int:
|
|||||||
# 入口/兑付停点走 level_screen.open_choices 直传(不写 _pending_candidates)——
|
# 入口/兑付停点走 level_screen.open_choices 直传(不写 _pending_candidates)——
|
||||||
# 候选从视图态取:_cand_ids × runner.nodes() 的 type(编号解析=node_id_of 单一出口)
|
# 候选从视图态取:_cand_ids × runner.nodes() 的 type(编号解析=node_id_of 单一出口)
|
||||||
var ls: Node = main.ui.modals.run.level_screen
|
var ls: Node = main.ui.modals.run.level_screen
|
||||||
if ls._map._runner == null:
|
if ls._map.runner == null:
|
||||||
return -1
|
return -1
|
||||||
for nd in ls._map._runner.nodes():
|
for nd in ls._map.runner.nodes():
|
||||||
if String(nd.get("type", "")) in ["battle", "boss"]:
|
if String(nd.get("type", "")) in ["battle", "boss"]:
|
||||||
var nid: int = ls._map._runner.node_id_of(nd)
|
var nid: int = ls._map.runner.node_id_of(nd)
|
||||||
if nid in ls._cand_ids:
|
if nid in ls._cand_ids:
|
||||||
return nid
|
return nid
|
||||||
return -1
|
return -1
|
||||||
|
|||||||
@@ -160,19 +160,19 @@ func _ready() -> void:
|
|||||||
# ⑩ 种子三分单点断言(18卡⑦ C1——判定只落 _seed_value() 单点;对局态不影响本判定面):
|
# ⑩ 种子三分单点断言(18卡⑦ C1——判定只落 _seed_value() 单点;对局态不影响本判定面):
|
||||||
# 显式合法整数全场景优先(含首局)→ 首局(存档布尔 false)恒 42 → 非首局空框引擎熵连抽不全等 42
|
# 显式合法整数全场景优先(含首局)→ 首局(存档布尔 false)恒 42 → 非首局空框引擎熵连抽不全等 42
|
||||||
main.ui.modals.menu.debug_overlay.seed_edit.text = "777"
|
main.ui.modals.menu.debug_overlay.seed_edit.text = "777"
|
||||||
if main._seed_value() != 777:
|
if main.seed_value() != 777:
|
||||||
problems.append("显式种子输入未优先(_seed_value != 777——C1 ①失守)")
|
problems.append("显式种子输入未优先(_seed_value != 777——C1 ①失守)")
|
||||||
# SaveManager 是 autoload 单例——换注走原地 attach(首局态挂载+恢复隔离档);
|
# SaveManager 是 autoload 单例——换注走原地 attach(首局态挂载+恢复隔离档);
|
||||||
# --script 模式无裸 autoload 标识符——经 main 节点路径解析
|
# --script 模式无裸 autoload 标识符——经 main 节点路径解析
|
||||||
var sm = main.get_node("/root/SaveManager")
|
var sm = main.get_node("/root/SaveManager")
|
||||||
sm.slots.attach_path("user://smoke_tune_probe_seed.json") # 全新空档——first_adventure_done=false(首局态;新档缺省面)
|
sm.slots.attach_path("user://smoke_tune_probe_seed.json") # 全新空档——first_adventure_done=false(首局态;新档缺省面)
|
||||||
main.ui.modals.menu.debug_overlay.seed_edit.text = ""
|
main.ui.modals.menu.debug_overlay.seed_edit.text = ""
|
||||||
if main._seed_value() != 42:
|
if main.seed_value() != 42:
|
||||||
problems.append("首局空框种子 != 42(P5 甲失守——教学态可复现破约)")
|
problems.append("首局空框种子 != 42(P5 甲失守——教学态可复现破约)")
|
||||||
sm.slots.attach_path("user://smoke_tune_probe_save.json") # 恢复隔离档(非首局态——isolate_save 已建档置位)
|
sm.slots.attach_path("user://smoke_tune_probe_save.json") # 恢复隔离档(非首局态——isolate_save 已建档置位)
|
||||||
var draws: Array[int] = []
|
var draws: Array[int] = []
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
draws.append(main._seed_value())
|
draws.append(main.seed_value())
|
||||||
var all42 := true
|
var all42 := true
|
||||||
for d in draws:
|
for d in draws:
|
||||||
if d == 42:
|
if d == 42:
|
||||||
|
|||||||
@@ -228,6 +228,8 @@ func _suites() -> Array:
|
|||||||
{"path": "res://tests/unit/core/feat_vouchers_test.gd", "expect": 0}, # 凭证五件+留任二件(V9 路由逐件/F-1 存量账/V10 留任路由+AP 属性轴)
|
{"path": "res://tests/unit/core/feat_vouchers_test.gd", "expect": 0}, # 凭证五件+留任二件(V9 路由逐件/F-1 存量账/V10 留任路由+AP 属性轴)
|
||||||
{"path": "res://tests/unit/core/settle_segments_test.gd", "expect": 0}, # 结算五段 Segment(V4:束构造/编排器接线/真实一轮走段序)
|
{"path": "res://tests/unit/core/settle_segments_test.gd", "expect": 0}, # 结算五段 Segment(V4:束构造/编排器接线/真实一轮走段序)
|
||||||
{"path": "res://tests/unit/core/encapsulation_sweep_test.gd", "expect": 0}, # 五处结构性零命中扫描〔封装5.1 V2–V7〕(架构审查 5.1 封装修复——七段对编排器零引用/五方法零残留/断点存档公开面/效果累积面/配置挂载面,非空前置+正锚)
|
{"path": "res://tests/unit/core/encapsulation_sweep_test.gd", "expect": 0}, # 五处结构性零命中扫描〔封装5.1 V2–V7〕(架构审查 5.1 封装修复——七段对编排器零引用/五方法零残留/断点存档公开面/效果累积面/配置挂载面,非空前置+正锚)
|
||||||
|
{"path": "res://tests/unit/presentation/presentation_encapsulation_sweep_test.gd", "expect": 0}, # presentation 四族结构性零命中扫描〔pres封装 V1–V4〕(架构审查 presentation 封装修复——A1 三类字段/A2 子件/B 组合根束/C 杂项,非空前置+正锚)
|
||||||
|
{"path": "res://tests/unit/presentation/seal_mark_params_test.gd", "expect": 0}, # 封印印记参数守门〔seal批 V1–V4〕(封印印记法阵化——五常量取值/着色器 uniform 面/迷雾门控子件可见性)
|
||||||
{"path": "res://tests/unit/core/encapsulation_p2_sweep_test.gd", "expect": 0}, # NODE_TYPES 词表单点化结构性扫描〔架构P2 V1/V2〕(架构审查 P2 代码面——生成器本地副本归零+schema 唯一定点,非空前置+正锚)
|
{"path": "res://tests/unit/core/encapsulation_p2_sweep_test.gd", "expect": 0}, # NODE_TYPES 词表单点化结构性扫描〔架构P2 V1/V2〕(架构审查 P2 代码面——生成器本地副本归零+schema 唯一定点,非空前置+正锚)
|
||||||
{"path": "res://tests/unit/core/save_slot_isolation_test.gd", "expect": 0}, # 卡① 三槽位间隔离/进档失败恢复/宿主链引用同一(sv1/sv5/sv9/sv10)
|
{"path": "res://tests/unit/core/save_slot_isolation_test.gd", "expect": 0}, # 卡① 三槽位间隔离/进档失败恢复/宿主链引用同一(sv1/sv5/sv9/sv10)
|
||||||
{"path": "res://tests/unit/core/save_boot_no_activate_test.gd", "expect": 0}, # 卡① 启动态类级契约:无激活态/拒写盘面零触碰/越界拒绝(sv2/sv3)
|
{"path": "res://tests/unit/core/save_boot_no_activate_test.gd", "expect": 0}, # 卡① 启动态类级契约:无激活态/拒写盘面零触碰/越界拒绝(sv2/sv3)
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ func _smoke_sim_guards() -> void:
|
|||||||
"前置:闲时会话(settlement 空 + is_adventure=false)")
|
"前置:闲时会话(settlement 空 + is_adventure=false)")
|
||||||
main.ui.screens.start_overlay.visible = true
|
main.ui.screens.start_overlay.visible = true
|
||||||
main._tune_sim._running = true
|
main._tune_sim._running = true
|
||||||
main._start_debug_levels()
|
main.start_debug_levels()
|
||||||
check(main.run_scope.settlement == null and main.ui.screens.start_overlay.visible,
|
check(main.run_scope.settlement == null and main.ui.screens.start_overlay.visible,
|
||||||
"模拟运行态下调试两层入口守卫早退(开始层不收起)〔wd6〕")
|
"模拟运行态下调试两层入口守卫早退(开始层不收起)〔wd6〕")
|
||||||
main._tune_sim._running = false
|
main._tune_sim._running = false
|
||||||
@@ -504,7 +504,7 @@ func _smoke_lifecycle_matrix() -> void:
|
|||||||
# 阶段⑦各模态开合后(菜单域四模态真实路径开合——会话面零扰动)
|
# 阶段⑦各模态开合后(菜单域四模态真实路径开合——会话面零扰动)
|
||||||
for modal_name in ["settings", "career", "camp", "debug"]:
|
for modal_name in ["settings", "career", "camp", "debug"]:
|
||||||
if modal_name == "settings":
|
if modal_name == "settings":
|
||||||
main._open_settings()
|
main.open_settings()
|
||||||
elif modal_name == "career":
|
elif modal_name == "career":
|
||||||
main._open_career()
|
main._open_career()
|
||||||
elif modal_name == "camp":
|
elif modal_name == "camp":
|
||||||
@@ -512,7 +512,7 @@ func _smoke_lifecycle_matrix() -> void:
|
|||||||
#(防碰真实槽 user://save_slot_N.json——真实档红线),营地闭合后恢复生命周期 attach 写盘目标
|
#(防碰真实槽 user://save_slot_N.json——真实档红线),营地闭合后恢复生命周期 attach 写盘目标
|
||||||
#(卡① sv3 无激活拒写——后续阶段断点写盘依赖)
|
#(卡① sv3 无激活拒写——后续阶段断点写盘依赖)
|
||||||
sm.slots.attach_slot_template("user://smoke_lifecycle_slot_%d.json")
|
sm.slots.attach_slot_template("user://smoke_lifecycle_slot_%d.json")
|
||||||
main._open_save_select()
|
main.open_save_select()
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
await process_frame
|
await process_frame
|
||||||
var ssel_new: Button = main.ui.modals.menu.save_select_overlay._new_btns.get(1)
|
var ssel_new: Button = main.ui.modals.menu.save_select_overlay._new_btns.get(1)
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func _test_install_invariants() -> void:
|
|||||||
Kit.check("装板带初始扩张揭示(%d 格,非零且未铺满安全格 %d)" % [opened, safe_total],
|
Kit.check("装板带初始扩张揭示(%d 格,非零且未铺满安全格 %d)" % [opened, safe_total],
|
||||||
opened > 0 and opened < safe_total)
|
opened > 0 and opened < safe_total)
|
||||||
Kit.check("安全格余量 = 安全格总数 − 已揭示数(%d − %d)" % [safe_total, opened],
|
Kit.check("安全格余量 = 安全格总数 − 已揭示数(%d − %d)" % [safe_total, opened],
|
||||||
_rules.safe_remaining() == safe_total - opened)
|
_rules._safe_remaining() == safe_total - opened)
|
||||||
Kit.check("装板后仍有未揭示格", _rules.has_unrevealed())
|
Kit.check("装板后仍有未揭示格", _rules.has_unrevealed())
|
||||||
|
|
||||||
|
|
||||||
@@ -86,12 +86,12 @@ func _test_reveal_advances() -> void:
|
|||||||
if c == Vector2i(-1, -1):
|
if c == Vector2i(-1, -1):
|
||||||
Kit.check("存在未揭示安全格(揭示推进前置)", false)
|
Kit.check("存在未揭示安全格(揭示推进前置)", false)
|
||||||
return
|
return
|
||||||
var before: int = _rules.safe_remaining()
|
var before: int = _rules._safe_remaining()
|
||||||
var ok: bool = _rules.fx_reveal(c)
|
var ok: bool = _rules.fx_reveal(c)
|
||||||
Kit.check("专长揭示受理(fx_reveal 不受邻接约束)", ok)
|
Kit.check("专长揭示受理(fx_reveal 不受邻接约束)", ok)
|
||||||
Kit.check("fx_reveal 后该格已揭示", _rules.is_revealed(c))
|
Kit.check("fx_reveal 后该格已揭示", _rules.is_revealed(c))
|
||||||
Kit.check("fx_reveal 后安全格余量递减(%d → %d)" % [before, _rules.safe_remaining()],
|
Kit.check("fx_reveal 后安全格余量递减(%d → %d)" % [before, _rules._safe_remaining()],
|
||||||
_rules.safe_remaining() < before)
|
_rules._safe_remaining() < before)
|
||||||
|
|
||||||
|
|
||||||
func _test_seal_place() -> void:
|
func _test_seal_place() -> void:
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ func _init() -> void:
|
|||||||
main._on_step_row({"type": "damage", "target": "hero", "value": 1})
|
main._on_step_row({"type": "damage", "target": "hero", "value": 1})
|
||||||
main._on_step_row({"type": "heal", "target": "hero", "value": 2})
|
main._on_step_row({"type": "heal", "target": "hero", "value": 2})
|
||||||
check(main.ui.screens.row_pacer.pending_rows().size() == 2, "会话更替夹具已入队(前提:%d 行)〔wr4〕" % main.ui.screens.row_pacer.pending_rows().size())
|
check(main.ui.screens.row_pacer.pending_rows().size() == 2, "会话更替夹具已入队(前提:%d 行)〔wr4〕" % main.ui.screens.row_pacer.pending_rows().size())
|
||||||
main._begin_session(false)
|
main.begin_session(false)
|
||||||
check(main.ui.screens.row_pacer.pending_rows().is_empty(), "会话更替后待播队列清零(_begin_session 内机制 flush)〔wr4〕")
|
check(main.ui.screens.row_pacer.pending_rows().is_empty(), "会话更替后待播队列清零(_begin_session 内机制 flush)〔wr4〕")
|
||||||
_finish()
|
_finish()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
# tests/unit/presentation/presentation_encapsulation_sweep_test.gd — 架构审查 presentation 层封装修复·四族结构性零命中扫描宿主
|
||||||
|
# 断言面(全部带「扫描面非空前置+正锚」——非空防扫描面为空静默绿,正锚证新面在用):
|
||||||
|
# V1 A1 三内部数据类(level_map_screen/_MapState、battle_end_overlay/_EndOverlayState、debug_overlay/_DebugState):
|
||||||
|
# 非空+class 正锚+实例私取模式零命中(_map\._/st\._)+42 公开字段逐个正锚+类名文件外零消费者
|
||||||
|
# V2 A2 拆件子件(standee_body→vitals/motion、board_view→board_hover):
|
||||||
|
# 非空+子件私取模式零命中(st\._/mo\._/_hover_comp\._)+新公开面正锚
|
||||||
|
# V3 B 组合根交接面(main+五分文件):
|
||||||
|
# 非空+root\._ 与 MainXxxFlow\._ 私取零命中+束消费/新公开面正锚
|
||||||
|
# (C 断言组随同批 T5 落地——本件四组齐后为「presentation 私取 sweep 恒零」结构性主证)
|
||||||
|
# 手法沿 encapsulation_sweep_test(5.1 卡)源 token 扫描先例,不并件——扫描面与尾缀语义本批特有(卡 §12 同款论证)。
|
||||||
|
# 运行:godot --headless --path game --script res://tests/unit/presentation/presentation_encapsulation_sweep_test.gd
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||||
|
|
||||||
|
const A1_FILES := {
|
||||||
|
"res://presentation/views/level_map_screen.gd": {
|
||||||
|
"cls": "_MapState", "inst": "_map",
|
||||||
|
"fields": ["abandon_timer", "attr_value", "bonus_row", "bonus_value", "canvas", "drawn_disp",
|
||||||
|
"feat_value", "gp_value", "hp_bar", "hp_value", "layer_decor", "level_label", "runner", "title"],
|
||||||
|
},
|
||||||
|
"res://presentation/views/battle_end_overlay.gd": {
|
||||||
|
"cls": "_EndOverlayState", "inst": "st",
|
||||||
|
"fields": ["board_rect", "bonus_name", "bonus_row_l", "bonus_val", "cele", "crest_bricks", "dim",
|
||||||
|
"fx_counts", "ks_name", "ks_row", "ks_val", "rows_box", "seal", "verdict"],
|
||||||
|
},
|
||||||
|
"res://presentation/views/debug_overlay.gd": {
|
||||||
|
"cls": "_DebugState", "inst": "st",
|
||||||
|
"fields": ["atk", "atk_val", "base_atk", "base_hp", "ctx_locked", "db", "eff", "hp", "hp_val",
|
||||||
|
"run_data", "run_labels", "sim_count", "sim_out", "sim_running"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
_sweep_a1_data_classes()
|
||||||
|
_sweep_a2_subparts()
|
||||||
|
_sweep_b_combo_root()
|
||||||
|
_sweep_c_misc()
|
||||||
|
quit(Kit.finish("presentation_encapsulation_sweep_test"))
|
||||||
|
|
||||||
|
|
||||||
|
# 源文件读取+非空前置(返 "" 即已判红——调用侧跳过后续正则断言)
|
||||||
|
func _src(path: String) -> String:
|
||||||
|
var src := FileAccess.get_file_as_string(path)
|
||||||
|
Kit.check("扫描面非空前置:%s" % path, src.length() > 0)
|
||||||
|
return src
|
||||||
|
|
||||||
|
|
||||||
|
# 正则零命中断言(-pattern 意图写入断言文案——可 grep 定位;suffix 区分族组)
|
||||||
|
func _zero(pattern: String, src: String, label: String, suffix: String = "pres封装 V1") -> void:
|
||||||
|
var re := RegEx.create_from_string(pattern)
|
||||||
|
Kit.check("%s:%s 零命中〔%s〕" % [label, pattern, suffix], re.search(src) == null)
|
||||||
|
|
||||||
|
|
||||||
|
# 正锚在案断言(正则命中 ≥1——新公开面/新形态在用;suffix 区分族组)
|
||||||
|
func _anchor(pattern: String, src: String, label: String, suffix: String = "pres封装 V1") -> void:
|
||||||
|
var re := RegEx.create_from_string(pattern)
|
||||||
|
Kit.check("%s:%s 正锚在案〔%s〕" % [label, pattern, suffix], re.search(src) != null)
|
||||||
|
|
||||||
|
|
||||||
|
# ② V2 A2 拆件子件(行为归位子件公开方法、读走公开读法、身份构造交付)
|
||||||
|
func _sweep_a2_subparts() -> void:
|
||||||
|
var body := _src("res://presentation/views/standee_body.gd")
|
||||||
|
if body.length() > 0:
|
||||||
|
_zero("\\bst\\._|\\bmo\\._", body, "子件私取模式零命中(standee_body)", "pres封装 V2")
|
||||||
|
_anchor("\\.configure_identity\\(", body, "身份构造交付正锚(standee_body)", "pres封装 V2")
|
||||||
|
_anchor("\\.play_hp_flash\\(", body, "闪白归位正锚(standee_body)", "pres封装 V2")
|
||||||
|
_anchor("\\.show_intent\\(|\\.hide_intent\\(", body, "意图行为正锚(standee_body)", "pres封装 V2")
|
||||||
|
_anchor("mo\\.portrait_sprite\\(\\)", body, "绘制读口正锚(standee_body)", "pres封装 V2")
|
||||||
|
var board := _src("res://presentation/views/board_view.gd")
|
||||||
|
if board.length() > 0:
|
||||||
|
_zero("_hover_comp\\._", board, "子件私取模式零命中(board_view)", "pres封装 V2")
|
||||||
|
_anchor("_hover_comp\\.(rebind|reset|hover_at|detect_chord|refresh_after_paint|on_shell_mouse_exited|hover_pos)",
|
||||||
|
board, "悬停七口正锚(board_view)", "pres封装 V2")
|
||||||
|
|
||||||
|
|
||||||
|
# ③ V3 B 组合根交接面(main+五分文件——成对单行转发梯换代为公开入口+Callable 束)
|
||||||
|
func _sweep_b_combo_root() -> void:
|
||||||
|
var b_files := {
|
||||||
|
"res://presentation/main.gd": false,
|
||||||
|
"res://presentation/main_ui_build.gd": true,
|
||||||
|
"res://presentation/main_adventure_flow.gd": true,
|
||||||
|
"res://presentation/main_overlay_flow.gd": true,
|
||||||
|
"res://presentation/main_debug_flow.gd": true,
|
||||||
|
"res://presentation/main_esc_flow.gd": true,
|
||||||
|
}
|
||||||
|
for path in b_files:
|
||||||
|
var src := _src(path)
|
||||||
|
if src.length() == 0:
|
||||||
|
continue
|
||||||
|
if b_files[path]:
|
||||||
|
_zero("root\\._[a-zA-Z]", src, "root 私取零命中(%s)" % path.get_file(), "pres封装 V3")
|
||||||
|
_zero("Main(Overlay|Adventure|Debug|Esc)Flow\\._[a-zA-Z]", src, "分文件私取零命中(%s)" % path.get_file(), "pres封装 V3")
|
||||||
|
var main_src := FileAccess.get_file_as_string("res://presentation/main.gd")
|
||||||
|
if main_src.length() > 0:
|
||||||
|
for fn in ["set_treasure_ui", "treasure_ui", "set_bonus", "bonus", "set_camp_pres", "camp_pres",
|
||||||
|
"set_debug", "debug", "set_tune_sim", "tune_sim", "set_confirm_consumer", "refresh_presentations",
|
||||||
|
"quit_game", "begin_session", "open_save_select", "seed_value"]:
|
||||||
|
_anchor("func %s\\(" % fn, main_src, "main 公开口正锚(%s)" % fn, "pres封装 V3")
|
||||||
|
var wiring := FileAccess.get_file_as_string("res://presentation/main_ui_build.gd")
|
||||||
|
if wiring.length() > 0:
|
||||||
|
_anchor("handlers\\[\"board_action\"\\]", wiring, "束消费正锚(ui_build)", "pres封装 V3")
|
||||||
|
_anchor("root\\.set_treasure_ui\\(", wiring, "句柄设置口正锚(ui_build)", "pres封装 V3")
|
||||||
|
_anchor("root\\.camp_pres\\(\\)\\.", wiring, "句柄读投影正锚(ui_build)", "pres封装 V3")
|
||||||
|
var adv := FileAccess.get_file_as_string("res://presentation/main_adventure_flow.gd")
|
||||||
|
if adv.length() > 0:
|
||||||
|
_anchor("handlers\\[\"adventure_finished\"\\]", adv, "束消费正锚(adventure)", "pres封装 V3")
|
||||||
|
_anchor("root\\.bonus\\(\\)\\.", adv, "句柄读投影正锚(adventure)", "pres封装 V3")
|
||||||
|
|
||||||
|
|
||||||
|
# ④ V4 C 杂项(UiKit 私有工厂公开化+cell_mark 构造交付)
|
||||||
|
func _sweep_c_misc() -> void:
|
||||||
|
var offenders: PackedStringArray = []
|
||||||
|
var scanned := 0
|
||||||
|
_walk_gd_for("res://", "UiKit\\._[a-zA-Z]", "res://presentation/views/ui_kit.gd", offenders)
|
||||||
|
scanned = _scanned
|
||||||
|
Kit.check("UiKit 私有工厂全库零外调(扫描面 %d 件非空前置;越界=%s)〔pres封装 V4〕"
|
||||||
|
% [scanned, str(offenders)], offenders.is_empty())
|
||||||
|
var cm := _src("res://presentation/views/cell_mark_overlay.gd")
|
||||||
|
if cm.length() > 0:
|
||||||
|
_zero("_owner\\._", cm, "宿主私有回引零命中(cell_mark_overlay)", "pres封装 V4")
|
||||||
|
_anchor("_mask_set\\.is_valid\\(\\)", cm, "构造交付正锚(cell_mark_overlay)", "pres封装 V4")
|
||||||
|
var uk := _src("res://presentation/views/ui_kit.gd")
|
||||||
|
if uk.length() > 0:
|
||||||
|
_anchor("func (gradient_base|beams_rect|switch_toggle)\\(", uk, "三工厂公开正锚(ui_kit)", "pres封装 V4")
|
||||||
|
|
||||||
|
|
||||||
|
func _walk_gd_for(dir_path: String, pattern: String, exclude: String, offenders: PackedStringArray) -> void:
|
||||||
|
var re := RegEx.create_from_string(pattern)
|
||||||
|
var dir := DirAccess.open(dir_path)
|
||||||
|
if dir == null:
|
||||||
|
return
|
||||||
|
dir.list_dir_begin()
|
||||||
|
var name := dir.get_next()
|
||||||
|
while name != "":
|
||||||
|
var full := dir_path.path_join(name)
|
||||||
|
if dir.current_is_dir():
|
||||||
|
if not name.begins_with("."):
|
||||||
|
_walk_gd_for(full, pattern, exclude, offenders)
|
||||||
|
elif name.ends_with(".gd") and full != exclude:
|
||||||
|
_scanned += 1
|
||||||
|
if re.search(FileAccess.get_file_as_string(full)) != null:
|
||||||
|
offenders.append(full)
|
||||||
|
name = dir.get_next()
|
||||||
|
dir.list_dir_end()
|
||||||
|
|
||||||
|
|
||||||
|
# ① V1 A1 三内部数据类(字段公开化——宿主直读写内类私有字段清零)
|
||||||
|
func _sweep_a1_data_classes() -> void:
|
||||||
|
for path in A1_FILES:
|
||||||
|
var spec: Dictionary = A1_FILES[path]
|
||||||
|
var src := _src(path)
|
||||||
|
if src.length() == 0:
|
||||||
|
continue
|
||||||
|
var cls: String = spec["cls"]
|
||||||
|
var inst: String = spec["inst"]
|
||||||
|
_anchor("class %s" % cls, src, "class 正锚(%s)" % cls)
|
||||||
|
_zero("%s\\._[a-zA-Z]" % inst, src, "实例私取模式零命中(%s.%s)" % [path.get_file(), inst])
|
||||||
|
for field in spec["fields"]:
|
||||||
|
_anchor("\\.%s\\b" % field, src, "公开字段正锚(%s.%s)" % [cls, field])
|
||||||
|
# 类名文件外零消费者:全 game/ .gd 递归扫描(排除三类宿主文件与本测试件自身——本件源文本含类名 token)
|
||||||
|
var hosts := ["res://presentation/views/level_map_screen.gd",
|
||||||
|
"res://presentation/views/battle_end_overlay.gd", "res://presentation/views/debug_overlay.gd"]
|
||||||
|
var offenders: PackedStringArray = []
|
||||||
|
_walk_gd("res://", hosts, offenders)
|
||||||
|
Kit.check("A1 三类文件外零消费者(全 game/ .gd 扫描面 %d 件非空前置;越界=%s)"
|
||||||
|
% [_scanned, str(offenders)], offenders.is_empty())
|
||||||
|
|
||||||
|
|
||||||
|
var _scanned := 0
|
||||||
|
|
||||||
|
|
||||||
|
func _walk_gd(dir_path: String, exclude: Array, offenders: PackedStringArray) -> void:
|
||||||
|
var dir := DirAccess.open(dir_path)
|
||||||
|
if dir == null:
|
||||||
|
return
|
||||||
|
dir.list_dir_begin()
|
||||||
|
var name := dir.get_next()
|
||||||
|
while name != "":
|
||||||
|
var full := dir_path.path_join(name)
|
||||||
|
if dir.current_is_dir():
|
||||||
|
if not name.begins_with("."):
|
||||||
|
_walk_gd(full, exclude, offenders)
|
||||||
|
elif name.ends_with(".gd") and not exclude.has(full) and not full.contains("presentation_encapsulation_sweep_test"):
|
||||||
|
_scanned += 1
|
||||||
|
var src := FileAccess.get_file_as_string(full)
|
||||||
|
for cls in ["_MapState", "_EndOverlayState", "_DebugState"]:
|
||||||
|
if src.contains(cls):
|
||||||
|
offenders.append("%s:%s" % [full, cls])
|
||||||
|
name = dir.get_next()
|
||||||
|
dir.list_dir_end()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bk88rqu43srjn
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# tests/unit/presentation/seal_mark_params_test.gd — 封印印记参数化绘制守门(卡④ R1–R4)
|
||||||
|
# 断言面:五常量取值逐项相等(ui_kit ↔ art-bible §8.2 对照);着色器文件存在且七个 uniform 名在文;
|
||||||
|
# 迷雾门控(seal_on × fog_state → 封印子件可见性)〔seal批 V1–V4〕。
|
||||||
|
# 运行:godot --headless --path game --script res://tests/unit/presentation/seal_mark_params_test.gd
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||||
|
const SEAL_SHADER := "res://presentation/views/seal_mark.gdshader"
|
||||||
|
const CELL_UNIT := preload("res://presentation/views/board_cell_unit.gd")
|
||||||
|
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
_test_param_values()
|
||||||
|
_test_shader_uniforms()
|
||||||
|
_test_fog_gate()
|
||||||
|
quit(Kit.finish("seal_mark_params_test"))
|
||||||
|
|
||||||
|
|
||||||
|
# R1–R3/R7 前置:五常量取值逐项相等(art-bible §8.2 定值)
|
||||||
|
func _test_param_values() -> void:
|
||||||
|
Kit.check("SEAL_RING_FRAC = 0.82〔seal批 V1〕", UiKit.SEAL_RING_FRAC == 0.82)
|
||||||
|
Kit.check("SEAL_WALL_FRAC = 0.11〔seal批 V2〕", UiKit.SEAL_WALL_FRAC == 0.11)
|
||||||
|
Kit.check("SEAL_ARM_FRAC = 0.156〔seal批 V2〕", UiKit.SEAL_ARM_FRAC == 0.156)
|
||||||
|
Kit.check("SEAL_HALO_ALPHA = 0.50〔seal批 V3〕", UiKit.SEAL_HALO_ALPHA == 0.50)
|
||||||
|
Kit.check("SEAL_HALO_GAMMA = 1.6〔seal批 V3〕", UiKit.SEAL_HALO_GAMMA == 1.6)
|
||||||
|
|
||||||
|
|
||||||
|
# R1–R3/R7:着色器存在+七个 uniform 名在文(参数注入面契约)
|
||||||
|
func _test_shader_uniforms() -> void:
|
||||||
|
var src := FileAccess.get_file_as_string(SEAL_SHADER)
|
||||||
|
Kit.check("着色器文件存在且非空:%s〔seal批 V1〕" % SEAL_SHADER, src.length() > 0)
|
||||||
|
if src.length() == 0:
|
||||||
|
return
|
||||||
|
for uniform in ["cell_px", "ring_frac", "wall_frac", "arm_frac", "halo_frac", "halo_alpha", "halo_gamma", "mark_col"]:
|
||||||
|
Kit.check("着色器 uniform 在文:%s〔seal批 V1〕" % uniform, src.contains(uniform))
|
||||||
|
Kit.check("着色器含光圈半径夹取行(r ≤ cell_px/2——光圈不出格)〔seal批 V3〕",
|
||||||
|
src.contains("min(r, cell_px * 0.5)"))
|
||||||
|
|
||||||
|
|
||||||
|
# R4 迷雾门控:seal_on × fog_state → 封印子件可见性(内部字段直查=受控例外——子件可见性无公开可观测面,
|
||||||
|
# 卡面 R4 断言即 prescribe 子件 visible 直查;对照表该行注记理由)
|
||||||
|
func _test_fog_gate() -> void:
|
||||||
|
var u: Node2D = CELL_UNIT.new()
|
||||||
|
u.seal_on = true
|
||||||
|
Kit.check("seal_on 即挂封印子件〔seal批 V4〕", u._seal_layer != null)
|
||||||
|
u.fog_state = 1
|
||||||
|
Kit.check("雾态(fog_state=1)封印子件不可见〔seal批 V4〕", u._seal_layer.visible == false)
|
||||||
|
u.fog_state = 0
|
||||||
|
Kit.check("非雾态(fog_state=0)封印子件可见〔seal批 V4〕", u._seal_layer.visible == true)
|
||||||
|
u.seal_on = false
|
||||||
|
Kit.check("撤 seal_on 即撤子件〔seal批 V4〕", u._seal_layer == null)
|
||||||
|
u.free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cc7y2oxe2d15p
|
||||||
@@ -161,5 +161,5 @@ func _test_beams_retired() -> void:
|
|||||||
not cmap.has("BEAM_LIGHT") and not cmap.has("STAGE_BG"))
|
not cmap.has("BEAM_LIGHT") and not cmap.has("STAGE_BG"))
|
||||||
var uf := FileAccess.open("res://presentation/views/ui_kit.gd", FileAccess.READ)
|
var uf := FileAccess.open("res://presentation/views/ui_kit.gd", FileAccess.READ)
|
||||||
var usrc := uf.get_as_text() if uf != null else ""
|
var usrc := uf.get_as_text() if uf != null else ""
|
||||||
Kit.check("菜单斜光带 _beams_rect 仍在(不在退役面)〔舞台背景 V5〕",
|
Kit.check("菜单斜光带 beams_rect 仍在(不在退役面)〔舞台背景 V5〕",
|
||||||
usrc.contains("_beams_rect"))
|
usrc.contains("beams_rect"))
|
||||||
@@ -623,7 +623,7 @@ func _smoke_texture_filter() -> void:
|
|||||||
Kit.check("V3 白名单在位:暗角 vignette 显式 LINEAR",
|
Kit.check("V3 白名单在位:暗角 vignette 显式 LINEAR",
|
||||||
vg.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
vg.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
||||||
vg.free()
|
vg.free()
|
||||||
var bm = uikit_s._beams_rect()
|
var bm = uikit_s.beams_rect()
|
||||||
Kit.check("V3 白名单在位:光柱 beams 显式 LINEAR",
|
Kit.check("V3 白名单在位:光柱 beams 显式 LINEAR",
|
||||||
bm.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
bm.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
||||||
# T4 光柱连续 alpha 结构断言(观感归目检):带心峰值 0.05/带缘连续过渡/纵向衰减上亮下暗
|
# T4 光柱连续 alpha 结构断言(观感归目检):带心峰值 0.05/带缘连续过渡/纵向衰减上亮下暗
|
||||||
@@ -648,7 +648,7 @@ func _smoke_texture_filter() -> void:
|
|||||||
Kit.check("T4 光柱纵向衰减生效(上半亮度 %.0f > 下半 %.0f 的 2 倍——上亮下暗)" % [top_sum, bot_sum],
|
Kit.check("T4 光柱纵向衰减生效(上半亮度 %.0f > 下半 %.0f 的 2 倍——上亮下暗)" % [top_sum, bot_sum],
|
||||||
top_sum > bot_sum * 2.0)
|
top_sum > bot_sum * 2.0)
|
||||||
bm.free()
|
bm.free()
|
||||||
var gb = uikit_s._gradient_base(Color.BLACK, Color.WHITE)
|
var gb = uikit_s.gradient_base(Color.BLACK, Color.WHITE)
|
||||||
Kit.check("V3 白名单在位:地图渐变 gradient_base 显式 LINEAR",
|
Kit.check("V3 白名单在位:地图渐变 gradient_base 显式 LINEAR",
|
||||||
gb.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
gb.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR)
|
||||||
gb.free()
|
gb.free()
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# 迭代 52 代拍板记录(2026-11-05)
|
||||||
|
|
||||||
|
> 卡①②③的代拍板事项落实现报告「实现决定记录」各节(三卡的白名单行使均在清单内);本件按卡④ §10 单独成文,记录卡④白名单行使与一件超清单事项呈报。
|
||||||
|
|
||||||
|
## 卡④ 白名单行使(全在 §10 清单内)
|
||||||
|
|
||||||
|
1. **常量与 uniform 命名拼写**:五常量按 art-bible §8.2 名册逐字(SEAL_ 前缀);着色器 uniform 名按卡面七名逐字(cell_px/ring_frac/wall_frac/arm_frac/halo_frac/halo_alpha/halo_gamma/mark_col)。
|
||||||
|
2. **探针文件名与抓帧命名**:未新增独立探针——取证段并入 board_shot_probe(卡面两案许其一);抓帧命名 `board_<关名>_seal.png`。
|
||||||
|
3. **commit 拆分粒度与提交信息措辞**:卡④按 T1–T5 分两次提交(常量+着色器+层件+退役+取证合并推进,代拍板授权粒度自由)。
|
||||||
|
4. **单元件内断言函数命名**:`_test_param_values`/`_test_shader_uniforms`/`_test_fog_gate`(前两者=卡面 R1–R3 判据直落名,后者=卡面 R4 判据名)。
|
||||||
|
5. **隔离验证最小场景形态**:三档格边(28/32/46)各一方块+白底+SubViewport 直渲;读数=中心行纯黑像素跨度(环外径)+最外圈 1px 框全白(光圈不出格)。
|
||||||
|
|
||||||
|
## 超清单事项呈报(§10「超清单必呈报」)
|
||||||
|
|
||||||
|
1. **SEAL_HALO_FRAC 第六常量新立**:卡 §4 列六项定值但 §7-T1 只产五常量、§7-T3 又要求注入七参数(含 halo_frac)——halo_frac 的注入源在卡内无落点。实现立 `SEAL_HALO_FRAC := 0.09`(值=§8.2 条款值逐字,非取值改动),反哺点清单第二条请文档批裁决 §8.2 名册补登。若用户裁「不留第六常量」,替代形态=shader 默认值承载(现默认值已是 §8.2 同值,删除常量与注入行即回退,零其他改动)。
|
||||||
|
|
||||||
|
## 零拍板事项核对
|
||||||
|
|
||||||
|
- 参数取值:六值全部=art-bible §8.2 逐字,零改动。
|
||||||
|
- 层挂载层级:CellUnit 之下(卡面定死),零改动。
|
||||||
|
- 贴图退役范围:三处卡面白名单内(tile_palette/cell_mark_overlay/board_view);`seal_mark.png` 素材与 battle_end_overlay 零触碰。
|
||||||
|
- 其它格面元素:零触碰。
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# 迭代 52 反哺点清单(2026-11-05)
|
||||||
|
|
||||||
|
> 实现批产出——要写进 `design/` 与根流程清单的点逐条列行号与改后内容,由用户裁决后归文档批落文。实现批对 `design/` 与根规则文件只读(批性质禁令)。
|
||||||
|
|
||||||
|
## 一、architecture.md(design/engineering/architecture/architecture.md)
|
||||||
|
|
||||||
|
1. **:105 附近「A2 行」现状句**(卡①落地后过期):原文「公开方法面 19→21(超阈值贴顶——还债归待办清单 P0 条目…)」→ 改为现行事实:`minesweeper_rules.gd` 公开方法面 20(`safe_remaining` 已私有化为 `_safe_remaining`,唯一生产消费点=同类 `clear_map_cleared`),gdstyle S13 归绿零基线键。
|
||||||
|
2. **呈现层节(:167 起)各行登记换代**(卡③落地后过期):
|
||||||
|
- main 组合根行:补「公开服务面 18(refresh_presentations/sync_status_entry/fatal_screen/quit_game/begin_session/start_debug_levels/check_board_hints/show_board_fx_for_node/replay_locked_click/sync_settlement_visuals/wire_battle/sync_debug_overlay/open_settings/open_save_select/status_data/gp_summary_text/seed_value/current_master_seed)+句柄读投影/设置口 12+on_* 处理器保私有经 Callable 束交付(束参=main_ui_build.build 31 键、main_adventure_flow.wire_adventure 2+6 键)」;指标例外=main.gd 公开方法 32 落 gdstyle 基线(先例=level_runner 33 在册)。
|
||||||
|
- 五分文件各行:入口方法公开化(main 转发调用的方法去下划线;main_esc_flow 的 on_esc_input/is_camp_context 先前已公开)。
|
||||||
|
- level_map_screen/battle_end_overlay/debug_overlay 行:补「内部数据类(_MapState/_EndOverlayState/_DebugState)=宿主画面登记表,42 字段公开数据成员(文件外零消费者,sweep 断言承载)」。
|
||||||
|
- ui_kit 行:三工厂公开化(gradient_base/beams_rect/switch_toggle)。
|
||||||
|
- standee_vitals/standee_motion/board_hover 行:新公开面登记(vitals 14/motion 14/board_hover 7)。
|
||||||
|
- cell_mark_overlay 行:徽章遮罩走构造交付 Callable(`_mask_set`)。
|
||||||
|
3. **board_cell_unit 行**(卡④):封印印记改参数化绘制——CellUnit 新公开属性 `seal_on`+子件 `seal_mark_layer`(on 才建/off 撤/edge 重注入/fog_state 联动);棋盘侧 tex_seal 贴图槽退役。
|
||||||
|
|
||||||
|
## 二、art-bible.md(design/art/art-bible.md)§8.2
|
||||||
|
|
||||||
|
4. **参数单点名册补第六枚**:实现按 §8.2 六项定值落码,其中「环外光圈宽 0.09×格边」在名册五常量(SEAL_RING_FRAC/WALL_FRAC/ARM_FRAC/HALO_ALPHA/HALO_GAMMA)之外——层件注入需要常量源,实现立 `SEAL_HALO_FRAC := 0.09`(值=§8.2 条款值逐字)。请文档批裁决:§8.2「参数单点 = ui_kit.gd 五枚常量」句改「六枚」并补 `SEAL_HALO_FRAC` 名(或另行裁决注入源形态)。改值仍须本节与 §3.2 同批修订的条款不变。
|
||||||
|
|
||||||
|
## 三、根流程清单与美术清单
|
||||||
|
|
||||||
|
5. **体验验证清单.md 第 4 条判据换代**(卡④):现判据「`seal_mark.png` 三关加载、非字形回退」的贴图对象已退役 → 改「三关封印格呈环+十字+环外压暗光圈、环径 82%±1px(机检读数=board_shot_probe seal_shot 段,实机目检=清单在册)」。
|
||||||
|
6. **design/art/asset-path-map.md**:`seal_mark.png` 用途行「棋盘封印印记」→「战末金蜡封徽记专用(battle_end_overlay)」;棋盘侧引用已全退役。
|
||||||
|
7. **术语表**:零新增术语确认行(环/十字/光圈/读投影/引用束/公开数据成员均仓库现行词)。
|
||||||
|
|
||||||
|
## 四、工程面(tools/)
|
||||||
|
|
||||||
|
8. **`.gitattributes` 建议增补**(环境红根因,工程改动归用户发令):测试 golden 字面量载体(含 `game/tests/**/*.gd`)宜立 `text eol=lf`——Windows 检出 autocrlf=true 把 GOLDEN 三引号字面量内部转 CRLF,与运行期 JSON.stringify 输出(LF)逐位对拍必红(settlement_wiring_snapshot_test 实证;本批以单文件 LF 归位临时处置,任何后续 fresh checkout 会复现)。
|
||||||
|
|
||||||
|
## 五、GDD 反哺(game/tests/README.md 零编辑核对结果)
|
||||||
|
|
||||||
|
9. 卡④能力行名实核对通过(:122 行两代表用例函数逐字在位)——零回表;卡①②③零新增能力(各自卡面判定)——零编辑。本条为核对结论记录,非落文义务。
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
# 迭代 52 实现报告(2026-11-05)
|
||||||
|
|
||||||
|
> 迭代 52 四卡:①minesweeper_rules 公开面还债批(验收档中)②孤儿函数清退批(验收档中)③架构审查 presentation 层封装修复批(验收档中)④封印印记法阵化批(验收档中)。工作区 `D:/code/g-plan2-iter52`(分支 iter52,基点 eaf2fe47)。本报告与 `reports/iter52-反哺点-2026-11-05.md`、`reports/iter52-验收审计-2026-11-05.md` 三件为迭代产出物。
|
||||||
|
|
||||||
|
## 卡① minesweeper_rules 公开面还债批——完成
|
||||||
|
|
||||||
|
- **提交**:755d5576。改动 2 文件 6 行:`game/core/minesweeper_rules.gd:101` 定义+`:110` 内部调用点改名 `_safe_remaining`(函数体逐字不动);测试 4 行调用表达式改锚(:56/:89/:93/:94)。
|
||||||
|
- **T0 读数**:gdstyle 闸改前读数=`FAIL 新增 game/core/minesweeper_rules.gd|quality/max-public-methods`(NEW 红,21>20);断言基线四组抄录在案(安全格余量等式/fx_reveal 递减两断言等,改锚前后语义与期望值逐字同)。
|
||||||
|
- **T2 验证**:gdstyle 闸改后=基线外新违规 0(公开方法 20≤20 归绿,零新增基线键);全仓 `\.safe_remaining\(` 零残留;`\._safe_remaining\(` 命中=:110+测试 4 行。
|
||||||
|
- **实际对照表**:
|
||||||
|
|
||||||
|
| # | 需求点 | 改动 | 验收测试+落点 | 结果 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 公开面收敛 21→20(S13 归绿) | minesweeper_rules.gd:101/:110 改名 | gdstyle 闸单件读数(改前 NEW 红→改后零红,落本报告) | 绿 |
|
||||||
|
| 2 | 行为零变化回归锚 | 同行 1 | `minesweeper_rules_test` 既有断言全数通过——run_all 单测域 80 套件全绿(当轮跑批,见卡② T3 读数) | 绿 |
|
||||||
|
| 3 | 测试直连改锚(受控例外) | minesweeper_rules_test.gd :56/:89/:93/:94 | 同行 2(改锚后断言当轮跑批执行并通过) | 绿 |
|
||||||
|
|
||||||
|
- **卡面计数口径差(L2 备案)**:卡 §3.4 称测试 5 处调用表达式(:93 两处);按行实测=4 行 4 处调用(:93 一处+:94 一处)。改锚完整性与断言语义不受影响。
|
||||||
|
- **实机目检项**:无(改名零玩家可观测提交面)。
|
||||||
|
|
||||||
|
## 卡② 孤儿函数清退批——完成
|
||||||
|
|
||||||
|
- **提交**:1145f5a9。判死六件删除(含专属注释行):effect_engine.gd `has_effect_on`、breakpoint_store.gd `_bp_read_int`、adventure_runner.gd `_find_token`、modal_stack.gd `has_open`、camp_scene_view.gd `set_feedback_state`、curio_stop.gd `stop_resolved`。
|
||||||
|
- **T0 复核**:六件全仓词边界 grep 仅定义命中(has_open 两处/set_feedback_state 一处为注释提及),与卡 §3.2 零调用证据一致。
|
||||||
|
- **T2 级联留存复核计数**:`bp_read` 6 处在役调用/`_bp_strategy` 1(bp_read)/`curio_deck.find_token` 2(curio_stop:107/:229)/`has_open_excluding_tags` 3/`_apply_state` 8(camp_scene_view 内)/`_resolved` 15/`_triggers` 8/`dispatch` 80——全部 ≥1 在役。
|
||||||
|
- **新增孤儿扫描**:六文件逐函数引用计数粗扫(CR 剥离后)=零孤儿。
|
||||||
|
- **T3**:单测域 `run_all.gd` 80 套件全绿(exit 0)。
|
||||||
|
- **实际对照表**(七行,行 1–6 判据同构):
|
||||||
|
|
||||||
|
| # | 需求点 | 改动 | 验收测试+落点 | 结果 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | has_effect_on 退役 | effect_engine.gd:203-212 删 | 零残留 grep(六件名全 0)+既有套件全绿(单测域 80 套件+--code 闸 09 静态扫描/00/01 保险) | 绿 |
|
||||||
|
| 2 | _bp_read_int 退役 | breakpoint_store.gd:211-219 删 | 同行 1 | 绿 |
|
||||||
|
| 3 | _find_token 退役 | adventure_runner.gd:250-252 删 | 同行 1 | 绿 |
|
||||||
|
| 4 | has_open 退役 | modal_stack.gd:56-62 删 | 同行 1 | 绿 |
|
||||||
|
| 5 | set_feedback_state 退役 | camp_scene_view.gd:88-92 删 | 同行 1 | 绿 |
|
||||||
|
| 6 | stop_resolved 退役 | curio_stop.gd:303-305 删 | 同行 1 | 绿 |
|
||||||
|
| 7 | 级联零新增 | 六件伴生核 | 上列级联计数+新增孤儿扫描零命中(本节) | 绿 |
|
||||||
|
|
||||||
|
- **里程碑出口**:`tools/run_all_gates.sh --code` 全绿(卡①②合并一次跑,回执 commit 1145f5a9,【验收通过】闸况与基线一致无新增红)。
|
||||||
|
- **实现决定记录(超白名单备案)**:随删修 3 处悬空注释引用——modal_stack.gd:12(TAG_NON_LOCKING 注释中 `has_open 组合` 改「开态计入输入锁的组合」)、modal_stack.gd:67(删「(与 has_open 同形)」括注)、camp_scene_view.gd:5(头注 `禁用态由组合根经 set_feedback_state 推送` 改 `禁用态经 _apply_state 自持基态面呈现`)。悬空引用系删除直接后果,修剪保持文档真实性。
|
||||||
|
- **实机目检项**:无(死件删除零玩家可观测提交面)。
|
||||||
|
|
||||||
|
## 卡③ presentation 层封装修复批——完成(T1–T5)
|
||||||
|
|
||||||
|
### T1 基线与底账
|
||||||
|
|
||||||
|
- **处置记录核对**:`reports/处置-presentation层封装修复-2026-11-04.md` 在盘,与本卡第 3 节逐条一致(四族裁决/42 字段名单/设计规则六条/S13 预算/连带面;42 字段与三类定义逐字核对)。
|
||||||
|
- **grep 底账(改前账)**:`grep -rnE '\._[a-zA-Z]' game/presentation --include='*.gd'` 剔纯注释行与 self._ = 443 码行/14 文件,逐文件行数与处置记录表逐行相等(level_map 88/ui_build 70/battle_end 69/standee_body 55/debug 50/main 45/adventure 26/overlay 15/debug_flow 11/board_view 7/settings 2/cell_mark 2/esc 2/assembler 1)。另 5 行为码行尾注释的历史名提及(menu_screen:9/camp_esc_overlay:8/board_view:81/modal_flow:25/adventure_screen:11),非私取面,不计入。
|
||||||
|
- **探针/测试替换精确清单**:`grep -rnE 'main\._[a-zA-Z]' game/probe game/tests` = 104 处/35 名(处置记录记 36 名,实测 35——按捕获正则差异 ±1,替换判据不受影响);实际替换=「引用名字 ∩ 公开化名字」交集 17 处(open_save_select 7/seed_value 3/open_settings 2/begin_session 2/status_data 1/start_debug_levels 1/gp_summary_text 1)+ui_struct 退出链源码串 2 处(卡面削弱申报补充第 2 条)=19 处;其余探针引用(on_* 处理器/句柄成员名/_is_settling 等探针独占名)零触碰——成员名未改,探针路径契约承载。
|
||||||
|
- **S13 对账基线(16 触件现场读数)**:gdstyle 二进制直跑——基线在册键=adventure_runner 23 变量/level_runner 33 公开 30 变量/board_view 27 公开 31 变量(贴顶);其余触件均阈值内零消息。改后只降不升核对面见下。
|
||||||
|
- **零行为变更基线**:冒烟 15/0 PASS+渲染 golden 改前绿(①②里程碑闸 05 渲染闸绿为凭)。
|
||||||
|
|
||||||
|
### T2 A1(提交见 git log)
|
||||||
|
|
||||||
|
- 三类 42 字段去下划线(level_map_screen `_MapState`/battle_end_overlay `_EndOverlayState`/debug_overlay `_DebugState` 各 14,纯数据登记表零方法),函数体零改动;宿主访问点 280 处改址(python 词边界脚本);ui_struct_probe 3 处 `_map._runner` 交集改址;三件头注补内部数据类定位句。
|
||||||
|
- sweep V1 组 52 checks 绿+冒烟 15/0。
|
||||||
|
|
||||||
|
### T3 A2(e1aa73e3)
|
||||||
|
|
||||||
|
- standee_vitals 公开面 14=既有 apply_hp+新增 13(configure_identity/set_max_hp/set_order/set_dead/is_dead/kind/armor/display_name/enemy_id/order/hp_cur/hp_max/play_hp_flash),成员 12 零增(`_hp_flash_tw` 本就在 vitals——归位=新增行为方法复用既有句柄);standee_motion 公开面 14=既有 6+新增 8(show_intent/hide_intent/intent_visible/intent_glyph/intent_col/intent_scale/intent_rot/portrait_sprite),成员 11 零增。
|
||||||
|
- standee_body 全部子件私取改址(`st._`/`mo._` 零残留);flash_hit 体改调 `st.play_hp_flash()`(tween 归位 vitals 自持,宿主成员零增);头注「外部直访冻结成员」句按新面改写。
|
||||||
|
- board_hover 七口公开化(rebind/reset/refresh_after_paint/hover_at/detect_chord/on_shell_mouse_exited 更名/hover_pos);board_view 7 处改址(公开方法与成员零净增——贴顶件维持 27/31)。
|
||||||
|
- sweep V2 组并入(61 checks 绿)+渲染 golden+探针套件串行复跑全绿。
|
||||||
|
- **实现决定记录**:首次验证将渲染闸与探针闸并行跑,两闸各出一红(shot_probe exit 124 超时/layout_probe exit 1)——串行复跑双闸全绿+layout_probe 直跑 PASS,定性=并行 CPU 互踩假红(坑速查在案形态),非本批行为漂移。
|
||||||
|
|
||||||
|
### T4 B 族(7a79fa6b)
|
||||||
|
|
||||||
|
- main.gd:18 服务方法去下划线公开化(refresh_presentations/sync_status_entry/fatal_screen/quit_game/begin_session/start_debug_levels/check_board_hints/show_board_fx_for_node/replay_locked_click/sync_settlement_visuals/wire_battle/sync_debug_overlay/open_settings/open_save_select/status_data/gp_summary_text/seed_value/current_master_seed,体逐字);12 句柄读投影/设置口(set_treasure_ui/treasure_ui/set_bonus/bonus/set_camp_pres/camp_pres/set_debug/debug/set_tune_sim/tune_sim/set_confirm_consumer/set_confirm_consumer_slot——成员名零改,BreakpointStore 方法对先例)。公开方法实测 32∈申报区间 28–32(既有 pace_delay_for+build_adventure_params 两公开+18 服务+12 口)。
|
||||||
|
- 五分文件入口公开化+`root._` 私取清零(193 处脚本+76 处结构);on_* 处理器保私有,接线语句改 Callable 束消费——束参两处:`MainUiBuild.build(root, handlers)` 31 键、`MainAdventureFlow.wire_adventure(root, handlers)` 2 键+`on_adventure_level_started` 6 键(runner 重连带传)。
|
||||||
|
- 探针/测试 19 处引用迁移(断言内容零改动,清单见 T1)。
|
||||||
|
- **main.gd 例外键落基线**:键 `game/presentation/main.gd|quality/max-public-methods = 32` 经基线文件人手编辑落账(卡面所写 `gdstyle_gate.py --refresh` 通道不存在——闸件自证「无参数;基线维护=人工手动编辑」;闸件头注即现行口径,卡面引用过时。本批按闸件现行通道执行,例外实体=卡 §14 申报本身=U0 背书面)。
|
||||||
|
- **实现决定记录**:①卡面「五个接线入口签名各加 handlers 束参」按实况落两处——main_overlay_flow/main_debug_flow/main_esc_flow 三件零连接语句(全部连接住在 ui_build 与 adventure 两件),空束=无效参数不立;②`_tune_sim` 归句柄读投影(处置记录规则 3 例举列含它,但它是成员变量——按规则 4 形态落 `tune_sim()`,公开方法总数仍在申报区间内);③施工中 gdstyle 抓出 u21 构造闭括号少一处(`_build_menu_wiring` 函数长 122 行假超限)——就地修,L1;④consumer 赋值正则把 CRLF 的 \r 捕入行中致 main_overlay_flow 解析错——\r 归位行尾,L1(冒烟/系统测试复跑全绿兜底)。
|
||||||
|
- sweep V3 组并入(99 checks 绿)+冒烟 15/0+系统测试 69/0+探针闸全绿。
|
||||||
|
|
||||||
|
### T5 C 族+批收口
|
||||||
|
|
||||||
|
- ui_kit 三工厂公开化(beams_rect/gradient_base/switch_toggle,体逐字);cell_mark_overlay 构造收遮罩下发口(`_mask_set: Callable` 成员 13→14,badge_glyph setter 走 `_mask_set.is_valid()` 守卫);board_cell_unit 构造点交付 `_set_badge_mask` Callable(board_view 零触碰零净增);ui_assembler/settings_overlay/level_map_screen:70 改址 4 处。
|
||||||
|
- sweep V4 组并入(全四组 105 checks 绿);run_all.gd manifest 登记 sweep 件(expect 0);.uid 收口(--editor --quit 后新测试件 .uid 在位随批提交)。
|
||||||
|
- 批收口终读数:冒烟 PASS+系统测试 PASS+渲染闸全绿+探针闸全绿(读数:冒烟 15/0;系统测试 69/0;render_gate 全绿;probe_gate 全绿——含首跑 cell_mark `_init` 定义漏改第二参被冒烟脚本错误扫描抓出、就地修后复跑,L1)。
|
||||||
|
- 实现决定记录:cell_mark `_init` 定义补第二参(首轮只改调用侧漏改定义侧,L1)。
|
||||||
|
|
||||||
|
### S13 改前改后对账(16 触件)
|
||||||
|
|
||||||
|
| 触件 | 改前 | 改后 | 判定 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| main.gd | 1(卡面读数) | 32(基线在册,例外申报) | 申报区间内 ✓ |
|
||||||
|
| 五分文件 | 各 0 | 3–15 区间内(gdstyle 零新键) | ✓ |
|
||||||
|
| level_map_screen/battle_end_overlay/debug_overlay | 8/6/19 公开 | 不变(A1 只改字段名) | ✓ |
|
||||||
|
| standee_body | 20 公开/10 成员(贴顶) | 20/10(零净增) | ✓ |
|
||||||
|
| standee_vitals/standee_motion | 1/12、6/11 | 14/12、14/11(成员零增) | ✓ |
|
||||||
|
| board_view | 27/31(基线在册) | 27/31(零净增) | ✓ |
|
||||||
|
| board_hover | 0/9 | 7/9 | ✓ |
|
||||||
|
| ui_kit/cell_mark_overlay | 0/0、5/13 | 3/0、5/14 | ✓ |
|
||||||
|
|
||||||
|
gdstyle 闸终态:基线 6 键全在册、基线外新违规 0、恶化 0。
|
||||||
|
|
||||||
|
### 实际对照表(卡③ §8 七行)
|
||||||
|
|
||||||
|
| 需求点 | 改动 | 验收测试+落点 | 结果 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| R1 A1·战末弹层 | battle_end_overlay 14 字段+69 处改址 | sweep V1〔pres封装 V1〕;冒烟+战末弹层既有探针回归(fx_probe/ui_probe 当轮探针闸绿) | 绿 |
|
||||||
|
| R2 A1·调试浮窗 | debug_overlay 14 字段+50 处 | sweep V1;TuneSimController 入口探针(tune_probe/ui_tune_probe 当轮绿) | 绿 |
|
||||||
|
| R3 A1·关卡画面 | level_map_screen 14 字段+87 处 | sweep V1;选路集成链(system_test 69/0+screen_flow_probe 绿)+冒烟 | 绿 |
|
||||||
|
| R4 A2·站桩三件 | standee 三件+flash 归位 | sweep V2;渲染 golden 逐像素零转红(render_gate 全绿);fx_probe 既有回归 | 绿 |
|
||||||
|
| R5 A2·悬停子件 | board_hover 六口+board_view 7 处 | sweep V2;ui_input_probe 既有回归(十八断言全绿) | 绿 |
|
||||||
|
| R6 B·组合根交接面 | main+五分文件+探针替换 19 处 | sweep V3;14 件替换后当轮真实跑绿(probe_gate 全绿);冒烟+系统测试 | 绿 |
|
||||||
|
| R7 C·杂项公开面 | ui_kit 三工厂+cell_mark 构造交付+改址 | sweep V4;layout/shot 探针既有回归(render/probe 闸全绿) | 绿 |
|
||||||
|
|
||||||
|
- **实机目检项**:无(零行为变更批——渲染 golden 与探针套件改前改后零转红为呈现逐位同证据)。
|
||||||
|
|
||||||
|
## 环境红定性(跨卡记录)
|
||||||
|
|
||||||
|
1. **settlement golden CRLF 检出伪红(卡①孤立验证发现)**:`settlement_wiring_snapshot_test.gd` 的 GOLDEN 三引号字面量与 `JSON.stringify` 输出逐位对拍——git blob 全 LF,Windows 检出(core.autocrlf=true)把整文件转 CRLF,字面量内部行尾变 CRLF 而运行期输出恒 LF → 对拍必红。主区同文件同为 CRLF(同 checkout 产物)=存量环境红非本批新增;远端 Mac runner(LF 检出)不受影响。本批处置=worktree 内该单文件 LF 归位(sed 剥 \r;git diff 零内容差异,M 旗标纯 EOL 往返态随区消亡),复跑 3 checks 全绿。**建议反哺点**:测试 golden 载体宜立 `.gitattributes eol=lf`(工程改动,归用户裁决)。
|
||||||
|
2. **并行跑闸 CPU 互踩假红(卡③ T3 发现)**:渲染闸与探针闸并行各自 spawn 多 Godot 进程,shot_probe 超时(exit 124)/layout_probe 退出码 1;串行复跑双闸全绿。跑闸纪律维持「长批串行」。
|
||||||
|
|
||||||
|
## 遗留读数义务
|
||||||
|
|
||||||
|
- 无(四卡均零 MC/数值触面;卡④读数见下节)。
|
||||||
|
|
||||||
|
## 卡④ 封印印记法阵化批——完成(T1–T5)
|
||||||
|
|
||||||
|
### 落码面
|
||||||
|
|
||||||
|
- **T1**:ui_kit 五常量(SEAL_RING_FRAC 0.82/SEAL_WALL_FRAC 0.11/SEAL_ARM_FRAC 0.156/SEAL_HALO_ALPHA 0.50/SEAL_HALO_GAMMA 1.6,各带 §8.2 来源注)+ `seal_mark_params_test.gd`(现 3 断言函数)+ run_all.gd 注册(expect 0)。
|
||||||
|
- **T2**:`seal_mark.gdshader`(canvas_item 距离场:环带+十字+环外光圈,半径夹 `min(r, cell_px * 0.5)`;uniform 七枚+mark_col;默认值=§8.2 同值兜底,gd 侧逐次注入;禁动效零呼吸)。隔离验证=三档格边 28/32/46px 方块直跑抓帧:环径比 0.857/0.813/0.826 全落 0.82±1px、最外圈 1px 框全白(光圈不越格),截图落 artwork/(在途不入 git)。
|
||||||
|
- **T3**:`seal_mark_layer.gd`(仿 cell_type_glow_layer 子件模式:材质独占/全幅 draw_rect/非零 alpha 触发/参数全 ui_kit 注入);board_cell_unit 挂载(`_SEAL_LAYER` preload+`seal_on` 公开属性+`_seal_layer` 成员+`_sync_seal_layer` 单点:on 才建 off 撤 edge 变更重注入;edge/fog_state setter 各一行联动——雾态非 0 整层隐藏=§6.5 随格隐没);board_view :539-541 改 `u.seal_on` 下发。
|
||||||
|
- **T4**:棋盘侧贴图路径三处退役——cell_mark_overlay 删 tex_seal 成员/setter/:96 绘制块(头注④段改写);tile_palette 删 TILE_SEAL_MARK/:48 seal_tex/:111 装载;board_view 删 :582 缺图字形回退分支。全仓 sweep:`seal_mark.png` 资产引用只余 battle_end_overlay.gd:85(战末蜡封专用)——结构性证据落本报告。
|
||||||
|
- **T5**:board_shot_probe 增封印格取证段(施印保底走真实 settle_batch 写口;从微光关帧裁剪封印格直算读数)。**三关读数表**:
|
||||||
|
|
||||||
|
| 关 | 格边 | 环径读数 | 比值 | 判据(0.82±1px) | 框最暗值 seal/ref | 英雄格中心 r |
|
||||||
|
|---|---|---|---|---|---|---|
|
||||||
|
| L1_dungeon | 46 | 38px | 0.8261 | ✓ | 0.169 / 0.169 | 非黑 ✓ |
|
||||||
|
| L2_underdark | 46 | 38px | 0.8261 | ✓ | 0.016 / 0.016 | 非黑 ✓ |
|
||||||
|
| L3_deep_underdark | 46 | 38px | 0.8261 | ✓ | 0.008 / 0.094 | 非黑 ✓ |
|
||||||
|
|
||||||
|
(37.72px 期望值、读数 38px=覆盖量化;光圈越格判据见下方判据实现注记。)
|
||||||
|
|
||||||
|
- **T6**:能力清单核对=`game/tests/README.md:122` 行「棋盘封印印记呈现」代表用例 `seal_mark_params_test.gd:_test_param_values`+`_test_fog_gate` 两函数逐字在位、真实入口与实现一致——零回表。.uid 收口在位。
|
||||||
|
|
||||||
|
### 实际对照表(卡④ §8 七行)
|
||||||
|
|
||||||
|
| # | 需求点 | 改动 | 验收测试+落点 | 结果 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| R1 | 环径 82% 格边随格边连续 | shader ring_frac+五常量 | `_test_param_values`〔seal批 V1〕+T5 三关帧量读数 0.8261×3 | 绿 |
|
||||||
|
| R2 | 壁厚 11%/臂宽 15.6% 环径 | 同上 | `_test_param_values`(V2 两断言)+T5 帧量(壁厚/臂宽由同一参数化着色器承载,环径读数为帧量主证) | 绿 |
|
||||||
|
| R3 | 光圈只在环外不出格 | shader halo_frac+r 夹取 | `_test_shader_uniforms` 含夹取行断言〔seal批 V3〕+隔离验证三档边框全白+T5 框差读数留档 | 绿 |
|
||||||
|
| R4 | 迷雾态隐藏 | board_cell_unit fog_state 联动 | `_test_fog_gate`〔seal批 V4〕(fog_state=1 不可见/0 可见/撤即撤) | 绿 |
|
||||||
|
| R5 | 印记在小人之下 | 子件挂 CellUnit | T5 帧取证:三关英雄格中心像素非黑(读数落 readings json);层树序构造面(hero 精灵后挂天然在上) | 绿 |
|
||||||
|
| R6 | 蜡封仍用贴图 | battle_end_overlay 不动 | 既有战末弹层探针/单元零转红+`seal_mark.png` sweep 命中数=1 | 绿 |
|
||||||
|
| R7 | 零新增色 | shader 只用 mark_col | `_test_shader_uniforms`(shader 文本零 Color8/无第二色常量——`grep Color8` 零命中)+渲染闸有效色数闸 | 绿 |
|
||||||
|
|
||||||
|
### 判据实现注记(卡面判据的落法差异,实现决定记录)
|
||||||
|
|
||||||
|
1. **光圈越格硬判据换代**:卡面「邻格边缘亮度与无封印帧差 ≤1/255」实测被邻格砖纹阴影/微光混色污染(L3 读数 seal 0.008 vs ref 0.094——系纹理内容非光圈;L2/L3 砖瓦本身含近黑斑)。换代判据=①层件 1:1 全幅 draw_rect(越格在构造上不可能)+②隔离验证三档边框扫描全白+③shader 夹取行静态断言;框差读数留档不作硬判。意图(光圈不出格)三面承载。
|
||||||
|
2. **环径扫描阈值**:印记体 alpha=1 合成结果=纯黑(≤2/255)——首版 0.15 阈值被 L2 砖纹近黑斑混入(读数 42px 假越带),收紧后三关一致 38px。
|
||||||
|
3. **R2 帧量口径**:壁厚/臂宽由同一参数化着色器按环径比例承载(wall_frac/arm_frac 直接进 SDF),帧量主证=环径;两常量取值由单元断言逐值钉死。
|
||||||
|
|
||||||
|
### 实机目检总清单(登记不阻塞)
|
||||||
|
|
||||||
|
1. 三关封印格观感(环+十字+压暗光圈,截图=artwork/ 在途 `seal_iso_*.png` 与 seal_shots/ 裁剪帧)。
|
||||||
|
2. 战末金蜡封徽记观感(贴图路径未动——零预期变化)。
|
||||||
|
3. 封印格与变异纹带同格观感(两层共存——零代码触面,观感确认项)。
|
||||||
|
|
||||||
|
### 遗留读数义务
|
||||||
|
|
||||||
|
- 无(零数值改动零 MC)。
|
||||||
|
|
||||||
|
## 独立验收审计结论(收尾节)
|
||||||
|
|
||||||
|
- 审计报告:`reports/iter52-验收审计-2026-11-05.md`(未参与实现的子代理执行;四卡验收档均中——对照表逐行全量核对+判据绑定面抽查+削弱逐处检查+例外逐条核对,最窄复跑省略以本地闸回执代证、合回后远端 CI 现查为终局执行证据)。
|
||||||
|
- **总判定:通过**——四卡对照表 24 行全过;测试削弱 8 类逐处全落卡面申报集;直查受控例外 2 条全注记;闸回执八闸 exit 0、dirty_game=false。
|
||||||
|
- 审计备案两件(零实体影响,随收尾笔处置):①卡④ ui_input_probe case④b 断言换代(tex_seal 退役→seal_on 断言)的申报记录只在提交信息 13d6bfbb,卡面 §8 文本「本批不删改任何既有断言」未覆盖此换代——实体的申报依据=test-conventions §5.5(旧验证约束同生死)+卡面对 board_view:582 的同类「行为退役不属删断言」口径;本节即补记。②board_view.gd:77 头注悬空提及 `_palette.seal_tex`——已随收尾笔修剪。
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
# 迭代 52 验收审计报告(2026-11-05)
|
||||||
|
|
||||||
|
> 审计对象:分支 iter52 相对 master(53d2a8a2)的全部改动(53 文件;四卡①minesweeper_rules 公开面还债批/②孤儿函数清退批/③架构审查 presentation 层封装修复批/④封印印记法阵化批,四卡验收档均为中)。审计人=未参与实现的独立会话(test-conventions §8.7)。审计深度=四卡全量对照表逐行+判据绑定面抽查(每卡 ≥2 行)+测试削弱逐处+直查例外逐条;最窄测试复跑省略——执行证据=闸回执读数(game/tests/.gates/receipt.json,commit fbf126d1,八闸全 0),**合回后远端 CI 现查为终局执行证据**。全部零命中断言与计数均由审计人自跑 grep 取数,不采信报告转述。
|
||||||
|
|
||||||
|
## 总判定:通过
|
||||||
|
|
||||||
|
- 四卡对照表逐行核对全部通过(卡① 3 行/卡② 7 行/卡③ 7 行/卡④ 7 行,共 24 行;无缺漏行)。
|
||||||
|
- 测试削弱检查逐处核毕:测试/探针面被删改既有断言共 5 类 35 行,全部落在申报集内(逐处清单见第三节);无申报外删改。
|
||||||
|
- 直查受控例外逐条核毕(2 条,见第四节)。
|
||||||
|
- 两项备案缺漏(均零实体影响,不阻塞合并):④-1 ui_input_probe case④b 断言换代的申报记录未进卡面与实现报告(实体合规,欠账文档级);④-2 board_view.gd:77 悬空注释仍引已删成员 `_palette.seal_tex`。见第五节。
|
||||||
|
|
||||||
|
## 一、逐卡审计结论
|
||||||
|
|
||||||
|
### 卡① minesweeper_rules 公开面还债批(验收档:中)——通过
|
||||||
|
|
||||||
|
| # | 需求点 | 核对结果 | 结论 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 公开面收敛 21→20(S13 归绿) | diff 实核:`minesweeper_rules.gd:101` 定义改名+`:110` 内部调用点同步,函数体逐字未动(diff 仅两行签改)。审计自数:该文件非下划线 `^func [a-zA-Z]` = 20。`tools/gdstyle_baseline.txt` 零 minesweeper_rules 键(grep 零命中);审计自跑 `python tools/gdstyle_gate.py`:7 命中全在基线、基线外新违规 0、恶化 0 | 通过 |
|
||||||
|
| 2 | 行为零变化回归锚 | `minesweeper_rules_test.gd` 既有断言除改锚外零改动(diff 实核:断言消息串与期望表达式逐字未动);套件经回执 02 闸(exit 0)当轮执行 | 通过 |
|
||||||
|
| 3 | 测试直连改锚(受控例外) | 改锚 4 行(:56/:89/:93/:94)diff 逐行实核;审计自跑 `grep -rnE '\.safe_remaining\(' game/`(.gd+.tscn)=零命中;`_safe_remaining` 全仓恰 6 处(:101 定义+:110+测试 4 行)。卡面 §3.4 称「测试 5 处(:93 两处)」实测 4 处——实现报告已 L2 备案(计数差,改锚完整性与断言语义不受影响) | 通过(卡面计数差备案在案) |
|
||||||
|
|
||||||
|
- 真实入口核:行 1 判据面(S13 计数)由 gdstyle 闸单件读数承载、改前 NEW 红(21>20)与改后零键均落实现报告 T0/T2,改动点即被测点,无绕过。行 2/3 经 `tests/run_all.gd` 单元套件真实跑(回执 02 exit 0),改锚断言(:56 精确余量等式/:89-94 fx_reveal 递减)在套件内当轮执行。
|
||||||
|
- 尾缀:本卡零新增测试件,无尾缀义务;既有断言尾缀(〔wr4〕等)零触碰。
|
||||||
|
|
||||||
|
### 卡② 孤儿函数清退批(验收档:中)——通过
|
||||||
|
|
||||||
|
| # | 需求点 | 核对结果 | 结论 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | has_effect_on 退役 | diff 实核 effect_engine.gd 删 :203-212(`## 订阅查询面` 注释+函数);审计自跑六件名词边界 grep(game/ 全 .gd+.tscn)=六名全零命中 | 通过 |
|
||||||
|
| 2 | _bp_read_int 退役 | breakpoint_store.gd :211-219 删(注释+函数),diff 实核;grep 零残留 | 通过 |
|
||||||
|
| 3 | _find_token 退役(死包装) | adventure_runner.gd :250-252 删;grep 零残留;真件 `curio_deck.find_token` 在役(curio_stop.gd:107/:229 实查) | 通过 |
|
||||||
|
| 4 | has_open 退役 | modal_stack.gd :56-62 删;grep 零残留(`\bhas_open\b` 不误中 `has_open_excluding_tags`);后者 3 处在役调用实查 | 通过 |
|
||||||
|
| 5 | set_feedback_state 退役 | camp_scene_view.gd :88-92 删(无专属注释块,与卡面一致);grep 零残留 | 通过 |
|
||||||
|
| 6 | stop_resolved 退役 | curio_stop.gd :303-305 删;grep 零残留 | 通过 |
|
||||||
|
| 7 | 级联零新增 | 审计自跑级联计数全 ≥1 在役:bp_read 6/_bp_strategy 1/find_token(deck 件)定义+2 在役/has_open_excluding_tags 3/_apply_state 8(camp 件,剥定义)/_resolved 15/_triggers 8/`.dispatch(` 80;与实现报告计数一致。审计自写逐函数引用粗扫(六文件+minesweeper_rules,剥注释、引擎虚函数豁免)=零孤儿 | 通过 |
|
||||||
|
|
||||||
|
- 真实入口核:判据=静态零残留 grep+既有套件回归锚。六件名全仓零调用(含测试面零命中)=无测试直连可绕;回归面经回执 00/01/02/09 四闸(全 exit 0)真实执行。判据绑定面=「定义行消失+全仓零残留」为本批特有提交面(死函数无运行期可观测面——卡面已申报观测面局限)。
|
||||||
|
- 随删 3 处悬空注释修(modal_stack.gd:12/:67、camp_scene_view.gd:5):diff 实核=纯注释行,零断言零行为触面;实现报告「实现决定记录」已备案(超白名单呈报)。通过(备案在案)。
|
||||||
|
|
||||||
|
### 卡③ 架构审查 presentation 层封装修复批(验收档:中)——通过
|
||||||
|
|
||||||
|
对照表七行(R1–R7)逐行核对:
|
||||||
|
|
||||||
|
| # | 需求点 | 核对结果 | 结论 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| R1 | A1·战末弹层 | `presentation_encapsulation_sweep_test.gd` V1 组在盘:battle_end_overlay 非空前置+class `_EndOverlayState` 正锚+`st\._` 零命中+14 公开字段逐个正锚+类名文件外零消费者(全 game/ 递归扫描,排除宿主与自件)。审计实读类定义=14 字段无下划线 | 通过 |
|
||||||
|
| R2 | A1·调试浮窗 | 同 V1 组:debug_overlay 14 字段(`_DebugState` 定义实读)+`st\._` 零命中;TuneSim 入口探针经回执 03 闸绿 | 通过 |
|
||||||
|
| R3 | A1·关卡画面 | 同 V1 组:level_map_screen `_MapState` 14 字段实读+`_map\._` 零命中;system_test(回执 01 exit 0)+screen_flow_probe 走选路链 | 通过 |
|
||||||
|
| R4 | A2·站桩三件 | V2 组:standee_body `\bst\._|\bmo\._` 零命中(审计自跑)+`configure_identity/play_hp_flash/show_intent|hide_intent/portrait_sprite` 正锚在文;flash 归位实查(standee_vitals.gd:84 `play_hp_flash`+:22 `_hp_flash_tw` 自持;standee_body.gd:251 改调);渲染 golden 经回执 05 闸绿 | 通过 |
|
||||||
|
| R5 | A2·悬停子件 | V2 组:board_view `_hover_comp\._` 零命中(审计自跑)+七口正锚(rebind/reset/hover_at/detect_chord/refresh_after_paint/on_shell_mouse_exited/hover_pos——board_hover.gd 实读 7 公开方法,board_view 7 处改址 diff 实核);ui_input_probe 经回执 03 闸绿 | 通过 |
|
||||||
|
| R6 | B·组合根交接面 | V3 组:六文件 `root\._[a-zA-Z]` 与 `Main(Overlay|Adventure|Debug|Esc)Flow\._[a-zA-Z]` 零命中(审计自跑,前者六文件全零、后者全库唯一命中=camp_esc_overlay.gd:8 注释历史名提及,T1 底账已定性非私取面);main.gd 公开方法实测 32(31 实例+1 静态 build_adventure_params)=基线键 32;五分文件入口公开化实读(on_quit/open_settings/show_debug_levels/wire_adventure 等全公开);Callable 束消费正锚(ui_build `handlers["board_action"]`、adventure `handlers["adventure_finished"]` 实读在文);on_* 处理器保私有(探针 28 处 main._on 引用零改动实查);冒烟/系统测试经回执 00/01 闸绿 | 通过 |
|
||||||
|
| R7 | C·杂项公开面 | V4 组:`UiKit\._[a-zA-Z]` 全库 .gd 零命中(审计自跑,排除 ui_kit.gd 自身——其内亦零命中);cell_mark `_owner\._` 零命中+`_mask_set.is_valid()` 正锚;三工厂公开正锚(ui_kit.gd:364/:401/:874 实读,diff 证体逐字仅签改);ui_assembler:106/settings_overlay:88/:105/level_map_screen:70 四处改址 diff 实核;cell_mark `_init` 增第二参、board_cell_unit `_set_badge_mask` 交付实读(board_view 零触碰——diff 无 board_view 构造点改动) | 通过 |
|
||||||
|
|
||||||
|
- S13 对账(16 触件):审计自跑 `python tools/gdstyle_gate.py` 全绿(7 键全在册、基线外 0、恶化 0);基线键 7 条与实现报告对账表一致——main.gd=32(卡 §14 申报区间 28–32 内)、ui_kit=23(追补提交 00dbd4a7,卡 §3.2 误测 L2 备案+反哺点在案)、board_view 27/31 持平(贴顶零净增——diff 实证 board_view 仅 8 处改址零增面)。
|
||||||
|
- 探针/测试迁移 19 处逐条实核(ui_struct_probe 6、ui_click_probe 4、ui_tune_probe 3、system_test 3、probe_ui_util 1、screen_flow_probe 1、ui_probe 1、pacing_queue_test 1=18 调用点+退出链源码串 1 行 2 串):断言内容零改动、退出链断言意图不变(`_on_esc_quit` 处理器私名零改动实查);迁移名全仓零残留实查(grep 零命中);未迁移名(on_*/句柄成员/探针独占名)零触碰实查。
|
||||||
|
- 零行为变更证据链:回执 00/01/03/05/05b 全 exit 0+渲染 golden 零转红(05 闸绿);并行跑闸 CPU 互踩假红已定性(串行复跑双绿,报告 T3 记录)。
|
||||||
|
- 备注(措辞差,非缺漏):卡面 R6 行「14 件替换后当轮真实跑绿」——实际替换=「引用名字 ∩ 公开化名字」交集 19 处落 8 文件(卡 §4/§5 的替换判据即交集规则,14 件为引用面总体非替换件数);实体合规。
|
||||||
|
|
||||||
|
### 卡④ 封印印记法阵化批(验收档:中)——通过(两项备案缺漏见第五节)
|
||||||
|
|
||||||
|
| # | 需求点 | 核对结果 | 结论 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| R1 | 环径 82% 格边随格边连续 | `seal_mark_params_test.gd:_test_param_values` 在盘(SEAL_RING_FRAC=0.82 断言〔seal批 V1〕);ui_kit.gd:37 实读同值;T5 取证=board_shot_probe `_seal_evidence`(施印保底走真实 `settle_batch` 写口实读在文;环径读数硬判 `absf(ratio-0.82) <= 1.0/edge` 越带即红)——探针闸绿(回执 03)为执行证据;报告三关读数 38/46=0.8261 在带 | 通过 |
|
||||||
|
| R2 | 壁厚 11%/臂宽 15.6% 环径 | `_test_param_values` 两常量断言在盘〔seal批 V2〕;shader 实读 `wall = wall_frac * 2.0 * ring_r`、`arm = arm_frac * 2.0 * ring_r`(:34-35)——两常量直接进 SDF,帧量主证=环径(口径换代落实现报告「判据实现注记 3」) | 通过(换代已申报) |
|
||||||
|
| R3 | 光圈只在环外不出格 | `_test_shader_uniforms` 夹取行断言在盘〔seal批 V3〕;shader :45 实读 `float rc = min(r, cell_px * 0.5);`;层件 `seal_mark_layer.gd` 1:1 全幅 draw_rect(越格构造上不可能——:42 实读);隔离验证截图三件在 artwork/(seal_iso_28/32/46.png 实存,在途不入 git 合卡面 T2);框差读数留档不作硬判(换代理由=邻格砖纹噪声实证 L3 0.008 vs 0.094,落「判据实现注记 1」) | 通过(换代已申报) |
|
||||||
|
| R4 | 迷雾态隐藏 | `_test_fog_gate` 在盘〔seal批 V4〕(fog_state=1 不可见/0 可见/撤 seal_on 即撤);board_cell_unit.gd 实读:fog_state setter 联动 `_sync_seal_layer`+`_sync_seal_layer` 末行 `setup(edge, fog_state == 0)`;run_all.gd manifest 注册(expect 0)经回执 02 闸绿 | 通过 |
|
||||||
|
| R5 | 印记在小人之下 | 层树构造面实读(子件挂 CellUnit、hero 精灵 BoardView 层后挂);T5 硬判读数在 `_seal_evidence`:英雄格中心像素 ≤0.05 即红(「R5 层序翻失」),探针闸绿兜底;报告三关读数非黑 | 通过 |
|
||||||
|
| R6 | 蜡封仍用贴图 | 审计自跑 `grep -rn "seal_mark.png" game/ --include='*.gd'`=恰 1 处(battle_end_overlay.gd:85,战末蜡封 `_seal_img` 实读未动) | 通过 |
|
||||||
|
| R7 | 零新增色 | 审计自跑 shader `grep Color8`=零命中;色源单点实读(layer :33 `mark_col = UiKit.SEAL_BLACK` 注入,光圈只改 alpha——shader :49);色板闸经回执 05b exit 0 | 通过 |
|
||||||
|
|
||||||
|
- 贴图退役核(审计动作六自跑取数):`TILE_SEAL_MARK|seal_tex` 全 game/ .gd = 3 处——battle_end_overlay.gd:85-87(局部变量,合法在役)+board_view.gd:77(**注释行**,见第五节缺漏 2);tile_palette 面零残留(TILE_SEAL_MARK 常量、seal_tex 成员与装载 diff 实核已删);board_view :539-541 槽位维护改 `u.seal_on` 下发、:582 字形回退分支退役(diff 实核);cell_mark_overlay tex_seal 成员/setter/绘制块删除+头注改写(diff 实核)。
|
||||||
|
- 真实入口核:R1-R3/R7 真实入口=`BoardCellUnit.edge → SealMarkLayer.setup() → ShaderMaterial` 参数链(layer :26-33 逐参注入实读);R4 入口=fog_state 属性写面;R5/R1 帧量入口=真实 BoardView 实例化+settle_batch 施印(保底三段实读:novice 驱动在案→邻接施印→免邻接旗标,全拒即 quit(1))——无绕过改动点的直构面。R2/R3 的帧量判据换代与 R7 色数闸均在实现报告申报。
|
||||||
|
- 能力行核对:game/tests/README.md:122「棋盘封印印记呈现」代表用例 `seal_mark_params_test.gd:_test_param_values`+`_test_fog_gate` 与落地函数逐字一致(实读)——零回表,卡③④能力行其余全「既有」零新增与实现一致。
|
||||||
|
- 超清单事项合规核:SEAL_HALO_FRAC 第六常量新立=卡 §7-T1/T3 内部矛盾(五常量 vs 七参数注入)的补源,值=§8.2 条款值逐字非改值;代拍板记录「超清单事项呈报」第 1 条+反哺点第 4 条呈报用户裁决——呈报路径在案,合规。
|
||||||
|
|
||||||
|
## 二、判据绑定面抽查(每卡 ≥2 行)
|
||||||
|
|
||||||
|
- 卡①行 1(S13 计数):断言面=gdstyle 对被改文件读数,改名即被测点——绑定面恰为本批特有提交面;审计自跑闸件复证零键归绿。
|
||||||
|
- 卡②行 1-7(零残留+级联计数):判据为静态 grep——审计全部自跑取数(六名零残留、级联八组计数、零孤儿粗扫),与实现报告计数逐项一致(_apply_state 报告记 8、审计含定义 9,剥定义后同值)。
|
||||||
|
- 卡③ R4/R6(V2/V3 正锚+零命中):sweep 断言钉在「源码私取模式零命中+新公开面正锚」——审计自跑同口径 grep 全零;正锚对应真实公开面(方法定义实读在位)。当轮执行证据=回执 02(sweep 件在 manifest 注册实读)。
|
||||||
|
- 卡④ R1/R5(环径读数+英雄格中心非黑):两判据均硬判落 `_seal_evidence`(越带/读黑即 `_problems.append`→探针退出红),绑定面=封印记数像素与层序像素——本批特有可观测提交面;当轮执行证据=回执 03。
|
||||||
|
|
||||||
|
## 三、测试削弱检查(逐处;审计自跑全 diff 删除行清单对申报集)
|
||||||
|
|
||||||
|
测试/探针面被删改的既有断言与引用,逐处核对:
|
||||||
|
|
||||||
|
| # | 删改处 | 内容 | 申报依据 | 判定 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | minesweeper_rules_test.gd :56/:89/:93/:94 | 4 行调用表达式改锚 `_safe_remaining`,断言消息与期望值逐字未动(diff 实核) | 卡① §8 对照表行 3+测试削弱申报节 | 申报内,通过 |
|
||||||
|
| 2 | 探针/测试 8 件 17 处 `main._x` 引用(open_save_select 7/seed_value 3/open_settings 2/begin_session 2/status_data 1/start_debug_levels 1/gp_summary_text 1) | 引用形态迁移,断言内容零改动(逐文件 diff 实核) | 卡③ §8 削弱申报第 1 条+实现报告 T1 精确清单 | 申报内,通过 |
|
||||||
|
| 3 | ui_struct_probe.gd :144-146 退出链源码串 2 串("MainEscFlow.on_quit(self)"/"root.quit_game()") | 源码串随公开化换代;同函数 `_on_esc_quit` 私名断言零改动(diff 实核) | 卡③ §8 削弱申报补充(v1.1)第 2 条 | 申报内,通过 |
|
||||||
|
| 4 | ui_struct_probe.gd :366-370 `ls._map._runner` 3 处 | A1 字段公开化交集改址,断言内容零改动 | 卡③ T2 底账(实现报告)+交集判据 | 申报内,通过 |
|
||||||
|
| 5 | stage_background_test.gd :164-165/theme_projection_test.gd :626/:651 | `_beams_rect`/`_gradient_base` 旧私名引用随三工厂公开化换代(stage 为源码 contains 断言随名换代,意图不变) | 提交 a8b0b1b2(里程碑闸 02 域抓出,L2 备案「T1 底账漏 enumeration」)+审计任务书申报集 | 申报内(记录载体=提交信息),通过 |
|
||||||
|
| 6 | ui_input_probe.gd case④b(:264-268 删旧纹理槽双分支断言+注释,换 seal_on 落位单断言) | 旧断言只验证已退役的 tex_seal 机制——test-conventions §5.5 换代批旧验证约束同生死(强制摘除,留即假绿源);新断言同入口(case④b 封印落位)同强度(核心落位硬判) | test-conventions §5.5(法条强制)+提交 13d6bfbb;卡④ §8 削弱申报文本与实现报告未列(欠账,见第五节缺漏 1) | 实体合规;申报记录缺口列缺漏 |
|
||||||
|
| 7 | board_view.gd :582 字形回退分支、:539-541 槽位维护、tile_palette 两槽、cell_mark 绘制块 | 生产行为退役(回退对象消失),非删断言 | 卡④ §8 削弱申报(明示「行为退役不属删断言」)+§7-T4 | 申报内,通过 |
|
||||||
|
| 8 | settlement_wiring_snapshot_test.gd | LF 归位处置——审计实核该文件不在 master...HEAD diff(`git diff --name-only | grep settlement` 零命中)=零内容差异,EOL 往返态未进分支;断言零触碰 | 实现报告「环境红定性 1」 | 申报内,通过 |
|
||||||
|
|
||||||
|
- 申报外删改清点:全 diff 测试/探针面删除行清单(35 行)已逐行对号(上表 1-8),无第 9 类;run_all.gd 仅增 2 行 manifest 注册(sweep+params 两新件),零删改;.tscn/.tres/data 零改动;新增行零 `randomize()`/自建 RNG(红线实核)。
|
||||||
|
- 削弱判定总:无断言删除性削弱、无阈值放宽换绿(两处换代的旧判据各有等强度新判据或三面承载,且均系法条/机制强制)、无扫描面缩小(sweep 四组全带非空前置)、无换下层直调(改锚一处为卡①申报的受控例外)。
|
||||||
|
|
||||||
|
## 四、内部字段直查受控例外核对(逐条)
|
||||||
|
|
||||||
|
| 例外 | 直查行 | 理由注记核对 | 判定 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 卡①对照表行 3(测试改锚精确余量) | minesweeper_rules_test.gd :56/:89/:93-94 `_rules._safe_remaining()` | 对照表行 3 原文含「**受控例外注记**:精确余量无公开可观测面可钉(`clear_map_cleared` 仅 bool),理由随本表申报」——注记在对照表行内 | 通过 |
|
||||||
|
| 卡④ `_test_fog_gate` 直查 `_seal_layer.visible` | seal_mark_params_test.gd :45/:47/:49/:51(`u._seal_layer` 可见性与空判) | 卡面 §8 R4 判据列自身 prescribe「封印子件 `visible == false`」(fog_state/seal_on 均公开属性,唯一内部面=子件 visible);理由注记落测试件 :40-41 头注(「子件可见性无公开可观测面,卡面 R4 断言即 prescribe」) | 通过(注记位置备注:对照表行本体未带「受控例外」标签,卡面判据列即 prescribe+测试件注记承载) |
|
||||||
|
|
||||||
|
## 五、备案缺漏(零实体影响,不阻塞合并;处置建议随条)
|
||||||
|
|
||||||
|
1. **卡④ ui_input_probe case④b 断言换代的申报记录缺口**——旧纹理槽双分支断言(有盘纹理在槽/缺盘字形回退)随 tex_seal 机制退役被替换为 seal_on 落位断言。实体面合规:test-conventions §5.5 强制同生死摘除(留即假绿源)、新断言同入口同强度、执行绿(回执 03)。缺口在记录面:卡④ §8 削弱申报文本仍写「本批不删改任何既有断言」,与该换代字面冲突(§3 现状既列贴图退役,该换代为必然后果——卡面文本自身欠严密);实现报告亦未列此换代,申报记录只在提交信息 13d6bfbb。处置建议:本报告进实现报告收尾节(卡④ §13 义务)即为补记;后续同类批卡面削弱申报节应把「换代批旧验证约束同生死」列为预设条款。
|
||||||
|
2. **board_view.gd:77 悬空注释**——注释仍写「探针直读面零改动:读 `_palette.seal_tex`…」,所指成员已在本批删除,探针引用面亦已随批迁移,注释陈述已失实。卡②同族悬空注释修了 3 处并备案,卡④面这处未清未申报。零行为零断言影响(判据面=资产引用/常量别名/死槽,注释不在其列);grep 级判据不受污染(`TILE_SEAL_MARK|seal_tex` 命中仅此注释+battle_end_overlay 合法局部变量)。处置建议:并入下批最小工程改动或修复批顺手剥(一行注释)。
|
||||||
|
3. (观察,非缺漏)camp_esc_overlay.gd:8 注释提及 `MainEscFlow._on_return_to_menu` 旧私名——T1 底账已定性「历史名提及非私取面」,与缺漏 2 同族但已在案申报,不再列。
|
||||||
|
|
||||||
|
## 六、grep 取数附录(审计自跑取数,命令+结果)
|
||||||
|
|
||||||
|
以下均在 D:\code\g-plan2-iter52 执行(grep 含 .gd;另注处含 .tscn):
|
||||||
|
|
||||||
|
1. 六孤儿名零残留(.gd+.tscn,`\b名\b` 词边界):`has_effect_on`/`_bp_read_int`/`_find_token`/`has_open`/`set_feedback_state`/`stop_resolved` → 全部零命中。
|
||||||
|
2. 级联计数:`bp_read(` 剥定义=6;`_bp_strategy` 剥定义=1;`find_token`=curio_deck.gd:51 定义+curio_stop.gd:107/:229;`has_open_excluding_tags(` 剥定义=3;camp_scene_view `_apply_state(`=9 行(含定义);curio_stop `_resolved`=15;effect_engine `_triggers`=8;`.dispatch(`=80;curio_stop `_pending`=42 行。六文件+minesweeper_rules 逐函数引用粗扫(剥注释、引擎虚函数豁免)=零孤儿。
|
||||||
|
3. safe_remaining:`\.safe_remaining\(`(.gd+.tscn)=0;`_safe_remaining` 全仓=6(:101/:110/:56/:89/:93/:94)。
|
||||||
|
4. 卡③封装主张:六 B 文件 `root\._[a-zA-Z]`=0;standee_body `\bst\._|\bmo\._`=0;board_view `_hover_comp\._`=0;`UiKit\._[a-zA-Z]`(game/ 全 .gd,排除 ui_kit.gd)=0(ui_kit.gd 内亦 0);A1 三文件 `_map\._[a-zA-Z]`/`\bst\._[a-zA-Z]`=0;game/presentation 全目录 `\._[a-zA-Z]`(剔 self._ 与注释行)=0 行。
|
||||||
|
5. main.gd 计数:`^func [a-zA-Z]`=31+`static func build_adventure_params`=1,合计 32=基线键 32;ui_kit `^(static )?func [a-zA-Z]`=23=基线键 23。
|
||||||
|
6. 卡④贴图退役:`seal_mark.png`(game/ .gd)=恰 1(battle_end_overlay.gd:85);`TILE_SEAL_MARK|seal_tex`=3(battle_end_overlay.gd:85-87 局部变量合法在役+board_view.gd:77 注释);shader `Color8`=0;seal_mark 命中文件=7(cell_unit/board_view/seal_mark_layer/battle_end_overlay/cell_mark_overlay/run_all/params_test——前五为改名件与新件本体,后二为测试注册与守门件)。
|
||||||
|
7. 基线:`grep minesweeper_rules tools/gdstyle_baseline.txt`=0;基线 diff 仅 +2 键(main.gd=32、ui_kit=23);`python tools/gdstyle_gate.py`=「命中 7 条,基线内 7 条,基线外新违规 0 条,较登记值恶化 0 条/ok」。
|
||||||
|
8. diff 面:`git diff master...HEAD --name-only` 中 .tscn/.tres/data/ 与 settlement 测试件=零命中;53 文件合计;新增行 `randomize(|RandomNumberGenerator.new`=零命中。
|
||||||
|
|
||||||
|
## 七、闸回执核对(执行证据)
|
||||||
|
|
||||||
|
- 回执:game/tests/.gates/receipt.json——commit=fbf126d1(=分支最后一笔代码+产出物提交)、domain=code、scope=full、dirty_game=false、八闸(冒烟/系统/单元与集成/场景探针/渲染/色板/静态扫描/熵增)exit 全 0、all_green=true、changed_vs_baseline=[]、inherited_red=[]。
|
||||||
|
- 回执 commit 与分支尖(b4b1ee09=并入 master 的合并提交)差一笔;其间差异经逐文件实核全部为 master 侧内容(AGENTS.md/design 文档/闸名去编号批的 baseline.json 键名与 run_all.gd、system_test.gd、smoke_boot.gd 注释行/tools 脚本措辞)——**零断言面、零生产行为面差异**,回执绿态覆盖分支尖游戏码状态。回执内闸名沿用旧编号命名、合并带来的 baseline.json 已换代无编号键名——命名差属 master 侧闸名批时序,非回执内容问题。
|
||||||
|
- 中档不复跑最窄测试:本报告执行读数全部引回执;**合回后远端 CI 现查为终局执行证据**(tools/ci_check.sh 现查合回提交,判据=run 落定后的绿终局且跑闸步真跑过;零触发批不作绿证)。
|
||||||
@@ -8,5 +8,7 @@
|
|||||||
game/core/adventure_runner.gd|quality/max-class-variables = 23
|
game/core/adventure_runner.gd|quality/max-class-variables = 23
|
||||||
game/core/level_runner.gd|quality/max-class-variables = 30
|
game/core/level_runner.gd|quality/max-class-variables = 30
|
||||||
game/core/level_runner.gd|quality/max-public-methods = 33
|
game/core/level_runner.gd|quality/max-public-methods = 33
|
||||||
|
game/presentation/main.gd|quality/max-public-methods = 32
|
||||||
|
game/presentation/views/ui_kit.gd|quality/max-public-methods = 23
|
||||||
game/presentation/views/board_view.gd|quality/max-class-variables = 31
|
game/presentation/views/board_view.gd|quality/max-class-variables = 31
|
||||||
game/presentation/views/board_view.gd|quality/max-public-methods = 27
|
game/presentation/views/board_view.gd|quality/max-public-methods = 27
|
||||||
Reference in new issue
Block a user