diff --git a/game/core/action_economy.gd b/game/core/action_economy.gd index 90c29b49..a559ad9f 100644 --- a/game/core/action_economy.gd +++ b/game/core/action_economy.gd @@ -41,12 +41,14 @@ var charge_layers: int: get: return _charge_layers # 效果引擎(dig_paid/charge_full 发射面;round_end 转存决策面) var _fx: EffectEngine = null +var _ctx: EffectContext = null var _last_stop_ap := 0 # 停手侧剩余 AP 记账(转存决策在 round_end 发射点——grant_ap(transfer) 订阅定夺) var _ap_exhausted_last := false # 上轮 AP 耗尽封印(一滴不剩 round_start when 面) -func set_fx(fx: EffectEngine) -> void: +func set_fx(fx: EffectEngine, ctx: EffectContext) -> void: _fx = fx + _ctx = ctx func _init(db_ref: ConfigDb) -> void: diff --git a/game/core/adventure_runner.gd b/game/core/adventure_runner.gd index 5c9b031c..9bc55a08 100644 --- a/game/core/adventure_runner.gd +++ b/game/core/adventure_runner.gd @@ -832,17 +832,9 @@ func abandon() -> bool: # ---- 关卡推进(私有——序列编排单一出口)---- -# 树限次计数按关重置(危险直觉锋/守两组「每关限次」账本键:跨战持久由 adventure -# 域导出/回灌承载,此处随关清零闭合生命周期四态;键集=效果引擎树合成行声明的 counter_id; -# 独立成口=V10 断言面直呼) -func _reset_tree_limited_counters() -> void: - for cid in ["tree_sense_sharp_used", "tree_sense_guard_used"]: - run_ledger.adventure_counters.erase(cid) - - func _start_current_level() -> bool: _runner = LevelRunner.new(db, rng) - _reset_tree_limited_counters() # 树限次计数按关重置(V10 生命周期四态闭合——断言面直呼本口) + # 树限次计数按关清零现由 LevelRunner.level_counters 随每关 new 天然承载(旧硬编码清除名单 _reset_tree_limited_counters 已删) # core↔core 接线只许方法 Callable(S6——lambda 捕获 self 会延长 RefCounted 生命周期乃至成环) _runner.node_entered.connect(_forward_node_entered) _runner.choices_presented.connect(_forward_choices_presented) diff --git a/game/core/battle_orchestrator.gd b/game/core/battle_orchestrator.gd index ff672721..c6814bbd 100644 --- a/game/core/battle_orchestrator.gd +++ b/game/core/battle_orchestrator.gd @@ -82,6 +82,9 @@ var _feat_first_dig_used := false # 效果引擎(发布订阅解释器;begin_battle 从持有集/装备集重建订阅。 # 施加面:发射点 dispatch 返回命中,发射点按组合规则施加) var _fx: EffectEngine +var fx_counters_round: Dictionary[Variant, Variant] = {} # round 桶(轮始整桶清空;随编排器生灭) +var fx_counters_battle: Dictionary[Variant, Variant] = {} # battle 桶(无前缀 id 缺省归此;随编排器每战 new 天然空) +var counters_ctx: EffectContext = null # 四桶引用束(_init 建、begin_battle 挂 adventure/level 引用) # 事件发射薄面(18 发射点统一入口——订阅空=零循环零扰动;确定性同步分发零 RNG) @@ -269,6 +272,9 @@ func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void: db = db_ref rng = rng_ref _fx = EffectEngine.new(db_ref) + counters_ctx = EffectContext.new() + counters_ctx.round_bucket = fx_counters_round # 挂自有两桶引用(与编排器成员字段同物异名同字典) + counters_ctx.battle_bucket = fx_counters_battle _board_generator = BoardGenerator.new() action_economy = ActionEconomy.new(db) minesweeper = MinesweeperRules.new(db, action_economy) @@ -277,9 +283,9 @@ func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void: _reward_economy = RewardEconomy.new(db, rng) _damage = DamageController.new(db, rng, _enemy_system, _status_effects) _damage.emit_row_cb = _emit_row # 行协议归属本类(9 类行协议 + 来源断言不外泄) - _damage.set_fx(_fx) # 效果引擎注入(attack_commit/clamp_check/armor_roll/kill/damage_taken 发射面) - action_economy.set_fx(_fx) # dig_paid/charge_full 发射面 - _reward_economy.set_fx(_fx) # reward_roll 发射面 + _damage.set_fx(_fx, counters_ctx) # 效果引擎注入(attack_commit/clamp_check/armor_roll/kill/damage_taken 发射面) + action_economy.set_fx(_fx, counters_ctx) # dig_paid/charge_full 发射面 + _reward_economy.set_fx(_fx, counters_ctx) # reward_roll 发射面 minesweeper.cell_revealed.connect(_on_cell_revealed) minesweeper.seal_judged.connect(_on_seal_judged) minesweeper.round_end_board.connect(_on_round_end) @@ -371,6 +377,10 @@ func begin_battle(enc: Dictionary) -> bool: _fx_bonus_delta = {"atk": 0, "max_hp": 0, "armor_class": 0, "ap": 0} var ledger_ref = enc.get("ledger", null) _ledger = ledger_ref if ledger_ref is RunLedger else RunLedger.new() # 缺省新账=调试/单场零扰动面 + counters_ctx.adventure_bucket = _ledger.adventure_counters # 挂冒险桶引用(跨战持久=同一字典引用,非副本搬运) + var level_ref: Variant = enc.get("level_counters") + if level_ref is Dictionary: + counters_ctx.level_bucket = level_ref # 挂关卡桶引用(LevelRunner 每关 new 下传) _damage.fx_reveal_request = _fx_enqueue_reveal _damage.fx_ac_request = _apply_ac_bonus var feat_ids: Array[Variant] = enc.get("feats", []) as Array diff --git a/game/core/damage_controller.gd b/game/core/damage_controller.gd index 59c49907..9e4fc7a7 100644 --- a/game/core/damage_controller.gd +++ b/game/core/damage_controller.gd @@ -44,6 +44,7 @@ var _hero_ac_override := -1 # 主角护甲等级合流入参(begin_battle # 效果引擎(attack_commit/clamp_check/armor_roll/kill/damage_taken # 发射+施加面:dispatch 返回命中,本类按组合规则施加) var _fx: EffectEngine = null +var _ctx: EffectContext = null # 战斗段运行态事实(编排器每轮刷新——fact 取数面:attack_commit 载荷 dig_streak / # charge_layers facts〔猎巢人 per/整备 attack_bonus per/厚积薄发 when/铁壁 shield per〕; # 流派档位两运行态〔magic 档一 rider+1 / 档二 rider 可暴击〕) @@ -67,8 +68,9 @@ func set_hero_ac_override(v: int) -> void: # 效果引擎注入(战斗编排器 _init——事件发射面接线) -func set_fx(fx: EffectEngine) -> void: +func set_fx(fx: EffectEngine, ctx: EffectContext) -> void: _fx = fx + _ctx = ctx # 事件发射薄面(发射+命中收集统一入口——订阅空=零循环零扰动;命中由各施加面按组合规则施加) diff --git a/game/core/effect_context.gd b/game/core/effect_context.gd new file mode 100644 index 00000000..d859a160 --- /dev/null +++ b/game/core/effect_context.gd @@ -0,0 +1,10 @@ +## EffectContext——效果引擎四桶计数器引用束(无状态引擎的外部状态承载)。 +## 四桶按生命周期分:round(轮始整桶清空)/battle(随编排器生灭)/level(随 LevelRunner 生灭)/ +## adventure(随 RunLedger 生灭)。本类零方法零行为,只持引用;桶容器由宿主对象 new,本类只挂引用。 +class_name EffectContext +extends RefCounted + +var round_bucket: Dictionary[Variant, Variant] = {} +var battle_bucket: Dictionary[Variant, Variant] = {} +var level_bucket: Dictionary[Variant, Variant] = {} +var adventure_bucket: Dictionary[Variant, Variant] = {} diff --git a/game/core/effect_context.gd.uid b/game/core/effect_context.gd.uid new file mode 100644 index 00000000..01a436bf --- /dev/null +++ b/game/core/effect_context.gd.uid @@ -0,0 +1 @@ +uid://6n45i76gkrmu diff --git a/game/core/level_runner.gd b/game/core/level_runner.gd index e304c378..64e4dad1 100644 --- a/game/core/level_runner.gd +++ b/game/core/level_runner.gd @@ -23,6 +23,7 @@ var node_index := -1 # 冒险模式 = AdventureRunner 共享字典(Dictionary 引用共享——hero_hp/gp 属性读写直接落冒险账本); # 单关模式 = 本实例私有账本(start_level 重建,既有单关语义逐位保留)。 var _ledger: Dictionary[Variant, Variant] = {"hero_hp": 0, "gp": 0} +var level_counters: Dictionary[Variant, Variant] = {} # 关卡桶(lvl_ 前缀计数器;每关随 LevelRunner new 天然空=按关清零,替代旧硬编码清除名单) var _rest_handler: Callable # 治疗封顶回报执行体(默认内置 rest_heal_amount;冒险模式 = AdventureRunner.apply_rest——接口③) var _external := false # 冒险模式标记(钱包收束时机与播种语义分叉点) # hero_hp / gp 属性化(既有读写点零改动——值类型经属性落 _ledger) @@ -469,6 +470,7 @@ func _start_battle(node: Dictionary) -> bool: "attack_type": _hero_attack_type, "armor_type": _hero_armor_type, # 两根类型轴(spawn 英雄快照;空串=锻造配置默认值回退) "attunement": _attunement, "ledger": run_ledger, # 共享四账单类下传(单引用键) + "level_counters": level_counters, # 关卡桶下传(同关跨战共享引用、随本类 new 天然空) "feats": _feats, "tree_rules": _tree_rules, "battle_index": _battle_index(), diff --git a/game/core/reward_economy.gd b/game/core/reward_economy.gd index 2bffccf3..71f685cf 100644 --- a/game/core/reward_economy.gd +++ b/game/core/reward_economy.gd @@ -18,10 +18,12 @@ var _clear_granted := false var _clear_snapshot := {} # 效果引擎(reward_roll 发射面;偏运硬币 bias_rewards 订阅面) var _fx: EffectEngine = null +var _ctx: EffectContext = null -func set_fx(fx: EffectEngine) -> void: +func set_fx(fx: EffectEngine, ctx: EffectContext) -> void: _fx = fx + _ctx = ctx func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void: diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index 8f74b2aa..ce2aba07 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -6119,13 +6119,7 @@ func _smoke_tree_rules() -> void: "守⑤ rig:次战编排启动(新战新队列实例)") check(int(orch2.action_economy.pending_ap_delta()) == 0, "守⑤:末轮判出不返(queue 只在 notify_round_start 兑现、战亡即弃——无跨战泄漏)") - # 按关重置清零点(adventure_runner._start_current_level) - var ar = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(777003)) - ar.run_ledger.adventure_counters = {"tree_sense_sharp_used": 2, "tree_sense_guard_used": 1, "unrelated_key": 9} # 计数账住 RunLedger - ar._reset_tree_limited_counters() - check(not ar.run_ledger.adventure_counters.has("tree_sense_sharp_used") and not ar.run_ledger.adventure_counters.has("tree_sense_guard_used") - and int(ar.run_ledger.adventure_counters.get("unrelated_key", 0)) == 9, - "限次按关重置:_start_current_level 清零点恰两键(他键零扰动——生命周期四态闭合)") + # 树限次按关清零改由 LevelRunner.level_counters 随 new 承载(旧硬编码名单冒烟断言随函数删除——换代同生死;新语义由 V4/V5 段承载) # 财富之道·散:商品标价折价(level_runner 计价单点) var lr = load("res://core/level_runner.gd").new(_db, _fresh_rng(777004)) lr.set_tree_rules([])