Files
gplan-2/game/core/battle_fx_host.gd
T
DKChan cc02bb9315 卡①T1+T2(拆件批wr1/wr2/wr3): BattleFxHost+RewardGrant两新件建件+fx/grant族迁移+use_treasure拆分+三触点分家——battle_fx_host.gd(14类变量:bundle7+grant_cb+engine+counters_ctx+ac/reveal两束;fx_emit/emit_round_start/apply_ac_bonus/enqueue_reveal/flush_pending_reveals取号序逐字/rebuild_subscriptions/mount_buckets/reset_battle_state/bonus_delta_drain/reveal_busy)+reward_grant.gd(15类变量:bundle11+escrow+defer+treasure_inventory+battle_ledger;grant_routed随att归因束改形/submit案C闸/use_treasure四步骨架+_charge_gate+_apply_use_kinds+_safe_dig_open+_cell_removal_open/grant_clear_reward三参形宿主态经参传入/reveal_redeem兑付回调面);宿主删fx族11成员+grant族3成员,组件出口fx_host()/reward_grant(),_fx_host_fact五事实单点+_attune_safe_seen_read读投影,treasure_inventory带setter转发,begin_battle七接线点改指,_battle_over改bonus_delta_drain,_roll_gp_drop读_reward_grant.escrow;两段三引用构造(与T4接口块同形先行)读写面改指(oc._submit实为7处G5清单漏1,oc._fx_bonus_delta axis/axis_f两形);treasure_interact_controller改ctx束8键+三现值同查+inventory_projection拆_projection_row/_auto_row;main_ui_build构造改束(grant_get=run_scope.settlement.reward_grant()现值);S7/S8登记两新件7→9;测试改址:adventure_feats 75+round_flow 8+treasure_effects 7(含G11漏载的ctrl4构造点)+settle_segments 3+seal_polarity 10(含G11漏载的_grant_clear_identity直调)+level_shop 4+forge 2,另修reward_grant内部_submit/_outcome_of旧名三处与adventure_feats orch._fx/orch0._fx.rebuild两残漏(脚本错误静默吞断言假绿形态,修后feats 138PASS/seal 73PASS恢复全额);代拍板:①RewardGrant bundle 12→11键(minesweeper改经fx_host同源引用)腾位battle_ledger独立成员(卡面15≤15算术缺口,16键=基线外NEW停卡不可取)②bind_grant落_reward_grant.reveal_redeem(query_full_snapshot唯授予件持有,D1「RewardGrant授予面」兑付回调口径)③续拆四私有(迁入形逐键过阈值义务)④grant_clear_reward测试改址传宿主态读(s._board_from_midround_refresh/perfect_sweep_earned)。验收:七套件直跑绿+零SCRIPT ERROR+gdstyle基线外新违规0(battle_orchestrator行数恶化键随拆件归绿989<1302;level_map_screen 22>21=iter38存量漏登记非本批触碰面)〔拆件批 V8〕
2026-10-27 06:07:15 +08:00

