T5 core/data结构段: config_db拆R1解析器+跨表校验器两类(门面38消费方签名零变化)+三选一双渠道参数化(_apply_bonus_pick共享/守卫收AuxItems.can_accept/替换子交互保守分轨注记)+rest回血单点+行主序键单点+魔法数结构化(bonus_candidate_count默认3/出生区9/数量域常量——值零改动)+level_runner Phase enum(外部读面零变化)+表访问收口(aux走访问器/行集直扫三处收口/删clamped_pool壳与死变量erow/_minesweeper_ref包装)+tune_sim反向依赖解除(构造注入缺省null兜底)+类型注批量;闸=冲烟636/0+run_all 15套+探针全绿+MC对拍200局逐位一致

This commit is contained in:
DKChan committed 2026-10-02 08:46:12 +08:00
1 parent 59f0c70ca3
commit d1460327a4
21 files changed
+491 -342

No files matched your search

+45 -34
View File
@@ -61,16 +61,19 @@ var bonus := {"atk": 0, "max_hp": 0, "armor_class": 0} # 统一冒险加算区
var base_override := {"atk": 0, "max_hp": 0, "armor_class": 0} # 永久强化 flat 注入(元进度实现批——冒险模式 = AdventureRunner 共享字典经 start_level_external 注入;单关测试模式 = 私有全零)
var _shop_purchased := {} # product_id → 已购档数(现价重算输入;冒险开始清零)
# 协作对象私有(E1/E3 封装收口 2026-09-13):settlement 读取经 current_battle() 成文出口
var _settlement = null # 当前战斗编排器(关卡结束置 null)
var aux_inventory = null # 魔法道具 关卡域库存(迭代 7 T3——AuxItems;跨战斗延续,
var _settlement: BattleOrchestrator = null # 当前战斗编排器(关卡结束置 null)
var aux_inventory: AuxItems = null # 魔法道具 关卡域库存(迭代 7 T3——AuxItems;跨战斗延续,
var _aux_unlocked := {} # aux 解锁门控集(迭代 7 T5——拍板③甲;空集=零投放)
# 关卡末清空+快照计数入 level_finished 载荷)
var hero_atk_pct := 0 # 测试面板覆盖值(切片专用)
var hero_hp_pct := 0
var _running := false
var level_result := "" # "" / "victory" / "defeat"
var _awaiting_choice := false # 选路态(兑付确认后、pick 前为零自动推进的可见停点)
# ---- 关卡相位轴(2026-10-02 修复批——布尔旗收拢:_running/_awaiting_choice 两旗 → 显式 Phase enum;
# 对齐 行动经济 Phase 先例(action_economy.gd:内部 enum + 守卫换算,外部读面契约零变化)——
# level_result:String 与 awaiting_choice() 被 AdventureRunner/呈现层消费的语义逐字不变)----
enum Phase { IDLE, RUNNING, AWAITING_CHOICE, ENDED }
var _phase: int = Phase.IDLE
var level_result := "" # "" / "victory" / "defeat"(外部契约面——语义零变化)
var _candidates: Array[Dictionary] = [] # 当前选路候选(节点引用数组)
var visited: Array[Dictionary] = [] # 已兑付/到达节点序列(呈现层图条数据源;含当前节点)
var _graph_mode := false # 图形态缓存(行集任一节点带 next;单链 = false)
@@ -81,6 +84,11 @@ func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void:
rng = rng_ref
# 进行中谓词(原 _running 语义——RUNNING 或 AWAITING_CHOICE 两相位合计;内部守卫专用)
func _is_running() -> bool:
return _phase == Phase.RUNNING or _phase == Phase.AWAITING_CHOICE
# ---- 测试面板覆盖(模拟天赋树属性提升——仅测试用,正式侧归 元进度;经 encounter 传入战斗)----
func set_hero_override(atk_pct: int, hp_pct: int) -> void:
@@ -135,7 +143,7 @@ func start_level(level_index: int, seed_val: int, base_override_in: Dictionary =
return false
node_index = -1
level_result = ""
_awaiting_choice = false
_phase = Phase.IDLE
_candidates = []
visited = []
_graph_mode = false
@@ -152,11 +160,11 @@ func start_level(level_index: int, seed_val: int, base_override_in: Dictionary =
hero_hp = effective_max_hp()
rng.new_adventure(seed_val) # 关卡起点 = 冒险起点(切片口径;跨关接续归 冒险结构)
level_row.assign(_resolve_template_row(row, template_pick)) # 池解析在播种后(node_map 抽签须已播种——EC7)
_running = true
_phase = Phase.RUNNING
var entry := _entry_node()
if entry.is_empty():
push_error("[关卡节点地图] 入口节点缺失(无入边唯一节点——图合法性校验应已拦截)")
_running = false
_phase = Phase.ENDED
return false
return _enter_node(entry)
@@ -189,7 +197,7 @@ func start_level_external(level_index: int, ledger: Dictionary, bonus_ref: Dicti
level_row.assign(_resolve_template_row(row, template_pick))
node_index = -1
level_result = ""
_awaiting_choice = false
_phase = Phase.IDLE
_candidates = []
visited = []
_graph_mode = false
@@ -197,7 +205,7 @@ func start_level_external(level_index: int, ledger: Dictionary, bonus_ref: Dicti
if node.has("next"):
_graph_mode = true
break
_running = true
_phase = Phase.RUNNING
# 断点续玩路径(迭代 8 卡①——defer_entry 之外的第三种停点入口):直接重建到停点所在节点,
# 零 RNG 消耗(模板已随 template_pick 强制、节点状态纯重建不 _enter_node——当场战斗从头打)。
# resume_state = {"node_id": int(-1 = 入口停点), "visited_ids": Array[int]};空字典 = 既有路径逐位不变。
@@ -207,10 +215,10 @@ func start_level_external(level_index: int, ledger: Dictionary, bonus_ref: Dicti
var entry := _entry_node()
if entry.is_empty():
push_error("[关卡节点地图] 入口节点缺失(无入边唯一节点——图合法性校验应已拦截)")
_running = false
_phase = Phase.ENDED
return false
if defer_entry:
_awaiting_choice = true # 入口停点(node_index 保持 -1——进节点前无 current_node)
_phase = Phase.AWAITING_CHOICE # 入口停点(node_index 保持 -1——进节点前无 current_node)
_candidates = [entry]
return true
return _enter_node(entry)
@@ -219,7 +227,7 @@ func start_level_external(level_index: int, ledger: Dictionary, bonus_ref: Dicti
# 入口停点呈现(停点前移批 2026-09-23——defer_entry=true 的第二步):发出入口候选供呈现层弹
# 选路层;非停点态(缺省自动进入路径)拒绝。零 RNG 消耗——呈现与行进取号解耦。
func present_entry_choice() -> bool:
if not _running or not _awaiting_choice or _candidates.is_empty() or node_index != -1:
if _phase != Phase.AWAITING_CHOICE or _candidates.is_empty() or node_index != -1:
push_error("[关卡节点地图] present_entry_choice 拒绝——非入口停点态(defer_entry 未开或已 pick)")
return false
choices_presented.emit(_candidates)
@@ -237,9 +245,9 @@ func _restore_to_stop(node_id: int, visited_ids: Array) -> bool:
var entry := _entry_node()
if entry.is_empty():
push_error("[关卡节点地图] 断点恢复失败——入口节点缺失")
_running = false
_phase = Phase.ENDED
return false
_awaiting_choice = true
_phase = Phase.AWAITING_CHOICE
_candidates = [entry]
return true
var stop: Dictionary = {}
@@ -249,7 +257,7 @@ func _restore_to_stop(node_id: int, visited_ids: Array) -> bool:
break
if stop.is_empty():
push_error("[关卡节点地图] 断点恢复失败——停点节点编号 %d 不在本关图" % node_id)
_running = false
_phase = Phase.ENDED
return false
node_index = nodes().find(stop)
visited = []
@@ -258,11 +266,11 @@ func _restore_to_stop(node_id: int, visited_ids: Array) -> bool:
if _node_id(node) == int(vid):
visited.append(node)
break
_awaiting_choice = true
_phase = Phase.AWAITING_CHOICE
_candidates = _out_nodes(stop)
if _candidates.is_empty():
push_error("[关卡节点地图] 断点恢复失败——停点节点 %d 无出边(非合法停点)" % node_id)
_running = false
_phase = Phase.ENDED
return false
return true
@@ -270,7 +278,7 @@ func _restore_to_stop(node_id: int, visited_ids: Array) -> bool:
# 停点呈现(断点续玩路径——present_entry_choice 的中途节点版):信号顺序契约同入口
# (呈现层须先经 level_started 重取 runner 实例)。零 RNG 消耗。
func present_resumed_choice() -> bool:
if not _running or not _awaiting_choice or _candidates.is_empty() or node_index < 0:
if _phase != Phase.AWAITING_CHOICE or _candidates.is_empty() or node_index < 0:
push_error("[关卡节点地图] present_resumed_choice 拒绝——非中途停点态")
return false
choices_presented.emit(_candidates)
@@ -286,10 +294,7 @@ func restore_aux_items(items: Array) -> void:
func _find_level_row(level_index: int) -> Dictionary:
for row in db.level.rows:
if int(row.level_index) == level_index:
return row
return {}
return db.level_row(level_index) # 表访问收口(2026-10-02——行集直扫归 LevelTable/ConfigDB 访问器)
# ---- 模板池解析(关卡节点图生成 v0.4——M-3 迭代 5 T5)----
@@ -411,11 +416,11 @@ func visited_ids() -> Array:
func awaiting_choice() -> bool:
return _awaiting_choice
return _phase == Phase.AWAITING_CHOICE
func _enter_node(node: Dictionary) -> bool:
if not _running:
if not _is_running():
return false
node_index = nodes().find(node)
visited.append(node)
@@ -490,7 +495,7 @@ func _on_battle_finished(payload: Dictionary) -> void:
var hp_left := hero_hp if result == "victory" else 0
if not _external:
close_wallet() # 单关模式:关卡收束即冒险收束(GP 清零);冒险模式归 AdventureRunner._settle
_running = false
_phase = Phase.ENDED
_settlement = null
var aux_cleared := 0
if aux_inventory != null:
@@ -505,12 +510,17 @@ func _on_battle_finished(payload: Dictionary) -> void:
_present_choices()
# 恢复数学单一路径(漂移③清偿——同一公式两个落点:本体内置默认 + AdventureRunner.apply_rest,
# 统一归并归后续批):floor(上限 × 比例 ÷ 100) 后封顶缺口;冒险结构 GDD 公式逐位一致
func rest_heal_amount(pct: int, hp: int, max_hp: int) -> int:
# 恢复数学单一路径(漂移③清偿;2026-10-02 修复批——同式双落点收口:算术宿主 = 本静态方法,
# AdventureRunner.apply_rest 同式委托,字面量双写退役)。floor(上限 × 比例 ÷ 100) 后封顶缺口;
# 冒险结构 GDD 公式逐位一致
static func rest_heal(pct: int, hp: int, max_hp: int) -> int:
return mini(int(floor(float(max_hp) * float(pct) / 100.0)), max_hp - hp)
func rest_heal_amount(pct: int, hp: int, max_hp: int) -> int:
return rest_heal(pct, hp, max_hp) # 公有成文出口保持(start_level 内置恢复执行体经 Callable 引用)
func _apply_rest() -> int:
var pct: int = int(level_row.get("rest_heal_pct", 0))
# 接口③治疗封顶回报:单关模式 = 内置 rest_heal_amount;冒险模式 = AdventureRunner.apply_rest
@@ -528,7 +538,7 @@ func _present_choices() -> bool:
if cands.is_empty():
push_error("[关卡节点地图] 当前节点无出边且非 Boss(图合法性校验应已拦截)")
return false
_awaiting_choice = true
_phase = Phase.AWAITING_CHOICE
_candidates = cands
choices_presented.emit(cands)
return true
@@ -536,11 +546,11 @@ func _present_choices() -> bool:
# 玩家选下一跳(候选外编号拒绝;Boss 恒无出边——选路只在中间节点发生)
func pick_next_node(node_id: int) -> bool:
if not _awaiting_choice:
if _phase != Phase.AWAITING_CHOICE:
return false
for cand in _candidates:
if _node_id(cand) == node_id:
_awaiting_choice = false
_phase = Phase.RUNNING
_candidates = []
return _enter_node(cand)
return false
@@ -563,7 +573,7 @@ func set_aux_unlocked(ids: Dictionary) -> void:
func grant_aux_item(item_id: String, source: String) -> Dictionary:
if aux_inventory == null:
aux_inventory = AuxItems.new(db)
if aux_inventory.holding_count() + 1 > maxi(0, int(db.adventure.transitional_sync_slots)):
if not AuxItems.can_accept(1, aux_inventory.holding_count(), db): # 同调位守卫单点(2026-10-02)
push_warning("[关卡节点地图] 同调位已满,授予拒绝: %s(%s)" % [item_id, source])
return {}
return aux_inventory.add_item(item_id, source, Vector2i(-1, -1), 0)
@@ -642,7 +652,8 @@ func buy_product(product_id: String) -> bool:
return false
var price := current_price(prow)
if gp < price:
return false # 余额不足(覆盖层按钮禁用为常态防线——此处兜底拒绝)
push_warning("[关卡节点地图] 购买拒绝——余额不足: %s(需 %d,钱包 %d)" % [product_id, price, gp])
return false # 余额不足(覆盖层按钮禁用为常态防线——此处兜底拒绝;2026-10-02 补静默留痕)
gp -= price
var flat := int(prow.get("flat_value", 0))
bonus[attr] = int(bonus[attr]) + flat