拆件批v1.3-B4(战斗指标面收编): battle_orchestrator.gd 三踩雷计数变量(_mines_hit_total/_mines_hit_last/_mines_hit_round)并入 _mines_hits 一账(开战清零/轮末转存/负向 blast 入账三时点逐位同,事实面读键 int 包装);_hero/_loadout 两成员删除改 encounter 派生读面 _journal()/_attune_loadout()(begin_battle 经 enc["journal"]/enc["loadout"] assign 后全生命期可读,null=直构跳过语义同);负向 blast 计数抽 _book_negative_blast 私有助手;注释重排把文件长拉回注册值口径(1314,基线登记 1302——恶化存量债归迭代 40 卡①)。验收:全量套件 63 绿+round_flow EV 锚 goblin 已知预期红 1(0.9148∉[1.00,1.20],等用户重锚);bp 对拍 292dumps×28 键 mismatch=0(双基线);冒烟 17 项 0 失败;gdstyle 基线外新违规 0/恶化恰 2;begin_battle 125 行≤141〔领域拆分批 V1〕
This commit is contained in:
1 parent
45faa92bc5
commit
741b6bd77b
1 file changed
+54
-59
@@ -67,16 +67,13 @@ var _combat_seg = null # CombatSegment(③战斗段)
|
||||
var _decay_seg = null # DecaySegment(④衰减段)
|
||||
var _verdict_seg = null # VerdictSegment(⑤判定段——返回裁定,终局早退语义归本类)
|
||||
var _refresh_used_this_round := 0 # 每轮刷新计数(Active 相位合计,兜底上限 = ActionEconomyTable.refresh_cap_per_round)
|
||||
var _mines_hit_total := 0 # 踩雷计数本场累计(触发条件事实面——负向 blast 守卫累加)
|
||||
var _mines_hit_last := 0 # 上轮踩雷值(轮次真正结束后转存)
|
||||
var _mines_hit_round := 0 # 当轮踩雷累计(轮内部分结算不更新)
|
||||
var _mines_hits: Dictionary[Variant, Variant] = {"total": 0, "last": 0, "round": 0} # 踩雷计数(触发条件事实面——本场累计/上轮转存/当轮累计三读数合一账)
|
||||
# 转存时点=_roll_round_actions 轮末(轮内部分结算不更新 last);开战清零归 begin_battle
|
||||
var _board_seq := 0 # 板序号(本战斗第几张板——快照归因用)
|
||||
var _board_from_midround_refresh := false # 装板 provenance:轮内刷新换来的图 = true(清图奖励守卫——刷新图不发清图奖励)
|
||||
var _seal_consumed := {} # 兑付资格以危险格实例为键(整图;换图重置)
|
||||
# 同调装配运行态(begin_battle 经 enc.attunement 注入;off=空集全部效果零扰动)
|
||||
var attunement: Array[Variant] = [] # 装备中同调件 item_id 集
|
||||
var loadout = null # 同调配装件(begin_battle 经 enc["loadout"] 持引用;直构 null=零装配——充能面跳过)
|
||||
var _hero: GainJournal = null # 加算日记(begin_battle 经 enc["journal"] 持引用;null=调试/单场直构面——账面消费跳过)
|
||||
var _attune_safe_seen := 0 # 积点制件 battle 域安全开格计数(装配集 ap_charge_safe 行扫描;满 charge_n 自动兑付当轮 AP+1,无玩家发起入口)
|
||||
# ---- 效果引擎扩签运行态(新效果类型施加面;空订阅零扰动)----
|
||||
var _fx_hero_ac_base := -1 # 主角 AC 基线快照(enc.hero_armor_class;-1=表值兜底未解析)
|
||||
@@ -98,6 +95,18 @@ var fx_counters_battle: Dictionary[Variant, Variant] = {} # battle 桶(无前
|
||||
var counters_ctx: EffectContext = null # 四桶引用束(_init 建、begin_battle 挂 adventure/level 引用)
|
||||
|
||||
|
||||
# 加算日记读面(begin_battle 经 enc["journal"] 派生——encounter.assign 后全生命期可读;
|
||||
# null=调试/单场直构面,账面消费跳过。领域拆分批成员删除后的引用承接,读面即引用、无第二账)
|
||||
func _journal() -> GainJournal:
|
||||
return encounter.get("journal", null) if encounter.get("journal", null) is GainJournal else null
|
||||
|
||||
|
||||
# 同调配装件读面(begin_battle 经 enc["loadout"] 派生——充能单源化的 reset_cycle/consume_charge
|
||||
# 消费面;null=直构零装配,充能面跳过)
|
||||
func _attune_loadout():
|
||||
return encounter.get("loadout", null)
|
||||
|
||||
|
||||
# 事件发射薄面(18 发射点统一入口——订阅空=零循环零扰动;确定性同步分发零 RNG)
|
||||
func _fx_emit(event: String, payload: Dictionary) -> Array:
|
||||
if _fx == null:
|
||||
@@ -237,9 +246,9 @@ func _attune_charge_safe_row() -> Dictionary:
|
||||
# (used handle 不回收=本轮已耗充能作废,补新 handle=「回满」;差额注入防双份=level_runner
|
||||
# set_attune_charges 同构)。reset ∈ {battle, level}——adventure 周期归冒险开始种子面)
|
||||
func _reseed_attune_charges(reset: String) -> void:
|
||||
if loadout == null or treasure_inventory == null:
|
||||
if _attune_loadout() == null or treasure_inventory == null:
|
||||
return # 直构零装配/库存未就位——充能回满跳过(空装配同语义)
|
||||
loadout.reset_cycle(reset, treasure_inventory) # 写时种行/补行(按周期筛——语义逐字承原循环体)
|
||||
_attune_loadout().reset_cycle(reset, treasure_inventory) # 写时种行/补行(按周期筛——语义逐字承原循环体)
|
||||
|
||||
|
||||
# 积点制件进度读数(自动兑付无玩家发起入口,读数口=C 区秘宝槽悬停浮窗进度行:
|
||||
@@ -311,10 +320,6 @@ func begin_battle(enc: Dictionary) -> bool:
|
||||
# 行有 atk_min 时按 [atk_min, atk_max] 骰 spawn 期整战持久值
|
||||
# (每拍抖动否决——数字可读性锚;中点 = 行值)。encounter 封闭流恰一 scope(数量骰先、atk 骰后);
|
||||
# 挖掘决策域之外——P1 合规;敌人系统 零随机纪律保持(收 override 即确定值)。
|
||||
# 遭遇骰(难度曲线与Boss GDD Core Rule 8):行有 unit_count_max 时按 [unit_count, max] 均匀骰;
|
||||
# 行有 atk_min 时按 [atk_min, atk_max] 骰 spawn 期整战持久值
|
||||
# (每拍抖动否决——数字可读性锚;中点 = 行值)。encounter 封闭流恰一 scope(数量骰先、atk 骰后);
|
||||
# 挖掘决策域之外——P1 合规;敌人系统 零随机纪律保持(收 override 即确定值)。
|
||||
# 逐行骰:混编行集**每行各掷自己的区间骰**——
|
||||
# 先按行序逐行数量骰、再按行序逐行 atk 骰(单行行集 = 既有一次数量骰 + 一次 atk 骰,判定条件、
|
||||
# 开流条件、消费序、消费次数逐位一致——零内容期随机流零变化;区间宽度为零的行不掷 = 「定值不骰」
|
||||
@@ -358,14 +363,11 @@ func begin_battle(enc: Dictionary) -> bool:
|
||||
if not _install_new_board():
|
||||
return false
|
||||
_reset_round_facts() # 首板 install 的初始展开事件不入轮 facts(resource 恒 false 的双保险)
|
||||
# 同调装配运行态注入(enc.attunement 携带;off=空集零扰动。淬毒 N 注入
|
||||
# 伤害控制器、偏运 N 注入地图战斗资源——均须先于首板 install)
|
||||
# 同调装配运行态注入(enc.attunement 携带;off=空集零扰动。淬毒 N 注入伤害控制器、偏运 N 注入地图战斗资源——均须先于首板 install)
|
||||
attunement = (enc.get("attunement", []) as Array).duplicate()
|
||||
_attune_safe_seen = 0
|
||||
# 淬毒/偏运=triggers 订阅行(淬毒=clamp_check
|
||||
# modify 窗口、偏运=reward_roll bias_rewards;value 行字段 value_from 定影,begin_battle 不注入)
|
||||
# 特性运行态(enc.feats 携带持有集:效果行为=数据行 triggers 经效果
|
||||
# 引擎分发;流派档位=FeatsEngine 纯函数求值两运行态注伤害控制器。魔矢每战首次开格计数同步归零)
|
||||
# 淬毒/偏运=triggers 订阅行(淬毒=clamp_check modify 窗口、偏运=reward_roll bias_rewards;value 行字段 value_from 定影,begin_battle 不注入)
|
||||
# 特性运行态(enc.feats 携带持有集:效果行为=数据行 triggers 经效果引擎分发;流派档位=FeatsEngine 纯函数求值两运行态注伤害控制器。魔矢每战首次开格计数同步归零)
|
||||
# 扩签运行态就位:AC 基线快照、累积器清零、adventure 计数器/加算区共享引用接收
|
||||
_fx_hero_ac_base = int(enc.get("hero_armor_class", -1))
|
||||
_fx_ac_round = 0
|
||||
@@ -373,11 +375,7 @@ func begin_battle(enc: Dictionary) -> bool:
|
||||
_fx_new_resource_types = {}
|
||||
_fx_pending_reveals = []
|
||||
_fx_bonus_delta = {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0}
|
||||
_mines_hit_total = 0 # 踩雷计数开战清零(事实面生命周期同款)
|
||||
_mines_hit_last = 0
|
||||
_mines_hit_round = 0
|
||||
loadout = enc.get("loadout", null)
|
||||
_hero = enc.get("journal", null) if enc.get("journal", null) is GainJournal else null # null=调试直构——账面消费跳过
|
||||
_mines_hits = {"total": 0, "last": 0, "round": 0} # 踩雷计数开战清零(事实面生命周期同款;装备/日记读面经 encounter 派生——无成员接收行)
|
||||
counters_ctx.adventure_bucket = enc.get("adv_bucket", null) if enc.get("adv_bucket", null) is Dictionary else {} # 冒险桶宿主字典(直构兜底自有空字典)
|
||||
var level_ref: Variant = enc.get("level_counters")
|
||||
if level_ref is Dictionary:
|
||||
@@ -390,35 +388,29 @@ func begin_battle(enc: Dictionary) -> bool:
|
||||
_damage.rider_tier_bonus = 0
|
||||
_damage.rider_tier_crit = false
|
||||
_feat_first_dig_used = false
|
||||
# 树 rule 键消费(Fork 激活侧效果=效果引擎合成
|
||||
# 订阅(rebuild 注入——round_start 首轮 AP+1 / damage_taken 减伤+1)。其余 rule 键
|
||||
# =stat 面投影不入战斗(T8 表内容 provisional 口径披露))
|
||||
# 树 rule 键消费(Fork 激活侧效果=效果引擎合成订阅(rebuild 注入——round_start 首轮 AP+1 / damage_taken 减伤+1)。
|
||||
# 其余 rule 键=stat 面投影不入战斗(T8 表内容 provisional 口径披露))
|
||||
var tree_rules: Array[Variant] = enc.get("tree_rules", []) as Array
|
||||
# 效果引擎订阅重建(每战从持有集/装备集重建,中途获得下一战生效;
|
||||
# 树规则合成订阅同面装载。装载序=feats 表序→treasure 表序→树规则,写死保种子复放。
|
||||
# 计数器四桶经 counters_ctx 引用宿主容器,无回灌时点(旧战首回灌时点删除))
|
||||
# 效果引擎订阅重建(每战从持有集/装备集重建,中途获得下一战生效;树规则合成订阅同面装载。
|
||||
# 装载序=feats 表序→treasure 表序→树规则,写死保种子复放。计数器四桶经 counters_ctx 引用宿主容器,无回灌时点(旧战首回灌时点删除))
|
||||
_fx.rebuild(feat_ids, attunement, tree_rules)
|
||||
# 秘宝常时参数注入(装配集 kind 分发:远程镐挖距放宽/信标网络封印可达豁免;
|
||||
# 缺省 0/false=零装配零扰动。注入在首板 install 之后〔板在早段〕——板生成不读两参数,
|
||||
# 参数只影响挖掘/插棋动作判据,时序安全)
|
||||
# 秘宝常时参数注入(装配集 kind 分发:远程镐挖距放宽/信标网络封印可达豁免;缺省 0/false=零装配零扰动。
|
||||
# 注入在首板 install 之后〔板在早段〕——板生成不读两参数,参数只影响挖掘/插棋动作判据,时序安全)
|
||||
minesweeper.dig_range_bonus = attune_param_sum("dig_range_bonus")
|
||||
minesweeper.seal_range_free = attune_param_sum("seal_range_free") > 0
|
||||
# 充能重置周期(battle=每战回满/level=每关首战回满〔battle_index==1〕;
|
||||
# adventure 周期维持冒险开始 _seed_attune_charges 单次)
|
||||
# 充能重置周期(battle=每战回满/level=每关首战回满〔battle_index==1〕;adventure 周期维持冒险开始种行单次)
|
||||
_reseed_attune_charges("battle")
|
||||
if int(enc.get("battle_index", 1)) == 1:
|
||||
_reseed_attune_charges("level")
|
||||
# board_installed 发射+施加(巢穴预告:装板后一次报本板危险格数量;
|
||||
# 只报数量不标位置=信息红线,不碰分布=棋盘事实不可变契约 3。命中=读数口落值,呈现归
|
||||
# 呈现桥消费(无格来源不进结算明细行——行来源纪律);板已就绪〔早段 install〕、订阅行已在 rebuild 装载)
|
||||
# board_installed 发射+施加(巢穴预告:装板后一次报本板危险格数量;只报数量不标位置=信息红线,
|
||||
# 不碰分布=棋盘事实不可变契约 3。命中=读数口落值,呈现归呈现桥消费(无格来源不进结算明细行——行来源纪律);板已就绪〔早段 install〕、订阅行已在 rebuild 装载)
|
||||
nest_preview_count = -1
|
||||
var bi_hits := _fx_emit("board_installed", {})
|
||||
for h in bi_hits:
|
||||
if String(h.get("kind", "")) == "mine_count_preview":
|
||||
nest_preview_count = minesweeper.mine_total()
|
||||
# 跨冒险行动点加成轴(统一冒险加算区第四轴):经排队修正通道兑现
|
||||
# 「每场战斗开始首轮 AP +加成值」(queue_ap_delta = 下轮开轮基线加算、notify_round_start 兑现后
|
||||
# 清零——首轮即消费,后续轮次不重复兑现;语义锚 = 行动经济 GDD「跨冒险行动点加成轴」节)
|
||||
# 跨冒险行动点加成轴(统一冒险加算区第四轴):经排队修正通道兑现「每场战斗开始首轮 AP +加成值」
|
||||
#(queue_ap_delta = 下轮开轮基线加算、notify_round_start 兑现后清零——首轮即消费,后续轮次不重复兑现;语义锚 = 行动经济 GDD「跨冒险行动点加成轴」节)
|
||||
var ap_bonus: int = int(enc.get("hero_ap_bonus", 0)) + int(enc.get("voucher_time_sand", 0)) # 时沙同通道(首轮池增量,不改上限)
|
||||
if ap_bonus > 0:
|
||||
action_economy.queue_ap_delta(ap_bonus)
|
||||
@@ -426,11 +418,8 @@ func begin_battle(enc: Dictionary) -> bool:
|
||||
var voucher_rap: int = int(enc.get("voucher_rap", 0))
|
||||
if voucher_rap > 0:
|
||||
action_economy.grant_reserve_ap(voucher_rap)
|
||||
# 工兵晨令=round_start grant_ap(mode:queue) 订阅行承载,
|
||||
# when round_index ≤ effective_rounds 行字段 value_from 定影;发射位先于轮切换=当轮兑现
|
||||
# round_start 发射+施加(发射位先于行动经济轮切换:树规则 grant_ap
|
||||
# mode:queue 当轮入队、notify_round_start 即兑现(先手压制=首轮 AP+1 语义锚);
|
||||
# 计数器 round_start 重置点同点生效)
|
||||
# 工兵晨令=round_start grant_ap(mode:queue) 订阅行承载,when round_index ≤ effective_rounds 行字段 value_from 定影;
|
||||
# 发射位先于轮切换=当轮兑现(树规则 grant_ap mode:queue 当轮入队、notify_round_start 即兑现——先手压制=首轮 AP+1 语义锚;计数器 round_start 重置点同点生效)
|
||||
round_index = 1
|
||||
_emit_round_start()
|
||||
if not action_economy.notify_round_start():
|
||||
@@ -752,13 +741,13 @@ func use_treasure(handle: int, target: Vector2i) -> Dictionary:
|
||||
return {"ok": false, "reason": "爆破工兵包:3×3 区域内无可移除危险格(须未揭示且未封印)"}
|
||||
var rec: Dictionary[Variant, Variant] = treasure_inventory.consume(handle)
|
||||
# 同调主动件充能消耗(单源化——行标 used 幂等承载,原字典扣减同点退役)
|
||||
if loadout != null and not rec.is_empty() and String(rec.get("source_class", "")) == "attunement":
|
||||
loadout.consume_charge(String(rec.get("item_id", "")), treasure_inventory)
|
||||
if _attune_loadout() != null and not rec.is_empty() and String(rec.get("source_class", "")) == "attunement":
|
||||
_attune_loadout().consume_charge(String(rec.get("item_id", "")), treasure_inventory)
|
||||
# 真视类工具使用计数(信标网络解锁行为条件:受理成功恰计一次;
|
||||
# 主角账单点记录,冒险收束聚合入档 save.add_vision_used)
|
||||
if kinds.has("reveal_tiles") or kinds.has("safe_dig") or kinds.has("mine_reveal"):
|
||||
if _hero != null:
|
||||
_hero.record_vision_use() # 受理成功恰计一次(未注入=调试直构不计——空账守卫同语义)
|
||||
if _journal() != null:
|
||||
_journal().record_vision_use() # 受理成功恰计一次(未注入=调试直构不计——空账守卫同语义)
|
||||
return {"ok": true, "item_id": v.item_id, "resolved": v.resolved, "record": rec}
|
||||
|
||||
|
||||
@@ -848,6 +837,14 @@ func _apply_gp_row(row: Dictionary, source_class: String, cell: Vector2i, ri: in
|
||||
# pierce/magic 正向 = 单目标克制直伤单据(attack_type 查克制矩阵,必中全额不掷点);负向 = 主角直伤单据。
|
||||
# 返回 "redeemed" = 实际有效兑付 / "zero" = 零兑付(行已自记)——读数 = 控制器结账 outcome(A 模式提交即结)。
|
||||
# sync = 同步开单(清图批——流程依赖完美第二份/高光份数读数,无视结账政策当场结账)。
|
||||
# 负向 blast(雷)踩雷计数入账(触发条件事实面——正向 spark_aoe/清图奖励同走 blast 分支不计入)
|
||||
func _book_negative_blast(row: Dictionary) -> void:
|
||||
if String(row.get("polarity", "positive")) != "negative":
|
||||
return
|
||||
_mines_hits["round"] += 1
|
||||
_mines_hits["total"] += 1
|
||||
|
||||
|
||||
func _apply_flat_row(row: Dictionary, source_class: String, cell: Vector2i, ri: int, highlight: String = "", label_suffix: String = "", sync := false) -> String:
|
||||
var ctype := String(row.cell_type)
|
||||
var power := int(row.power)
|
||||
@@ -858,9 +855,7 @@ func _apply_flat_row(row: Dictionary, source_class: String, cell: Vector2i, ri:
|
||||
_emit_row("effect", source_class, cell, ri, "%s(下轮行动点 %+d)" % [display, delta], delta, {"effect_id": "ap_delta", "pool_value": action_economy.pending_ap_delta()}, highlight)
|
||||
return "redeemed"
|
||||
if ctype == "blast":
|
||||
if String(row.get("polarity", "positive")) == "negative":
|
||||
_mines_hit_round += 1 # 负向 blast(雷)踩雷计数——正向 spark_aoe/清图奖励同走此分支不计入
|
||||
_mines_hit_total += 1
|
||||
_book_negative_blast(row) # 负向 blast(雷)踩雷计数——正向 spark_aoe/清图奖励同走此分支不计入
|
||||
var t := _damage.open_ticket(DamageController.KIND_BOARD_BLAST, source_class, display, "board", power, \
|
||||
DamageController.TARGET_ALL_ALIVE, ri, cell, "", 0, highlight, {"batch_key": String(row.reward_id)})
|
||||
return _outcome_of(_submit(t, sync))
|
||||
@@ -964,8 +959,8 @@ func _roll_round_actions() -> void:
|
||||
var facts := {
|
||||
"round_index": round_index,
|
||||
"last_round_end": "none" if (action_economy.last_round_end as Dictionary).is_empty() else String((action_economy.last_round_end as Dictionary).get("path_tag", "none")),
|
||||
"mines_hit_last": _mines_hit_last,
|
||||
"mines_hit_total": _mines_hit_total,
|
||||
"mines_hit_last": int(_mines_hits["last"]),
|
||||
"mines_hit_total": int(_mines_hits["total"]),
|
||||
}
|
||||
for u in _enemy_system.query_alive("enemy"):
|
||||
# Boss 半血解锁闩(迭代14④ T4——开轮摇号前逐敌检查;一次过门单向闩;解锁出一次归因明细行
|
||||
@@ -981,7 +976,7 @@ func _roll_round_actions() -> void:
|
||||
# 非 Boss 专属——Boss 语义留给订阅者 when 判定。pct=本次解锁条目的 trigger 行值)
|
||||
var pct_v := 0
|
||||
for pe in (u.get("pool", []) as Array):
|
||||
var pe_d: Dictionary = pe
|
||||
var pe_d: Dictionary[Variant, Variant] = pe
|
||||
if String(pe_d.get("skill_id", "")) == sid and (pe_d.get("trigger", {}) as Dictionary).has("value"):
|
||||
pct_v = int((pe_d.get("trigger", {}) as Dictionary).get("value", 0))
|
||||
break
|
||||
@@ -1000,8 +995,8 @@ func _roll_round_actions() -> void:
|
||||
var stream: RandomNumberGenerator = rng.open_stream("behavior_roll")
|
||||
_enemy_system.set_pending_action(u, SkillLottery.draw(entries, stream))
|
||||
_enemy_system.tick_cooldowns() # 递减在摇号读值之后——"施放后连续 N 拍不可摇中"的等价实现(单位容器 注记)
|
||||
_mines_hit_last = _mines_hit_round # 轮次真正结束转存(轮内部分结算不更新)
|
||||
_mines_hit_round = 0
|
||||
_mines_hits["last"] = _mines_hits["round"] # 轮次真正结束转存(轮内部分结算不更新)
|
||||
_mines_hits["round"] = 0
|
||||
|
||||
|
||||
# ---- 战斗段 ----
|
||||
@@ -1133,10 +1128,10 @@ func _battle_over(result: String) -> void:
|
||||
if String(h.get("kind", "")) == "heal":
|
||||
var hu_w: Dictionary[Variant, Variant] = _enemy_system.hero_unit()
|
||||
hu_w["hp"] = mini(int(hu_w.get("hp", 0)) + int(h.get("value", 0)), maxi(1, int(hu_w.get("max_hp", 1))))
|
||||
# bonus_delta 战末汇入(血税双向账:本战累积经主角账单写原语汇入获得日记三层后清零)
|
||||
if _hero != null:
|
||||
# bonus_delta 战末汇入(血税双向账:本战累积经加算日记单写原语汇入获得日记三层后清零)
|
||||
if _journal() != null:
|
||||
for axis in _fx_bonus_delta.keys():
|
||||
_hero.gain_bonus(String(axis), int(_fx_bonus_delta[axis]), "battle_export", String(axis))
|
||||
_journal().gain_bonus(String(axis), int(_fx_bonus_delta[axis]), "battle_export", String(axis))
|
||||
_fx_bonus_delta = {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0}
|
||||
# 搬运链删除:adventure 桶经 ctx 引用直写宿主字典,无战末导出时点(旧导出/汇入搬运链删除)
|
||||
# 映射随战斗结束退役(地图战斗资源 义务④——下一场战斗 = 新板新 scope 批,roll_board 相位守卫的前提)
|
||||
|
||||
Reference in new issue
Block a user