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:
1 parent
c25e8bab3e
commit
836e0176fe
7 files changed
+178
-27
No files matched your search
@@ -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"))
|
||||
|
||||
@@ -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 照常兑付——惊动巢穴),
|
||||
# 标中不发(旗已随挖掘擦除、不入轮末判定基线)。
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 同族护栏)。
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
Reference in new issue
Block a user