169 lines
9.7 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 效果引擎宿主件(自 battle_orchestrator 收编 fx 族):事件发射面(fx_emit——18 发射点统一入口)、
## 补充事实判定(charge_layers 自答,余五事实转宿主)、主角 AC 三值累积与同步(本轮/本战累积器+
## 基线快照)、bonus_delta 四轴累积(战末宿主 drain 汇入账本)、揭示待兑队列与兑付(含再入闸——
## 同步信号回环防二次缓冲二次兑付)、round/battle 桶计数器持有(桶随编排器生灭语义不变)、
## round_start 发射与施加、订阅重建、桶挂引用。生命周期=随编排器(编排器 _init 同建同灭,每战新建)。
## 跨件单向接线(🔴 契约红线):行发射与五事实经构造注入的 emit_cb/facts_cb 回调宿主——协议面单点
## 留宿主,禁回调宿主私有族;揭示奖励兑付走 bind_grant 注入的兑付回调(RewardGrant 授予面——
## snapshot 查询与 grant_routed 同面);对本件零反向强引用(禁 RefCounted 双向环——两件均随每战新建)。
## 随机只经注入 rng 的 fx_reveal 封闭流(除该流外零随机;零 await——效果引擎全同步解释器)。
## 类变量封闭面(14≤15):bundle 7 项(db/rng/minesweeper/action_economy/damage/emit_cb/facts_cb,
## 缺一键 assert——引用束注入防 _init max-parameters 新键)+grant_cb+engine+counters_ctx+
## ac 束(键集封闭 base/round/battle)+_fx_bonus_delta+_fx_new_resource_types+reveal 束
## (键集封闭 queue/busy)。禁实现期增删键;禁为机检文本保留无效成员(原编排器 fx_counters_round/
## battle 两零读者成员迁入即删——同物异名同字典,桶引用经 counters_ctx 承载)。
class_name BattleFxHost
extends RefCounted
var db: ConfigDb
var rng: RngServiceCore
var minesweeper: MinesweeperRules
var action_economy: ActionEconomy
var damage: DamageController
var emit_cb: Callable # 宿主 _emit_row——行协议面单点(束形改形后随束形)
var facts_cb: Callable # 宿主 _fx_host_fact——round_index/battle_index/seals_count/nest_count/hp_ratio 五事实宿主侧单点
var grant_cb: Callable = Callable() # 揭示兑付回调=RewardGrant 授予面(bind_grant 注入;构造序解法——本件对授予面零强引用)
var engine: EffectEngine # 效果引擎(原编排器 _fx——宿主 _init 经此转注 damage/action_economy/reward_economy 三 set_fx)
var counters_ctx: EffectContext # 四桶引用束(round/battle 两桶本件自有;adventure/level 桶 begin_battle mount_buckets 挂引用)
var ac := {"base": -1, "round": 0, "battle": 0} # ac 束(base=主角 AC 基线快照 enc.hero_armor_class,-1=表值兜底未解析;round=ac_bonus 本轮累积器〔封印桩,round_start 清零〕;battle=本战累积器〔石肤,cap 封顶,begin_battle 清零〕)
var _fx_bonus_delta := {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0} # 本战 bonus_delta 累积(战末宿主 bonus_delta_drain 读后清零)
var _fx_new_resource_types := {} # 本战已见资源类型集(地质学家 fact new_resource_type 判定——battle 域)
var reveal := {"queue": [], "busy": false} # reveal 束(queue=揭示效果待兑队列〔见血开窍/斩首学者/地质学家/跳格采掘共用——授予段末统一兑付,防轮 facts 迭代中追加重入〕;busy=兑付中标记——宿主 _on_cell_revealed 缓冲旁路判定,防二次缓冲二次兑付)
func _init(bundle: Dictionary) -> void:
for k in ["db", "rng", "minesweeper", "action_economy", "damage", "emit_cb", "facts_cb"]:
assert(bundle.has(k), "[效果引擎宿主] 引用束缺键: %s" % k)
db = bundle.db
rng = bundle.rng
minesweeper = bundle.minesweeper
action_economy = bundle.action_economy
damage = bundle.damage
emit_cb = bundle.emit_cb
facts_cb = bundle.facts_cb
engine = EffectEngine.new(db)
counters_ctx = EffectContext.new() # round/battle 两桶即 ctx 自带字典——编排器旧 fx_counters 两成员同物异名零读者,不再另立
# 揭示兑付回调挂接(宿主 _init 建两件后接线——构造序禁环)
func bind_grant(cb: Callable) -> void:
grant_cb = cb
# 事件发射薄面(18 发射点统一入口——订阅空=零循环零扰动;确定性同步分发零 RNG)
func fx_emit(event: String, payload: Dictionary) -> Array:
return engine.dispatch(counters_ctx, event, payload, _fx_fact)
# round_start 发射+施加(grant_ap mode:queue=当轮入队,行动经济轮切换即兑现;计数器 round_start
# 重置点在 dispatch 内生效。调用点两处:begin_battle 首轮 / 轮始段续轮。payload 携 round〔宿主侧
# 事实单点〕+ap_exhausted_last〔一滴不剩 when 面〕;发射前 ac_bonus 本轮累积器清零并同步主角 AC)
func emit_round_start() -> void:
ac.round = 0
_sync_hero_ac()
for h in fx_emit("round_start", {"round": int(facts_cb.call("round_index")),
"ap_exhausted_last": action_economy.ap_exhausted_last_round()}):
if String(h.get("kind", "")) == "grant_ap" and String(h.get("mode", "")) == "queue":
action_economy.queue_ap_delta(int(h.get("value", 0)))
# ac_bonus 施加(mode=round 本轮累积器〔封印桩,round_start 清零〕/
# mode=battle 本战累积器〔石肤,cap 封顶;缺省 battle〕;cap=0/缺省=无上限)
func apply_ac_bonus(h: Dictionary) -> void:
var mode := String(h.get("mode", "battle"))
var cap := int(h.get("cap", 0))
if mode == "round":
ac.round = int(ac.round) + int(h.get("value", 0))
else:
ac.battle = int(ac.battle) + int(h.get("value", 0)) if cap <= 0 else mini(cap, int(ac.battle) + int(h.get("value", 0)))
_sync_hero_ac()
# 揭示效果入队(fx_reveal 掷格兑付延后到授予段末——防轮 facts 迭代中追加重入;见血开窍/
# 斩首学者〔经伤害控制器 fx_reveal_request 回调〕/地质学家/跳格采掘共用)
func enqueue_reveal() -> void:
reveal.queue.append({"round": int(facts_cb.call("round_index"))})
# 揭示效果兑付(授予段末统一——fx_reveal 封闭流从未揭示安全格掷 1 格全揭示;
# 信息红线=只揭真格〔危险格不入候选〕;空候选=零兑付留归因行且不取号;
# 揭示奖励经兑付回调正向路由直接入账——reveal.busy 旁路宿主 _on_cell_revealed 缓冲防二次兑付)
func flush_pending_reveals(ri: int) -> void:
if (reveal.queue as Array).is_empty():
return
var board: BoardData = minesweeper.current_board()
while not (reveal.queue as Array).is_empty():
(reveal.queue as Array).pop_back()
var cands: Array[Variant] = []
for c in board.all_cells():
if not minesweeper.is_revealed(c) and not board.is_mine(c):
cands.append(c)
if cands.is_empty():
emit_cb.call("extended", "fx_reveal", Vector2i(-1, -1), ri, "揭示落空(无未揭示安全格)", 0, {"effect_id": "fx_reveal"}, "")
continue
var rg: RandomNumberGenerator = rng.open_stream("fx_reveal")
var cell: Vector2i = cands[rg.randi_range(0, cands.size() - 1)]
reveal.busy = true
var ok: bool = minesweeper.fx_reveal(cell)
reveal.busy = false
if not ok:
emit_cb.call("extended", "fx_reveal", Vector2i(-1, -1), ri, "揭示落空(格子不可揭)", 0, {"effect_id": "fx_reveal"}, "")
continue
grant_cb.call(cell, ri)
emit_cb.call("extended", "fx_reveal", cell, ri, "专长揭示", 0, {"effect_id": "fx_reveal"}, "fx_reveal")
# 效果引擎订阅重建(每战从持有集/装备集重建,中途获得下一战生效;树规则合成订阅同面装载。
# 装载序=feats 表序→treasure 表序→树规则,写死保种子复放。计数器四桶经 counters_ctx 引用宿主容器,无回灌时点)
func rebuild_subscriptions(feats: Array, attunement: Array, tree_rules: Array) -> void:
engine.rebuild(feats, attunement, tree_rules)
# begin_battle 桶挂引用(adventure 桶=账本共享引用跨战持久=同一字典引用,非副本搬运;
# level 非 Dictionary 即不挂——LevelRunner 每关 new 下传)
func mount_buckets(adv_bucket: Dictionary, level_bucket: Variant) -> void:
counters_ctx.adventure_bucket = adv_bucket
if level_bucket is Dictionary:
counters_ctx.level_bucket = level_bucket
# begin_battle 运行态清零(ac 三值/bonus_delta 四轴/new_resource_types/揭示队列+再入闸——
# 原编排器 begin_battle 扩签运行态就位段原序)
func reset_battle_state(ac_base: int) -> void:
ac.base = ac_base
ac.round = 0
ac.battle = 0
_fx_new_resource_types = {}
reveal.queue = []
reveal.busy = false
_fx_bonus_delta = {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0}
# 战末 drain(读后清零;宿主 _battle_over 单消费——读改清三拍合一,时序等价)
func bonus_delta_drain() -> Dictionary:
var out := _fx_bonus_delta
_fx_bonus_delta = {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0}
return out
# 揭示兑付中读投影(宿主 _on_cell_revealed 旁路判定——fx 揭示的奖励由兑付点直接入账,
# 此处缓冲会导致二次兑付)
func reveal_busy() -> bool:
return bool(reveal.busy)
# 补充事实面(fact 取值第二优先源——payload 未携带的运行态读数;charge_layers 本件自答
# 〔action_economy 直读〕,余五事实转宿主 facts_cb——宿主侧单点,未知事实回落 null)
func _fx_fact(fact: String) -> Variant:
if fact == "charge_layers":
return action_economy.charge_layers
return facts_cb.call(fact)
# ac_bonus 累积后同步主角 AC(石肤/封印桩消费面——defender_ac 经 set_hero_ac_override 单点;
# 基线 = enc 口径,-1(表值兜底态)时解析为表值后叠加,守恒口径与 begin_battle 注入一致)
func _sync_hero_ac() -> void:
if int(ac.base) < 0:
ac.base = int(db.hero.armor_class)
damage.set_hero_ac_override(int(ac.base) + int(ac.round) + int(ac.battle))