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:
1 parent
59f0c70ca3
commit
d1460327a4
21 files changed
+491
-342
No files matched your search
+45
-34
@@ -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
|
||||
|
||||
Reference in new issue
Block a user