iter44-卡1:卡①(组合根注册面批): ui_registry+三域容器建件·main.gd 49→15·全消费面改址main.ui.*·四闸主证行为零变化
This commit is contained in:
1 parent
14054d9dfb
commit
d2b36e59cb
41 files changed
+1073
-1070
No files matched your search
+76
-264
@@ -1,7 +1,8 @@
|
||||
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
## 组合根:唯一的模式流转与 core↔view 接线处(垂直切片验证:线性第一关承载元进度循环)。
|
||||
## db.hero 运行期只读,加成经 runner.set_hero_override / debug_session 生效值入战斗。
|
||||
## 禁链式穿透 settlement.*(相位读取只走 presentation_snapshot);模态开合只走 _open_modal/_close_modal。
|
||||
## 禁链式穿透 settlement.*(相位读取只走 presentation_snapshot);模态开合只走 ui.modals.flow(注册面编排口)。
|
||||
## 界面句柄与层清单在 ui 注册面(ui_registry.gd)——屏壳/战区/模态三域句柄与 LAYER_CONTRACT 单点宿主。
|
||||
## 局态全在 run_scope.gd 节点,禁在屏/视图侧持有局态引用;autoload 节点路径常量单点在 AUTOLOAD_PATH_*。
|
||||
extends Control
|
||||
|
||||
@@ -15,10 +16,8 @@ const AUTOLOAD_PATH_META := "/root/MetaProgression"
|
||||
|
||||
const UiAssembler := preload("res://presentation/ui_assembler.gd")
|
||||
const Narrator := preload("res://presentation/battle_narrator.gd")
|
||||
const ModalStack := preload("res://presentation/modal_stack.gd")
|
||||
const TuneSimController := preload("res://presentation/tune_sim_controller.gd")
|
||||
const DebugSessionScript := preload("res://presentation/debug_session.gd")
|
||||
const RowPacer := preload("res://presentation/row_pacer.gd") # 结算行排播泵
|
||||
const TreasureInteractController := preload("res://presentation/treasure_interact_controller.gd") # 秘宝两步交互
|
||||
const CurioInteractController := preload("res://presentation/curio_interact_controller.gd") # 三选一与替换子交互
|
||||
const CampShopPresenter := preload("res://presentation/camp_shop_presenter.gd") # 营地/商店投影
|
||||
@@ -31,33 +30,6 @@ const MenuScreenScene := preload("res://presentation/scenes/menu_screen.tscn")
|
||||
const CampScreenScene := preload("res://presentation/scenes/camp_screen.tscn")
|
||||
const AdventureScreenScene := preload("res://presentation/scenes/adventure_screen.tscn")
|
||||
|
||||
# ==================== 视觉层合同(唯一事实源——树序=登记序=z 序;改序只改此表) ====================
|
||||
# kind: shell=屏壳容器(成员随壳不占独立树位;level_screen 例外另占登记位)/modal=模态层(入登记册,
|
||||
# tags 随登记)/state=全屏态(占树位不入登记册)/node=非视觉节点(占树位不入登记册)。
|
||||
# host=宿住屏壳(树序随宿主、登记序按本合同);shell=模态成员的屏壳(成员与屏壳同槽:屏壳占该树位、
|
||||
# 成员占该登记位)。落位=_apply_layer_contract(全仓唯一层序落位点,add_child 之后统一排序+登记)。
|
||||
const LAYER_CONTRACT: Array[Dictionary] = [
|
||||
{"key": "adventure_screen", "kind": "shell"},
|
||||
{"key": "menu_screen", "kind": "shell"},
|
||||
{"key": "row_pacer", "kind": "node"},
|
||||
{"key": "legend_overlay", "kind": "modal", "tags": []},
|
||||
{"key": "node_overlay", "kind": "modal", "tags": []},
|
||||
{"key": "level_screen", "kind": "modal", "tags": [ModalStack.TAG_SCREEN_STATE], "host": "adventure_screen"},
|
||||
{"key": "curio_overlay", "kind": "modal", "tags": []},
|
||||
{"key": "end_overlay", "kind": "modal", "tags": []},
|
||||
{"key": "shop_overlay", "kind": "modal", "tags": []},
|
||||
{"key": "camp_overlay", "kind": "modal", "tags": [], "shell": "camp_screen"},
|
||||
{"key": "settings_overlay", "kind": "modal", "tags": []},
|
||||
{"key": "status_panel", "kind": "modal", "tags": []},
|
||||
{"key": "career_overlay", "kind": "modal", "tags": []},
|
||||
{"key": "save_select_overlay", "kind": "modal", "tags": []}, # 选档界面(营地交互重做卡③——登记生涯同档)
|
||||
{"key": "inter_overlay", "kind": "state", "tags": []},
|
||||
{"key": "confirm_dialog", "kind": "modal", "tags": []},
|
||||
{"key": "debug_overlay", "kind": "modal", "tags": [ModalStack.TAG_NON_LOCKING]},
|
||||
{"key": "debug_badge", "kind": "float"}, # 调试入口全局浮层——末位=最顶绘制序;
|
||||
# float 类不注册 ModalStack(open() 遮挡记账只隐藏登记层)→ 任何 UI 打开都不遮它
|
||||
]
|
||||
|
||||
var db
|
||||
var run_scope = null # 会话状态承载(run_scope.gd;_ready 即建闲时态,永非 null)
|
||||
# SaveManager/MetaProgression 升格 autoload——成员名保留为「autoload 读视图」
|
||||
@@ -71,99 +43,24 @@ var meta: MetaProgressionCore:
|
||||
return get_node(AUTOLOAD_PATH_META)
|
||||
var logger = null # 试玩日志器(JSONL 持久化 + 卡死诊断转储——呈现层组件)
|
||||
var _debug_entry := false # 调试会话门控(缺省 false=发布态:角标恒隐、浮窗无 UI 开启口;沿革查 git log)
|
||||
var _seed_edit: LineEdit
|
||||
var confirm_dialog: ConfirmDialog # 通用确认弹窗(消费方编排——现行消费方=选档删档确认;新冒险互斥确认已随卡②主菜单撤出,归卡④大门)
|
||||
var ui: UiRegistry # 界面注册面(ui_registry.gd——界面句柄/层序合同/模态编排句柄的单点宿主)
|
||||
var _confirm_consumer := "" # 确认弹窗消费方状态量(契约 3 编排——open 前设、分派后清)
|
||||
var _confirm_consumer_slot := 0 # 消费方附随槽号(delete_slot 消费方专用)
|
||||
var curio_overlay: CurioPickOverlay # 提升三选一覆盖层(level-clear.md v2 选择面承载;奖励节点共用)
|
||||
var _start_overlay: Control
|
||||
var _end_overlay: BattleEndOverlay
|
||||
var _inter_overlay: Control
|
||||
var _inter_label: Label
|
||||
var level_screen: LevelMapScreen # 关卡画面句柄(指向 adventure_screen.level_screen)
|
||||
var _battle_root: Control # 战斗屏宿主句柄(指向 adventure_screen.battle_root)
|
||||
|
||||
# 调试模式编排(单场/连续两层——状态机与战斗生命周期归 debug_session.gd,本类只接线与出 UI)
|
||||
var _debug = null
|
||||
|
||||
# 视图(views/)——battle.md 三区(节点链进度
|
||||
# 由关卡画面本体选路覆盖层承载)
|
||||
var stage: BattleStageView # B 区(含 log_view 明细带)——句柄指向 adventure_screen
|
||||
var log_view: BattleLogView
|
||||
var info_panel: HeroInfoPanelView # C 区(攻击/AC 数据框+两预留区)
|
||||
var board_zone: BoardZoneView # D 区(含 ap_bar/board_view/toast/fx)
|
||||
var board_view: BoardView # 探针兼容别名(= board_zone.board_view)
|
||||
var ap_bar: ApBarView # 探针兼容别名(= board_zone.ap_bar)
|
||||
var settlement_fx: SettlementFxView # 结算演出覆盖层(跨区弹道/光带——A–D 之上、模态之下)
|
||||
|
||||
# 三屏壳实例(屏成员经本类句柄暴露;探针挂载假设 main.X 一级路径)
|
||||
var _menu_screen = null # MenuScreen(开始菜单屏壳)
|
||||
var _camp_screen = null # CampScreen(营地屏壳)
|
||||
var _adventure_screen = null # AdventureScreen(冒险屏壳——内含关卡地图/战斗两容器)
|
||||
|
||||
# 拆件后的组合根持有面(职责见各类头注;装配见 _build_ui)
|
||||
var _row_pacer = null # 结算行排播泵(row_pacer.gd——本类只入队/排空/读队列)
|
||||
var _treasure_ui = null # 秘宝两步交互(treasure_interact_controller.gd——本类只接线与转发意图)
|
||||
var _bonus = null # 三选一与替换子交互(curio_interact_controller.gd——本类只接线与回调注入)
|
||||
var _camp_pres = null # 营地/商店投影(camp_shop_presenter.gd——本类只接线、探针缝保缝转发)
|
||||
|
||||
# 排播队列只读委托面(探针/测试读 main._row_queue——与 RowPacer 队列共享同一 Array 引用)
|
||||
var _row_queue: Array[Variant]:
|
||||
get:
|
||||
return _row_pacer.pending_rows()
|
||||
|
||||
# 模态 overlay(z 序 = 登记序;pattern 6 层级纪律)
|
||||
var legend_overlay: LegendOverlay
|
||||
var node_overlay: NodeOverlay
|
||||
var shop_overlay: ShopOverlay # 商店覆盖层(商店房节点兑付呈现)
|
||||
var camp_overlay: CampOverlay # 营地覆盖层句柄(指向 camp_screen.camp_overlay)
|
||||
var settings_store # 系统级设置独立存储(音量/全屏/减动效)
|
||||
var settings_overlay: SettingsOverlay # 设置覆盖层(最小设置面)
|
||||
var status_panel: StatusPanel # 局内状态面板·只读(钥石余额+营地三柜台进度查看;登记设置层同档)
|
||||
var career_overlay: CareerOverlay # 生涯页·只读全屏页(跨局汇总六类九项;登记营地同档〔设置层旁、确认弹窗之前〕)
|
||||
var save_select_overlay: SaveSelectOverlay # 选档界面·3 存档位(新档/进档/删档——营地交互重做卡③;登记生涯同档)
|
||||
var debug_overlay: DebugOverlay # 调试浮窗(种子/数值调整/批量模拟/两层调试入口收一)
|
||||
var debug_badge: Button # 调试浮层入口角标(UI 最顶层浮层——LAYER_CONTRACT 末位 float 类,任何 UI 不遮挡)
|
||||
|
||||
var _modal_flow = null # 模态编排纯逻辑类(modal_flow.gd——依赖仅 ModalStack+查询 Callable)
|
||||
var _modals = null # 模态层级状态机(=_modal_flow.stack——探针 _list 登记序断言缝保留)
|
||||
var _tune_sim = null # 调试浮窗批量模拟控制器(tune_sim_controller.gd)
|
||||
|
||||
# 结算框挂起态属性化(探针/冒烟直读写接缝语义零变化——读=armed,写=arm/disarm;计时器随会话住
|
||||
# run_scope.settlement_stop_timer)
|
||||
var _settlement_stop_pending: bool:
|
||||
get:
|
||||
return run_scope.settlement_stop_timer.is_armed() if run_scope != null else false
|
||||
set(v):
|
||||
if run_scope == null:
|
||||
return
|
||||
if v:
|
||||
run_scope.settlement_stop_timer.arm()
|
||||
else:
|
||||
run_scope.settlement_stop_timer.disarm()
|
||||
|
||||
# 锁期点击重放(v3.1):延迟一帧重入唯一动作通道——此刻队列空锁已解,按普通动作受理
|
||||
#(局面在演播期无变化:逻辑先行、演播只是回放——点击语义保真;_row_queue=RowPacer 委托面,
|
||||
# 排播泵本体在 row_pacer.gd)。
|
||||
var _deferred_modal: Control: # 演播后开窗挂起只读视图(t17_defer_probe 挂起态断言缝;本体归 _modal_flow)
|
||||
get:
|
||||
return _modal_flow._deferred if _modal_flow != null else null
|
||||
|
||||
|
||||
# 演播后排窗(伤害过程演完才切结算窗口):排播队列在播=挂起,演播完边沿
|
||||
# (_on_pump_ended 派发)再开——旧路径 _open_modal 前置 flush 会把击杀轮的伤害/死亡演出
|
||||
# 同帧倒掉(「直接跳战斗胜利」缺陷本体)。队列空=立即开(行为同旧路径)。
|
||||
func _open_modal_after_playback(m: Control) -> void:
|
||||
_modal_flow.open_after_playback(m) # 演播后排窗挂起编排归 ModalFlow
|
||||
|
||||
|
||||
# 演播完边沿派发(row_pacer.pump_ended 注入口——先开挂起 modal,后锁期点击重放):
|
||||
func _on_pump_ended() -> void:
|
||||
_modal_flow.pump_ended() # 派发编排归 ModalFlow(重放经注入 Callable 回本类)
|
||||
|
||||
|
||||
func _replay_locked_click() -> void:
|
||||
if run_scope.locked_click.is_empty() or not _row_queue.is_empty():
|
||||
if run_scope.locked_click.is_empty() or not ui.screens.row_pacer.pending_rows().is_empty():
|
||||
return
|
||||
var click: Dictionary[Variant, Variant] = run_scope.locked_click
|
||||
run_scope.locked_click = {}
|
||||
@@ -173,7 +70,7 @@ func _replay_locked_click() -> void:
|
||||
# 会话生命周期:_ready 建闲时态(永非 null——全组合根零空判责),
|
||||
# 开局/续玩/调试两层各建新会话,旧会话整节点 queue_free()(帧末回收;新节点先挂树无真空窗)。
|
||||
func _begin_session(adventure_session: bool) -> void:
|
||||
_row_pacer.flush() # 会话更替即清队(待播行不住局态——机制保证,不靠时序约定)
|
||||
ui.screens.row_pacer.flush() # 会话更替即清队(待播行不住局态——机制保证,不靠时序约定)
|
||||
if run_scope != null:
|
||||
run_scope.queue_free()
|
||||
run_scope = RunScope.new()
|
||||
@@ -194,10 +91,11 @@ func _ready() -> void:
|
||||
settings_store = SettingsStore.new()
|
||||
settings_store.load_settings()
|
||||
settings_store.apply()
|
||||
ui = UiRegistry.new() # 注册面先于装配建(_build_ui 八步向容器登记——装配时序零变化)
|
||||
_build_ui()
|
||||
_begin_session(false) # 闲时会话(gp_ledger 等探针注入面自 _ready 起恒在——ui_probe 合成段时序)
|
||||
_start_overlay.visible = true
|
||||
debug_badge.visible = _debug_entry # 浮层角标可见性须门控落定后赋值(构建/连接在 _build_ui);_debug_entry 缺省 false=发布态恒隐
|
||||
ui.screens.start_overlay.visible = true
|
||||
ui.screens.debug_badge.visible = _debug_entry # 浮层角标可见性须门控落定后赋值(构建/连接在 _build_ui);_debug_entry 缺省 false=发布态恒隐
|
||||
# boot 菜单优先——启动不自动开浮窗(开始屏不得被调试面板盖住);
|
||||
# 调试入口=UI 最顶层全局浮层角标(LAYER_CONTRACT 末位 float 类,任何 UI 不遮挡)
|
||||
|
||||
@@ -206,94 +104,13 @@ func _ready() -> void:
|
||||
|
||||
func _build_ui() -> void:
|
||||
MainUiBuild.build(self)
|
||||
debug_overlay.diagnose_requested.connect(_on_diagnose_pressed) # 诊断转储入口
|
||||
ui.modals.debug_overlay.diagnose_requested.connect(_on_diagnose_pressed) # 诊断转储入口
|
||||
|
||||
|
||||
func _fatal_screen(msg: String) -> void:
|
||||
MainUiBuild.fatal_screen(self, msg)
|
||||
|
||||
|
||||
# ==================== 模态 overlay 层级管理(pattern 6 / 缺陷⑤——状态机归 modal_stack.gd) ====================
|
||||
|
||||
func _register_modal(m: Control, tags: Array = []) -> void:
|
||||
# 撑满宿主(Control 默认锚 = 0×0——全屏变暗层与居中布局整体失效;route 选路层预览截图实证后
|
||||
# 统一收口:六个模态同病,探针经信号直发绕过真实点击从未暴露。anchors_and_offsets 而非 anchors
|
||||
# ——后者会把控件重置回最小内容尺寸,ui_assembler 头注同款纪律)
|
||||
m.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
_modal_flow.register(m, tags) # 排除组随层登记(non_locking=调试浮窗/screen_state=关卡地图屏)
|
||||
|
||||
|
||||
# 合同层寻址(key→节点;纯查表不含层序语义——层序唯一事实源=LAYER_CONTRACT)
|
||||
func _layer_node(key: String) -> Node:
|
||||
match key:
|
||||
"adventure_screen": return _adventure_screen
|
||||
"menu_screen": return _menu_screen
|
||||
"row_pacer": return _row_pacer
|
||||
"legend_overlay": return legend_overlay
|
||||
"node_overlay": return node_overlay
|
||||
"level_screen": return level_screen
|
||||
"curio_overlay": return curio_overlay
|
||||
"end_overlay": return _end_overlay
|
||||
"shop_overlay": return shop_overlay
|
||||
"camp_screen": return _camp_screen
|
||||
"camp_overlay": return camp_overlay
|
||||
"settings_overlay": return settings_overlay
|
||||
"status_panel": return status_panel
|
||||
"career_overlay": return career_overlay
|
||||
"save_select_overlay": return save_select_overlay
|
||||
"inter_overlay": return _inter_overlay
|
||||
"confirm_dialog": return confirm_dialog
|
||||
"debug_overlay": return debug_overlay
|
||||
"debug_badge": return debug_badge
|
||||
return null
|
||||
|
||||
|
||||
# 合同装配(_build_ui 尾调用):按 LAYER_CONTRACT 序统一落位——直接子层 move_child 到合同槽、
|
||||
# 模态层按合同序登记;宿住层(host)树序随宿主只登记;成员层(shell)与屏壳同槽(屏壳占树位、成员占登记位)。
|
||||
# 本函数是全仓唯一层序落位点(move_child 单口)——改层序只改 LAYER_CONTRACT。
|
||||
func _apply_layer_contract() -> void:
|
||||
var slot := 0
|
||||
for entry: Dictionary in LAYER_CONTRACT:
|
||||
var tags: Array[Variant] = entry.get("tags", [])
|
||||
if entry.has("shell"):
|
||||
var shell: Node = _layer_node(String(entry["shell"]))
|
||||
var member: Node = _layer_node(String(entry["key"]))
|
||||
if shell != null:
|
||||
move_child(shell, slot)
|
||||
slot += 1
|
||||
if member != null:
|
||||
_register_modal(member as Control, tags)
|
||||
else:
|
||||
push_error("[合同装配] 层缺失: %s" % String(entry["key"]))
|
||||
continue
|
||||
var node: Node = _layer_node(String(entry["key"]))
|
||||
if node == null:
|
||||
push_error("[合同装配] 层缺失: %s" % String(entry["key"]))
|
||||
continue
|
||||
if entry.has("host"):
|
||||
_register_modal(node as Control, tags)
|
||||
continue
|
||||
move_child(node, slot)
|
||||
slot += 1
|
||||
if String(entry["kind"]) == "modal":
|
||||
_register_modal(node as Control, tags)
|
||||
|
||||
|
||||
func _open_modal(m: Control) -> void:
|
||||
_modal_flow.open(m) # 挂起兜底/排播排空/遮挡记账/开侧同步编排归 ModalFlow
|
||||
|
||||
func _close_modal(m: Control) -> void:
|
||||
_modal_flow.close(m) # 关闭恢复+关侧同步归 ModalFlow(同上)
|
||||
|
||||
func _on_modal_closed(m: Control) -> void:
|
||||
_close_modal(m)
|
||||
|
||||
|
||||
func _input_locked() -> bool:
|
||||
# 模态/非战斗期棋盘输入锁(判据编排归 ModalFlow.locks_input:互斥域随层登记
|
||||
# [non_locking=调试浮窗]+ 三例外经查询 Callable 注入;本函数留探针缝)
|
||||
return _modal_flow.locks_input()
|
||||
|
||||
# ==================== 冒险模式入口(唯一试玩入口)====================
|
||||
|
||||
func _start_adventure_from_menu() -> void:
|
||||
@@ -301,7 +118,7 @@ func _start_adventure_from_menu() -> void:
|
||||
# 弹窗本体与两分支逻辑归卡④大门承接)。本函数为探针直调中间态保留(mn10——冒险段探针
|
||||
# 直调位点逐个登记实现报告「已知中间态」;卡④到位后由大门两分支换代)。无激活态写盘拒绝
|
||||
# 由卡① sv3 承接(结算不落盘)。
|
||||
_start_overlay.visible = false
|
||||
ui.screens.start_overlay.visible = false
|
||||
_start_adventure()
|
||||
|
||||
|
||||
@@ -309,16 +126,16 @@ func _start_adventure_from_menu() -> void:
|
||||
#(确认才删、取消只关窗——裁决 3)。"new_adventure" 消费方已随卡② 主菜单确认链摘除退役
|
||||
#(mn6/V5——主菜单零确认残留),分派机制保留(卡④ 到位接入第三消费方不返工)。
|
||||
func _on_confirm_accepted() -> void:
|
||||
_close_modal(confirm_dialog) # 模态栈单口
|
||||
ui.modals.flow.close(ui.modals.confirm_dialog) # 模态栈单口
|
||||
match _confirm_consumer:
|
||||
"delete_slot":
|
||||
save_manager.slots.delete_slot(_confirm_consumer_slot)
|
||||
save_select_overlay.open_save_select(HudPresenter.save_select_data(save_manager)) # 就地刷新(该槽回空态)
|
||||
ui.modals.save_select_overlay.open_save_select(HudPresenter.save_select_data(save_manager)) # 就地刷新(该槽回空态)
|
||||
_confirm_consumer = ""
|
||||
|
||||
|
||||
func _on_confirm_declined() -> void:
|
||||
_close_modal(confirm_dialog) # 只关窗(取消无状态变更——裁决 3:取消不删);关侧恢复归 ModalFlow
|
||||
ui.modals.flow.close(ui.modals.confirm_dialog) # 只关窗(取消无状态变更——裁决 3:取消不删);关侧恢复归 ModalFlow
|
||||
_confirm_consumer = ""
|
||||
|
||||
|
||||
@@ -334,16 +151,16 @@ func _resume_from_menu() -> void:
|
||||
if not save_manager.has_breakpoint():
|
||||
return
|
||||
var bp: Dictionary[Variant, Variant] = save_manager.breakpoint_snapshot()
|
||||
_close_modal(debug_overlay) # 开冒险路径显式关浮窗(续玩同口径)
|
||||
_start_overlay.visible = false
|
||||
ui.modals.flow.close(ui.modals.debug_overlay) # 开冒险路径显式关浮窗(续玩同口径)
|
||||
ui.screens.start_overlay.visible = false
|
||||
_begin_session(true)
|
||||
_wire_adventure()
|
||||
run_scope.level_active = true
|
||||
_sync_status_entry() # 续玩恢复点亮状态面板入口角标
|
||||
level_screen.set_abandon_available(true)
|
||||
log_view.clear()
|
||||
ui.modals.level_screen.set_abandon_available(true)
|
||||
ui.battle.log_view.clear()
|
||||
logger.start_session(int(bp.get("master_seed", 0)))
|
||||
run_scope.adventure.set_hero_override(debug_overlay.atk_pct(), debug_overlay.hp_pct())
|
||||
run_scope.adventure.set_hero_override(ui.modals.debug_overlay.atk_pct(), ui.modals.debug_overlay.hp_pct())
|
||||
# 同调三键随续玩下传(build_adventure_params 统一构造,与开新局同源同口径)
|
||||
if not run_scope.adventure.resume_adventure(bp, build_adventure_params(save_manager, meta,
|
||||
{"treasure_unlocked": _treasure_ui.unlocked_set()})):
|
||||
@@ -379,16 +196,16 @@ static func build_adventure_params(save_manager_ref: SaveManagerCore, meta_ref:
|
||||
# 冒险模式(三关连探——AdventureRunner 编排;转发信号签名与 runner 一致,接线照原样对接;
|
||||
# 信号连接只在组合根)
|
||||
func _start_adventure() -> void:
|
||||
_close_modal(debug_overlay) # 开冒险路径显式关浮窗(调试浮窗默认开态下开局不带窗;对局中经角标再开)
|
||||
ui.modals.flow.close(ui.modals.debug_overlay) # 开冒险路径显式关浮窗(调试浮窗默认开态下开局不带窗;对局中经角标再开)
|
||||
_begin_session(true)
|
||||
_wire_adventure()
|
||||
run_scope.level_active = true
|
||||
_sync_status_entry() # 进对局点亮状态面板入口角标
|
||||
level_screen.set_abandon_available(true) # 放弃入口挂选路停点(天然非战斗期)
|
||||
log_view.clear()
|
||||
ui.modals.level_screen.set_abandon_available(true) # 放弃入口挂选路停点(天然非战斗期)
|
||||
ui.battle.log_view.clear()
|
||||
var seed_val := _seed_value()
|
||||
logger.start_session(seed_val)
|
||||
run_scope.adventure.set_hero_override(debug_overlay.atk_pct(), debug_overlay.hp_pct())
|
||||
run_scope.adventure.set_hero_override(ui.modals.debug_overlay.atk_pct(), ui.modals.debug_overlay.hp_pct())
|
||||
# 永久强化注入:冒险开始参数面——meta 现算 override 显式传参(全零 = 白板)
|
||||
# 开局参数面(同调三键同源构造——确定性承载=固定种子+参数档,首局教学图由种子域三分判定给 42)
|
||||
if not run_scope.adventure.start_adventure(seed_val, build_adventure_params(save_manager, meta,
|
||||
@@ -435,33 +252,33 @@ func _on_inter_next_pressed() -> void:
|
||||
func _show_board_fx_for_node(node_type: String = "") -> void:
|
||||
# Boss 遭遇变体:紫赤影子爬棋盘一次性占位演出(§2.6)
|
||||
if node_type == "boss":
|
||||
board_zone.fx.play_boss_shadow()
|
||||
ui.battle.board_zone.fx.play_boss_shadow()
|
||||
|
||||
|
||||
func _on_battle_finished(payload: Dictionary) -> void:
|
||||
# 仅调试模式接线(冒险的关卡结束归 AdventureRunner._on_level_finished——大奖励/冒险终局分派)
|
||||
var result: String = String(payload.get("result", ""))
|
||||
_sync_settlement_visuals() # → 全关(battle_over 反馈面)
|
||||
HudPresenter.battle_end_feedback(stage, 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)
|
||||
match String(decision.outcome):
|
||||
"next_layer":
|
||||
_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)]
|
||||
_inter_overlay.visible = true
|
||||
ui.screens.inter_overlay.visible = true
|
||||
_refresh_presentations()
|
||||
return
|
||||
"level_end":
|
||||
_end_overlay.open_victory(Narrator.battle_end_text("victory", true),
|
||||
"返回", board_view.get_global_rect(), _end_victory_opts(payload))
|
||||
ui.modals.end_overlay.open_victory(Narrator.battle_end_text("victory", true),
|
||||
"返回", ui.battle.board_zone.board_view.get_global_rect(), _end_victory_opts(payload))
|
||||
"standalone_end":
|
||||
if result == "victory":
|
||||
_end_overlay.open_victory(Narrator.battle_end_text("victory", false),
|
||||
"回到遭遇选择", board_view.get_global_rect(), _end_victory_opts(payload))
|
||||
ui.modals.end_overlay.open_victory(Narrator.battle_end_text("victory", false),
|
||||
"回到遭遇选择", ui.battle.board_zone.board_view.get_global_rect(), _end_victory_opts(payload))
|
||||
else:
|
||||
_end_overlay.open_defeat(Narrator.battle_end_text("defeat", false),
|
||||
"返回", board_view.get_global_rect())
|
||||
_open_modal_after_playback(_end_overlay)
|
||||
ui.modals.end_overlay.open_defeat(Narrator.battle_end_text("defeat", false),
|
||||
"返回", ui.battle.board_zone.board_view.get_global_rect())
|
||||
ui.modals.flow.open_after_playback(ui.modals.end_overlay)
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
@@ -499,22 +316,17 @@ func _on_step_row(row: Dictionary) -> void:
|
||||
# 清图奖励可感知反馈(挖完全图须有奖励感——clear_blast 兑付对敌伤害
|
||||
# 零可见,toast 桥接归组合根呈现层;零兑付(未生效)不弹安静留明细带)
|
||||
if String(row.get("source_class", "")) == "clear_reward" and String(row.get("type", "")) != "reward_ineffective":
|
||||
board_zone.toast.show_toast("清图奖励:%s" % String(row.get("display", "")).replace("(清图奖励)", ""), "info")
|
||||
ui.battle.board_zone.toast.show_toast("清图奖励:%s" % String(row.get("display", "")).replace("(清图奖励)", ""), "info")
|
||||
# 排播入口:减动效=延迟归零同帧直落(行呈现不跳过);常态入队按段阶梯播放
|
||||
if UiKit.motion_scale < 1.0:
|
||||
_row_pacer.consume_now(row)
|
||||
ui.screens.row_pacer.consume_now(row)
|
||||
return
|
||||
_row_pacer.enqueue(row)
|
||||
ui.screens.row_pacer.enqueue(row)
|
||||
|
||||
|
||||
# 段间延迟取数面(减动效双态断言用——pacing_queue_test 直读;委托 row_pacer 同名面)
|
||||
func pace_delay_for(prev_seg: String, next_seg: String) -> float:
|
||||
return _row_pacer.pace_delay_for(prev_seg, next_seg)
|
||||
|
||||
|
||||
# 强制排空(模态开启前调用——明细回看/停点覆盖层/终局面所见明细带恒完整;pacing_queue_test 直读)
|
||||
func _flush_row_queue() -> void:
|
||||
_row_pacer.flush()
|
||||
return ui.screens.row_pacer.pace_delay_for(prev_seg, next_seg)
|
||||
|
||||
|
||||
func _on_round_started(ri: int) -> void:
|
||||
@@ -522,10 +334,10 @@ func _on_round_started(ri: int) -> void:
|
||||
#(view 内判减动效=静态化变体)。减动效快路=分隔行同帧直落(不跳过——consume_now 复用
|
||||
# _consume_row 轮首分隔行分支)。
|
||||
if UiKit.motion_scale < 1.0:
|
||||
_row_pacer.consume_now({"__round_line": ri})
|
||||
ui.screens.row_pacer.consume_now({"__round_line": ri})
|
||||
else:
|
||||
_row_pacer.enqueue({"__round_line": ri})
|
||||
settlement_fx.play_round_banner(ri)
|
||||
ui.screens.row_pacer.enqueue({"__round_line": ri})
|
||||
ui.battle.settlement_fx.play_round_banner(ri)
|
||||
# 秘宝呈现同步:每战首轮装配链
|
||||
# 显式重算〔🔴 契约复原语义:下一战装配链重算即含「未装配→写 0」复原〕。
|
||||
# 挂点时序依据:round_started 首轮发射位在 begin_battle 尾(attunement 注入之后)。
|
||||
@@ -534,7 +346,7 @@ func _on_round_started(ri: int) -> void:
|
||||
_sync_treasure_glow()
|
||||
# 巢穴预告呈现(装板报数量读数口消费:≥0=本战装配命中,toast 一次性提示)
|
||||
if run_scope.settlement != null and int(run_scope.settlement.nest_preview_count) >= 0:
|
||||
board_zone.toast.show_toast("巢穴预告——本板危险格共 %d 个" % int(run_scope.settlement.nest_preview_count), "info")
|
||||
ui.battle.board_zone.toast.show_toast("巢穴预告——本板危险格共 %d 个" % int(run_scope.settlement.nest_preview_count), "info")
|
||||
# 开战横幅——整图地形变异预告:首轮快照 board_variants
|
||||
# 非空才发射(Boss 图恒带一型=替换制;普通图空快照零发射);轮横幅下方叠行,view 内判减动效。
|
||||
if ri == 1 and run_scope.settlement != null:
|
||||
@@ -542,7 +354,7 @@ func _on_round_started(ri: int) -> void:
|
||||
if not bvs.is_empty():
|
||||
var vlines: Array[String] = HudPresenter.board_variant_lines(db, bvs)
|
||||
if not vlines.is_empty():
|
||||
settlement_fx.play_board_variant_banner("地形变异 · " + " · ".join(vlines))
|
||||
ui.battle.settlement_fx.play_board_variant_banner("地形变异 · " + " · ".join(vlines))
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
@@ -552,19 +364,19 @@ func _on_board_changed() -> void:
|
||||
run_scope.settlement = run_scope.runner.current_battle()
|
||||
if run_scope.settlement == null:
|
||||
return
|
||||
board_view.rebuild(run_scope.settlement.minesweeper.current_board(), run_scope.settlement.minesweeper)
|
||||
ui.battle.board_zone.board_view.rebuild(run_scope.settlement.minesweeper.current_board(), run_scope.settlement.minesweeper)
|
||||
_check_board_hints()
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
# 秘宝视野呈现桥:阔视野带 light_radius_bonus
|
||||
# 装配参数合计显式写给 board_view.set_fog_glow_bonus(装配=半径 8+4 / 未装配=复原 0),写入即 setter
|
||||
# 装配参数合计显式写给 ui.battle.board_zone.board_view.set_fog_glow_bonus(装配=半径 8+4 / 未装配=复原 0),写入即 setter
|
||||
# 内 refresh 全板重算雾态。调用点=每战首轮装配链(_on_round_started ri==1)——纯呈现边界 🔴 契约 2:
|
||||
# 只写呈现态参数,minesweeper 结算零触碰;off 态(未装配)写 0=缺省基线。
|
||||
func _sync_treasure_glow() -> void:
|
||||
if run_scope.settlement == null or board_view == null:
|
||||
if run_scope.settlement == null or ui.battle.board_zone.board_view == null:
|
||||
return
|
||||
board_view.set_fog_glow_bonus(run_scope.settlement.attune_param_sum("light_radius_bonus"))
|
||||
ui.battle.board_zone.board_view.set_fog_glow_bonus(run_scope.settlement.attune_param_sum("light_radius_bonus"))
|
||||
|
||||
|
||||
# ---- 一次性非模态提示(每 run 一次——pattern 10)与诚实提示 ----
|
||||
@@ -575,10 +387,10 @@ func _check_board_hints() -> void:
|
||||
return
|
||||
# 零合法板(棋盘生成 EC5 降级)诚实提示——非静默(toast,非模态)
|
||||
if board.illegal_product:
|
||||
board_zone.toast.show_toast("本板为零合法板降级产物——出图器已尽力,数据面诚实告知", "warn")
|
||||
ui.battle.board_zone.toast.show_toast("本板为零合法板降级产物——出图器已尽力,数据面诚实告知", "warn")
|
||||
# 接受最优降级(有合法板但无一达标)——降级标记独立于非法产物标记,同走诚实告知
|
||||
elif board.degraded_product:
|
||||
board_zone.toast.show_toast("本板为接受最优降级产物(未达可推理率及格线)——数据面诚实告知", "warn")
|
||||
ui.battle.board_zone.toast.show_toast("本板为接受最优降级产物(未达可推理率及格线)——数据面诚实告知", "warn")
|
||||
|
||||
|
||||
func _on_hover_forbidden(_cell: Vector2i) -> void:
|
||||
@@ -594,7 +406,7 @@ func _on_chord_attempted(_cell: Vector2i) -> void:
|
||||
func _show_hint(text: String, hint_id: String) -> void:
|
||||
run_scope.hints_shown[hint_id] = true
|
||||
logger.log_ux("ux_hint_shown", {"hint_id": hint_id})
|
||||
board_zone.toast.show_toast(text, "info")
|
||||
ui.battle.board_zone.toast.show_toast(text, "info")
|
||||
|
||||
|
||||
# ---- 节点覆盖层"继续"(奖励/恢复点兑付确认)与节点图选路覆盖层 ----
|
||||
@@ -706,15 +518,15 @@ func _on_wallet_changed(event: String, gp: int, extra: Dictionary)-> void:
|
||||
|
||||
func _on_board_action(cell: Vector2i, kind: String) -> void:
|
||||
# 玩家动作 → 核心写调用的唯一通道(模态/无战斗拒绝在此收口)
|
||||
if _input_locked():
|
||||
if ui.modals.flow.locks_input():
|
||||
return
|
||||
# 结算演播期棋盘冻结(v3 口径——不可点/不可移/不可挖):
|
||||
# 锁面=排播队列活跃(纯队列判据;排播泵尾迹窗口不可作演播中标志——见 row_pacer._process 注)。
|
||||
# 队列排空即解锁、无状态残留;HUD 按钮不在锁面(停手/明细回看各自通路,开启前
|
||||
# _flush_row_queue 自行排空)。
|
||||
# 开层前排空钩子(flow.flush_rows——模态开启前明细带恒完整)。
|
||||
# **点击不丢弃**(v3.1——「卡死」体感根因):锁期点击缓存最后一次,演播完边沿
|
||||
# (_process 泵 _was_pumping 分支)自动重放——玩家操作零丢失、体感=「演播一停动作就生效」。
|
||||
if not _row_queue.is_empty():
|
||||
if not ui.screens.row_pacer.pending_rows().is_empty():
|
||||
run_scope.locked_click = {"cell": cell, "kind": kind}
|
||||
return
|
||||
# 秘宝选中态劫持(两步交互第二步):点格=使用目标拾取,不落挖格;
|
||||
@@ -734,22 +546,22 @@ func _on_board_action(cell: Vector2i, kind: String) -> void:
|
||||
# settle_batch 内部同步走完 结算→战斗结束→关卡推进(事件同步发射)——关卡终局时 settlement 已被
|
||||
# runner 置空,清图演出判定须先判 settlement(重入隐患守卫)
|
||||
if accepted and kind == "dig" and run_scope.settlement != null and run_scope.settlement.minesweeper.current_board() != null and run_scope.settlement.minesweeper.clear_map_cleared():
|
||||
board_zone.fx.play_clear_burst()
|
||||
ui.battle.board_zone.fx.play_clear_burst()
|
||||
if accepted and kind == "dig" and run_scope.settlement != null and run_scope.settlement.minesweeper != null:
|
||||
# 挖掘演出:挥铲三帧 + 角色弹跳——触发=格子点开那一刻
|
||||
#(settle_batch 同步受理即状态已变,动画纯表现与 refresh 同拍零竞态;
|
||||
# 挖掘不移动英雄,出手方向 = 目标格−英雄格,圆心=英雄持握手位)
|
||||
var hero_cell: Vector2i = run_scope.settlement.minesweeper.hero_pos()
|
||||
board_zone.fx.play_shovel_swing(board_view.hero_hand_point(), cell - hero_cell, board_view.hero_sprite_scale())
|
||||
board_view.play_hero_dig_bounce()
|
||||
ui.battle.board_zone.fx.play_shovel_swing(ui.battle.board_zone.board_view.hero_hand_point(), cell - hero_cell, ui.battle.board_zone.board_view.hero_sprite_scale())
|
||||
ui.battle.board_zone.board_view.play_hero_dig_bounce()
|
||||
elif accepted and kind == "move":
|
||||
board_view.notify_hero_move() # 原地移动(目标=当前格幂等受理)帧闪回执——refresh diff 前置告知
|
||||
board_view.refresh()
|
||||
ui.battle.board_zone.board_view.notify_hero_move() # 原地移动(目标=当前格幂等受理)帧闪回执——refresh diff 前置告知
|
||||
ui.battle.board_zone.board_view.refresh()
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
func _on_stop_pressed() -> void:
|
||||
if _input_locked():
|
||||
if ui.modals.flow.locks_input():
|
||||
return
|
||||
# stop 经批次提交(排雷玩法 D1×6①——不直调 行动经济)
|
||||
if run_scope.settlement == null:
|
||||
@@ -758,15 +570,15 @@ func _on_stop_pressed() -> void:
|
||||
logger.log_action("stop", Vector2i(-1, -1), not outcomes.is_empty() and bool(outcomes[0].accepted))
|
||||
if not outcomes.is_empty() and String(outcomes[0].get("outcome", "")) == "voided":
|
||||
# voided ≠ 拒绝——独立文案(pattern 1:防静默改判读感欺骗)
|
||||
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"})
|
||||
board_view.refresh()
|
||||
ui.battle.board_zone.board_view.refresh()
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
func _on_refresh_confirmed() -> void:
|
||||
# 弃图刷新(挖掘期 Active 当场换图继续挖——D4;RAP 按门槛扣费 · 旧板封印作废,每轮上限读表)
|
||||
if _input_locked():
|
||||
if ui.modals.flow.locks_input():
|
||||
return
|
||||
var ok: bool = false
|
||||
if run_scope.level_active and run_scope.runner != null:
|
||||
@@ -776,7 +588,7 @@ func _on_refresh_confirmed() -> void:
|
||||
logger.log_action("refresh", Vector2i(-1, -1), ok)
|
||||
if ok:
|
||||
logger.log_ux("ux_refresh_attempt", {"result": "accepted", "round_refresh_index": _refresh_used_snapshot()})
|
||||
board_zone.toast.show_toast("RAP−%d · 旧板封印作废——新图已就位,AP 保留继续挖" % int(db.run.action_economy.rap_refresh_cost), "gold")
|
||||
ui.battle.board_zone.toast.show_toast("RAP−%d · 旧板封印作废——新图已就位,AP 保留继续挖" % int(db.run.action_economy.rap_refresh_cost), "gold")
|
||||
else:
|
||||
# 资源面/上限拒绝(EC13 合法拒绝可见;行动经济 无载荷——客户端按上下文推断)
|
||||
var rap: int = int(run_scope.settlement.presentation_snapshot().get("rap", 0)) if run_scope.settlement != null else 0
|
||||
@@ -784,11 +596,11 @@ func _on_refresh_confirmed() -> void:
|
||||
var result := "rejected_rap" if rap < cost else "rejected_cap"
|
||||
logger.log_ux("ux_refresh_attempt", {"result": result, "round_refresh_index": _refresh_used_snapshot() + 1})
|
||||
if result == "rejected_rap":
|
||||
board_zone.toast.show_toast("RAP 不足 · 还差 %d 点(弃图刷新需 8)" % (cost - rap), "warn")
|
||||
ap_bar.pulse_rap()
|
||||
ui.battle.board_zone.toast.show_toast("RAP 不足 · 还差 %d 点(弃图刷新需 8)" % (cost - rap), "warn")
|
||||
ui.battle.board_zone.ap_bar.pulse_rap()
|
||||
else:
|
||||
board_zone.toast.show_toast("本轮刷新次数已用完(每轮 2 次)", "warn")
|
||||
board_view.refresh()
|
||||
ui.battle.board_zone.toast.show_toast("本轮刷新次数已用完(每轮 2 次)", "warn")
|
||||
ui.battle.board_zone.board_view.refresh()
|
||||
_refresh_presentations()
|
||||
|
||||
|
||||
@@ -798,9 +610,9 @@ func _handle_outcome_feedback(outcome: Dictionary) -> void:
|
||||
return
|
||||
logger.log_ux("ux_reject", {"source": String(outcome.get("reject_reason", "")),
|
||||
"sub_reason": String(outcome.get("sub_reason", ""))})
|
||||
board_zone.toast.show_toast(HudPresenter.outcome_text(outcome), "warn")
|
||||
ui.battle.board_zone.toast.show_toast(HudPresenter.outcome_text(outcome), "warn")
|
||||
if String(outcome.get("reject_reason", "")) == "resource_face":
|
||||
ap_bar.pulse_ap()
|
||||
ui.battle.board_zone.ap_bar.pulse_ap()
|
||||
|
||||
|
||||
# ==================== 全屏 States 状态机(挖掘/结算/窗口/终局)====================
|
||||
@@ -816,7 +628,7 @@ func _refresh_used_snapshot() -> int:
|
||||
func _refresh_presentations() -> void:
|
||||
# 每个核心信号/写调用返回后的全量重查装配(更新触发注记——无推送信号,命令式重查)
|
||||
var refresh_remaining: int = maxi(0, int(db.run.action_economy.refresh_cap_per_round) - _refresh_used_snapshot())
|
||||
HudPresenter.refresh(stage, info_panel, 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 区秘宝槽重查(试炼镐积点进度随挖格刷新悬停浮窗)
|
||||
_sync_settlement_visuals()
|
||||
|
||||
@@ -825,9 +637,9 @@ func _sync_settlement_visuals() -> void:
|
||||
# 结算阶段(round_end → 下一轮):D 区去饱和+金橙偏移锁输入(明度不变)+ 明细带展开 84px
|
||||
var settling := _is_settling()
|
||||
if settling and not run_scope.was_settling:
|
||||
settlement_fx.play_round_sweep(board_view.get_global_rect()) # 结算轮光带——时序敏感演出触发,例外留在组合根
|
||||
ui.battle.settlement_fx.play_round_sweep(ui.battle.board_zone.board_view.get_global_rect()) # 结算轮光带——时序敏感演出触发,例外留在组合根
|
||||
run_scope.was_settling = settling
|
||||
HudPresenter.sync_settlement_visuals(stage, board_view, log_view, settling,
|
||||
HudPresenter.sync_settlement_visuals(ui.battle.stage, ui.battle.board_zone.board_view, ui.battle.log_view, settling,
|
||||
HudPresenter.phase_text(run_scope.settlement, run_scope.runner, run_scope.boss_active, db))
|
||||
|
||||
|
||||
@@ -836,13 +648,13 @@ func _is_settling() -> bool:
|
||||
# 判据若只跟逻辑态,演播期棋盘会提前恢复可挖观感=「没意识到在结算演出」感知缺口根源;
|
||||
# 演播期维持去饱和+禁挖光(结算中语义),放完自然回挖掘认知。判据=纯队列(排播泵尾迹
|
||||
# 窗口不可作演播中标志——row_pacer._process 注)。battle 收尾演播例外:
|
||||
# overlay 开启即 _flush_row_queue 排空,视觉随队列空同步交接结算框。
|
||||
# overlay 开启经 flow.flush_rows 钩子排空,视觉随队列空同步交接结算框。
|
||||
# 相位取数经 presentation_snapshot 成文面——禁 settlement.action_economy 链式穿透)。
|
||||
if run_scope.settlement == null or not run_scope.settlement.is_battle_live():
|
||||
return not _row_queue.is_empty()
|
||||
return not ui.screens.row_pacer.pending_rows().is_empty()
|
||||
if String(run_scope.settlement.presentation_snapshot().get("phase", "")) == ActionEconomy.PHASE_WAITING:
|
||||
return true
|
||||
return not _row_queue.is_empty()
|
||||
return not ui.screens.row_pacer.pending_rows().is_empty()
|
||||
|
||||
|
||||
# 相位行 —— 承接体见 HudPresenter.phase_text(caller 直接改引)
|
||||
@@ -908,8 +720,8 @@ func _seed_value() -> int:
|
||||
# 重放模板 0 即在此种子下标定〕;置位 true=教学局已收束的非首局走 ③ 随机);
|
||||
# ③非首局空/非法框=引擎全局熵 randi()(Godot 4 启动自播种子,headless 同;不走 rng_service
|
||||
# 封闭流、禁 randomize()/自建 RNG——组合根建种子属引擎熵豁免面,不进玩法 RNG 消费)
|
||||
if _seed_edit.text.is_valid_int():
|
||||
return int(_seed_edit.text)
|
||||
if ui.modals.debug_overlay.seed_edit.text.is_valid_int():
|
||||
return int(ui.modals.debug_overlay.seed_edit.text)
|
||||
if save_manager.meta_state.career_state().first_adventure_done:
|
||||
return randi() # rng-seed-exempt(非首局空框引擎熵——组合根建种子不进玩法 RNG 消费,static_scan S1/S2 标记豁免)
|
||||
return 42
|
||||
Reference in new issue
Block a user