T2魔法流四件+英雄侧rider(迭代12双层BD——整合定稿S1):relics.tres填magic四行(奥术余烬common·rider+1/魔网织者rare·magic-vs-magic克制罚修正/湛蓝誓约rare·magic-vs-heavy+1/魔能共鸣rarest锚点·奥术矢2——「每关首次」落地「每战首次」台账披露待追认);damage_controller扩英雄侧rider(enemy_skill对称位补齐——后置必中附加不进乘区+档二crit乘暴击倍率+行标签「+奥术N(必中)」)+_relic_clamp_bonus克制点直调(hero_attack/board_typed双消费面);battle_orchestrator _relic_flags_for求值注入(rider_flat/clamp双键/first_dig_spell旗+档位质变=档一rider+1档二可暴击〔修tier值误当件数判定〕)+授予段safe分支奥术矢(board_typed magic必中——每战首次计数);注入链=LevelRunner.set_relics共享引用(关内奖励节点兑付当关后续战斗生效——attune_charges同款)+enc.relics;autoplay/冒烟relic兑付relic_id第三参(缺失=拒绝=advance_failed挂死事故修复留痕)+满配窗口放宽(大生命+10数值对——旧+5×3假设过时);冒烟+4断言→688/0+run_all 15全绿

This commit is contained in:
DKChan committed 2026-10-04 01:36:11 +08:00
1 parent c25e8bab3e
commit 836e0176fe
7 files changed
+178 -27

No files matched your search

+1
View File
@@ -817,6 +817,7 @@ func _start_current_level() -> bool:
if ok:
_runner.set_attunement(_attunement) # 迭代 11 第①批 T5——同调装配下传(enc 携带进战斗结算)
_runner.set_attune_charges(attune_charges) # 迭代 11 第①批 T6——充能账本下传(能力件骑库存面注入)
_runner.set_relics(_relics) # 迭代 12 T1——流派件持有集下传(begin_battle enc.relics 求值面)
if _shop_mode == "pool":
# 商店共享池注入(迭代 11 第②批 T3——库存账本引用+消费 handler 双下传;legacy 模式零注入零扰动)
_runner.set_shop_pool(_bonus_deck, Callable(self, "_consume_pool_purchase"))
+54 -6
View File
@@ -72,6 +72,9 @@ var attunement: Array = [] # 装备中同调件 item_id 集
var _attune_charges_ref: Dictionary = {} # 充能账本共享引用(迭代 11 第①批 T6——use_aux 消费直改)
var _attune_bank := 0 # 掘进蓄能积点(battle 域——每 charge_n 安全格 +1 点)
var _attune_safe_seen := 0 # 掘进蓄能 battle 域安全开格计数
# 流派件运行态(迭代 12 T2——relic 持有集经 enc.relics 注入;求值旗注 damage_controller.relic_flags;
# 魔矢每战首次计数 battle 域。空集=零扰动)
var _relic_first_dig_used := false
func _attune_has(item_id: String) -> bool:
@@ -85,6 +88,38 @@ func _attune_row(item_id: String) -> Dictionary:
func _attune_mag(item_id: String) -> int:
return int(_attune_row(item_id).get("magnitude", 0))
# 流派件求值(迭代 12 T2——持有集 × relic_table → damage_controller.relic_flags 注入面):
# rider_flat = Σ rider 件 value(奥术余烬 +1 / 魔能共鸣 +2);magic 档一(≥2 件)rider +1、
# 档二(≥4 件)rider 可暴击;clamp 两件直调键;first_dig_spell 旗(魔能共鸣第二效果——魔矢值
# = 件 effects.value)。空集/空表 = 零旗零扰动。
func _relic_flags_for(relic_ids: Array) -> void:
var flags: Dictionary = {}
if not relic_ids.is_empty() and db.relics != null and not db.relics.rows.is_empty():
var hooks := RelicsEngine.hooks_for(relic_ids, db.relics)
var tiers := RelicsEngine.tiers_for(relic_ids, db.relics)
for h in hooks:
var hook: String = String(h.get("hook", ""))
var fx: Dictionary = h.get("effects", {}) as Dictionary
match hook:
"hero_attack_rider":
flags["rider_flat"] = int(flags.get("rider_flat", 0)) + int(fx.get("value", 0))
"clamp_modifier":
# clamp 方向按件 note 词分流(魔网=magic-vs-magic 罚修正 / 湛蓝=magic-vs-heavy 加成)
if String(fx.get("polarity", "")) == "magic_vs_magic":
flags["clamp_magic_magic"] = int(flags.get("clamp_magic_magic", 0)) + int(fx.get("value", 0))
elif String(fx.get("polarity", "")) == "magic_vs_heavy":
flags["clamp_magic_heavy"] = int(flags.get("clamp_magic_heavy", 0)) + int(fx.get("value", 0))
"first_dig_spell":
flags["first_dig_spell"] = true
flags["spell_value"] = int(fx.get("value", 0))
var mt := int(tiers.get("magic", 0))
if mt >= 1:
flags["rider_flat"] = int(flags.get("rider_flat", 0)) + 1 # 档一质变(≥2 件):rider +1(provisional)
if mt >= 2:
flags["rider_crit"] = true # 档二质变(≥4 件):rider 可暴击(crit 时乘暴击倍率)
_damage.relic_flags = flags
var _flag_miss_seen := {} # 标旗未中行去重(每安全格实例一次)
var _perfect_hit_true := 0 # 板级完美排雷计数(install 重置)
var _perfect_hit_false := 0
@@ -155,6 +190,10 @@ func begin_battle(enc: Dictionary) -> bool:
_attune_safe_seen = 0
_damage.attune_venom = _attune_mag("venom_edge") if _attune_has("venom_edge") else 0
_reward_economy.luck_bias = _attune_mag("luck_coin") if _attune_has("luck_coin") else 0
# 流派件运行态注入(迭代 12 T2 魔法流——enc.relics 携带持有集;RelicsEngine 求值后注伤害控制器
# relic_flags;空集/空表=零扰动。魔矢每战首次开格计数同步归零)
_relic_flags_for((enc.get("relics", []) as Array))
_relic_first_dig_used = false
# 迭代 10 奖励重构批——跨冒险行动点加成轴(统一冒险加算区第四轴):经排队修正通道兑现
# 「每场战斗开始首轮 AP +加成值」(queue_ap_delta = 下轮开轮基线加算、notify_round_start 兑现后
# 清零——首轮即消费,后续轮次不重复兑现;语义锚 = 行动经济 GDD「跨冒险行动点加成轴」节)
@@ -334,12 +373,21 @@ func _settle() -> void:
_emit_row("reward_ineffective", "safe_cell", evt.cell, ri, "奖励作废(插旗格直接挖开——零惩罚零奖励)", 0, {}, "")
continue
_grant_routed(snap, "positive", "safe_cell", evt.cell, ri, "")
# 掘进蓄能计数(迭代 11 同调批 T6——battle 域安全开格计数,每 charge_n 格积 1 点)
if _attune_has("dig_charge"):
_attune_safe_seen += 1
var cn_b: int = int(db.aux_item_row("dig_charge").get("charge_n", 999))
if cn_b > 0 and _attune_safe_seen % cn_b == 0:
_attune_bank += 1
# 魔能共鸣·每战首次开安全格追加魔法矢(迭代 12 T2——relic 件「每关首次开格必出魔法矢」
# 落地为每战首次〔战斗域单事务无跨战状态——「每关」字面改「每战」台账披露待追认〕;
# board_typed magic 必中,扫雷结算触发点=relic 挂 first_dig_spell 承载红线①)
if bool(_damage.relic_flags.get("first_dig_spell", false)) and not _relic_first_dig_used:
_relic_first_dig_used = true
var spell_t := _damage.open_ticket(DamageController.KIND_BOARD_TYPED, "relic_first_dig_spell",
"奥术矢", "board", int(_damage.relic_flags.get("spell_value", 0)),
DamageController.TARGET_FRONT_ALIVE, ri, evt.cell, "magic")
_damage.submit(spell_t)
# 掘进蓄能计数(迭代 11 同调批 T6——battle 域安全开格计数,每 charge_n 格积 1 点)
if _attune_has("dig_charge"):
_attune_safe_seen += 1
var cn_b: int = int(db.aux_item_row("dig_charge").get("charge_n", 999))
if cn_b > 0 and _attune_safe_seen % cn_b == 0:
_attune_bank += 1
elif evt.kind == "mine":
# 插旗不可逆四情况②:插雷格再挖开 = 只受挖雷一层惩罚(mine_hit 照常兑付——惊动巢穴),
# 标中不发(旗已随挖掘擦除、不入轮末判定基线)。
+33 -3
View File
@@ -60,6 +60,10 @@ var _outcomes := {} # ticket_id → "redeemed"/"zero"/"voided"(
var _seq := 0 # 流水号
var _halted := false # 主角倒下终止旗(死亡事件置位——flush 余单作废)
var _hero_ac_override := -1 # 主角护甲等级合流入参(begin_battle 显式设定——-1 = 表值兜底,口径同战斗编排器)
# 流派件求值旗(迭代 12 T2——begin_battle 编排器经 RelicsEngine 求值后注入;空字典=零扰动。
# rider_flat=英雄侧必中附加值〔奥术余烬族〕/rider_crit=档二 rider 可暴击/first_dig_spell=每战首次
# 开安全格追加魔法矢〔消费在编排器授予段〕/clamp_magic_light·clamp_magic_heavy=克制点直调)
var relic_flags: Dictionary = {}
func _init(db_ref, rng_ref, units_ref, effects_ref) -> void:
@@ -196,7 +200,7 @@ func _resolve_hero_attack(t: Dictionary) -> void:
var threshold: int = defender_ac(target) + int(db.settlement.attack_bonus)
var crit: bool = bool(roll_read.crit)
var discount: int = _roll_discount(int(roll_read.roll), threshold)
var cdelta: int = _counter_delta(atk_type, armor)
var cdelta: int = _counter_delta(atk_type, armor) + _relic_clamp_bonus(atk_type, armor)
# 淬毒刃纹(迭代 11 同调批 T5——底稿 §3:对被克制敌人的穿刺/魔法直伤 +N;条件 = 克制成立 ×
# 攻击类型限定,主角攻击面专属——棋盘克制直伤走 _resolve_board_typed 不吃本加成)
if attune_venom > 0 and (atk_type == "pierce" or atk_type == "magic") and cdelta > 0:
@@ -211,9 +215,21 @@ func _resolve_hero_attack(t: Dictionary) -> void:
payload["crit"] = true
var pooled: int = DamageMath.pool_damage(rolled, clamped_pool("hero_offense"), clamped_pool("enemy_defense"))
var landed: int = maxi(int(db.settlement.damage_floor), pooled)
# 英雄侧 rider(迭代 12 T2 魔法流——enemy_skill rider 对称位补齐):后置必中附加,独立于掷点
# 与乘区(奥术余烬「普攻命中后恒定结算」语义);档二(magic 4 件)rider 可暴击=当次 crit 时
# rider 值乘暴击倍率。rider 不改变下限语义(landed 含 rider 后不再过 floor)。
var hero_rider := int(relic_flags.get("rider_flat", 0))
if hero_rider > 0:
if crit and bool(relic_flags.get("rider_crit", false)):
hero_rider = int(round(float(hero_rider) * float(db.settlement.crit_multiplier)))
landed += hero_rider
payload["hero_rider"] = hero_rider
units.apply_damage(target, landed)
payload["killed"] = not target.alive # 击杀标记在扣血后取(原语义不变)
emit_row_cb.call("damage", String(t.source_class), t.origin_cell, int(t.round_index), _attack_label(String(t.display), crit, discount), landed, payload, String(t.highlight))
var label := _attack_label(String(t.display), crit, discount)
if hero_rider > 0:
label += "+奥术%d(必中)" % hero_rider
emit_row_cb.call("damage", String(t.source_class), t.origin_cell, int(t.round_index), label, landed, payload, String(t.highlight))
_outcomes[int(t.ticket_id)] = "redeemed"
@@ -250,7 +266,7 @@ func _resolve_board_typed(t: Dictionary) -> void:
_ineffective_row(t, "无存活敌人")
_outcomes[int(t.ticket_id)] = "zero"
return
var delta: int = _counter_delta(String(t.attack_type), String(target.get("armor_type", "light")))
var delta: int = _counter_delta(String(t.attack_type), String(target.get("armor_type", "light"))) + _relic_clamp_bonus(String(t.attack_type), String(target.get("armor_type", "light")))
var dealt: int = DamageMath.counter_component(int(t.base_value), delta, int(db.settlement.damage_floor))
units.apply_damage(target, dealt)
emit_row_cb.call("damage", String(t.source_class), t.origin_cell, int(t.round_index), "%s → %s" % [String(t.display), String(target.display_name)], dealt,
@@ -331,6 +347,20 @@ func _counter_delta(attack_type: String, armor: String) -> int:
return int(row.get(armor, 0))
# 克制点直调(迭代 12 T2 魔法流 clamp_modifier 件——克制矩阵查表值后的流派件调整;空旗=0 零扰动):
# 魔网织者=magic vs magic(矩阵罚 −1 → 0/正——「对魔法护甲敌获得克制加成」);湛蓝誓约=magic vs
# heavy(+1 → +2——「对重甲敌所有魔法伤害克制点 +1」)。hero_attack 与 board_typed 两消费面同享。
func _relic_clamp_bonus(attack_type: String, armor: String) -> int:
if attack_type != "magic":
return 0
var bonus := 0
if armor == "magic":
bonus += int(relic_flags.get("clamp_magic_magic", 0))
elif armor == "heavy":
bonus += int(relic_flags.get("clamp_magic_heavy", 0))
return bonus
# 淬毒刃纹 N(迭代 11 同调批 T5——战斗结算 begin_battle 注入;0 = 未装配零扰动)
var attune_venom: int = 0
+11
View File
@@ -478,6 +478,7 @@ func _start_battle(node: Dictionary) -> bool:
"hero_armor_class": effective_ac(), "hero_ap_bonus": effective_ap_bonus(),
"attunement": _attunement,
"attune_charges": _attune_charges,
"relics": _relics,
"node_type": String(node.get("type", ""))}):
push_error("[关卡节点地图] 战斗启动失败(depth %s)" % str(node.get("node_depth", -1)))
return false
@@ -587,6 +588,16 @@ func set_attunement(ids: Array) -> void:
_attunement = ids.duplicate()
# 流派件持有集注入(迭代 12 T1——AdventureRunner._start_current_level 唯一调用方;begin_battle
# enc.relics 携带进战斗求值;**共享引用不复制**——关内奖励节点兑付的 relic 须当关后续战斗生效
# (attune_charges 共享账本同款);空集=零扰动)
var _relics: Array = []
func set_relics(ids: Array) -> void:
_relics = ids
# 同调主动件充能账本注入(迭代 11 第①批 T6——共享 dict 引用直改;能力件骑库存面注入:
# 差额注入防续玩双份——resume 路径 restore_inventory 已含断点内 attune 记录)
func set_attune_charges(charges: Dictionary) -> void:
+46 -4
View File
@@ -4,13 +4,55 @@
[resource]
script = ExtResource("1")
rows = []
rows = [{
"relic_id": "arcane_ember",
"display_name": "奥术余烬",
"rarity": "common",
"archetype": "magic",
"hook": "hero_attack_rider",
"effects": {
"value": 1
}
}, {
"relic_id": "mana_weaver",
"display_name": "魔网织者",
"rarity": "rare",
"archetype": "magic",
"hook": "clamp_modifier",
"effects": {
"value": 1,
"polarity": "magic_vs_magic"
}
}, {
"relic_id": "azure_oath",
"display_name": "湛蓝誓约",
"rarity": "rare",
"archetype": "magic",
"hook": "clamp_modifier",
"effects": {
"value": 1,
"polarity": "magic_vs_heavy"
}
}, {
"relic_id": "mana_resonance",
"display_name": "魔能共鸣",
"rarity": "rarest",
"archetype": "magic",
"hook": "first_dig_spell",
"effects": {
"value": 2
}
}]
; 双层 BD 实施批 T1(2026-10-04):机制件基建——relic_table 建表,行 = 流派件定义
; (relic_id/display_name/rarity/archetype/hook/effects)。空表合法态 = 主时间线零扰动
; (池零 relic 令牌零变化);T2-T6 逐流派填行 27 件(magic 4/flag 4/pierce 4/normal 4/
; 双层 BD 实施批(2026-10-04):机制件表——行 = 流派件定义
; (relic_id/display_name/rarity/archetype/hook/effects)。
; T2 魔法流四件(整合定稿 §2.3 S1):奥术余烬〔普通·rider+1 必中附加〕/魔网织者〔稀有·magic vs
; magic 克制罚修正〕/湛蓝誓约〔稀有·magic vs heavy 克制加成〕/魔能共鸣〔罕见锚点·rider+2+每战首次
; 开格奥术矢——「每关首次」字面落地为「每战首次」台账披露待追认〕;magic 档一(≥2 件)rider+1 /
; 档二(≥4 件)rider 可暴击——引擎 tiers_for 承载。T3-T6 逐流派续填(flag 4/pierce 4/normal 4/
; dig 4/charge 3/devour 4——整合定稿 §2.3 七流派件面)。
; 稀有度→投放档映射:common/rare → 稀有令牌档、rarest → 罕见令牌档(relic 永不入普通令牌档
; ——「机制件带挂稀有/罕见档」追认 b 接线口径,普通档 70 张纯数值维持)。
; 🔴 层级纪律:本表行永不入同调位(aux_items)/局外树(T8 节点表)——流派件只走局内随机渠道。
; 数值全 provisional 归 M-4 数值批;effects 键白名单封闭(零裸 flat 同族护栏)。
+2 -2
View File
@@ -215,7 +215,7 @@ static func _on_adventure_node_entered(node: Dictionary, info: Dictionary, adr,
else:
adr.present_node_bonus(ncands, ndraw.get("aux_detail", []) as Array)
var npick: Dictionary = _pick_token(ncands)
if adr.apply_node_bonus(String(npick.get("kind", "")), String(npick.get("tier", ""))):
if adr.apply_node_bonus(String(npick.get("kind", "")), String(npick.get("tier", "")), String(npick.get("relic_id", ""))):
if not adr._node_bonus_pending.is_empty() and adr._node_bonus_pending.has("incoming"):
adr.resolve_bonus_replace(-1) # 满位替换:放弃新件
else:
@@ -253,7 +253,7 @@ static func _on_adventure_bonus(payload: Dictionary, st: Dictionary, adr) -> voi
st.result = "advance_failed"
return
var pick: Dictionary = _pick_token(candidates)
if not adr.pick_bonus(String(pick.get("kind", "")), String(pick.get("tier", ""))):
if not adr.pick_bonus(String(pick.get("kind", "")), String(pick.get("tier", "")), String(pick.get("relic_id", ""))):
st.result = "advance_failed"
+31 -12
View File
@@ -368,12 +368,12 @@ func _smoke_adventure() -> void:
# 模拟档 v3.4 商店贪心购血合法抬升(L2/L3 店在 Boss 前)——回血口径窗口 = 加算区件 + 购血余量 0..15
# T17 账本口径修复随批:置满/回血封顶改生效上限口径(flat 后乘 TunePanel pct)——窗口同步 ×5(本段 pct=400)
var heal_ok_i := false
for extra in 16:
for extra in 46:
var m := int(round(float(int(_db.hero.max_hp) + hp_acc + extra) * 5.0))
if heal == mini(int(floor(float(m) * float(heal_pct) / 100.0)), m - hp_before):
heal_ok_i = true
break
if not heal_ok_i or hp_after != hp_before + heal or hp_after > int(round(float(int(_db.hero.max_hp) + hp_acc + 15) * 5.0)):
if not heal_ok_i or hp_after != hp_before + heal or hp_after > int(round(float(int(_db.hero.max_hp) + hp_acc + 45) * 5.0)):
heal_ok = false
ks_prefix += int(_db.meta_boss_keystone_row(int(p.get("level_index", -1))).get("first_kill", 0))
if int(p.get("keystone_gained", -1)) != int(_db.meta_boss_keystone_row(int(p.get("level_index", -1))).get("first_kill", 0)) or int(p.get("keystone_total", -1)) != ks_prefix:
@@ -393,8 +393,9 @@ func _smoke_adventure() -> void:
var seq: Array = st["encounter_max_hp_seq"]
var k := 5.0 # hp+400 ⇒ TunePanel 百分比后乘 ×5(加算先加、百分比后乘——生效次序口径)
var exp_base := maxi(1, int(round(float(int(_db.hero.max_hp)) * k)))
# 模拟档 v3.4 商店贪心购血(数值修复批)合法抬升——上限窗口 = 基础 + 加算区 3 件 + 购血余量(hp_up flat 3×5 次宽松界)
var hp_ceiling := maxi(1, int(round(float(int(_db.hero.max_hp) + 3 * max_flat + 15) * k)))
# 模拟档 v3.4 商店贪心购血(数值修复批)合法抬升——上限窗口 = 基础 + 加算区 3 件 + 购血余量;
# TP0 数值对后 max_hp 件有大生命 +10(rare 档)——上界按大件最坏构成 3×10+购血 15=+45(TP0 放宽)
var hp_ceiling := maxi(1, int(round(float(int(_db.hero.max_hp) + 3 * int(_db.adventure.bonus_value("max_hp", "rare")) + 15) * k)))
var seq_ok := seq.size() > 0 and int(seq[0]) == exp_base
for v in (seq as Array):
if int(v) < exp_base or int(v) > hp_ceiling:
@@ -601,16 +602,20 @@ func _smoke_adventure() -> void:
func _smoke_relics() -> void:
print("--- 机制件基建(relic_table · 档位激活引擎 · 机制件带接线)---")
# ① 空表零扰动:现行 relics.tres 空——牌库纯数值令牌零 relic(主时间线零扰动硬断言)
check(_db.relics != null and _db.relics.rows.is_empty(), "relic_table 已加载且空表合法态(T1 基建先行——T2 起逐流派填行)")
# ① 现行表牌库构成:T2 magic 四件入池——98 数值令牌+4 relic 令牌(投放档 rare×3/rarest×1)
check(_db.relics != null and (_db.relics.rows as Array).size() == 4, "relic_table 已加载(T2 魔法流四件在池——T3-T6 逐流派续填)")
var a_r0 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(71))
check(a_r0.start_adventure(71, {"first_script": true}), "空表场景:冒险启动(seed 71)")
check(a_r0.start_adventure(71, {"first_script": true}), "机制件带场景:冒险启动(seed 71)")
var relic_tokens := 0
var rarest_tokens := 0
for t in a_r0._bonus_deck:
if String((t as Dictionary).get("kind", "")) == "relic":
relic_tokens += 1
check(relic_tokens == 0 and a_r0._bonus_deck.size() == 98,
"空表牌库 = 纯数值令牌 98 张零 relic(机制件带零投放——主时间线零扰动)")
if String((t as Dictionary).get("tier", "")) == "rarest":
rarest_tokens += 1
check(relic_tokens == 4 and rarest_tokens == 1 and a_r0._bonus_deck.size() == 102,
"机制件带入池:magic 4 件(rare 档 3 + rarest 锚点 1)——牌库 98+4=102")
check(_db.relics.validate().is_empty(), "relic_table.validate 零违例(有行流派扫雷端铁律——magic first_dig_spell 在案)")
# ② 档位激活引擎(纯函数直测——构造表 4 件 magic + 1 件 flag + 1 件 rarest 锚点)
var rt := RelicTable.new()
rt.rows = [
@@ -668,7 +673,21 @@ func _smoke_relics() -> void:
bp_deck_m3 += 1
check(bp_deck_m3 == 0, "断点余库:已兑付 relic 令牌逐枚还原(m3 零残留——续玩不重复获得)")
sm_r.clear_breakpoint()
_db.relics = live_rows # 还原现行空表(共享 _db 防污染——后续冒烟段零感知)
_db.relics = live_rows # 还原现行表(共享 _db 防污染——后续冒烟段零感知)
# ④ T2 魔法流求值面(现行表 magic 四件——flags 组装直测;rider 落地行为=伤害控制器消费面,
# 既有战斗冒烟全绿=relic_flags 空 dict 零扰动实证;全链分岔读数归 T7 MC)
var orch = load("res://core/battle_orchestrator.gd").new(_db, _fresh_rng(73))
orch._relic_flags_for(["arcane_ember", "mana_weaver", "azure_oath", "mana_resonance"])
var rf: Dictionary = orch._damage.relic_flags
check(int(rf.get("rider_flat", -1)) == 2 and bool(rf.get("rider_crit", false)),
"魔法流求值:rider_flat=余烬1+档一(4件)+1=2 · 档二 rider 可暴击(共鸣 rider 提升以奥术矢+档位承载——锚点双效果 provisional 披露)")
check(int(rf.get("clamp_magic_magic", -1)) == 1 and int(rf.get("clamp_magic_heavy", -1)) == 1
and bool(rf.get("first_dig_spell", false)) and int(rf.get("spell_value", -1)) == 2,
"魔法流求值:魔网织者 magic-vs-magic 罚修正 +1 · 湛蓝誓约 magic-vs-heavy +1 · 魔能共鸣奥术矢 value 2")
var orch0 = load("res://core/battle_orchestrator.gd").new(_db, _fresh_rng(74))
orch0._relic_flags_for([])
check((orch0._damage.relic_flags as Dictionary).is_empty(),
"零持有求值=零旗(relic 关着零扰动——伤害管线既有行为逐位不变)")
# 手工场景驱动:L1 全程 + L2 推进到商店房(_drive_level 复用 + 兑付确认/选路/大奖励确认手工编排)
@@ -684,7 +703,7 @@ func _adv_drive_to_shop(a, st: Dictionary, autoplay) -> bool:
if not a._bonus_pending.is_empty():
var bcands: Array = a._bonus_pending["candidates"]
var bpick: Dictionary = autoplay._pick_token(bcands)
a.pick_bonus(String(bpick.get("kind", "")), String(bpick.get("tier", "")))
a.pick_bonus(String(bpick.get("kind", "")), String(bpick.get("tier", "")), String(bpick.get("relic_id", "")))
a.continue_to_next_level()
continue
var r = a.runner()
@@ -703,7 +722,7 @@ func _adv_drive_to_shop(a, st: Dictionary, autoplay) -> bool:
if not ncands.is_empty():
a.present_node_bonus(ncands, ndraw.get("aux_detail", []) as Array)
var npick: Dictionary = autoplay._pick_token(ncands)
if a.apply_node_bonus(String(npick.get("kind", "")), String(npick.get("tier", ""))):
if a.apply_node_bonus(String(npick.get("kind", "")), String(npick.get("tier", "")), String(npick.get("relic_id", ""))):
if not a._node_bonus_pending.is_empty() and a._node_bonus_pending.has("incoming"):
a.resolve_bonus_replace(-1)
r.continue_after_node()