diff --git a/data/bonds.json b/data/bonds.json index 92847302..d75f3374 100644 --- a/data/bonds.json +++ b/data/bonds.json @@ -1 +1 @@ -{"yanShip":{"bondId":"yanShip","name":"炎","identifier":1,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["yan","sui","lungmen","lee","lgd"],"iconId":"icon_yanShip","activeCount":3,"thresholds":[3,6,9],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【炎】干员攻击力提升(受层数影响)\n<在场6名不同【炎】干员>战斗开始时召唤可自主行动的“炎佑”,其攻击力生命值分别为开战时【炎】干员攻击力生命值总和的30%,“炎佑”同时攻击3个目标,可使用“祛恶之焰”,攻击时附带攻击力一定比例的灼燃损伤且周围敌人受到一定比例的元素脆弱\n<在场9名不同【炎】干员>改为召唤2只“炎佑”,攻击力提升至1.5倍,受到的伤害-90%","descRaw":"【炎】干员<@ba.vup>攻击力提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>6名不同【炎】干员>战斗开始时召唤可自主行动的<@ba.vup>“炎佑”,其攻击力生命值分别为开战时【炎】干员攻击力生命值总和的30%,“炎佑”同时攻击3个目标,可使用<@ba.vup>“祛恶之焰”,攻击时附带攻击力一定比例的灼燃损伤且周围敌人受到一定比例的元素脆弱\n<在场<@autochess.dgreen>9名不同【炎】干员>改为召唤2只<@ba.vup>“炎佑”,攻击力提升至<@ba.vup>1.5倍,受到的伤害<@ba.vup>-90%","effectId":"bondeffect_yan","effectName":"炎","effectDesc":"【炎】干员攻击力+{0:0%}(受层数影响)\n<在场6名不同【炎】干员>战斗开始时收集【炎】干员部分属性召唤“炎佑”(其攻击力和生命值为【炎】干员攻击力和生命值总和的30%);“炎佑”同时攻击3个目标,攻击附带20%攻击力的灼燃损伤,周围敌人受到20%的元素脆弱,周期性使用“祛恶之焰”\n<在场9名不同【炎】干员>改为召唤2只“炎佑”;“炎佑”攻击力提升至1.5倍,受到的伤害-90%","effectDescRaw":"【炎】干员攻击力<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【炎】干员>战斗开始时收集【炎】干员部分属性召唤“炎佑”(其攻击力和生命值为【炎】干员攻击力和生命值总和的30%);“炎佑”同时攻击3个目标,攻击附带20%<@ba.vup>攻击力的<@ba.vup>灼燃损伤,周围敌人受到20%的<@ba.vup>元素脆弱,周期性使用“祛恶之焰”\n<在场<@ba.vup>9名不同【炎】干员>改为召唤2只“炎佑”;“炎佑”攻击力提升至1.5倍,受到的伤害-90%","effectDescParams":[{"index":0,"format":"0%","base":"base_atk","perStack":"atk_per_stack"}],"bb":{"base_atk":0.23,"atk_per_stack":0.009,"power_bond_char_cnt":6,"ex_bond_char_cnt":9,"damage_resistance":0.9,"atk":1.5},"bbStr":{"key":"act1autochess_bond_eff_yan"},"buffs":[{"key":"env_gbuff_new","bb":{"base_atk":0.23,"atk_per_stack":0.009,"power_bond_char_cnt":6,"ex_bond_char_cnt":9,"damage_resistance":0.9,"atk":1.5},"bbStr":{"key":"act1autochess_bond_eff_yan"}}],"baseParams":["base_atk"],"perStackParams":["atk_per_stack"],"members":["chess_char_1_03_a","chess_char_2_04_a","chess_char_3_03_a","chess_char_3_04_a","chess_char_4_15_a","chess_char_4_17_a","chess_char_5_03_a","chess_char_5_12_a","chess_char_5_23_a","chess_char_6_03_a","chess_char_6_15_a"],"visibleMembers":["chess_char_1_03_a","chess_char_2_04_a","chess_char_3_03_a","chess_char_3_04_a","chess_char_4_17_a","chess_char_5_03_a","chess_char_5_12_a","chess_char_5_23_a","chess_char_6_03_a","chess_char_6_15_a"],"spec":{"tiers":[{"need":"3 distinct 炎 on board","effect":"炎 members (+调和 members) ATK x(1 + 0.23 + 0.009*L)."},{"need":"6 distinct","effect":"At battle start spawn 1 \"炎佑\" (enemy_9012_acloon template, allied flying ranged unit, not blockable, moves on its own). ATK = 0.30 x sum(ATK of 炎 operators on board at battle start), maxHP = 0.30 x sum(maxHP of those operators). Template: DEF 200, RES 0, BAT 2.5 s, ASPD 100, attack range radius 2.0 tiles, magic damage, hits up to 3 targets; every hit adds 灼燃损伤 (burn elemental damage) = 20% of its ATK and applies 元素脆弱 (elemental damage taken x1.2) to enemies within 0.8 tiles of the target. Skill \"祛恶之焰\": cooldown 15 s (first cast 15 s after spawn), channels a flame on one enemy in range dealing 60% ATK magic damage per second to it and to enemies within 1.0 tile, for up to 20 s."},{"need":"9 distinct","effect":"Spawn 2 炎佑 instead; each has ATK x1.5 and takes 90% less damage (damage_resistance 0.9)."}],"formulas":{"atkMultiplier":"1 + 0.23 + 0.009*L"},"caps":"none","layerGain":"Economy-driven: 惊蛰 获得时 +shop level (no activation needed); 小满 休整期结束 +1 per operator gained this round; 夕 +2 炎/奥术 per operator gained; 录武官 获得时 +6 炎 +3 奇迹; 星熊 获得时 +8 own bonds; 烛煌 获得时 +5 炎/维多利亚; 机变 \"诗怀雅的盟誓\" +10. Strategy 杜遥夜: first 2 manual refreshes each round prefer a 炎 operator.","howToPlay":"Buy many operators each round (every gain feeds 小满/夕), rush 6 炎 for the 炎佑 spike; 琳琅诗怀雅 / 诗怀雅 give early gold. 9 炎 is a late-game luxury.","assumed":["炎佑 base stats are replaced (not added) by the 30% sums","祛恶之焰 hit_duration=20 read as 20 one-second ticks","spawn point: centre of the player's board / near the objective","targets = 3 nearest enemies in range"]}},"sargonShip":{"bondId":"sargonShip","name":"萨尔贡","identifier":2,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["sargon"],"iconId":"icon_sargonShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【萨尔贡】干员开启技能时,所有【萨尔贡】干员攻击速度提升(有上限),持续一定时间(受层数影响,每层持续时间独立计算)\n<在场6名不同【萨尔贡】干员>开启技能还会为所有【萨尔贡】干员提供等持续时间的攻击力(有上限)\n选择策略【娜仁图亚】时,<在场6名不同【萨尔贡】干员>的效果会有所改变","descRaw":"【萨尔贡】干员开启技能时,所有【萨尔贡】干员<@ba.vup>攻击速度提升(有上限),持续一定时间<@autochess.gray>(受层数影响,每层持续时间独立计算)\n<在场<@autochess.dgreen>6名不同【萨尔贡】干员>开启技能还会为所有【萨尔贡】干员提供等持续时间的<@ba.vup>攻击力(有上限)\n<@ba.acrem>选择策略【娜仁图亚】时,<在场6名不同【萨尔贡】干员>的效果会有所改变","effectId":"bondeffect_sargon","effectName":"萨尔贡","effectDesc":"【萨尔贡】干员开启技能时,所有【萨尔贡】干员攻击速度+12(至多+300),持续{0:0}秒(受层数影响)\n<在场6名不同【萨尔贡】干员>开启技能还会使所有【萨尔贡】干员攻击力+12%(至多+300%)\n选择策略【娜仁图亚】时,<在场6名不同【萨尔贡】干员>的效果会有所改变","effectDescRaw":"【萨尔贡】干员开启技能时,所有【萨尔贡】干员攻击速度+12(至多<@ba.vup>+300),持续<@ba.vup>{0:0}秒<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【萨尔贡】干员>开启技能还会使所有【萨尔贡】干员攻击力+12%(至多<@ba.vup>+300%)\n<@ba.acrem>选择策略【娜仁图亚】时,<在场6名不同【萨尔贡】干员>的效果会有所改变","effectDescParams":[{"index":0,"format":"0","base":"base_time","perStack":"time_per_stack"}],"bb":{"base_time":5,"time_per_stack":0.22,"max_buff_stack_cnt":25,"base_attack_speed":12,"power_bond_char_cnt":6,"base_atk":0.12,"base_power_time":60,"power_time_per_stack":0,"filter_item_level":5},"bbStr":{"key":"act1autochess_bond_eff_sargon","invalid_in_band":"band_narant","valid_in_band":"band_narant"},"buffs":[{"key":"env_gbuff_new","bb":{"base_time":5,"time_per_stack":0.22,"max_buff_stack_cnt":25,"base_attack_speed":12,"power_bond_char_cnt":6,"base_atk":0.12},"bbStr":{"key":"act1autochess_bond_eff_sargon","invalid_in_band":"band_narant"}},{"key":"env_gbuff_new","bb":{"base_time":5,"time_per_stack":0.22,"max_buff_stack_cnt":25,"base_attack_speed":12,"power_bond_char_cnt":6,"base_power_time":60,"power_time_per_stack":0,"filter_item_level":5},"bbStr":{"key":"act2autochess_bond_eff_sargon[share]","valid_in_band":"band_narant"}}],"baseParams":["base_time"],"perStackParams":["time_per_stack"],"members":["chess_char_1_12_a","chess_char_2_06_a","chess_char_2_08_a","chess_char_3_06_a","chess_char_3_13_a","chess_char_4_05_a","chess_char_4_23_a","chess_char_4_24_a","chess_char_5_02_a","chess_char_5_18_a","chess_char_6_05_a","chess_char_6_06_a"],"visibleMembers":["chess_char_1_12_a","chess_char_2_06_a","chess_char_2_08_a","chess_char_3_06_a","chess_char_3_13_a","chess_char_4_23_a","chess_char_4_24_a","chess_char_5_02_a","chess_char_6_05_a","chess_char_6_06_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"Whenever any 萨尔贡 member activates its skill, every 萨尔贡 member on the field gains one stack: ASPD +12 for (5 + 0.22*L) s. Each stack has its own timer; at most 25 concurrent stacks (=> +300 ASPD cap)."},{"need":"6 distinct","effect":"Each stack additionally gives ATK +12% (25 stacks => +300% cap), same duration."},{"need":"6 distinct AND strategy 娜仁图亚 (band_narant)","effect":"Replaces the 6-member effect: when a 萨尔贡 member activates its skill, operators on its 8 surrounding tiles also enjoy the effects of the equipment (tier <= V, filter_item_level 5) it carries, for 60 s (base_power_time 60, power_time_per_stack 0)."}],"formulas":{"stackDurationSec":"5 + 0.22*L","aspdPerStack":"12","atkPerStack(6)":"0.12","maxStacks":"25"},"caps":"25 stacks: +300 ASPD, +300% ATK","layerGain":"In battle on skill activation: 菲莱 +6 每次开技能, 百炼嘉维尔 +9 每次开技能, 莎草 +5 首次开技能, 缇缇 +1 萨尔贡/精准 per sleep/stun in range (<=24/battle); 艾丝黛尔 获得时 +2; 机变 \"缇缇的盟誓\" +10. Strategy 佩佩: after shop level 2/4/6 one special refresh preferring 萨尔贡.","howToPlay":"Fast-cycling skills (萨尔贡浓茶 / 黄沙罗盘 items) keep many stacks alive; L mainly extends duration, so stacks overlap more.","notes":["PRTS: the in-level UI shows twice the real duration (display bug); real duration is 5+0.22L."],"assumed":["When a 26th stack would be added, it replaces the stack with the shortest remaining time","stack granted to all 萨尔贡 members including the caster"]}},"victoriaShip":{"bondId":"victoriaShip","name":"维多利亚","identifier":3,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["victoria","glasgow"],"iconId":"icon_victoriaShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":25,"mode":"every","effect":"bond_layer_added_reward_equip"}],"desc":"携带装备的【维多利亚】干员造成的伤害提升(受层数影响)\n<每叠加25层>获得1件带有随机效果的维式重锤\n<在场6名不同【维多利亚】干员>携带装备的【维多利亚】干员攻击力提升,携带进阶装备时额外提升","descRaw":"携带装备的【维多利亚】干员造成的<@ba.vup>伤害提升<@autochess.gray>(受层数影响)\n<每叠加<@autochess.dgreen>25层>获得1件带有随机效果的<@ba.vup>维式重锤\n<在场<@autochess.dgreen>6名不同【维多利亚】干员>携带装备的【维多利亚】干员<@ba.vup>攻击力提升,携带进阶装备时额外提升","effectId":"bondeffect_victoria","effectName":"维多利亚","effectDesc":"携带装备的【维多利亚】干员伤害提升至{0:0%}(受层数影响)\n<每叠加25层>获得一件带有随机特殊效果的维式重锤\n<在场6名不同【维多利亚】干员>【维多利亚】干员每携带1件装备攻击力+50%,携带进阶装备改为+80%","effectDescRaw":"<@ba.vup>携带装备的【维多利亚】干员伤害提升至<@ba.vup>{0:0%}<@ba.acrem>(受层数影响)\n<每叠加<@ba.vup>25层>获得一件带有随机特殊效果的维式重锤\n<在场<@ba.vup>6名不同【维多利亚】干员>【维多利亚】干员每携带1件装备攻击力<@ba.vup>+50%,携带进阶装备改为<@ba.vup>+80%","effectDescParams":[{"index":0,"format":"0%","base":"base_damage_scale","perStack":"damage_scale_per_stack"}],"bb":{"damage_scale_per_stack":0.008,"base_damage_scale":1.25,"power_bond_char_cnt":6,"atk_normal_equip":0.5,"atk_golden_equip":0.3,"layer":25,"count":1},"bbStr":{"key":"act1autochess_bond_eff_victoria","pool":"pool_equip_vict"},"buffs":[{"key":"env_gbuff_new","bb":{"damage_scale_per_stack":0.008,"base_damage_scale":1.25,"power_bond_char_cnt":6,"atk_normal_equip":0.5,"atk_golden_equip":0.3},"bbStr":{"key":"act1autochess_bond_eff_victoria"}},{"key":"bond_layer_added_reward_equip","bb":{"layer":25,"count":1},"bbStr":{"pool":"pool_equip_vict"}}],"baseParams":["base_damage_scale"],"perStackParams":["damage_scale_per_stack"],"members":["chess_char_1_06_a","chess_char_2_05_a","chess_char_2_10_a","chess_char_3_08_a","chess_char_4_07_a","chess_char_4_11_a","chess_char_5_03_a","chess_char_5_08_a","chess_char_6_07_a","chess_char_6_08_a"],"visibleMembers":["chess_char_1_06_a","chess_char_2_05_a","chess_char_2_10_a","chess_char_3_08_a","chess_char_4_07_a","chess_char_4_11_a","chess_char_5_03_a","chess_char_5_08_a","chess_char_6_07_a","chess_char_6_08_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"维多利亚 members that carry >= 1 equipment: all damage dealt x(1.25 + 0.008*L)."},{"need":"every 25 layers (cumulative)","effect":"Gain 1 维式重锤 with a random special effect (pool_equip_vict)."},{"need":"6 distinct","effect":"维多利亚 members: ATK +50% per equipped item; an advanced (进阶/golden) item gives +80% instead (atk_normal_equip 0.5 + atk_golden_equip 0.3)."}],"formulas":{"damageMultiplier":"1.25 + 0.008*L (only if carrying equipment)","hammerPayouts":"floor(L/25)","atkPerItem(6)":"0.5 normal, 0.8 advanced"},"caps":"none","layerGain":"休整期结束: 薄绿 +2 per distinct tier of 维多利亚 on board, 维娜·维多利亚 +3 per distinct tier (and 奇迹 +2 per distinct tier of 奇迹), 刺玫 +1, 号角 +2 per distinct-tier operator of the highest-layer bond; in battle: 风笛 first 3 kills +2 维多利亚/远见/不屈; 烛煌 获得时 +5; 机变 \"风笛的盟誓\" +8. Strategy 哈洛德: from round 4 gain 1 维多利亚 operator every 2 rounds.","howToPlay":"Field 维多利亚 of as many different tiers as possible (T1..T6) for 薄绿/维娜; hand all equipment (incl. free hammers) to 维多利亚 carries; 蒸汽之心 copies all hammer effects.","assumed":["pool_equip_vict = uniform random among 灼燃/坚固/加速/战栗维式重锤 (normal grade)","hammer payout also counts layers added while the bond is inactive"]}},"kjeragShip":{"bondId":"kjeragShip","name":"谢拉格","identifier":4,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["kjerag","karlan"],"iconId":"icon_kjeragShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【谢拉格】干员造成的伤害提升,对寒冷、冻结敌人获得额外提升(受层数影响)\n<在场6名不同【谢拉格】干员>战场上每25秒过一阵寒风使场上的敌人寒冷一定时间(受层数影响)","descRaw":"【谢拉格】干员造成的<@ba.vup>伤害提升,对<@ba.vup>寒冷、冻结敌人获得额外提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>6名不同【谢拉格】干员>战场上每25秒过一阵寒风使场上的敌人寒冷一定时间<@autochess.gray>(受层数影响)","effectId":"bondeffect_kjerag","effectName":"谢拉格","effectDesc":"【谢拉格】干员伤害提升至125%,对寒冷和冻结敌人额外提升至{0:0%}(受层数影响)\n<在场6名不同【谢拉格】干员>战场上每25秒吹过一阵寒风使敌人寒冷{1:0}秒(受层数影响)","effectDescRaw":"【谢拉格】干员伤害提升至<@ba.vup>125%,对寒冷和冻结敌人额外提升至<@ba.vup>{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【谢拉格】干员>战场上每25秒吹过一阵寒风使敌人寒冷<@ba.vup>{1:0}秒<@ba.acrem>(受层数影响)","effectDescParams":[{"index":0,"format":"0%","base":"base_ex_damage_scale","perStack":"ex_damage_scale_per_stack"},{"index":1,"format":"0","base":"bond_eff_kjerag[storm].base_time","perStack":"bond_eff_kjerag[storm].time_per_stack"}],"bb":{"base_damage_scale":1.25,"base_ex_damage_scale":1.35,"ex_damage_scale_per_stack":0.01,"power_bond_char_cnt":6,"bond_eff_kjerag[storm].interval":25,"bond_eff_kjerag[storm].base_time":20,"bond_eff_kjerag[storm].time_per_stack":0.1},"bbStr":{"key":"act1autochess_bond_eff_kjerag"},"buffs":[{"key":"env_gbuff_new","bb":{"base_damage_scale":1.25,"base_ex_damage_scale":1.35,"ex_damage_scale_per_stack":0.01,"power_bond_char_cnt":6,"bond_eff_kjerag[storm].interval":25,"bond_eff_kjerag[storm].base_time":20,"bond_eff_kjerag[storm].time_per_stack":0.1},"bbStr":{"key":"act1autochess_bond_eff_kjerag"}}],"baseParams":["base_ex_damage_scale","bond_eff_kjerag[storm].base_time"],"perStackParams":["ex_damage_scale_per_stack","bond_eff_kjerag[storm].time_per_stack"],"members":["chess_char_1_02_a","chess_char_2_03_a","chess_char_2_05_a","chess_char_3_11_a","chess_char_3_14_a","chess_char_3_20_a","chess_char_4_03_a","chess_char_4_13_a","chess_char_4_22_a","chess_char_5_14_a","chess_char_6_02_a","chess_char_6_19_a"],"visibleMembers":["chess_char_1_02_a","chess_char_2_05_a","chess_char_3_11_a","chess_char_3_14_a","chess_char_3_20_a","chess_char_4_13_a","chess_char_4_22_a","chess_char_5_14_a","chess_char_6_02_a","chess_char_6_19_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"谢拉格 members deal damage x1.25; against enemies that are 寒冷 (cold) or 冻结 (frozen) x(1.35 + 0.01*L) instead."},{"need":"6 distinct","effect":"Every 25 s a cold wind applies 寒冷 to every enemy on the field for (20 + 0.1*L) s."}],"formulas":{"damageMultiplier":"1.25","damageMultiplierVsColdOrFrozen":"1.35 + 0.01*L","windIntervalSec":"25","windColdDurationSec":"20 + 0.1*L"},"caps":"none","layerGain":"In battle, freeze-driven: 初雪 and 银灰 - each enemy in range that becomes frozen: 50% chance +1; 凛御银灰 gives the 谢拉格 operator in front of it a 60% version (<=200/battle); 锏 部署时 +8 own active bonds (<=24/battle). 获得时: 角峰 +2, 崖心 +3 (hidden), 雪猎 +5, 灵知 +5, 锏 +8. 机变 \"银灰的盟誓\" +8. Strategy 休露丝: first 谢拉格 bought each round costs 1.","howToPlay":"Standard AK rule: applying 寒冷 to an already-cold enemy freezes it. The 6-member wind + cold-on-hit sources (谢拉格不融冰 12% 1.5 s cold) create constant freezes, so layers can reach hundreds per battle.","notes":["巴哈姆特: avoid lighting 3 奥术 alongside max-layer 谢拉格 (圣聆初雪 gets damage-capped)."],"assumed":["first wind at t = 25 s","wind re-applying cold on a cold enemy triggers freeze like any cold source"]}},"lateranoShip":{"bondId":"lateranoShip","name":"拉特兰","identifier":5,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["laterano"],"iconId":"icon_lateranoShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【拉特兰】干员开启技能获得的弹药量提升(受层数影响)\n<在场6名不同【拉特兰】干员>【拉特兰】干员每消耗1发弹药,所有【拉特兰】干员攻击力提升(有上限)","descRaw":"【拉特兰】干员开启技能获得的<@ba.vup>弹药量提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>6名不同【拉特兰】干员>【拉特兰】干员每消耗1发弹药,所有【拉特兰】干员<@ba.vup>攻击力提升(有上限)","effectId":"bondeffect_laterano","effectName":"拉特兰","effectDesc":"【拉特兰】干员开启技能时获得的弹药量+{0:0%}(受层数影响)\n<在场6名不同【拉特兰】干员>任意【拉特兰】干员每消耗1发弹药,全体【拉特兰】干员攻击力+4%,至多+200%","effectDescRaw":"【拉特兰】干员开启技能时获得的弹药量<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【拉特兰】干员>任意【拉特兰】干员每消耗1发弹药,全体【拉特兰】干员攻击力+4%,至多<@ba.vup>+200%","effectDescParams":[{"index":0,"format":"0%","base":"base_ammo_percent","perStack":"ammo_percent_per_stack"}],"bb":{"base_ammo_percent":0.05,"ammo_percent_per_stack":0.015,"power_bond_char_cnt":6,"atk_per_consume":0.04,"max_atk_for_consume":2},"bbStr":{"key":"act1autochess_bond_eff_laterano"},"buffs":[{"key":"env_gbuff_new","bb":{"base_ammo_percent":0.05,"ammo_percent_per_stack":0.015,"power_bond_char_cnt":6,"atk_per_consume":0.04,"max_atk_for_consume":2},"bbStr":{"key":"act1autochess_bond_eff_laterano"}}],"baseParams":["base_ammo_percent"],"perStackParams":["ammo_percent_per_stack"],"members":["chess_char_1_01_a","chess_char_2_01_a","chess_char_3_01_a","chess_char_3_07_a","chess_char_3_21_a","chess_char_4_01_a","chess_char_4_02_a","chess_char_5_01_a","chess_char_6_01_a","chess_char_6_09_a","chess_char_6_13_a"],"visibleMembers":["chess_char_1_01_a","chess_char_2_01_a","chess_char_3_01_a","chess_char_3_21_a","chess_char_4_01_a","chess_char_4_02_a","chess_char_5_01_a","chess_char_6_01_a","chess_char_6_09_a","chess_char_6_13_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"When a 拉特兰 member activates a skill that grants ammo, ammo gained x(1 + 0.05 + 0.015*L), rounded down."},{"need":"6 distinct","effect":"Every ammo consumed by any 拉特兰 member: all 拉特兰 members ATK +4% (until battle end), max +200% (= 50 ammo)."}],"formulas":{"ammoMultiplier":"floor(baseAmmo * (1.05 + 0.015*L))","atkPerAmmo(6)":"0.04","atkCap(6)":"2.0"},"caps":"+200% ATK from the 6-member effect","layerGain":"Ammo consumption in battle: 圣约送葬人 each 7 bullets +7 拉特兰 (7 triggers => 49/battle) and +3 远见 (<=21/battle); 莫斯提马 ops in its 4 adjacent tiles each 6 ammo +1; 蕾缪安 each 10 bullets with 3 ops in its row +2 拉特兰/精准; 送葬人 first kill +3 精准/拉特兰. Prep: 空弦 进入休整期 +3 to self and front tile operator's active bonds. 机变 \"莫斯提马的盟誓\" +10. Strategy 潘格尼尼: after spending 55 gold gain a random elite T4+ 拉特兰.","howToPlay":"Only ammo-skill operators benefit from the 3-tier; the bond is weak until 6 (巴哈姆特: \"3人效果較差\").","assumed":["non-ammo skills unaffected","\"ammo consumed\" = each shot/bullet decrement"]}},"egirShip":{"bondId":"egirShip","name":"阿戈尔","identifier":6,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["egir","abyssal"],"iconId":"icon_egirShip","activeCount":3,"thresholds":[3,5],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【阿戈尔】干员生命值提升(受层数影响)\n战斗开始时,【阿戈尔】干员会吞噬身前一格干员对其造成5000点物理伤害并获得其基础攻击力和阻挡数,使【阿戈尔】叠加等于被吞噬者等阶的盟约层数(【阿戈尔】之间优先更靠左和靠上的干员发起吞噬)\n<在场5名不同【阿戈尔】干员>前3名【阿戈尔】干员首次被击倒时立刻复活","descRaw":"【阿戈尔】干员<@ba.vup>生命值提升<@autochess.gray>(受层数影响)\n战斗开始时,【阿戈尔】干员会<@ba.vup>吞噬身前一格干员对其造成<@ba.vdown>5000点物理伤害并获得其<@ba.vup>基础攻击力和<@ba.vup>阻挡数,使【阿戈尔】叠加等于被吞噬者等阶的<@ba.vup>盟约层数<@autochess.gray>(【阿戈尔】之间优先更靠左和靠上的干员发起吞噬)\n<在场<@autochess.dgreen>5名不同【阿戈尔】干员>前3名【阿戈尔】干员首次被击倒时<@ba.vup>立刻复活","effectId":"bondeffect_egir","effectName":"阿戈尔","effectDesc":"【阿戈尔】干员生命值+{0:0%}(受层数影响)\n战斗开始时【阿戈尔】干员依次吞噬身前一格干员造成5000点物理伤害并获得其基础攻击力和阻挡数,并叠加等于被吞噬者等阶的盟约层数(【阿戈尔】之间优先更靠左和靠上的干员发起吞噬)\n<在场5名不同【阿戈尔】干员>前3名【阿戈尔】干员首次被击倒时立刻复活","effectDescRaw":"【阿戈尔】干员生命值<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n战斗开始时【阿戈尔】干员依次吞噬身前一格干员造成<@ba.vdown>5000点物理伤害并获得其<@ba.vup>基础攻击力和<@ba.vup>阻挡数,并叠加等于被吞噬者等阶的盟约层数<@ba.acrem>(【阿戈尔】之间优先更靠左和靠上的干员发起吞噬)\n<在场<@ba.vup>5名不同【阿戈尔】干员>前3名【阿戈尔】干员首次被击倒时<@ba.vup>立刻复活","effectDescParams":[{"index":0,"format":"0%","base":"base_max_hp","perStack":"max_hp_per_stack"}],"bb":{"base_max_hp":0.35,"max_hp_per_stack":0.01,"damage_value":5000,"power_bond_char_cnt":5,"max_free_respawn_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_egir","bond_type":"bond_by_id","bond_id":"egirShip","bond_add_type":"by_charlevel"},"buffs":[{"key":"env_gbuff_new","bb":{"base_max_hp":0.35,"max_hp_per_stack":0.01,"damage_value":5000,"power_bond_char_cnt":5,"max_free_respawn_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_egir","bond_type":"bond_by_id","bond_id":"egirShip","bond_add_type":"by_charlevel"}}],"baseParams":["base_max_hp"],"perStackParams":["max_hp_per_stack"],"members":["chess_char_1_04_a","chess_char_2_07_a","chess_char_3_05_a","chess_char_3_09_a","chess_char_4_09_a","chess_char_4_12_a","chess_char_5_05_a","chess_char_5_13_a","chess_char_6_04_a"],"visibleMembers":["chess_char_1_04_a","chess_char_2_07_a","chess_char_3_05_a","chess_char_3_09_a","chess_char_4_09_a","chess_char_4_12_a","chess_char_5_05_a","chess_char_5_13_a","chess_char_6_04_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"阿戈尔 members maxHP x(1 + 0.35 + 0.01*L)."},{"need":"3 distinct (battle start)","effect":"Devour (吞噬): see algorithm."},{"need":"5 distinct","effect":"The first 3 阿戈尔 members by position (the devour order: leftmost first, then topmost; fixed at battle start) each revive immediately on their own first knock-out, whatever the order of knock-outs (max_free_respawn_cnt 3)."}],"algorithm":["Order: 阿戈尔 members sorted leftmost first, then topmost (\"更靠左和靠上\").","Each 阿戈尔 in order marks the unit on the tile directly in front of it (its facing direction) and also the front-tile unit of every 阿戈尔 it has marked (chain). It never marks itself, a unit it already marked, or a unit that marked it.","The marker immediately gains the base ATK of every unit it marked (added to base ATK at the final stage) and their block counts.","After all marks are placed, each mark makes its target suffer one 5000-point physical 流失 (HP loss, source = the target itself; if it dies, the kill is credited to the marker), resolved in marking order. A target that dies cancels its remaining pending marks.","Each devoured unit adds layers to 阿戈尔 equal to its tier (1-6), once per unit per battle.","(5-member tier) Revive is implemented as: when the unit leaves the field for any reason other than being moved, its next deployment has 0 redeploy time and 0 cost (PRTS). Devour layers: each devoured unit adds its tier once per battle (refreshes next round)."],"formulas":{"hpMultiplier":"1.35 + 0.01*L","devourDamage":"5000","layersPerDevoured":"tier of devoured unit"},"caps":"3 revives per battle","layerGain":"Devour (tier per devoured unit, every battle); 幽灵鲨 被击倒 +3; 归溟幽灵鲨 被击倒/替身切换 +5 阿戈尔 +5 不屈; 斯卡蒂 each 2 kills +1 阿戈尔/坚守/突袭; 海霓 first kill (enemy or ally) +3 阿戈尔/奥术; 机变 \"斯卡蒂的盟誓\" +8. Strategy 克莱门莎: an 阿戈尔 knocked out adds layers = its tier.","howToPlay":"Put cheap/high-tier fodder in front of 阿戈尔 carries: they steal base ATK and block, gain layers, and (5) revive. Tier-6 fodder gives +6 layers per battle.","assumed":["5000 physical 流失 ignores DEF and shields","marked allied units are the player's own operators (devour hits allies)"]}},"siracusaShip":{"bondId":"siracusaShip","name":"叙拉古","identifier":7,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["siracusa","chiave"],"iconId":"icon_siracusaShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【叙拉古】干员部署后攻击速度提升,持续一定时间(受层数影响)\n<在场6名不同【叙拉古】干员>【叙拉古】干员部署后进入等时长的隐匿状态,【叙拉古】干员隐匿状态下和脱离隐匿10秒内对敌人攻击时有3%的概率造成一定真实伤害(受层数影响)并恐惧3秒","descRaw":"【叙拉古】干员部署后<@ba.vup>攻击速度提升,持续一定时间<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>6名不同【叙拉古】干员>【叙拉古】干员部署后进入等时长的隐匿状态,【叙拉古】干员隐匿状态下和脱离隐匿<@ba.vup>10秒内对敌人攻击时有<@ba.vup>3%的概率造成一定真实伤害<@autochess.gray>(受层数影响)并<@ba.vup>恐惧3秒","effectId":"bondeffect_siracusa","effectName":"叙拉古","effectDesc":"【叙拉古】干员部署后攻击速度+{0:0},持续{1:0}秒(受层数影响)\n<在场6名不同【叙拉古】干员>【叙拉古】干员部署后还会进入等时长的隐匿状态,【叙拉古】干员在隐匿状态和脱离隐匿10秒内对敌人攻击时有3%概率造成{2:0}(受层数影响)点真实伤害并恐惧目标3秒","effectDescRaw":"【叙拉古】干员部署后攻击速度<@ba.vup>+{0:0},持续<@ba.vup>{1:0}秒<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【叙拉古】干员>【叙拉古】干员部署后还会进入等时长的隐匿状态,【叙拉古】干员在隐匿状态和脱离隐匿10秒内对敌人攻击时有3%概率造成<@ba.vup>{2:0}<@ba.acrem>(受层数影响)点真实伤害并<@ba.vup>恐惧目标3秒","effectDescParams":[{"index":0,"format":"0","base":"base_attack_speed","perStack":"attack_speed_per_stack"},{"index":1,"format":"0","base":"base_duration","perStack":"duration_per_stack"},{"index":2,"format":"0","base":"base_damage","perStack":"damage_per_stack"}],"bb":{"base_duration":32,"duration_per_stack":0.4,"base_attack_speed":25,"attack_speed_per_stack":0.8,"power_bond_char_cnt":6,"ex_bond_char_cnt":6,"end_duration":10,"prob":0.03,"base_damage":5000,"damage_per_stack":50,"fear":3},"bbStr":{"key":"act2autochess_bond_eff_siracusa"},"buffs":[{"key":"env_gbuff_new","bb":{"base_duration":32,"duration_per_stack":0.4,"base_attack_speed":25,"attack_speed_per_stack":0.8,"power_bond_char_cnt":6,"ex_bond_char_cnt":6,"end_duration":10,"prob":0.03,"base_damage":5000,"damage_per_stack":50,"fear":3},"bbStr":{"key":"act2autochess_bond_eff_siracusa"}}],"baseParams":["base_attack_speed","base_duration","base_damage"],"perStackParams":["attack_speed_per_stack","duration_per_stack","damage_per_stack"],"members":["chess_char_1_07_a","chess_char_1_08_a","chess_char_2_16_a","chess_char_3_15_a","chess_char_3_18_a","chess_char_3_19_a","chess_char_4_10_a","chess_char_4_16_a","chess_char_5_10_a","chess_char_5_20_a","chess_char_6_18_a"],"visibleMembers":["chess_char_1_07_a","chess_char_1_08_a","chess_char_2_16_a","chess_char_3_18_a","chess_char_3_19_a","chess_char_4_10_a","chess_char_4_16_a","chess_char_5_10_a","chess_char_5_20_a","chess_char_6_18_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"After every deployment (incl. redeploy) a 叙拉古 member gains ASPD +(25 + 0.8*L) for (32 + 0.4*L) s."},{"need":"6 distinct","effect":"After deployment also 隐匿 (camouflage) for the same duration. While camouflaged and for 10 s after it ends, each normal damage instance it deals may add (5000 + 50*L) true damage (source = the operator) and 恐惧 (fear) 3 s. Nominal 3% chance, implemented as pseudo-random: all 叙拉古 members share one counter; attempt n since last proc succeeds with p = 0.00139*n (guaranteed at n = 720); counter resets on proc."}],"formulas":{"aspd":"25 + 0.8*L","durationSec":"32 + 0.4*L","procDamage":"5000 + 50*L","prdStep":"0.00139"},"caps":"none","layerGain":"Shop refresh-driven: 拉普兰德 first manual refresh each round +4 (works from bench); 安洁莉娜 休整期结束 +4 per refresh this round (<=12/round); 阿罗玛 +2 叙拉古/奥术 per refresh (<=6); 伺夜 first 3 kills +2 叙拉古 +1 奇迹; 荒芜拉普兰德 each kill +2 (elite: every 叙拉古 gets this, <=100/battle); 忍冬 获得时 +6 own bonds (x2/x3 with 投资人); 机变 \"德克萨斯的盟誓\" +10. Strategy 贾维: every 6 manual refreshes get a free 叙拉古 (<=2/round).","howToPlay":"Refresh a lot in prep (free refresh sources: 普罗旺斯, 德克萨斯, 缄默德克萨斯, 巫恋) to feed 拉普兰德/安洁莉娜; pair with 投资人 for 忍冬.","notes":["PRTS: the 10 s post-stealth window restarts if the operator's status effects or immunities change."],"assumed":["隐匿 = standard AK camouflage (not targeted by ranged enemies unless blocking)"]}},"kazimierzShip":{"bondId":"kazimierzShip","name":"卡西米尔","identifier":8,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["kazimierz","pinus"],"iconId":"icon_kazimierzShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"每次有干员部署时,【卡西米尔】干员攻击力+20%持续至战斗结束(上限受层数影响)\n<在场6名不同【卡西米尔】干员>【卡西米尔】干员阻挡敌人时每2秒对周围敌人造成120%攻击力真实伤害和0.1秒晕眩,未阻挡敌人时攻击附带30%攻击力的真实伤害","descRaw":"每次有干员部署时,【卡西米尔】干员攻击力<@ba.vup>+20%持续至战斗结束<@autochess.gray>(上限受层数影响)\n<在场<@autochess.dgreen>6名不同【卡西米尔】干员>【卡西米尔】干员阻挡敌人时每<@ba.vup>2秒对周围敌人造成<@ba.vup>120%攻击力真实伤害和<@ba.vup>0.1秒晕眩,未阻挡敌人时攻击附带<@ba.vup>30%攻击力的真实伤害","effectId":"bondeffect_kazimierz","effectName":"卡西米尔","effectDesc":"每次有干员部署时【卡西米尔】干员攻击力+20%(至多+{0:0%})(受层数影响)\n<在场6名不同【卡西米尔】干员>【卡西米尔】干员阻挡敌人时每2秒对周围敌人造成120%攻击力真实伤害和0.1秒晕眩,未阻挡敌人时攻击附带30%攻击力的真实伤害","effectDescRaw":"每次有干员部署时【卡西米尔】干员攻击力+20%(至多<@ba.vup>+{0:0%})<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【卡西米尔】干员>【卡西米尔】干员阻挡敌人时每2秒对周围敌人造成<@ba.vup>120%攻击力真实伤害和<@ba.vup>0.1秒晕眩,未阻挡敌人时攻击附带<@ba.vup>30%攻击力的真实伤害","effectDescParams":[{"index":0,"format":"0%","base":"base_max_atk_when_born","perStack":"max_atk_when_born_per_stack"}],"bb":{"atk_when_born":0.2,"base_max_atk_when_born":0.5,"max_atk_when_born_per_stack":0.01,"damage_interval":2,"damage_atk_scale":1.2,"stun":0.1,"range_radius":0.8,"power_bond_char_cnt":6,"pure_atk_scale":0.3},"bbStr":{"key":"act2autochess_bond_eff_kazimierz"},"buffs":[{"key":"env_gbuff_new","bb":{"atk_when_born":0.2,"base_max_atk_when_born":0.5,"max_atk_when_born_per_stack":0.01,"damage_interval":2,"damage_atk_scale":1.2,"stun":0.1,"range_radius":0.8,"power_bond_char_cnt":6,"pure_atk_scale":0.3},"bbStr":{"key":"act2autochess_bond_eff_kazimierz"}}],"baseParams":["base_max_atk_when_born"],"perStackParams":["max_atk_when_born_per_stack"],"members":["chess_char_1_19_a","chess_char_2_12_a","chess_char_2_18_a","chess_char_3_12_a","chess_char_3_17_a","chess_char_4_19_a","chess_char_4_20_a","chess_char_5_19_a","chess_char_6_17_a","chess_char_6_19_a"],"visibleMembers":["chess_char_1_19_a","chess_char_2_12_a","chess_char_2_18_a","chess_char_3_12_a","chess_char_3_17_a","chess_char_4_19_a","chess_char_4_20_a","chess_char_5_19_a","chess_char_6_17_a","chess_char_6_19_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"Every time any friendly operator is deployed (incl. redeploys) each 卡西米尔 member gains ATK +20% until battle end, capped at +(50 + 1*L)%."},{"need":"6 distinct","effect":"While blocking >= 1 enemy: every 2 s deals 120% ATK true damage to all enemies within radius 0.8 tiles and stuns them 0.1 s. While not blocking: each normal damage instance adds 30% ATK sourceless true damage."}],"formulas":{"atkPerDeploy":"0.20","atkCap":"0.50 + 0.01*L"},"caps":"ATK bonus cap 50%+1%/layer","layerGain":"Deploy-driven in battle: 砾 部署时 +1; 瑕光 部署时 +4 own active bonds (<=12/battle); 远牙 grants the right-most operator in its row \"部署时 +4 卡西米尔/精准 (<=24/battle)\"; 锏 部署时 +8 (<=24); 获得时: 野鬃 +2, 灰毫 +3 to highest-layer bond; 机变 \"玛恩纳的盟誓\" +12. Strategy 玛恩纳: +1 gold next round per 卡西米尔 bought (<=3).","howToPlay":"Maximise deploy events: low redeploy time (助力 -30%, 骑士戒律), operators that die/retreat and come back (砾 + 不屈). 巴哈姆特: do not light 坚守 (damage sharing keeps 砾 alive).","assumed":["initial auto-deployments at battle start also count as deploys","buff applies to members deployed later too (stored globally, capped)"]}},"preciShip":{"bondId":"preciShip","name":"精准","identifier":9,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_preciShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【精准】干员攻击力提升(受层数影响)\n<在场3名不同【精准】干员>生效范围变为【精准】干员和所有远程干员,且攻击无视一定的防御力和法术抗性","descRaw":"【精准】干员<@ba.vup>攻击力提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>3名不同【精准】干员>生效范围变为【精准】干员和所有远程干员,且攻击无视一定的<@ba.vup>防御力和<@ba.vup>法术抗性","effectId":"bondeffect_preci","effectName":"精准","effectDesc":"【精准】干员攻击力+{0:0%}(受层数影响)\n<在场3名不同【精准】干员>生效范围变为所有【精准】干员和远程干员,且攻击无视30%防御力和法术抗性","effectDescRaw":"【精准】干员攻击力<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>3名不同【精准】干员>生效范围变为所有【精准】干员和远程干员,且攻击无视<@ba.vup>30%防御力和法术抗性","effectDescParams":[{"index":0,"format":"0%","base":"base_atk","perStack":"atk_per_stack"}],"bb":{"base_atk":0.1,"atk_per_stack":0.012,"power_def_penetrate":0.3,"power_magic_resist_penetrate":0.3,"power_bond_char_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_preci"},"buffs":[{"key":"env_gbuff_new","bb":{"base_atk":0.1,"atk_per_stack":0.012,"power_def_penetrate":0.3,"power_magic_resist_penetrate":0.3,"power_bond_char_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_preci"}}],"baseParams":["base_atk"],"perStackParams":["atk_per_stack"],"members":["chess_char_1_09_a","chess_char_1_17_a","chess_char_2_01_a","chess_char_3_11_a","chess_char_4_06_a","chess_char_4_14_a","chess_char_4_20_a","chess_char_5_02_a","chess_char_6_01_a","chess_char_6_05_a","chess_char_6_08_a","chess_char_6_12_a"],"visibleMembers":["chess_char_1_09_a","chess_char_1_17_a","chess_char_2_01_a","chess_char_3_11_a","chess_char_4_06_a","chess_char_4_14_a","chess_char_4_20_a","chess_char_5_02_a","chess_char_6_01_a","chess_char_6_05_a","chess_char_6_08_a","chess_char_6_12_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"精准 members ATK x(1 + 0.10 + 0.012*L)."},{"need":"3 distinct","effect":"Scope becomes 精准 members + every RANGED operator; affected units also ignore 30% of target DEF and 30% of target RES."}],"formulas":{"atkMultiplier":"1.10 + 0.012*L","defPenetrateRatio(3)":"0.3","resPenetrateRatio(3)":"0.3"},"layerGain":"Kill/skill/deploy in battle: 寒芒克洛丝 gives front operator \"开技能 +1 精准 (<=10/battle)\"; 远牙 grant (+4/deploy); 缇缇 +1 per sleep/stun; 蕾缪安, 送葬人; 莱恩哈特 休整期结束 +5 own active bonds; 获得时: 深靛 +2, 雪猎 +5. 机变 \"缇缇的盟誓\" +10.","assumed":["penetration = ratio ignore (like 无视 x% 防御)"]}},"swiftShip":{"bondId":"swiftShip","name":"迅捷","identifier":10,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_swiftShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":40,"mode":"reach","effect":"env_gbuff_new"}],"desc":"【迅捷】干员技能结束时有概率(受层数影响)立刻回复12点技力\n<达到40层>所有干员技能结束时有等概率额外回复15点技力","descRaw":"【迅捷】干员技能结束时有概率<@autochess.gray>(受层数影响)立刻回复<@ba.vup>12点技力\n<达到<@autochess.dgreen>40层>所有干员技能结束时有等概率额外回复<@ba.vup>15点技力","effectId":"bondeffect_swift","effectName":"迅捷","effectDesc":"【迅捷】干员技能结束时有{0:0%}概率(受层数影响)立刻回复12点技力\n<达到40层>所有干员技能结束时有等概率额外回复15点技力","effectDescRaw":"【迅捷】干员技能结束时有<@ba.vup>{0:0%}概率<@ba.acrem>(受层数影响)立刻回复<@ba.vup>12点技力\n<达到<@ba.vup>40层>所有干员技能结束时有等概率额外回复<@ba.vup>15点技力","effectDescParams":[{"index":0,"format":"0%","base":"base_prob","perStack":"prob_per_stack"}],"bb":{"base_prob":0.2,"prob_per_stack":0.0035,"power_bond_stack_cnt":40,"normal_sp":12,"power_sp":15},"bbStr":{"key":"act1autochess_bond_eff_swift"},"buffs":[{"key":"env_gbuff_new","bb":{"base_prob":0.2,"prob_per_stack":0.0035,"power_bond_stack_cnt":40,"normal_sp":12,"power_sp":15},"bbStr":{"key":"act1autochess_bond_eff_swift"}}],"baseParams":["base_prob"],"perStackParams":["prob_per_stack"],"members":["chess_char_1_01_a","chess_char_1_16_a","chess_char_1_19_a","chess_char_2_13_a","chess_char_2_19_a","chess_char_3_10_a","chess_char_3_18_a","chess_char_4_14_a","chess_char_5_14_a","chess_char_5_15_a","chess_char_5_22_a","chess_char_6_05_a","chess_char_6_10_a","chess_char_6_19_a"],"visibleMembers":["chess_char_1_01_a","chess_char_1_19_a","chess_char_2_13_a","chess_char_2_19_a","chess_char_3_10_a","chess_char_3_18_a","chess_char_4_14_a","chess_char_5_14_a","chess_char_5_15_a","chess_char_5_22_a","chess_char_6_05_a","chess_char_6_19_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"When a 迅捷 member's skill ends: with p = min(1, 0.20 + 0.0035*L) immediately +12 SP."},{"need":"L >= 40","effect":"Every operator whose skill ends: with the same p, additionally +15 SP."}],"formulas":{"p":"min(1, 0.20 + 0.0035*L)","reaches100%AtL":"229"},"layerGain":"妮芙 休整期结束 +2 per operator on the bench; 蒂比 进入休整期 +2 own active bonds; 莱恩哈特 +5; 引星棘刺 +4 self & front; 获得时: 锡人/野鬃 +2, 忍冬 +6, 锏 +8. 机变 \"银灰的盟誓\" +8.","assumed":["迅捷 members roll both the 12 SP and the 15 SP independently"]}},"skillfulShip":{"bondId":"skillfulShip","name":"灵巧","identifier":11,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_skillfulShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":40,"mode":"reach","effect":"env_gbuff_new"}],"desc":"【灵巧】干员及周围4格干员攻击速度提升(受层数影响)\n<达到40层>生效范围变为【灵巧】干员周围8格","descRaw":"【灵巧】干员及周围4格干员<@ba.vup>攻击速度提升<@autochess.gray>(受层数影响)\n<达到<@autochess.dgreen>40层>生效范围变为【灵巧】干员周围8格","effectId":"bondeffect_skillful","effectName":"灵巧","effectDesc":"【灵巧】干员及周围4格的干员攻击速度+{0:0}(受层数影响)\n <达到40层>生效范围变为【灵巧】干员周围8格","effectDescRaw":"【灵巧】干员及周围4格的干员攻击速度<@ba.vup>+{0:0}<@ba.acrem>(受层数影响)\n <达到<@ba.vup>40层>生效范围变为【灵巧】干员周围8格","effectDescParams":[{"index":0,"format":"0","base":"base_attack_speed","perStack":"attack_speed_per_stack"}],"bb":{"base_attack_speed":10,"attack_speed_per_stack":1,"power_bond_stack_cnt":40},"bbStr":{"key":"act1autochess_bond_eff_skillful"},"buffs":[{"key":"env_gbuff_new","bb":{"base_attack_speed":10,"attack_speed_per_stack":1,"power_bond_stack_cnt":40},"bbStr":{"key":"act1autochess_bond_eff_skillful"}}],"baseParams":["base_attack_speed"],"perStackParams":["attack_speed_per_stack"],"members":["chess_char_1_14_a","chess_char_2_04_a","chess_char_2_13_a","chess_char_3_02_a","chess_char_3_13_a","chess_char_3_21_a","chess_char_4_11_a","chess_char_4_13_a","chess_char_4_21_a","chess_char_5_06_a","chess_char_5_16_a","chess_char_6_16_a"],"visibleMembers":["chess_char_1_14_a","chess_char_2_04_a","chess_char_2_13_a","chess_char_3_02_a","chess_char_3_13_a","chess_char_3_21_a","chess_char_4_11_a","chess_char_4_13_a","chess_char_4_21_a","chess_char_5_06_a","chess_char_6_16_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"灵巧 members and operators on their 4 orthogonally adjacent tiles: ASPD +(10 + 1*L)."},{"need":"L >= 40","effect":"Area becomes the 8 surrounding tiles."}],"formulas":{"aspd":"10 + L"},"layerGain":"溯光星源 休整期结束 +2 灵巧/奥术 per 3 gold spent this round ; 断崖 +3 self & behind; 空弦 +3 self & front; 蒂比 +2; 获得时 灵知 +5. (act1 灵巧 also had a 20-layer shop reward; removed in act2.)","assumed":["a unit covered by several 灵巧 auras gets the bonus once"]}},"arcaneShip":{"bondId":"arcaneShip","name":"奥术","identifier":12,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_arcaneShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【奥术】干员造成法术伤害时使目标受到的法术伤害提升(受层数影响),持续3秒\n<在场3名不同【奥术】干员>【奥术】干员对生命值低于50%的敌人施加的伤害提升比例提升(受层数影响)","descRaw":"【奥术】干员造成法术伤害时使目标受到的法术伤害提升<@autochess.gray>(受层数影响),持续3秒\n<在场<@autochess.dgreen>3名不同【奥术】干员>【奥术】干员对生命值低于<@ba.vup>50%的敌人施加的伤害提升比例提升<@autochess.gray>(受层数影响)","effectId":"bondeffect_arcane","effectName":"奥术","effectDesc":"【奥术】干员造成法术伤害时使目标受到的法术伤害提升{0:0%}(受层数影响),持续3秒\n<在场3名不同【奥术】干员>【奥术】干员对生命值低于50%的敌人施加的伤害提升比例为{1:0%}(受层数影响)","effectDescRaw":"【奥术】干员造成法术伤害时使目标受到的法术伤害提升<@ba.vup>{0:0%}<@ba.acrem>(受层数影响),持续3秒\n<在场<@ba.vup>3名不同【奥术】干员>【奥术】干员对生命值低于50%的敌人施加的伤害提升比例为<@ba.vup>{1:0%}<@ba.acrem>(受层数影响)","effectDescParams":[{"index":0,"format":"0%","base":"base_damage_scale_show","perStack":"damage_scale_per_stack"},{"index":1,"format":"0%","base":"base_damage_scale_show_ex","perStack":"damage_scale_per_stack_show_ex"}],"bb":{"weak_duration":3,"base_damage_scale":1.2,"damage_scale_per_stack":0.01,"power_bond_char_cnt":3,"power_weak_scale":1.4,"hp_ratio":0.5,"base_damage_scale_show":0.2,"base_damage_scale_show_ex":0.68,"damage_scale_per_stack_show_ex":0.014},"bbStr":{"key":"act2autochess_bond_eff_arcane"},"buffs":[{"key":"env_gbuff_new","bb":{"weak_duration":3,"base_damage_scale":1.2,"damage_scale_per_stack":0.01,"power_bond_char_cnt":3,"power_weak_scale":1.4,"hp_ratio":0.5,"base_damage_scale_show":0.2,"base_damage_scale_show_ex":0.68,"damage_scale_per_stack_show_ex":0.014},"bbStr":{"key":"act2autochess_bond_eff_arcane"}}],"baseParams":["base_damage_scale_show","base_damage_scale_show_ex"],"perStackParams":["damage_scale_per_stack","damage_scale_per_stack_show_ex"],"members":["chess_char_1_17_a","chess_char_2_10_a","chess_char_2_15_a","chess_char_3_09_a","chess_char_4_02_a","chess_char_4_10_a","chess_char_5_07_a","chess_char_5_12_a","chess_char_6_02_a","chess_char_6_16_a"],"visibleMembers":["chess_char_1_17_a","chess_char_2_10_a","chess_char_3_09_a","chess_char_4_02_a","chess_char_4_10_a","chess_char_5_07_a","chess_char_5_12_a","chess_char_6_02_a","chess_char_6_16_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"When an 奥术 member deals magic damage, the target takes magic damage x(1.20 + 0.01*L) (i.e. +(20+L)%) for 3 s. ONE instance per target whatever applies it: the strongest value wins, a weaker one resumes if it outlasts it; reapplying refreshes (corrected 2026-10-01: PRTS 作战机制 同名buff默认只表现出一个; 巴哈姆特 12316 the two players of a pair field compete for it)."},{"need":"3 distinct","effect":"Against enemies below 50% HP the multiplier is 1.4 x (1.20 + 0.01*L) = 1.68 + 0.014*L (i.e. +(68+1.4L)%)."}],"formulas":{"magicTakenMul":"1.20 + 0.01*L","magicTakenMulLowHp(3)":"1.4*(1.20 + 0.01*L)","hpThreshold":"0.5","durationSec":"3"},"layerGain":"夕 +2 per operator gained; 阿罗玛 +2 per refresh (<=6); 溯光星源 +2 per 3 gold spent; 海霓 first kill +3; 获得时: 深靛 +2, 协律 +4 (hidden). 机变 \"莫斯提马的盟誓\" +10.","assumed":["one instance per target, the strongest (the engine's default same-name rule; the two players of a pair field compete for it) — until v2.5 the remake kept one per player and they multiplied"]}},"steadShip":{"bondId":"steadShip","name":"坚守","identifier":13,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_steadShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"所有干员生命值提升(受层数影响)\n<在场3名不同【坚守】干员>场上非【坚守】干员受到伤害时,所受伤害的40%由所有【坚守】干员平均承担。【坚守】干员受到伤害时,伤害来源将受到一定法术伤害(受层数影响,每0.2秒至多触发1次)和持续5秒的40%脆弱效果","descRaw":"所有干员<@ba.vup>生命值提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>3名不同【坚守】干员>场上非【坚守】干员受到伤害时,所受伤害的<@ba.vup>40%由所有【坚守】干员<@ba.vup>平均承担。【坚守】干员受到伤害时,伤害来源将受到一定法术伤害<@autochess.gray>(受层数影响,每0.2秒至多触发1次)和持续<@ba.vup>5秒的<@ba.vup>40%脆弱效果","effectId":"bondeffect_stead","effectName":"坚守","effectDesc":"所有干员生命值+{0:0%}(受层数影响)\n<在场3名不同【坚守】干员>场上非【坚守】干员受到伤害时,所受伤害的40%由【坚守】干员平均承担;【坚守】干员受到伤害时,伤害来源受到{1:0}点法术伤害(受层数影响,每0.2秒至多触发1次)和持续5秒的40%的脆弱效果","effectDescRaw":"所有干员生命值<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>3名不同【坚守】干员>场上非【坚守】干员受到伤害时,所受伤害的<@ba.vup>40%由【坚守】干员平均承担;【坚守】干员受到伤害时,伤害来源受到<@ba.vup>{1:0}点法术伤害<@ba.acrem>(受层数影响,每0.2秒至多触发1次)和持续5秒的<@ba.vup>40%的脆弱效果","effectDescParams":[{"index":0,"format":"0%","base":"base_max_hp","perStack":"max_hp_per_stack"},{"index":1,"format":"0","base":"base_damage_value","perStack":"damage_value_per_stack"}],"bb":{"base_max_hp":0.25,"max_hp_per_stack":0.012,"damage_resistance":0.4,"power_bond_char_cnt":3,"cd_duration":0.2,"weak[limit]":5,"damage_scale":1.4,"base_damage_value":850,"damage_value_per_stack":10},"bbStr":{"key":"act1autochess_bond_eff_stead"},"buffs":[{"key":"env_gbuff_new","bb":{"base_max_hp":0.25,"max_hp_per_stack":0.012,"damage_resistance":0.4,"power_bond_char_cnt":3,"cd_duration":0.2,"weak[limit]":5,"damage_scale":1.4,"base_damage_value":850,"damage_value_per_stack":10},"bbStr":{"key":"act1autochess_bond_eff_stead"}}],"baseParams":["base_max_hp","base_damage_value"],"perStackParams":["max_hp_per_stack","damage_value_per_stack"],"members":["chess_char_1_02_a","chess_char_1_10_a","chess_char_2_08_a","chess_char_2_17_a","chess_char_2_18_a","chess_char_3_05_a","chess_char_3_16_a","chess_char_4_01_a","chess_char_5_11_a","chess_char_6_03_a"],"visibleMembers":["chess_char_1_02_a","chess_char_1_10_a","chess_char_2_08_a","chess_char_2_17_a","chess_char_2_18_a","chess_char_3_05_a","chess_char_3_16_a","chess_char_4_01_a","chess_char_5_11_a","chess_char_6_03_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"ALL operators maxHP x(1 + 0.25 + 0.012*L)."},{"need":"3 distinct","effect":"When a non-坚守 operator takes damage, 40% of that damage is taken instead by the 坚守 members, split evenly. When a 坚守 member takes damage, the damage source takes (850 + 10*L) sourceless magic damage and 脆弱 (damage taken x1.4) for 5 s; each 坚守 member can reflect at most once per 0.2 s."}],"formulas":{"hpMultiplier":"1.25 + 0.012*L","redirectRatio":"0.4","thornsDamage":"850 + 10*L","thornsCooldownSec":"0.2","fragile":"1.4 for 5 s"},"layerGain":"折桠 休整期结束 +4; 蛇屠箱 +1 per operator in same row; 斯卡蒂 kills; 获得时 角峰 +2; 机变 \"斯卡蒂的盟誓\" +8.","notes":["PRTS: thorns hit whatever the damage source is; sourceless damage can consume the thorns cooldown."]}},"deputShip":{"bondId":"deputShip","name":"助力","identifier":14,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_deputShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"所有干员防御力提升(受层数影响),再部署时间减少\n休整期结束时,使当前所有已激活盟约层数+2\n<在场3名不同【助力】干员>改为层数+4","descRaw":"所有干员<@ba.vup>防御力提升<@autochess.gray>(受层数影响),<@ba.vup>再部署时间减少\n休整期结束时,使当前所有已激活盟约层数<@ba.vup>+2\n<在场<@autochess.dgreen>3名不同【助力】干员>改为层数<@ba.vup>+4","effectId":"bondeffect_deput","effectName":"助力","effectDesc":"所有干员防御力+{0:0%}(受层数影响),再部署时间-30%\n休整期结束时,使当前所有已激活的盟约层数+2\n<在场3名不同【助力】干员>改为层数+4","effectDescRaw":"所有干员防御力<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响),再部署时间<@ba.vup>-30%\n休整期结束时,使当前所有已激活的盟约层数<@ba.vup>+2\n<在场<@ba.vup>3名不同【助力】干员>改为层数<@ba.vup>+4","effectDescParams":[{"index":0,"format":"0%","base":"base_def","perStack":"def_per_stack"}],"bb":{"base_def":0.15,"def_per_stack":0.012,"respawn_time":-0.3,"layer":2,"count":3,"more_layer":4},"bbStr":{"key":"act1autochess_bond_eff_deput","bond":"deputShip"},"buffs":[{"key":"env_gbuff_new","bb":{"base_def":0.15,"def_per_stack":0.012,"respawn_time":-0.3},"bbStr":{"key":"act1autochess_bond_eff_deput"}},{"key":"bond_activated_add_layer","bb":{"layer":2,"count":3,"more_layer":4},"bbStr":{"bond":"deputShip"}}],"baseParams":["base_def"],"perStackParams":["def_per_stack"],"members":["chess_char_1_06_a","chess_char_1_13_a","chess_char_2_14_a","chess_char_2_15_a","chess_char_3_15_a","chess_char_3_20_a","chess_char_4_03_a","chess_char_4_05_a","chess_char_4_21_a","chess_char_4_24_a","chess_char_5_16_a","chess_char_6_14_a","chess_char_6_20_a"],"visibleMembers":["chess_char_1_06_a","chess_char_1_13_a","chess_char_2_14_a","chess_char_3_20_a","chess_char_4_21_a","chess_char_4_24_a","chess_char_6_14_a","chess_char_6_20_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"ALL operators DEF x(1 + 0.15 + 0.012*L); redeploy time -30%. At the end of every prep phase (休整期结束时) every currently active bond (incl. 助力) gets +2 layers."},{"need":"3 助力 (distinct name or elite state)","effect":"+4 layers instead of +2."}],"formulas":{"defMultiplier":"1.15 + 0.012*L","redeployTimeMul":"0.7","layersPerRound":"2 (4 at 3 members) to every active bond"},"layerGain":"波登可 +1 / 调香师 +2 to highest-layer bond at prep end (work from bench); 流明 +2 to active bonds of every bench operator; 纯烬艾雅法拉 +3 highest-layer bond per skill; its own +2/+4 per round.","howToPlay":"Cheap universal layer engine: activate as many bonds as possible so each gets +2/+4 every round (helps the hidden-round threshold)."}},"visiShip":{"bondId":"visiShip","name":"远见","identifier":15,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_visiShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD_AND_DECK","countsHand":true,"countsGoldenOnly":false,"activeType":"ALL","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":10,"mode":"every","effect":"bond_layer_gain_coin"},{"layer":80,"mode":"first","effect":"bond_multi_layer_char_goods_price_bond_discount"},{"layer":150,"mode":"first","effect":"bond_multi_layer_char_goods_price_bond_discount"}],"desc":"<每叠加10层>获得一次2资金\n<首次达到80层>所有【远见】干员购买价格永久-1资金\n<首次达到150层>以上效果改为调度中心内所有干员的购买价格永久-1资金(整备区的【远见】干员也可用于激活盟约)","descRaw":"<每叠加<@autochess.dgreen>10层>获得一次<@ba.vup>2资金\n<首次达到<@autochess.dgreen>80层>所有【远见】干员购买价格<@ba.vup>永久-1资金\n<首次达到<@autochess.dgreen>150层>以上效果改为调度中心内所有干员的购买价格<@ba.vup>永久-1资金(整备区的【远见】干员也可用于激活盟约)","effectId":"bondeffect_visi","effectName":"远见","effectDesc":"<每叠加10层>获得一次2资金\n<首次到达80层>所有【远见】干员购买价格永久-1资金\n<首次到达150层>上述效果改为所有干员购买价格永久-1资金\n整备区的【远见】干员也可用于激活盟约","effectDescRaw":"<每叠加<@ba.vup>10层>获得一次<@ba.vup>2资金\n<首次到达<@ba.vup>80层>所有【远见】干员购买价格永久-1资金\n<首次到达<@ba.vup>150层>上述效果改为所有干员购买价格永久-1资金\n整备区的【远见】干员也可用于激活盟约","effectDescParams":[],"bb":{"layer":10,"count":2,"layer1":80,"discount":1,"layer2":150},"bbStr":{"bond":"visiShip"},"buffs":[{"key":"bond_layer_gain_coin","bb":{"layer":10,"count":2},"bbStr":{}},{"key":"bond_multi_layer_char_goods_price_bond_discount","bb":{"layer1":80,"discount":1,"layer2":150},"bbStr":{"bond":"visiShip"}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_11_a","chess_char_2_02_a","chess_char_3_03_a","chess_char_3_14_a","chess_char_4_04_a","chess_char_4_07_a","chess_char_5_01_a","chess_char_5_21_a","chess_char_6_12_a"],"visibleMembers":["chess_char_2_02_a","chess_char_3_03_a","chess_char_3_14_a","chess_char_4_04_a","chess_char_4_07_a","chess_char_5_01_a","chess_char_5_21_a","chess_char_6_12_a"],"spec":{"tiers":[{"need":"2 distinct (board + bench)","effect":"Each time cumulative L passes a multiple of 10: +2 gold."},{"need":"first time L >= 80","effect":"All 远见 operators' shop price permanently -1."},{"need":"first time L >= 150","effect":"Replaces the above: every operator in the shop permanently -1 (overrides, does not stack; 3/27 update)."}],"formulas":{"goldPayouts":"2 * floor(L/10)"},"layerGain":"寒檀 进入/结束休整期 +4 each; 伊内丝 +5 own active bonds; 赫默 +2; 圣约送葬人 +3 per 7 bullets (<=21/battle); 风笛 kills +2; 机变 \"风笛的盟誓\" +8.","assumed":["no floor but 0 (owner's decision 2026-10-04; a floor of 1 was assumed until 0.1.3)"]}},"miraShip":{"bondId":"miraShip","name":"奇迹","identifier":16,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_miraShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD_AND_DECK","countsHand":true,"countsGoldenOnly":false,"activeType":"ALL","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":100,"mode":"every","effect":"bond_layer_gain_coin"}],"desc":"刷新调度中心时,有概率使下次刷新不消耗资金(受层数影响)\n<每叠加100层>获得20资金(整备区的【奇迹】干员也可用于激活盟约)","descRaw":"刷新调度中心时,有概率使下次刷新<@ba.vup>不消耗资金<@autochess.gray>(受层数影响)\n<每叠加<@autochess.dgreen>100层>获得<@ba.vup>20资金(整备区的【奇迹】干员也可用于激活盟约)","effectId":"bondeffect_mira","effectName":"奇迹","effectDesc":"刷新调度中心时,有{0:0%}(受层数影响)概率使下次刷新不消耗资金\n<每叠加100层>获得20资金\n整备区的【奇迹】干员也可用于激活盟约","effectDescRaw":"刷新调度中心时,有<@ba.vup>{0:0%}<@ba.acrem>(受层数影响)概率使下次刷新不消耗资金\n<每叠加<@ba.vup>100层>获得<@ba.vup>20资金\n整备区的【奇迹】干员也可用于激活盟约","effectDescParams":[{"index":0,"format":"0%","base":"baseprob","perStack":"prob"}],"bb":{"probk":0.3,"prob":0.003,"baseprob":0.18,"layer":100,"count":20},"bbStr":{},"buffs":[{"key":"bond_refresh_shop_next_free","bb":{"probk":0.3,"prob":0.003,"baseprob":0.18},"bbStr":{}},{"key":"bond_layer_gain_coin","bb":{"layer":100,"count":20},"bbStr":{}}],"baseParams":["baseprob"],"perStackParams":["prob"],"members":["chess_char_1_11_a","chess_char_2_11_a","chess_char_3_01_a","chess_char_3_19_a","chess_char_4_15_a","chess_char_4_26_a","chess_char_5_04_a","chess_char_5_15_a","chess_char_5_20_a","chess_char_5_23_a","chess_char_6_07_a"],"visibleMembers":["chess_char_2_11_a","chess_char_3_01_a","chess_char_3_19_a","chess_char_4_26_a","chess_char_5_15_a","chess_char_5_20_a","chess_char_5_23_a","chess_char_6_07_a"],"spec":{"tiers":[{"need":"2 distinct (board + bench)","effect":"After each shop refresh, if the player has 0 free refreshes: with p = 0.18 + 0.003*L gain 1 free refresh."},{"need":"every 100 layers","effect":"+20 gold."}],"formulas":{"p":"min(1, 0.18 + 0.003*L)","goldPayouts":"20 * floor(L/100)"},"layerGain":"维娜·维多利亚 +2 per distinct-tier 奇迹; 录武官 获得时 +3; 伺夜 kills +1; 引星棘刺 +4 self & front; 华法琳 (奇迹 member) gives the operator in front \"开技能时 +1 own active bonds\" (data: <=7/battle, elite +2 <=14; PRTS 3/27 patch note says cap raised to 12/24).","notes":["blackboard probk = 0.3: meaning unknown (not in any description) [UNKNOWN]."]}},"investShip":{"bondId":"investShip","name":"投资人","identifier":17,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_investShip","activeCount":3,"thresholds":[3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD_AND_DECK","countsHand":true,"countsGoldenOnly":false,"activeType":"ALL","isActiveInDeck":false,"noStack":false,"weight":0,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":100,"mode":"reach","effect":"bond_layer_char_garrison_bonus"}],"desc":"干员的“获得时”类特质每次触发2次\n<达到100层>“获得时”类特质每次触发3次(整备区的【投资人】干员也可用于激活盟约)","descRaw":"干员的“获得时”类特质每次<@ba.vup>触发2次\n<达到<@autochess.dgreen>100层>“获得时”类特质每次<@ba.vup>触发3次(整备区的【投资人】干员也可用于激活盟约)","effectId":"bondeffect_invest","effectName":"投资人","effectDesc":"干员的“获得时”类特质每次触发2次\n<达到100层>“获得时”类特质每次触发3次\n整备区的【投资人】干员也可用于激活盟约","effectDescRaw":"干员的“获得时”类特质每次触发2次\n<达到<@ba.vup>100层>“获得时”类特质每次触发3次\n整备区的【投资人】干员也可用于激活盟约","effectDescParams":[],"bb":{"layer":0,"count":2},"bbStr":{"event":"SERVER_GAIN"},"buffs":[{"key":"bond_layer_char_garrison_bonus","bb":{"layer":0,"count":2},"bbStr":{"event":"SERVER_GAIN"}},{"key":"bond_layer_char_garrison_bonus","bb":{"layer":100,"count":3},"bbStr":{"event":"SERVER_GAIN"}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_16_a","chess_char_2_19_a","chess_char_3_04_a","chess_char_5_14_a","chess_char_5_17_a"],"visibleMembers":["chess_char_2_19_a","chess_char_3_04_a","chess_char_5_14_a","chess_char_5_17_a"],"spec":{"tiers":[{"need":"3 distinct (board + bench)","effect":"Every \"获得时\" (SERVER_GAIN) trait of every operator triggers 2 times."},{"need":"L >= 100","effect":"Triggers 3 times."}],"formulas":{"gainTraitRepeat":"2 if L < 100 else 3"},"layerGain":"山 休整期结束 +1 per operator gained this round; 机变 \"诗怀雅的盟誓\" +10, \"银灰的盟誓\" +8; generic sources.","howToPlay":"Pair with high \"获得时 +N 自身所属盟约\" operators (忍冬 +6, 锏 +8, 星熊 +8, 雪猎 +5) - their layers double/triple."}},"raidShip":{"bondId":"raidShip","name":"突袭","identifier":18,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_raidShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":50,"mode":"reach","effect":"env_gbuff_new"}],"desc":"【突袭】干员10秒内未进行攻击或技能就绪时,若范围内没有敌人,则保留技力立即再部署至一名地面敌人周围,期间攻击力和生命值提升(受层数影响)\n<达到50层>所有干员攻击速度+50","descRaw":"【突袭】干员<@ba.vup>10秒内未进行攻击或技能就绪时,若范围内没有敌人,则保留技力立即<@ba.vup>再部署至一名地面敌人周围,期间<@ba.vup>攻击力和<@ba.vup>生命值提升<@autochess.gray>(受层数影响)\n<达到<@autochess.dgreen>50层>所有干员攻击速度<@ba.vup>+50","effectId":"bondeffect_raid","effectName":"突袭","effectDesc":"【突袭】干员10秒内未进行攻击或技能就绪时,若范围内没有敌人,则保留技力立即再部署至一名地面敌人周围,期间攻击力和生命值+{0:0%}(受层数影响)\n <达到50层>所有干员攻击速度+50","effectDescRaw":"【突袭】干员10秒内未进行攻击或技能就绪时,若范围内没有敌人,则保留技力立即再部署至一名地面敌人周围,期间攻击力和生命值<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n <达到<@ba.vup>50层>所有干员攻击速度<@ba.vup>+50","effectDescParams":[{"index":0,"format":"0%","base":"base_atk","perStack":"atk_per_stack"}],"bb":{"base_attack_speed":0,"attack_speed_per_stack":0,"base_atk":0.25,"atk_per_stack":0.01,"base_max_hp":0.25,"max_hp_per_stack":0.01,"power_bond_stack_cnt":50,"power_attack_speed":50,"no_attack_duration":10},"bbStr":{"key":"act1autochess_bond_eff_raid"},"buffs":[{"key":"env_gbuff_new","bb":{"base_attack_speed":0,"attack_speed_per_stack":0,"base_atk":0.25,"atk_per_stack":0.01,"base_max_hp":0.25,"max_hp_per_stack":0.01,"power_bond_stack_cnt":50,"power_attack_speed":50,"no_attack_duration":10},"bbStr":{"key":"act1autochess_bond_eff_raid"}}],"baseParams":["base_atk"],"perStackParams":["atk_per_stack"],"members":["chess_char_1_18_a","chess_char_2_09_a","chess_char_3_05_a","chess_char_3_12_a","chess_char_4_04_a","chess_char_4_16_a","chess_char_5_07_a","chess_char_6_15_a","chess_char_6_17_a"],"visibleMembers":["chess_char_1_18_a","chess_char_2_09_a","chess_char_3_05_a","chess_char_3_12_a","chess_char_4_04_a","chess_char_4_16_a","chess_char_5_07_a","chess_char_6_15_a","chess_char_6_17_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"If a 突袭 member has not attacked for 10 s, or its skill is ready, and no enemy is in its range: it is immediately redeployed (keeping SP) onto a tile next to a ground enemy; while in that redeployed state its ATK and maxHP x(1 + 0.25 + 0.01*L)."},{"need":"L >= 50","effect":"ALL operators ASPD +50."}],"formulas":{"atkHpMultiplier":"1.25 + 0.01*L","idleSec":"10","aspdAll(L>=50)":"50"},"layerGain":"史尔特尔 部署时 +8 (<=50/battle); 休谟斯 each 2 kills +1; 瑕光 +4/deploy; 斯卡蒂; 伊内丝 +5; 机变 \"斯卡蒂的盟誓\" +8, \"德克萨斯的盟誓\" +10.","assumed":["target enemy = the ground enemy closest to the player's objective (its own field's; another field's only while its own has none) that the member can reach; landing tile = the nearest free deployable tile within 2 tiles of it from which the member's attack range covers it. No such tile for any of the 8 most advanced -> no jump; the poll looks again every 0.25 s (GitHub issue #51 - up to 0.1.1 the idle trigger landed out of reach and hopped every 10 s; DESIGN §22.2)","the buff lasts until the operator leaves the field"]}},"indomShip":{"bondId":"indomShip","name":"不屈","identifier":19,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_indomShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"地面干员被击倒时,有概率立即重新部署(受层数影响)\n<在场3名不同【不屈】干员>地面干员被击倒时使场上所有干员技力+5","descRaw":"<@ba.vup>地面干员被击倒时,有概率立即<@ba.vup>重新部署<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>3名不同【不屈】干员><@ba.vup>地面干员被击倒时使场上所有干员<@ba.vup>技力+5","effectId":"bondeffect_indom","effectName":"不屈","effectDesc":"地面干员被击倒时,有{0:0%}(受层数影响)概率立刻重新部署\n<在场3名不同【不屈】干员>地面干员被击倒时使场上所有干员技力+5","effectDescRaw":"<@ba.vup>地面干员被击倒时,有<@ba.vup>{0:0%}<@ba.acrem>(受层数影响)概率立刻重新部署\n<在场<@ba.vup>3名不同【不屈】干员><@ba.vup>地面干员被击倒时使场上所有干员技力<@ba.vup>+5","effectDescParams":[{"index":0,"format":"0%","base":"base_prob","perStack":"prob_per_stack"}],"bb":{"base_prob":0.18,"prob_per_stack":0.004,"power_bond_stack_cnt":0,"sp":5,"power_bond_char_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_indom"},"buffs":[{"key":"env_gbuff_new","bb":{"base_prob":0.18,"prob_per_stack":0.004,"power_bond_stack_cnt":0,"sp":5,"power_bond_char_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_indom"}}],"baseParams":["base_prob"],"perStackParams":["prob_per_stack"],"members":["chess_char_1_05_a","chess_char_1_20_a","chess_char_2_03_a","chess_char_2_12_a","chess_char_3_16_a","chess_char_4_07_a","chess_char_5_06_a","chess_char_5_13_a","chess_char_6_06_a"],"visibleMembers":["chess_char_1_20_a","chess_char_2_12_a","chess_char_3_16_a","chess_char_4_07_a","chess_char_5_06_a","chess_char_5_13_a","chess_char_6_06_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"When a ground operator is knocked out / retreats / swaps 替身<->本体: with p = min(1, 0.18 + 0.004*L) it is redeployed at once (next deployment has 0 redeploy time and 0 cost). Also consumes a \"复活\" charge if it had one."},{"need":"3 distinct","effect":"When a ground operator is knocked out: every operator on the field +5 SP."}],"formulas":{"p":"min(1, 0.18 + 0.004*L)","reaches100%AtL":"205"},"layerGain":"雷蛇 休整期结束 +1; 砾 被击倒 +2; 归溟幽灵鲨 +5; 风笛 kills +2; 机变 \"风笛的盟誓\" +8."}},"maniShip":{"bondId":"maniShip","name":"调和","identifier":20,"isCore":false,"bondType":"REGULAR","bondOrder":1,"powerIdList":[],"iconId":"icon_maniShip","activeCount":1,"thresholds":[1],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"MANI","isActiveInDeck":false,"noStack":true,"weight":0,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"激活时使场上核心盟约的激活人数+1,【调和】干员享受已激活的核心盟约的效果","descRaw":"激活时使场上核心盟约的<@ba.vup>激活人数+1,【调和】干员享受已激活的核心盟约的效果","effectId":"bondeffect_mani","effectName":"调和","effectDesc":"激活时可以使场上核心盟约的激活人数+1,【调和】干员享受已激活的核心盟约的效果","effectDescRaw":"激活时可以使场上核心盟约的<@ba.vup>激活人数+1,【调和】干员<@ba.vup>享受已激活的核心盟约的效果","effectDescParams":[],"bb":{"count":1},"bbStr":{},"buffs":[{"key":"other_bond_add_trigger_cnt","bb":{"count":1},"bbStr":{}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_15_a","chess_char_6_11_a"],"visibleMembers":["chess_char_6_11_a"],"spec":{"tiers":[{"need":"1 调和 on board","effect":"Every core bond's member count +1; 调和 operators receive the effects of all active core bonds."}],"members":"缪尔赛思 (T6) and 盟约·辅助干员 (T1, hidden; given in round 1 by strategy Pith \"优等生\").","assumed":["+1 only for core bonds with >=1 real member","one +1 total no matter how many 调和 operators"]}},"emptyShip":{"bondId":"emptyShip","name":"协防干员","identifier":21,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_emptyShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":true,"weight":0,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"所有干员受到的物理和法术伤害-20%,【协防干员】伤害提升至120%,精锐【协防】干员造成伤害提升至140%","descRaw":"所有干员受到的物理和法术伤害<@ba.vup>-20%,【协防干员】伤害提升至<@ba.vup>120%,精锐【协防】干员造成伤害提升至<@ba.vup>140%","effectId":"bondeffect_empty","effectName":"协防干员","effectDesc":"所有干员受到的物理和法术伤害-20%;【协防干员】伤害提升至120%,精锐【协防干员】造成伤害提升至140%","effectDescRaw":"所有干员受到的物理和法术伤害<@ba.vup>-20%;【协防干员】伤害提升至<@ba.vup>120%,精锐【协防干员】造成伤害提升至<@ba.vup>140%","effectDescParams":[],"bb":{"damage_resistance":0.2,"damage_scale_normal":1.2,"damage_scale_extra":1.4},"bbStr":{"key":"act1autochess_bond_eff_assis"},"buffs":[{"key":"env_gbuff_new","bb":{"damage_resistance":0.2,"damage_scale_normal":1.2,"damage_scale_extra":1.4},"bbStr":{"key":"act1autochess_bond_eff_assis"}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_15_a","chess_char_2_14_a","chess_char_3_10_a","chess_char_4_08_a","chess_char_4_25_a","chess_char_5_09_a","chess_char_5_10_a","chess_char_6_12_a"],"visibleMembers":["chess_char_2_14_a","chess_char_3_10_a","chess_char_4_25_a","chess_char_5_10_a","chess_char_6_12_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"ALL operators take -20% physical and magic damage; 协防干员 members deal damage x1.2 (elite 协防 x1.4)."}],"meaning":"\"协防干员\" (assist operators) = fallback bond (constData.fallbackBondId). DIY/self-selected 6-star operators whose faction matches no core bond become 协防干员; some preset operators (调香师, 松果, 瑰盐, 魔王, 铃兰, 迷迭香, 盟约·辅助干员) are natively 协防.","formulas":{"damageTakenMul":"0.8","memberDamageMul":"1.2 (elite 1.4)"},"notes":["noStack=true: no layer-scaled effect, but layers are still counted (巴哈姆特)."]}},"soloShip":{"bondId":"soloShip","name":"独行","identifier":22,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_soloShip","activeCount":1,"thresholds":[1],"maxCount":1,"thresholdTemplate":"count_threshold_downward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":true,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"<在场1名【独行】干员>【独行】干员攻击力和生命值+60%,初始技力+15(在场2名及以上【独行】干员时失效)","descRaw":"<在场1名【独行】干员>【独行】干员攻击力和生命值<@ba.vup>+60%,初始技力<@ba.vup>+15(在场2名及以上【独行】干员时失效)","effectId":"bondeffect_solo","effectName":"独行","effectDesc":"<在场1名【独行】干员>【独行】干员攻击力和生命值+60%,初始技力+15(在场2名及以上【独行】干员时失效)","effectDescRaw":"<在场<@ba.vup>1名【独行】干员>【独行】干员攻击力和生命值<@ba.vup>+60%,初始技力<@ba.vup>+15<@ba.acrem>(在场2名及以上【独行】干员时失效)","effectDescParams":[],"bb":{"atk":0.6,"max_hp":0.6,"sp":15},"bbStr":{"key":"act2autochess_bond_eff_solo"},"buffs":[{"key":"env_gbuff_new","bb":{"atk":0.6,"max_hp":0.6,"sp":15},"bbStr":{"key":"act2autochess_bond_eff_solo"}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_08_a","chess_char_2_17_a","chess_char_3_17_a","chess_char_4_09_a","chess_char_4_18_a","chess_char_5_11_a"],"visibleMembers":["chess_char_1_08_a","chess_char_2_17_a","chess_char_3_17_a","chess_char_4_09_a","chess_char_4_18_a","chess_char_5_11_a"],"spec":{"tiers":[{"need":"exactly 1 distinct 独行 on board","effect":"That operator ATK +60%, maxHP +60%, +15 SP when deployed. Disabled when 2+ different 独行 operators are on the board."}],"formulas":{"atkMul":"1.6","hpMul":"1.6","spOnDeploy":"15"},"notes":["noStack=true"]}},"suntShip":{"bondId":"suntShip","name":"绝技","identifier":23,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_suntShip","activeCount":2,"thresholds":[2,5],"maxCount":null,"thresholdTemplate":"count_threshold_upward_golden","countMode":"BOARD_ALL_CHESS","countsHand":false,"countsGoldenOnly":true,"activeType":"BATTLE","isActiveInDeck":false,"noStack":true,"weight":0,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"<在场2名精锐状态的干员>精锐状态的干员攻击力+30%\n<在场5名精锐状态的干员>精锐状态的干员技力消耗-30%\n(所有干员的精锐状态均可激活本盟约)","descRaw":"<在场<@autochess.dgreen>2名精锐状态的干员>精锐状态的干员攻击力<@ba.vup>+30%\n<在场<@autochess.dgreen>5名精锐状态的干员>精锐状态的干员技力消耗<@ba.vup>-30%\n<@ba.acrem>(所有干员的精锐状态均可激活本盟约)","effectId":"bondeffect_sunt","effectName":"绝技","effectDesc":"<在场2名精锐状态的干员>精锐状态的干员攻击力+30%\n<在场5名精锐状态的干员>精锐状态的干员技力消耗-30%\n(所有干员的精锐状态均可激活本盟约)","effectDescRaw":"<在场<@ba.vup>2名精锐状态的干员>精锐状态的干员攻击力<@ba.vup>+30%\n<在场<@ba.vup>5名精锐状态的干员>精锐状态的干员技力消耗<@ba.vup>-30%\n<@ba.acrem>(所有干员的精锐状态均可激活本盟约)","effectDescParams":[],"bb":{"power_char_cnt":2,"ex_char_cnt":5,"power_atk":0.3,"sp_ratio":0.7},"bbStr":{"key":"act2autochess_bond_eff_sunt"},"buffs":[{"key":"env_gbuff_new","bb":{"power_char_cnt":2,"ex_char_cnt":5,"power_atk":0.3,"sp_ratio":0.7},"bbStr":{"key":"act2autochess_bond_eff_sunt"}}],"baseParams":[],"perStackParams":[],"members":[],"visibleMembers":[],"spec":{"tiers":[{"need":"2 elite (精锐) operators on board (any operators, duplicates count)","effect":"All elite operators ATK +30%."},{"need":"5 elite operators on board","effect":"At battle start every elite operator and its summons have skill SP cost x0.7 (rounded down, may become 0)."}],"formulas":{"atkMul":"1.3","spCostMul":"floor(sp*0.7)"},"notes":["isHiddenCharList=true, chessIdList empty: no member operators; elites are not \"members\" of 绝技 (PRTS).","noStack=true"]}}} \ No newline at end of file +{"yanShip":{"bondId":"yanShip","name":"炎","identifier":1,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["yan","sui","lungmen","lee","lgd"],"iconId":"icon_yanShip","activeCount":3,"thresholds":[3,6,9],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【炎】干员攻击力提升(受层数影响)\n<在场6名不同【炎】干员>战斗开始时召唤可自主行动的“炎佑”,其攻击力生命值分别为开战时【炎】干员攻击力生命值总和的30%,“炎佑”同时攻击3个目标,可使用“祛恶之焰”,攻击时附带攻击力一定比例的灼燃损伤且周围敌人受到一定比例的元素脆弱\n<在场9名不同【炎】干员>改为召唤2只“炎佑”,攻击力提升至1.5倍,受到的伤害-90%","descRaw":"【炎】干员<@ba.vup>攻击力提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>6名不同【炎】干员>战斗开始时召唤可自主行动的<@ba.vup>“炎佑”,其攻击力生命值分别为开战时【炎】干员攻击力生命值总和的30%,“炎佑”同时攻击3个目标,可使用<@ba.vup>“祛恶之焰”,攻击时附带攻击力一定比例的灼燃损伤且周围敌人受到一定比例的元素脆弱\n<在场<@autochess.dgreen>9名不同【炎】干员>改为召唤2只<@ba.vup>“炎佑”,攻击力提升至<@ba.vup>1.5倍,受到的伤害<@ba.vup>-90%","effectId":"bondeffect_yan","effectName":"炎","effectDesc":"【炎】干员攻击力+{0:0%}(受层数影响)\n<在场6名不同【炎】干员>战斗开始时收集【炎】干员部分属性召唤“炎佑”(其攻击力和生命值为【炎】干员攻击力和生命值总和的30%);“炎佑”同时攻击3个目标,攻击附带20%攻击力的灼燃损伤,周围敌人受到20%的元素脆弱,周期性使用“祛恶之焰”\n<在场9名不同【炎】干员>改为召唤2只“炎佑”;“炎佑”攻击力提升至1.5倍,受到的伤害-90%","effectDescRaw":"【炎】干员攻击力<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【炎】干员>战斗开始时收集【炎】干员部分属性召唤“炎佑”(其攻击力和生命值为【炎】干员攻击力和生命值总和的30%);“炎佑”同时攻击3个目标,攻击附带20%<@ba.vup>攻击力的<@ba.vup>灼燃损伤,周围敌人受到20%的<@ba.vup>元素脆弱,周期性使用“祛恶之焰”\n<在场<@ba.vup>9名不同【炎】干员>改为召唤2只“炎佑”;“炎佑”攻击力提升至1.5倍,受到的伤害-90%","effectDescParams":[{"index":0,"format":"0%","base":"base_atk","perStack":"atk_per_stack"}],"bb":{"base_atk":0.23,"atk_per_stack":0.009,"power_bond_char_cnt":6,"ex_bond_char_cnt":9,"damage_resistance":0.9,"atk":1.5},"bbStr":{"key":"act1autochess_bond_eff_yan"},"buffs":[{"key":"env_gbuff_new","bb":{"base_atk":0.23,"atk_per_stack":0.009,"power_bond_char_cnt":6,"ex_bond_char_cnt":9,"damage_resistance":0.9,"atk":1.5},"bbStr":{"key":"act1autochess_bond_eff_yan"}}],"baseParams":["base_atk"],"perStackParams":["atk_per_stack"],"members":["chess_char_1_03_a","chess_char_2_04_a","chess_char_3_03_a","chess_char_3_04_a","chess_char_4_15_a","chess_char_4_17_a","chess_char_5_03_a","chess_char_5_12_a","chess_char_5_23_a","chess_char_6_03_a","chess_char_6_15_a"],"visibleMembers":["chess_char_1_03_a","chess_char_2_04_a","chess_char_3_03_a","chess_char_3_04_a","chess_char_4_17_a","chess_char_5_03_a","chess_char_5_12_a","chess_char_5_23_a","chess_char_6_03_a","chess_char_6_15_a"],"spec":{"tiers":[{"need":"3 distinct 炎 on board","effect":"炎 members (+调和 members) ATK x(1 + 0.23 + 0.009*L)."},{"need":"6 distinct","effect":"At battle start spawn 1 \"炎佑\" (enemy_9012_acloon template, allied flying ranged unit, not blockable, moves on its own). ATK = 0.30 x sum(ATK of 炎 operators on board at battle start), maxHP = 0.30 x sum(maxHP of those operators). Template: DEF 200, RES 0, BAT 2.5 s, ASPD 100, attack range radius 2.0 tiles, magic damage, hits up to 3 targets; every hit adds 灼燃损伤 (burn elemental damage) = 20% of its ATK and applies 元素脆弱 (elemental damage taken x1.2) to enemies within 0.8 tiles of the target. Skill \"祛恶之焰\": cooldown 15 s (first cast 15 s after spawn), channels a flame on one enemy in range dealing 60% ATK magic damage per second to it and to enemies within 1.0 tile, for up to 20 s."},{"need":"9 distinct","effect":"Spawn 2 炎佑 instead; each has ATK x1.5 and takes 90% less damage (damage_resistance 0.9)."}],"formulas":{"atkMultiplier":"1 + 0.23 + 0.009*L"},"caps":"none","layerGain":"Economy-driven: 惊蛰 获得时 +shop level (no activation needed); 小满 休整期结束 +1 per operator gained this round; 夕 +2 炎/奥术 per operator gained; 录武官 获得时 +6 炎 +3 奇迹; 星熊 获得时 +8 own bonds; 烛煌 获得时 +5 炎/维多利亚; 机变 \"诗怀雅的盟誓\" +10. Strategy 杜遥夜: first 2 manual refreshes each round prefer a 炎 operator.","howToPlay":"Buy many operators each round (every gain feeds 小满/夕), rush 6 炎 for the 炎佑 spike; 琳琅诗怀雅 / 诗怀雅 give early gold. 9 炎 is a late-game luxury.","assumed":["炎佑 base stats are replaced (not added) by the 30% sums","祛恶之焰 hit_duration=20 read as 20 one-second ticks","spawn point: centre of the player's board / near the objective","targets = 3 nearest enemies in range"]}},"sargonShip":{"bondId":"sargonShip","name":"萨尔贡","identifier":2,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["sargon"],"iconId":"icon_sargonShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【萨尔贡】干员开启技能时,所有【萨尔贡】干员攻击速度提升(有上限),持续一定时间(受层数影响,每层持续时间独立计算)\n<在场6名不同【萨尔贡】干员>开启技能还会为所有【萨尔贡】干员提供等持续时间的攻击力(有上限)\n选择策略【娜仁图亚】时,<在场6名不同【萨尔贡】干员>的效果会有所改变","descRaw":"【萨尔贡】干员开启技能时,所有【萨尔贡】干员<@ba.vup>攻击速度提升(有上限),持续一定时间<@autochess.gray>(受层数影响,每层持续时间独立计算)\n<在场<@autochess.dgreen>6名不同【萨尔贡】干员>开启技能还会为所有【萨尔贡】干员提供等持续时间的<@ba.vup>攻击力(有上限)\n<@ba.acrem>选择策略【娜仁图亚】时,<在场6名不同【萨尔贡】干员>的效果会有所改变","effectId":"bondeffect_sargon","effectName":"萨尔贡","effectDesc":"【萨尔贡】干员开启技能时,所有【萨尔贡】干员攻击速度+12(至多+300),持续{0:0}秒(受层数影响)\n<在场6名不同【萨尔贡】干员>开启技能还会使所有【萨尔贡】干员攻击力+12%(至多+300%)\n选择策略【娜仁图亚】时,<在场6名不同【萨尔贡】干员>的效果会有所改变","effectDescRaw":"【萨尔贡】干员开启技能时,所有【萨尔贡】干员攻击速度+12(至多<@ba.vup>+300),持续<@ba.vup>{0:0}秒<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【萨尔贡】干员>开启技能还会使所有【萨尔贡】干员攻击力+12%(至多<@ba.vup>+300%)\n<@ba.acrem>选择策略【娜仁图亚】时,<在场6名不同【萨尔贡】干员>的效果会有所改变","effectDescParams":[{"index":0,"format":"0","base":"base_time","perStack":"time_per_stack"}],"bb":{"base_time":5,"time_per_stack":0.22,"max_buff_stack_cnt":25,"base_attack_speed":12,"power_bond_char_cnt":6,"base_atk":0.12,"base_power_time":60,"power_time_per_stack":0,"filter_item_level":5},"bbStr":{"key":"act1autochess_bond_eff_sargon","invalid_in_band":"band_narant","valid_in_band":"band_narant"},"buffs":[{"key":"env_gbuff_new","bb":{"base_time":5,"time_per_stack":0.22,"max_buff_stack_cnt":25,"base_attack_speed":12,"power_bond_char_cnt":6,"base_atk":0.12},"bbStr":{"key":"act1autochess_bond_eff_sargon","invalid_in_band":"band_narant"}},{"key":"env_gbuff_new","bb":{"base_time":5,"time_per_stack":0.22,"max_buff_stack_cnt":25,"base_attack_speed":12,"power_bond_char_cnt":6,"base_power_time":60,"power_time_per_stack":0,"filter_item_level":5},"bbStr":{"key":"act2autochess_bond_eff_sargon[share]","valid_in_band":"band_narant"}}],"baseParams":["base_time"],"perStackParams":["time_per_stack"],"members":["chess_char_1_12_a","chess_char_2_06_a","chess_char_2_08_a","chess_char_3_06_a","chess_char_3_13_a","chess_char_4_05_a","chess_char_4_23_a","chess_char_4_24_a","chess_char_5_02_a","chess_char_5_18_a","chess_char_6_05_a","chess_char_6_06_a"],"visibleMembers":["chess_char_1_12_a","chess_char_2_06_a","chess_char_2_08_a","chess_char_3_06_a","chess_char_3_13_a","chess_char_4_23_a","chess_char_4_24_a","chess_char_5_02_a","chess_char_6_05_a","chess_char_6_06_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"Whenever any 萨尔贡 member activates its skill, every 萨尔贡 member on the field gains one stack: ASPD +12 for (5 + 0.22*L) s. Each stack has its own timer; at most 25 concurrent stacks (=> +300 ASPD cap)."},{"need":"6 distinct","effect":"Each stack additionally gives ATK +12% (25 stacks => +300% cap), same duration."},{"need":"6 distinct AND strategy 娜仁图亚 (band_narant)","effect":"Replaces the 6-member effect: when a 萨尔贡 member activates its skill, operators on its 8 surrounding tiles also enjoy the effects of the equipment (tier <= V, filter_item_level 5) it carries, for 60 s (base_power_time 60, power_time_per_stack 0)."}],"formulas":{"stackDurationSec":"5 + 0.22*L","aspdPerStack":"12","atkPerStack(6)":"0.12","maxStacks":"25"},"caps":"25 stacks: +300 ASPD, +300% ATK","layerGain":"In battle on skill activation: 菲莱 +6 每次开技能, 百炼嘉维尔 +9 每次开技能, 莎草 +5 首次开技能, 缇缇 +1 萨尔贡/精准 per sleep/stun in range (<=24/battle); 艾丝黛尔 获得时 +2; 机变 \"缇缇的盟誓\" +10. Strategy 佩佩: after shop level 2/4/6 one special refresh preferring 萨尔贡.","howToPlay":"Fast-cycling skills (萨尔贡浓茶 / 黄沙罗盘 items) keep many stacks alive; L mainly extends duration, so stacks overlap more.","notes":["PRTS: the in-level UI shows twice the real duration (display bug); real duration is 5+0.22L."],"assumed":["When a 26th stack would be added, it replaces the stack with the shortest remaining time","stack granted to all 萨尔贡 members including the caster"]}},"victoriaShip":{"bondId":"victoriaShip","name":"维多利亚","identifier":3,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["victoria","glasgow"],"iconId":"icon_victoriaShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":25,"mode":"every","effect":"bond_layer_added_reward_equip"}],"desc":"携带装备的【维多利亚】干员造成的伤害提升(受层数影响)\n<每叠加25层>获得1件带有随机效果的维式重锤\n<在场6名不同【维多利亚】干员>携带装备的【维多利亚】干员攻击力提升,携带进阶装备时额外提升","descRaw":"携带装备的【维多利亚】干员造成的<@ba.vup>伤害提升<@autochess.gray>(受层数影响)\n<每叠加<@autochess.dgreen>25层>获得1件带有随机效果的<@ba.vup>维式重锤\n<在场<@autochess.dgreen>6名不同【维多利亚】干员>携带装备的【维多利亚】干员<@ba.vup>攻击力提升,携带进阶装备时额外提升","effectId":"bondeffect_victoria","effectName":"维多利亚","effectDesc":"携带装备的【维多利亚】干员伤害提升至{0:0%}(受层数影响)\n<每叠加25层>获得一件带有随机特殊效果的维式重锤\n<在场6名不同【维多利亚】干员>【维多利亚】干员每携带1件装备攻击力+50%,携带进阶装备改为+80%","effectDescRaw":"<@ba.vup>携带装备的【维多利亚】干员伤害提升至<@ba.vup>{0:0%}<@ba.acrem>(受层数影响)\n<每叠加<@ba.vup>25层>获得一件带有随机特殊效果的维式重锤\n<在场<@ba.vup>6名不同【维多利亚】干员>【维多利亚】干员每携带1件装备攻击力<@ba.vup>+50%,携带进阶装备改为<@ba.vup>+80%","effectDescParams":[{"index":0,"format":"0%","base":"base_damage_scale","perStack":"damage_scale_per_stack"}],"bb":{"damage_scale_per_stack":0.008,"base_damage_scale":1.25,"power_bond_char_cnt":6,"atk_normal_equip":0.5,"atk_golden_equip":0.3,"layer":25,"count":1},"bbStr":{"key":"act1autochess_bond_eff_victoria","pool":"pool_equip_vict"},"buffs":[{"key":"env_gbuff_new","bb":{"damage_scale_per_stack":0.008,"base_damage_scale":1.25,"power_bond_char_cnt":6,"atk_normal_equip":0.5,"atk_golden_equip":0.3},"bbStr":{"key":"act1autochess_bond_eff_victoria"}},{"key":"bond_layer_added_reward_equip","bb":{"layer":25,"count":1},"bbStr":{"pool":"pool_equip_vict"}}],"baseParams":["base_damage_scale"],"perStackParams":["damage_scale_per_stack"],"members":["chess_char_1_06_a","chess_char_2_05_a","chess_char_2_10_a","chess_char_3_08_a","chess_char_4_07_a","chess_char_4_11_a","chess_char_5_03_a","chess_char_5_08_a","chess_char_6_07_a","chess_char_6_08_a"],"visibleMembers":["chess_char_1_06_a","chess_char_2_05_a","chess_char_2_10_a","chess_char_3_08_a","chess_char_4_07_a","chess_char_4_11_a","chess_char_5_03_a","chess_char_5_08_a","chess_char_6_07_a","chess_char_6_08_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"维多利亚 members that carry >= 1 equipment: all damage dealt x(1.25 + 0.008*L)."},{"need":"every 25 layers (cumulative)","effect":"Gain 1 维式重锤 with a random special effect (pool_equip_vict)."},{"need":"6 distinct","effect":"维多利亚 members: ATK +50% per equipped item; an advanced (进阶/golden) item gives +80% instead (atk_normal_equip 0.5 + atk_golden_equip 0.3)."}],"formulas":{"damageMultiplier":"1.25 + 0.008*L (only if carrying equipment)","hammerPayouts":"floor(L/25)","atkPerItem(6)":"0.5 normal, 0.8 advanced"},"caps":"none","layerGain":"休整期结束: 薄绿 +2 per distinct tier of 维多利亚 on board, 维娜·维多利亚 +3 per distinct tier (and 奇迹 +2 per distinct tier of 奇迹), 刺玫 +1, 号角 +2 per distinct-tier operator of the highest-layer bond; in battle: 风笛 first 3 kills +2 维多利亚/远见/不屈; 烛煌 获得时 +5; 机变 \"风笛的盟誓\" +8. Strategy 哈洛德: from round 4 gain 1 维多利亚 operator every 2 rounds.","howToPlay":"Field 维多利亚 of as many different tiers as possible (T1..T6) for 薄绿/维娜; hand all equipment (incl. free hammers) to 维多利亚 carries; 蒸汽之心 copies all hammer effects.","assumed":["pool_equip_vict = uniform random among 灼燃/坚固/加速/战栗维式重锤 (normal grade)","hammer payout also counts layers added while the bond is inactive"]}},"kjeragShip":{"bondId":"kjeragShip","name":"谢拉格","identifier":4,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["kjerag","karlan"],"iconId":"icon_kjeragShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【谢拉格】干员造成的伤害提升,对寒冷、冻结敌人获得额外提升(受层数影响)\n<在场6名不同【谢拉格】干员>战场上每25秒过一阵寒风使场上的敌人寒冷一定时间(受层数影响)","descRaw":"【谢拉格】干员造成的<@ba.vup>伤害提升,对<@ba.vup>寒冷、冻结敌人获得额外提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>6名不同【谢拉格】干员>战场上每25秒过一阵寒风使场上的敌人寒冷一定时间<@autochess.gray>(受层数影响)","effectId":"bondeffect_kjerag","effectName":"谢拉格","effectDesc":"【谢拉格】干员伤害提升至125%,对寒冷和冻结敌人额外提升至{0:0%}(受层数影响)\n<在场6名不同【谢拉格】干员>战场上每25秒吹过一阵寒风使敌人寒冷{1:0}秒(受层数影响)","effectDescRaw":"【谢拉格】干员伤害提升至<@ba.vup>125%,对寒冷和冻结敌人额外提升至<@ba.vup>{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【谢拉格】干员>战场上每25秒吹过一阵寒风使敌人寒冷<@ba.vup>{1:0}秒<@ba.acrem>(受层数影响)","effectDescParams":[{"index":0,"format":"0%","base":"base_ex_damage_scale","perStack":"ex_damage_scale_per_stack"},{"index":1,"format":"0","base":"bond_eff_kjerag[storm].base_time","perStack":"bond_eff_kjerag[storm].time_per_stack"}],"bb":{"base_damage_scale":1.25,"base_ex_damage_scale":1.35,"ex_damage_scale_per_stack":0.01,"power_bond_char_cnt":6,"bond_eff_kjerag[storm].interval":25,"bond_eff_kjerag[storm].base_time":20,"bond_eff_kjerag[storm].time_per_stack":0.1},"bbStr":{"key":"act1autochess_bond_eff_kjerag"},"buffs":[{"key":"env_gbuff_new","bb":{"base_damage_scale":1.25,"base_ex_damage_scale":1.35,"ex_damage_scale_per_stack":0.01,"power_bond_char_cnt":6,"bond_eff_kjerag[storm].interval":25,"bond_eff_kjerag[storm].base_time":20,"bond_eff_kjerag[storm].time_per_stack":0.1},"bbStr":{"key":"act1autochess_bond_eff_kjerag"}}],"baseParams":["base_ex_damage_scale","bond_eff_kjerag[storm].base_time"],"perStackParams":["ex_damage_scale_per_stack","bond_eff_kjerag[storm].time_per_stack"],"members":["chess_char_1_02_a","chess_char_2_03_a","chess_char_2_05_a","chess_char_3_11_a","chess_char_3_14_a","chess_char_3_20_a","chess_char_4_03_a","chess_char_4_13_a","chess_char_4_22_a","chess_char_5_14_a","chess_char_6_02_a","chess_char_6_19_a"],"visibleMembers":["chess_char_1_02_a","chess_char_2_05_a","chess_char_3_11_a","chess_char_3_14_a","chess_char_3_20_a","chess_char_4_13_a","chess_char_4_22_a","chess_char_5_14_a","chess_char_6_02_a","chess_char_6_19_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"谢拉格 members deal damage x1.25; against enemies that are 寒冷 (cold) or 冻结 (frozen) x(1.35 + 0.01*L) instead."},{"need":"6 distinct","effect":"Every 25 s a cold wind applies 寒冷 to every enemy on the field for (20 + 0.1*L) s."}],"formulas":{"damageMultiplier":"1.25","damageMultiplierVsColdOrFrozen":"1.35 + 0.01*L","windIntervalSec":"25","windColdDurationSec":"20 + 0.1*L"},"caps":"none","layerGain":"In battle, freeze-driven: 初雪 and 银灰 - each enemy in range that becomes frozen: 50% chance +1; 凛御银灰 gives the 谢拉格 operator in front of it a 60% version (<=200/battle); 锏 部署时 +8 own active bonds (<=24/battle). 获得时: 角峰 +2, 崖心 +3 (hidden), 雪猎 +5, 灵知 +5, 锏 +8. 机变 \"银灰的盟誓\" +8. Strategy 休露丝: first 谢拉格 bought each round costs 1.","howToPlay":"Standard AK rule: applying 寒冷 to an already-cold enemy freezes it. The 6-member wind + cold-on-hit sources (谢拉格不融冰 12% 1.5 s cold) create constant freezes, so layers can reach hundreds per battle.","notes":["巴哈姆特: avoid lighting 3 奥术 alongside max-layer 谢拉格 (圣聆初雪 gets damage-capped)."],"assumed":["first wind at t = 25 s","wind re-applying cold on a cold enemy triggers freeze like any cold source"]}},"lateranoShip":{"bondId":"lateranoShip","name":"拉特兰","identifier":5,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["laterano"],"iconId":"icon_lateranoShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【拉特兰】干员开启技能获得的弹药量提升(受层数影响)\n<在场6名不同【拉特兰】干员>【拉特兰】干员每消耗1发弹药,所有【拉特兰】干员攻击力提升(有上限)","descRaw":"【拉特兰】干员开启技能获得的<@ba.vup>弹药量提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>6名不同【拉特兰】干员>【拉特兰】干员每消耗1发弹药,所有【拉特兰】干员<@ba.vup>攻击力提升(有上限)","effectId":"bondeffect_laterano","effectName":"拉特兰","effectDesc":"【拉特兰】干员开启技能时获得的弹药量+{0:0%}(受层数影响)\n<在场6名不同【拉特兰】干员>任意【拉特兰】干员每消耗1发弹药,全体【拉特兰】干员攻击力+4%,至多+200%","effectDescRaw":"【拉特兰】干员开启技能时获得的弹药量<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【拉特兰】干员>任意【拉特兰】干员每消耗1发弹药,全体【拉特兰】干员攻击力+4%,至多<@ba.vup>+200%","effectDescParams":[{"index":0,"format":"0%","base":"base_ammo_percent","perStack":"ammo_percent_per_stack"}],"bb":{"base_ammo_percent":0.05,"ammo_percent_per_stack":0.015,"power_bond_char_cnt":6,"atk_per_consume":0.04,"max_atk_for_consume":2},"bbStr":{"key":"act1autochess_bond_eff_laterano"},"buffs":[{"key":"env_gbuff_new","bb":{"base_ammo_percent":0.05,"ammo_percent_per_stack":0.015,"power_bond_char_cnt":6,"atk_per_consume":0.04,"max_atk_for_consume":2},"bbStr":{"key":"act1autochess_bond_eff_laterano"}}],"baseParams":["base_ammo_percent"],"perStackParams":["ammo_percent_per_stack"],"members":["chess_char_1_01_a","chess_char_2_01_a","chess_char_3_01_a","chess_char_3_07_a","chess_char_3_21_a","chess_char_4_01_a","chess_char_4_02_a","chess_char_5_01_a","chess_char_6_01_a","chess_char_6_09_a","chess_char_6_13_a"],"visibleMembers":["chess_char_1_01_a","chess_char_2_01_a","chess_char_3_01_a","chess_char_3_21_a","chess_char_4_01_a","chess_char_4_02_a","chess_char_5_01_a","chess_char_6_01_a","chess_char_6_09_a","chess_char_6_13_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"When a 拉特兰 member activates a skill that grants ammo, ammo gained x(1 + 0.05 + 0.015*L), rounded down."},{"need":"6 distinct","effect":"Every ammo consumed by any 拉特兰 member: all 拉特兰 members ATK +4% (until battle end), max +200% (= 50 ammo)."}],"formulas":{"ammoMultiplier":"floor(baseAmmo * (1.05 + 0.015*L))","atkPerAmmo(6)":"0.04","atkCap(6)":"2.0"},"caps":"+200% ATK from the 6-member effect","layerGain":"Ammo consumption in battle: 圣约送葬人 each 7 bullets +7 拉特兰 (7 triggers => 49/battle) and +3 远见 (<=21/battle); 莫斯提马 ops in its 4 adjacent tiles each 6 ammo +1; 蕾缪安 each 10 bullets with 3 ops in its row +2 拉特兰/精准; 送葬人 first kill +3 精准/拉特兰. Prep: 空弦 进入休整期 +3 to self and front tile operator's active bonds. 机变 \"莫斯提马的盟誓\" +10. Strategy 潘格尼尼: after spending 55 gold gain a random elite T4+ 拉特兰.","howToPlay":"Only ammo-skill operators benefit from the 3-tier; the bond is weak until 6 (巴哈姆特: \"3人效果較差\").","assumed":["non-ammo skills unaffected","\"ammo consumed\" = each shot/bullet decrement"]}},"egirShip":{"bondId":"egirShip","name":"阿戈尔","identifier":6,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["egir","abyssal"],"iconId":"icon_egirShip","activeCount":3,"thresholds":[3,5],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【阿戈尔】干员生命值提升(受层数影响)\n战斗开始时,【阿戈尔】干员会吞噬身前一格干员对其造成5000点物理伤害并获得其基础攻击力和阻挡数,使【阿戈尔】叠加等于被吞噬者等阶的盟约层数(【阿戈尔】之间优先更靠左和靠上的干员发起吞噬)\n<在场5名不同【阿戈尔】干员>前3名【阿戈尔】干员首次被击倒时立刻复活","descRaw":"【阿戈尔】干员<@ba.vup>生命值提升<@autochess.gray>(受层数影响)\n战斗开始时,【阿戈尔】干员会<@ba.vup>吞噬身前一格干员对其造成<@ba.vdown>5000点物理伤害并获得其<@ba.vup>基础攻击力和<@ba.vup>阻挡数,使【阿戈尔】叠加等于被吞噬者等阶的<@ba.vup>盟约层数<@autochess.gray>(【阿戈尔】之间优先更靠左和靠上的干员发起吞噬)\n<在场<@autochess.dgreen>5名不同【阿戈尔】干员>前3名【阿戈尔】干员首次被击倒时<@ba.vup>立刻复活","effectId":"bondeffect_egir","effectName":"阿戈尔","effectDesc":"【阿戈尔】干员生命值+{0:0%}(受层数影响)\n战斗开始时【阿戈尔】干员依次吞噬身前一格干员造成5000点物理伤害并获得其基础攻击力和阻挡数,并叠加等于被吞噬者等阶的盟约层数(【阿戈尔】之间优先更靠左和靠上的干员发起吞噬)\n<在场5名不同【阿戈尔】干员>前3名【阿戈尔】干员首次被击倒时立刻复活","effectDescRaw":"【阿戈尔】干员生命值<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n战斗开始时【阿戈尔】干员依次吞噬身前一格干员造成<@ba.vdown>5000点物理伤害并获得其<@ba.vup>基础攻击力和<@ba.vup>阻挡数,并叠加等于被吞噬者等阶的盟约层数<@ba.acrem>(【阿戈尔】之间优先更靠左和靠上的干员发起吞噬)\n<在场<@ba.vup>5名不同【阿戈尔】干员>前3名【阿戈尔】干员首次被击倒时<@ba.vup>立刻复活","effectDescParams":[{"index":0,"format":"0%","base":"base_max_hp","perStack":"max_hp_per_stack"}],"bb":{"base_max_hp":0.35,"max_hp_per_stack":0.01,"damage_value":5000,"power_bond_char_cnt":5,"max_free_respawn_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_egir","bond_type":"bond_by_id","bond_id":"egirShip","bond_add_type":"by_charlevel"},"buffs":[{"key":"env_gbuff_new","bb":{"base_max_hp":0.35,"max_hp_per_stack":0.01,"damage_value":5000,"power_bond_char_cnt":5,"max_free_respawn_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_egir","bond_type":"bond_by_id","bond_id":"egirShip","bond_add_type":"by_charlevel"}}],"baseParams":["base_max_hp"],"perStackParams":["max_hp_per_stack"],"members":["chess_char_1_04_a","chess_char_2_07_a","chess_char_3_05_a","chess_char_3_09_a","chess_char_4_09_a","chess_char_4_12_a","chess_char_5_05_a","chess_char_5_13_a","chess_char_6_04_a"],"visibleMembers":["chess_char_1_04_a","chess_char_2_07_a","chess_char_3_05_a","chess_char_3_09_a","chess_char_4_09_a","chess_char_4_12_a","chess_char_5_05_a","chess_char_5_13_a","chess_char_6_04_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"阿戈尔 members maxHP x(1 + 0.35 + 0.01*L)."},{"need":"3 distinct (battle start)","effect":"Devour (吞噬): see algorithm."},{"need":"5 distinct","effect":"The first 3 阿戈尔 members by position (the devour order: leftmost first, then topmost; fixed at battle start) each revive immediately on their own first knock-out, whatever the order of knock-outs (max_free_respawn_cnt 3)."}],"algorithm":["Order: 阿戈尔 members sorted leftmost first, then topmost (\"更靠左和靠上\").","Each 阿戈尔 in order marks the unit on the tile directly in front of it (its facing direction) and also the front-tile unit of every 阿戈尔 it has marked (chain). It never marks itself, a unit it already marked, or a unit that marked it.","The marker immediately gains the base ATK of every unit it marked (added to base ATK at the final stage) and their block counts.","After all marks are placed, each mark makes its target suffer one 5000-point physical 流失 (HP loss, source = the target itself; if it dies, the kill is credited to the marker), resolved in marking order. A target that dies cancels its remaining pending marks.","Each devoured unit adds layers to 阿戈尔 equal to its tier (1-6), once per unit per battle.","(5-member tier) Revive is implemented as: when the unit leaves the field for any reason other than being moved, its next deployment has 0 redeploy time and 0 cost (PRTS). Devour layers: each devoured unit adds its tier once per battle (refreshes next round)."],"formulas":{"hpMultiplier":"1.35 + 0.01*L","devourDamage":"5000","layersPerDevoured":"tier of devoured unit"},"caps":"3 revives per battle","layerGain":"Devour (tier per devoured unit, every battle); 幽灵鲨 被击倒 +3; 归溟幽灵鲨 被击倒/替身切换 +5 阿戈尔 +5 不屈; 斯卡蒂 each 2 kills +1 阿戈尔/坚守/突袭; 海霓 first kill (enemy or ally) +3 阿戈尔/奥术; 机变 \"斯卡蒂的盟誓\" +8. Strategy 克莱门莎: an 阿戈尔 knocked out adds layers = its tier.","howToPlay":"Put cheap/high-tier fodder in front of 阿戈尔 carries: they steal base ATK and block, gain layers, and (5) revive. Tier-6 fodder gives +6 layers per battle.","assumed":["5000 physical 流失 ignores DEF and shields","marked allied units are the player's own operators (devour hits allies)"]}},"siracusaShip":{"bondId":"siracusaShip","name":"叙拉古","identifier":7,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["siracusa","chiave"],"iconId":"icon_siracusaShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【叙拉古】干员部署后攻击速度提升,持续一定时间(受层数影响)\n<在场6名不同【叙拉古】干员>【叙拉古】干员部署后进入等时长的隐匿状态,【叙拉古】干员隐匿状态下和脱离隐匿10秒内对敌人攻击时有3%的概率造成一定真实伤害(受层数影响)并恐惧3秒","descRaw":"【叙拉古】干员部署后<@ba.vup>攻击速度提升,持续一定时间<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>6名不同【叙拉古】干员>【叙拉古】干员部署后进入等时长的隐匿状态,【叙拉古】干员隐匿状态下和脱离隐匿<@ba.vup>10秒内对敌人攻击时有<@ba.vup>3%的概率造成一定真实伤害<@autochess.gray>(受层数影响)并<@ba.vup>恐惧3秒","effectId":"bondeffect_siracusa","effectName":"叙拉古","effectDesc":"【叙拉古】干员部署后攻击速度+{0:0},持续{1:0}秒(受层数影响)\n<在场6名不同【叙拉古】干员>【叙拉古】干员部署后还会进入等时长的隐匿状态,【叙拉古】干员在隐匿状态和脱离隐匿10秒内对敌人攻击时有3%概率造成{2:0}(受层数影响)点真实伤害并恐惧目标3秒","effectDescRaw":"【叙拉古】干员部署后攻击速度<@ba.vup>+{0:0},持续<@ba.vup>{1:0}秒<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【叙拉古】干员>【叙拉古】干员部署后还会进入等时长的隐匿状态,【叙拉古】干员在隐匿状态和脱离隐匿10秒内对敌人攻击时有3%概率造成<@ba.vup>{2:0}<@ba.acrem>(受层数影响)点真实伤害并<@ba.vup>恐惧目标3秒","effectDescParams":[{"index":0,"format":"0","base":"base_attack_speed","perStack":"attack_speed_per_stack"},{"index":1,"format":"0","base":"base_duration","perStack":"duration_per_stack"},{"index":2,"format":"0","base":"base_damage","perStack":"damage_per_stack"}],"bb":{"base_duration":32,"duration_per_stack":0.4,"base_attack_speed":25,"attack_speed_per_stack":0.8,"power_bond_char_cnt":6,"ex_bond_char_cnt":6,"end_duration":10,"prob":0.03,"base_damage":5000,"damage_per_stack":50,"fear":3},"bbStr":{"key":"act2autochess_bond_eff_siracusa"},"buffs":[{"key":"env_gbuff_new","bb":{"base_duration":32,"duration_per_stack":0.4,"base_attack_speed":25,"attack_speed_per_stack":0.8,"power_bond_char_cnt":6,"ex_bond_char_cnt":6,"end_duration":10,"prob":0.03,"base_damage":5000,"damage_per_stack":50,"fear":3},"bbStr":{"key":"act2autochess_bond_eff_siracusa"}}],"baseParams":["base_attack_speed","base_duration","base_damage"],"perStackParams":["attack_speed_per_stack","duration_per_stack","damage_per_stack"],"members":["chess_char_1_07_a","chess_char_1_08_a","chess_char_2_16_a","chess_char_3_15_a","chess_char_3_18_a","chess_char_3_19_a","chess_char_4_10_a","chess_char_4_16_a","chess_char_5_10_a","chess_char_5_20_a","chess_char_6_18_a"],"visibleMembers":["chess_char_1_07_a","chess_char_1_08_a","chess_char_2_16_a","chess_char_3_18_a","chess_char_3_19_a","chess_char_4_10_a","chess_char_4_16_a","chess_char_5_10_a","chess_char_5_20_a","chess_char_6_18_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"After every deployment (incl. redeploy) a 叙拉古 member gains ASPD +(25 + 0.8*L) for (32 + 0.4*L) s."},{"need":"6 distinct","effect":"After deployment also 隐匿 (camouflage) for the same duration. While camouflaged and for 10 s after it ends, each normal damage instance (普通伤害 = attack type NORMAL: attacks, skill hits, drone attacks; not 溅射 / 持续 / 附加 — `bonds/core.js siracusaRolls`) it deals may add (5000 + 50*L) true damage (source = the operator) and 恐惧 (fear) 3 s. Nominal 3% chance, implemented as pseudo-random: all 叙拉古 members share one counter; attempt n since last proc succeeds with p = 0.00139*n (guaranteed at n = 720); counter resets on proc."}],"formulas":{"aspd":"25 + 0.8*L","durationSec":"32 + 0.4*L","procDamage":"5000 + 50*L","prdStep":"0.00139"},"caps":"none","layerGain":"Shop refresh-driven: 拉普兰德 first manual refresh each round +4 (works from bench); 安洁莉娜 休整期结束 +4 per refresh this round (<=12/round); 阿罗玛 +2 叙拉古/奥术 per refresh (<=6); 伺夜 first 3 kills +2 叙拉古 +1 奇迹; 荒芜拉普兰德 each kill +2 (elite: every 叙拉古 gets this, <=100/battle); 忍冬 获得时 +6 own bonds (x2/x3 with 投资人); 机变 \"德克萨斯的盟誓\" +10. Strategy 贾维: every 6 manual refreshes get a free 叙拉古 (<=2/round).","howToPlay":"Refresh a lot in prep (free refresh sources: 普罗旺斯, 德克萨斯, 缄默德克萨斯, 巫恋) to feed 拉普兰德/安洁莉娜; pair with 投资人 for 忍冬.","notes":["PRTS: the 10 s post-stealth window restarts if the operator's status effects or immunities change."],"assumed":["隐匿 = standard AK camouflage (not targeted by ranged enemies unless blocking)"]}},"kazimierzShip":{"bondId":"kazimierzShip","name":"卡西米尔","identifier":8,"isCore":true,"bondType":"SEASON","bondOrder":2,"powerIdList":["kazimierz","pinus"],"iconId":"icon_kazimierzShip","activeCount":3,"thresholds":[3,6],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"每次有干员部署时,【卡西米尔】干员攻击力+20%持续至战斗结束(上限受层数影响)\n<在场6名不同【卡西米尔】干员>【卡西米尔】干员阻挡敌人时每2秒对周围敌人造成120%攻击力真实伤害和0.1秒晕眩,未阻挡敌人时攻击附带30%攻击力的真实伤害","descRaw":"每次有干员部署时,【卡西米尔】干员攻击力<@ba.vup>+20%持续至战斗结束<@autochess.gray>(上限受层数影响)\n<在场<@autochess.dgreen>6名不同【卡西米尔】干员>【卡西米尔】干员阻挡敌人时每<@ba.vup>2秒对周围敌人造成<@ba.vup>120%攻击力真实伤害和<@ba.vup>0.1秒晕眩,未阻挡敌人时攻击附带<@ba.vup>30%攻击力的真实伤害","effectId":"bondeffect_kazimierz","effectName":"卡西米尔","effectDesc":"每次有干员部署时【卡西米尔】干员攻击力+20%(至多+{0:0%})(受层数影响)\n<在场6名不同【卡西米尔】干员>【卡西米尔】干员阻挡敌人时每2秒对周围敌人造成120%攻击力真实伤害和0.1秒晕眩,未阻挡敌人时攻击附带30%攻击力的真实伤害","effectDescRaw":"每次有干员部署时【卡西米尔】干员攻击力+20%(至多<@ba.vup>+{0:0%})<@ba.acrem>(受层数影响)\n<在场<@ba.vup>6名不同【卡西米尔】干员>【卡西米尔】干员阻挡敌人时每2秒对周围敌人造成<@ba.vup>120%攻击力真实伤害和<@ba.vup>0.1秒晕眩,未阻挡敌人时攻击附带<@ba.vup>30%攻击力的真实伤害","effectDescParams":[{"index":0,"format":"0%","base":"base_max_atk_when_born","perStack":"max_atk_when_born_per_stack"}],"bb":{"atk_when_born":0.2,"base_max_atk_when_born":0.5,"max_atk_when_born_per_stack":0.01,"damage_interval":2,"damage_atk_scale":1.2,"stun":0.1,"range_radius":0.8,"power_bond_char_cnt":6,"pure_atk_scale":0.3},"bbStr":{"key":"act2autochess_bond_eff_kazimierz"},"buffs":[{"key":"env_gbuff_new","bb":{"atk_when_born":0.2,"base_max_atk_when_born":0.5,"max_atk_when_born_per_stack":0.01,"damage_interval":2,"damage_atk_scale":1.2,"stun":0.1,"range_radius":0.8,"power_bond_char_cnt":6,"pure_atk_scale":0.3},"bbStr":{"key":"act2autochess_bond_eff_kazimierz"}}],"baseParams":["base_max_atk_when_born"],"perStackParams":["max_atk_when_born_per_stack"],"members":["chess_char_1_19_a","chess_char_2_12_a","chess_char_2_18_a","chess_char_3_12_a","chess_char_3_17_a","chess_char_4_19_a","chess_char_4_20_a","chess_char_5_19_a","chess_char_6_17_a","chess_char_6_19_a"],"visibleMembers":["chess_char_1_19_a","chess_char_2_12_a","chess_char_2_18_a","chess_char_3_12_a","chess_char_3_17_a","chess_char_4_19_a","chess_char_4_20_a","chess_char_5_19_a","chess_char_6_17_a","chess_char_6_19_a"],"spec":{"tiers":[{"need":"3 distinct","effect":"Every time any friendly operator is deployed (incl. redeploys) each 卡西米尔 member gains ATK +20% until battle end, capped at +(50 + 1*L)%."},{"need":"6 distinct","effect":"While blocking >= 1 enemy: every 2 s deals 120% ATK true damage to all enemies within radius 0.8 tiles and stuns them 0.1 s. While not blocking: each normal damage instance adds 30% ATK sourceless true damage."}],"formulas":{"atkPerDeploy":"0.20","atkCap":"0.50 + 0.01*L"},"caps":"ATK bonus cap 50%+1%/layer","layerGain":"Deploy-driven in battle: 砾 部署时 +1; 瑕光 部署时 +4 own active bonds (<=12/battle); 远牙 grants the right-most operator in its row \"部署时 +4 卡西米尔/精准 (<=24/battle)\"; 锏 部署时 +8 (<=24); 获得时: 野鬃 +2, 灰毫 +3 to highest-layer bond; 机变 \"玛恩纳的盟誓\" +12. Strategy 玛恩纳: +1 gold next round per 卡西米尔 bought (<=3).","howToPlay":"Maximise deploy events: low redeploy time (助力 -30%, 骑士戒律), operators that die/retreat and come back (砾 + 不屈). 巴哈姆特: do not light 坚守 (damage sharing keeps 砾 alive).","assumed":["initial auto-deployments at battle start also count as deploys","buff applies to members deployed later too (stored globally, capped)"]}},"preciShip":{"bondId":"preciShip","name":"精准","identifier":9,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_preciShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【精准】干员攻击力提升(受层数影响)\n<在场3名不同【精准】干员>生效范围变为【精准】干员和所有远程干员,且攻击无视一定的防御力和法术抗性","descRaw":"【精准】干员<@ba.vup>攻击力提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>3名不同【精准】干员>生效范围变为【精准】干员和所有远程干员,且攻击无视一定的<@ba.vup>防御力和<@ba.vup>法术抗性","effectId":"bondeffect_preci","effectName":"精准","effectDesc":"【精准】干员攻击力+{0:0%}(受层数影响)\n<在场3名不同【精准】干员>生效范围变为所有【精准】干员和远程干员,且攻击无视30%防御力和法术抗性","effectDescRaw":"【精准】干员攻击力<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>3名不同【精准】干员>生效范围变为所有【精准】干员和远程干员,且攻击无视<@ba.vup>30%防御力和法术抗性","effectDescParams":[{"index":0,"format":"0%","base":"base_atk","perStack":"atk_per_stack"}],"bb":{"base_atk":0.1,"atk_per_stack":0.012,"power_def_penetrate":0.3,"power_magic_resist_penetrate":0.3,"power_bond_char_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_preci"},"buffs":[{"key":"env_gbuff_new","bb":{"base_atk":0.1,"atk_per_stack":0.012,"power_def_penetrate":0.3,"power_magic_resist_penetrate":0.3,"power_bond_char_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_preci"}}],"baseParams":["base_atk"],"perStackParams":["atk_per_stack"],"members":["chess_char_1_09_a","chess_char_1_17_a","chess_char_2_01_a","chess_char_3_11_a","chess_char_4_06_a","chess_char_4_14_a","chess_char_4_20_a","chess_char_5_02_a","chess_char_6_01_a","chess_char_6_05_a","chess_char_6_08_a","chess_char_6_12_a"],"visibleMembers":["chess_char_1_09_a","chess_char_1_17_a","chess_char_2_01_a","chess_char_3_11_a","chess_char_4_06_a","chess_char_4_14_a","chess_char_4_20_a","chess_char_5_02_a","chess_char_6_01_a","chess_char_6_05_a","chess_char_6_08_a","chess_char_6_12_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"精准 members ATK x(1 + 0.10 + 0.012*L)."},{"need":"3 distinct","effect":"Scope becomes 精准 members + every RANGED operator; affected units also ignore 30% of target DEF and 30% of target RES."}],"formulas":{"atkMultiplier":"1.10 + 0.012*L","defPenetrateRatio(3)":"0.3","resPenetrateRatio(3)":"0.3"},"layerGain":"Kill/skill/deploy in battle: 寒芒克洛丝 gives front operator \"开技能 +1 精准 (<=10/battle)\"; 远牙 grant (+4/deploy); 缇缇 +1 per sleep/stun; 蕾缪安, 送葬人; 莱恩哈特 休整期结束 +5 own active bonds; 获得时: 深靛 +2, 雪猎 +5. 机变 \"缇缇的盟誓\" +10.","assumed":["penetration = ratio ignore (like 无视 x% 防御)"]}},"swiftShip":{"bondId":"swiftShip","name":"迅捷","identifier":10,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_swiftShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":40,"mode":"reach","effect":"env_gbuff_new"}],"desc":"【迅捷】干员技能结束时有概率(受层数影响)立刻回复12点技力\n<达到40层>所有干员技能结束时有等概率额外回复15点技力","descRaw":"【迅捷】干员技能结束时有概率<@autochess.gray>(受层数影响)立刻回复<@ba.vup>12点技力\n<达到<@autochess.dgreen>40层>所有干员技能结束时有等概率额外回复<@ba.vup>15点技力","effectId":"bondeffect_swift","effectName":"迅捷","effectDesc":"【迅捷】干员技能结束时有{0:0%}概率(受层数影响)立刻回复12点技力\n<达到40层>所有干员技能结束时有等概率额外回复15点技力","effectDescRaw":"【迅捷】干员技能结束时有<@ba.vup>{0:0%}概率<@ba.acrem>(受层数影响)立刻回复<@ba.vup>12点技力\n<达到<@ba.vup>40层>所有干员技能结束时有等概率额外回复<@ba.vup>15点技力","effectDescParams":[{"index":0,"format":"0%","base":"base_prob","perStack":"prob_per_stack"}],"bb":{"base_prob":0.2,"prob_per_stack":0.0035,"power_bond_stack_cnt":40,"normal_sp":12,"power_sp":15},"bbStr":{"key":"act1autochess_bond_eff_swift"},"buffs":[{"key":"env_gbuff_new","bb":{"base_prob":0.2,"prob_per_stack":0.0035,"power_bond_stack_cnt":40,"normal_sp":12,"power_sp":15},"bbStr":{"key":"act1autochess_bond_eff_swift"}}],"baseParams":["base_prob"],"perStackParams":["prob_per_stack"],"members":["chess_char_1_01_a","chess_char_1_16_a","chess_char_1_19_a","chess_char_2_13_a","chess_char_2_19_a","chess_char_3_10_a","chess_char_3_18_a","chess_char_4_14_a","chess_char_5_14_a","chess_char_5_15_a","chess_char_5_22_a","chess_char_6_05_a","chess_char_6_10_a","chess_char_6_19_a"],"visibleMembers":["chess_char_1_01_a","chess_char_1_19_a","chess_char_2_13_a","chess_char_2_19_a","chess_char_3_10_a","chess_char_3_18_a","chess_char_4_14_a","chess_char_5_14_a","chess_char_5_15_a","chess_char_5_22_a","chess_char_6_05_a","chess_char_6_19_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"When a 迅捷 member's skill ends: with p = min(1, 0.20 + 0.0035*L) immediately +12 SP."},{"need":"L >= 40","effect":"Every operator whose skill ends: with the same p, additionally +15 SP."}],"formulas":{"p":"min(1, 0.20 + 0.0035*L)","reaches100%AtL":"229"},"layerGain":"妮芙 休整期结束 +2 per operator on the bench; 蒂比 进入休整期 +2 own active bonds; 莱恩哈特 +5; 引星棘刺 +4 self & front; 获得时: 锡人/野鬃 +2, 忍冬 +6, 锏 +8. 机变 \"银灰的盟誓\" +8.","assumed":["迅捷 members roll both the 12 SP and the 15 SP independently"]}},"skillfulShip":{"bondId":"skillfulShip","name":"灵巧","identifier":11,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_skillfulShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":40,"mode":"reach","effect":"env_gbuff_new"}],"desc":"【灵巧】干员及周围4格干员攻击速度提升(受层数影响)\n<达到40层>生效范围变为【灵巧】干员周围8格","descRaw":"【灵巧】干员及周围4格干员<@ba.vup>攻击速度提升<@autochess.gray>(受层数影响)\n<达到<@autochess.dgreen>40层>生效范围变为【灵巧】干员周围8格","effectId":"bondeffect_skillful","effectName":"灵巧","effectDesc":"【灵巧】干员及周围4格的干员攻击速度+{0:0}(受层数影响)\n <达到40层>生效范围变为【灵巧】干员周围8格","effectDescRaw":"【灵巧】干员及周围4格的干员攻击速度<@ba.vup>+{0:0}<@ba.acrem>(受层数影响)\n <达到<@ba.vup>40层>生效范围变为【灵巧】干员周围8格","effectDescParams":[{"index":0,"format":"0","base":"base_attack_speed","perStack":"attack_speed_per_stack"}],"bb":{"base_attack_speed":10,"attack_speed_per_stack":1,"power_bond_stack_cnt":40},"bbStr":{"key":"act1autochess_bond_eff_skillful"},"buffs":[{"key":"env_gbuff_new","bb":{"base_attack_speed":10,"attack_speed_per_stack":1,"power_bond_stack_cnt":40},"bbStr":{"key":"act1autochess_bond_eff_skillful"}}],"baseParams":["base_attack_speed"],"perStackParams":["attack_speed_per_stack"],"members":["chess_char_1_14_a","chess_char_2_04_a","chess_char_2_13_a","chess_char_3_02_a","chess_char_3_13_a","chess_char_3_21_a","chess_char_4_11_a","chess_char_4_13_a","chess_char_4_21_a","chess_char_5_06_a","chess_char_5_16_a","chess_char_6_16_a"],"visibleMembers":["chess_char_1_14_a","chess_char_2_04_a","chess_char_2_13_a","chess_char_3_02_a","chess_char_3_13_a","chess_char_3_21_a","chess_char_4_11_a","chess_char_4_13_a","chess_char_4_21_a","chess_char_5_06_a","chess_char_6_16_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"灵巧 members and operators on their 4 orthogonally adjacent tiles: ASPD +(10 + 1*L)."},{"need":"L >= 40","effect":"Area becomes the 8 surrounding tiles."}],"formulas":{"aspd":"10 + L"},"layerGain":"溯光星源 休整期结束 +2 灵巧/奥术 per 3 gold spent this round ; 断崖 +3 self & behind; 空弦 +3 self & front; 蒂比 +2; 获得时 灵知 +5. (act1 灵巧 also had a 20-layer shop reward; removed in act2.)","assumed":["a unit covered by several 灵巧 auras gets the bonus once"]}},"arcaneShip":{"bondId":"arcaneShip","name":"奥术","identifier":12,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_arcaneShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"【奥术】干员造成法术伤害时使目标受到的法术伤害提升(受层数影响),持续3秒\n<在场3名不同【奥术】干员>【奥术】干员对生命值低于50%的敌人施加的伤害提升比例提升(受层数影响)","descRaw":"【奥术】干员造成法术伤害时使目标受到的法术伤害提升<@autochess.gray>(受层数影响),持续3秒\n<在场<@autochess.dgreen>3名不同【奥术】干员>【奥术】干员对生命值低于<@ba.vup>50%的敌人施加的伤害提升比例提升<@autochess.gray>(受层数影响)","effectId":"bondeffect_arcane","effectName":"奥术","effectDesc":"【奥术】干员造成法术伤害时使目标受到的法术伤害提升{0:0%}(受层数影响),持续3秒\n<在场3名不同【奥术】干员>【奥术】干员对生命值低于50%的敌人施加的伤害提升比例为{1:0%}(受层数影响)","effectDescRaw":"【奥术】干员造成法术伤害时使目标受到的法术伤害提升<@ba.vup>{0:0%}<@ba.acrem>(受层数影响),持续3秒\n<在场<@ba.vup>3名不同【奥术】干员>【奥术】干员对生命值低于50%的敌人施加的伤害提升比例为<@ba.vup>{1:0%}<@ba.acrem>(受层数影响)","effectDescParams":[{"index":0,"format":"0%","base":"base_damage_scale_show","perStack":"damage_scale_per_stack"},{"index":1,"format":"0%","base":"base_damage_scale_show_ex","perStack":"damage_scale_per_stack_show_ex"}],"bb":{"weak_duration":3,"base_damage_scale":1.2,"damage_scale_per_stack":0.01,"power_bond_char_cnt":3,"power_weak_scale":1.4,"hp_ratio":0.5,"base_damage_scale_show":0.2,"base_damage_scale_show_ex":0.68,"damage_scale_per_stack_show_ex":0.014},"bbStr":{"key":"act2autochess_bond_eff_arcane"},"buffs":[{"key":"env_gbuff_new","bb":{"weak_duration":3,"base_damage_scale":1.2,"damage_scale_per_stack":0.01,"power_bond_char_cnt":3,"power_weak_scale":1.4,"hp_ratio":0.5,"base_damage_scale_show":0.2,"base_damage_scale_show_ex":0.68,"damage_scale_per_stack_show_ex":0.014},"bbStr":{"key":"act2autochess_bond_eff_arcane"}}],"baseParams":["base_damage_scale_show","base_damage_scale_show_ex"],"perStackParams":["damage_scale_per_stack","damage_scale_per_stack_show_ex"],"members":["chess_char_1_17_a","chess_char_2_10_a","chess_char_2_15_a","chess_char_3_09_a","chess_char_4_02_a","chess_char_4_10_a","chess_char_5_07_a","chess_char_5_12_a","chess_char_6_02_a","chess_char_6_16_a"],"visibleMembers":["chess_char_1_17_a","chess_char_2_10_a","chess_char_3_09_a","chess_char_4_02_a","chess_char_4_10_a","chess_char_5_07_a","chess_char_5_12_a","chess_char_6_02_a","chess_char_6_16_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"When an 奥术 member deals magic damage, the target takes magic damage x(1.20 + 0.01*L) (i.e. +(20+L)%) for 3 s. ONE instance per target whatever applies it: the strongest value wins, a weaker one resumes if it outlasts it; reapplying refreshes (corrected 2026-10-01: PRTS 作战机制 同名buff默认只表现出一个; 巴哈姆特 12316 the two players of a pair field compete for it)."},{"need":"3 distinct","effect":"Against enemies below 50% HP the multiplier is 1.4 x (1.20 + 0.01*L) = 1.68 + 0.014*L (i.e. +(68+1.4L)%)."}],"formulas":{"magicTakenMul":"1.20 + 0.01*L","magicTakenMulLowHp(3)":"1.4*(1.20 + 0.01*L)","hpThreshold":"0.5","durationSec":"3"},"layerGain":"夕 +2 per operator gained; 阿罗玛 +2 per refresh (<=6); 溯光星源 +2 per 3 gold spent; 海霓 first kill +3; 获得时: 深靛 +2, 协律 +4 (hidden). 机变 \"莫斯提马的盟誓\" +10.","assumed":["one instance per target, the strongest (the engine's default same-name rule; the two players of a pair field compete for it) — until v2.5 the remake kept one per player and they multiplied"]}},"steadShip":{"bondId":"steadShip","name":"坚守","identifier":13,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_steadShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"所有干员生命值提升(受层数影响)\n<在场3名不同【坚守】干员>场上非【坚守】干员受到伤害时,所受伤害的40%由所有【坚守】干员平均承担。【坚守】干员受到伤害时,伤害来源将受到一定法术伤害(受层数影响,每0.2秒至多触发1次)和持续5秒的40%脆弱效果","descRaw":"所有干员<@ba.vup>生命值提升<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>3名不同【坚守】干员>场上非【坚守】干员受到伤害时,所受伤害的<@ba.vup>40%由所有【坚守】干员<@ba.vup>平均承担。【坚守】干员受到伤害时,伤害来源将受到一定法术伤害<@autochess.gray>(受层数影响,每0.2秒至多触发1次)和持续<@ba.vup>5秒的<@ba.vup>40%脆弱效果","effectId":"bondeffect_stead","effectName":"坚守","effectDesc":"所有干员生命值+{0:0%}(受层数影响)\n<在场3名不同【坚守】干员>场上非【坚守】干员受到伤害时,所受伤害的40%由【坚守】干员平均承担;【坚守】干员受到伤害时,伤害来源受到{1:0}点法术伤害(受层数影响,每0.2秒至多触发1次)和持续5秒的40%的脆弱效果","effectDescRaw":"所有干员生命值<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n<在场<@ba.vup>3名不同【坚守】干员>场上非【坚守】干员受到伤害时,所受伤害的<@ba.vup>40%由【坚守】干员平均承担;【坚守】干员受到伤害时,伤害来源受到<@ba.vup>{1:0}点法术伤害<@ba.acrem>(受层数影响,每0.2秒至多触发1次)和持续5秒的<@ba.vup>40%的脆弱效果","effectDescParams":[{"index":0,"format":"0%","base":"base_max_hp","perStack":"max_hp_per_stack"},{"index":1,"format":"0","base":"base_damage_value","perStack":"damage_value_per_stack"}],"bb":{"base_max_hp":0.25,"max_hp_per_stack":0.012,"damage_resistance":0.4,"power_bond_char_cnt":3,"cd_duration":0.2,"weak[limit]":5,"damage_scale":1.4,"base_damage_value":850,"damage_value_per_stack":10},"bbStr":{"key":"act1autochess_bond_eff_stead"},"buffs":[{"key":"env_gbuff_new","bb":{"base_max_hp":0.25,"max_hp_per_stack":0.012,"damage_resistance":0.4,"power_bond_char_cnt":3,"cd_duration":0.2,"weak[limit]":5,"damage_scale":1.4,"base_damage_value":850,"damage_value_per_stack":10},"bbStr":{"key":"act1autochess_bond_eff_stead"}}],"baseParams":["base_max_hp","base_damage_value"],"perStackParams":["max_hp_per_stack","damage_value_per_stack"],"members":["chess_char_1_02_a","chess_char_1_10_a","chess_char_2_08_a","chess_char_2_17_a","chess_char_2_18_a","chess_char_3_05_a","chess_char_3_16_a","chess_char_4_01_a","chess_char_5_11_a","chess_char_6_03_a"],"visibleMembers":["chess_char_1_02_a","chess_char_1_10_a","chess_char_2_08_a","chess_char_2_17_a","chess_char_2_18_a","chess_char_3_05_a","chess_char_3_16_a","chess_char_4_01_a","chess_char_5_11_a","chess_char_6_03_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"ALL operators maxHP x(1 + 0.25 + 0.012*L)."},{"need":"3 distinct","effect":"When a non-坚守 operator takes damage, 40% of that damage is taken instead by the 坚守 members, split evenly. When a 坚守 member takes damage, the damage source takes (850 + 10*L) sourceless magic damage and 脆弱 (damage taken x1.4) for 5 s; each 坚守 member can reflect at most once per 0.2 s."}],"formulas":{"hpMultiplier":"1.25 + 0.012*L","redirectRatio":"0.4","thornsDamage":"850 + 10*L","thornsCooldownSec":"0.2","fragile":"1.4 for 5 s"},"layerGain":"折桠 休整期结束 +4; 蛇屠箱 +1 per operator in same row; 斯卡蒂 kills; 获得时 角峰 +2; 机变 \"斯卡蒂的盟誓\" +8.","notes":["PRTS: thorns hit whatever the damage source is; sourceless damage can consume the thorns cooldown."]}},"deputShip":{"bondId":"deputShip","name":"助力","identifier":14,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_deputShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"所有干员防御力提升(受层数影响),再部署时间减少\n休整期结束时,使当前所有已激活盟约层数+2\n<在场3名不同【助力】干员>改为层数+4","descRaw":"所有干员<@ba.vup>防御力提升<@autochess.gray>(受层数影响),<@ba.vup>再部署时间减少\n休整期结束时,使当前所有已激活盟约层数<@ba.vup>+2\n<在场<@autochess.dgreen>3名不同【助力】干员>改为层数<@ba.vup>+4","effectId":"bondeffect_deput","effectName":"助力","effectDesc":"所有干员防御力+{0:0%}(受层数影响),再部署时间-30%\n休整期结束时,使当前所有已激活的盟约层数+2\n<在场3名不同【助力】干员>改为层数+4","effectDescRaw":"所有干员防御力<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响),再部署时间<@ba.vup>-30%\n休整期结束时,使当前所有已激活的盟约层数<@ba.vup>+2\n<在场<@ba.vup>3名不同【助力】干员>改为层数<@ba.vup>+4","effectDescParams":[{"index":0,"format":"0%","base":"base_def","perStack":"def_per_stack"}],"bb":{"base_def":0.15,"def_per_stack":0.012,"respawn_time":-0.3,"layer":2,"count":3,"more_layer":4},"bbStr":{"key":"act1autochess_bond_eff_deput","bond":"deputShip"},"buffs":[{"key":"env_gbuff_new","bb":{"base_def":0.15,"def_per_stack":0.012,"respawn_time":-0.3},"bbStr":{"key":"act1autochess_bond_eff_deput"}},{"key":"bond_activated_add_layer","bb":{"layer":2,"count":3,"more_layer":4},"bbStr":{"bond":"deputShip"}}],"baseParams":["base_def"],"perStackParams":["def_per_stack"],"members":["chess_char_1_06_a","chess_char_1_13_a","chess_char_2_14_a","chess_char_2_15_a","chess_char_3_15_a","chess_char_3_20_a","chess_char_4_03_a","chess_char_4_05_a","chess_char_4_21_a","chess_char_4_24_a","chess_char_5_16_a","chess_char_6_14_a","chess_char_6_20_a"],"visibleMembers":["chess_char_1_06_a","chess_char_1_13_a","chess_char_2_14_a","chess_char_3_20_a","chess_char_4_21_a","chess_char_4_24_a","chess_char_6_14_a","chess_char_6_20_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"ALL operators DEF x(1 + 0.15 + 0.012*L); redeploy time -30%. At the end of every prep phase (休整期结束时) every currently active bond (incl. 助力) gets +2 layers."},{"need":"3 助力 (distinct name or elite state)","effect":"+4 layers instead of +2."}],"formulas":{"defMultiplier":"1.15 + 0.012*L","redeployTimeMul":"0.7","layersPerRound":"2 (4 at 3 members) to every active bond"},"layerGain":"波登可 +1 / 调香师 +2 to highest-layer bond at prep end (work from bench); 流明 +2 to active bonds of every bench operator; 纯烬艾雅法拉 +3 highest-layer bond per skill; its own +2/+4 per round.","howToPlay":"Cheap universal layer engine: activate as many bonds as possible so each gets +2/+4 every round (helps the hidden-round threshold)."}},"visiShip":{"bondId":"visiShip","name":"远见","identifier":15,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_visiShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD_AND_DECK","countsHand":true,"countsGoldenOnly":false,"activeType":"ALL","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":10,"mode":"every","effect":"bond_layer_gain_coin"},{"layer":80,"mode":"first","effect":"bond_multi_layer_char_goods_price_bond_discount"},{"layer":150,"mode":"first","effect":"bond_multi_layer_char_goods_price_bond_discount"}],"desc":"<每叠加10层>获得一次2资金\n<首次达到80层>所有【远见】干员购买价格永久-1资金\n<首次达到150层>以上效果改为调度中心内所有干员的购买价格永久-1资金(整备区的【远见】干员也可用于激活盟约)","descRaw":"<每叠加<@autochess.dgreen>10层>获得一次<@ba.vup>2资金\n<首次达到<@autochess.dgreen>80层>所有【远见】干员购买价格<@ba.vup>永久-1资金\n<首次达到<@autochess.dgreen>150层>以上效果改为调度中心内所有干员的购买价格<@ba.vup>永久-1资金(整备区的【远见】干员也可用于激活盟约)","effectId":"bondeffect_visi","effectName":"远见","effectDesc":"<每叠加10层>获得一次2资金\n<首次到达80层>所有【远见】干员购买价格永久-1资金\n<首次到达150层>上述效果改为所有干员购买价格永久-1资金\n整备区的【远见】干员也可用于激活盟约","effectDescRaw":"<每叠加<@ba.vup>10层>获得一次<@ba.vup>2资金\n<首次到达<@ba.vup>80层>所有【远见】干员购买价格永久-1资金\n<首次到达<@ba.vup>150层>上述效果改为所有干员购买价格永久-1资金\n整备区的【远见】干员也可用于激活盟约","effectDescParams":[],"bb":{"layer":10,"count":2,"layer1":80,"discount":1,"layer2":150},"bbStr":{"bond":"visiShip"},"buffs":[{"key":"bond_layer_gain_coin","bb":{"layer":10,"count":2},"bbStr":{}},{"key":"bond_multi_layer_char_goods_price_bond_discount","bb":{"layer1":80,"discount":1,"layer2":150},"bbStr":{"bond":"visiShip"}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_11_a","chess_char_2_02_a","chess_char_3_03_a","chess_char_3_14_a","chess_char_4_04_a","chess_char_4_07_a","chess_char_5_01_a","chess_char_5_21_a","chess_char_6_12_a"],"visibleMembers":["chess_char_2_02_a","chess_char_3_03_a","chess_char_3_14_a","chess_char_4_04_a","chess_char_4_07_a","chess_char_5_01_a","chess_char_5_21_a","chess_char_6_12_a"],"spec":{"tiers":[{"need":"2 distinct (board + bench)","effect":"Each time cumulative L passes a multiple of 10: +2 gold."},{"need":"first time L >= 80","effect":"All 远见 operators' shop price permanently -1."},{"need":"first time L >= 150","effect":"Replaces the above: every operator in the shop permanently -1 (overrides, does not stack; 3/27 update)."}],"formulas":{"goldPayouts":"2 * floor(L/10)"},"layerGain":"寒檀 进入/结束休整期 +4 each; 伊内丝 +5 own active bonds; 赫默 +2; 圣约送葬人 +3 per 7 bullets (<=21/battle); 风笛 kills +2; 机变 \"风笛的盟誓\" +8.","assumed":["no floor but 0 (owner's decision 2026-10-04; a floor of 1 was assumed until 0.1.3)"]}},"miraShip":{"bondId":"miraShip","name":"奇迹","identifier":16,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_miraShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD_AND_DECK","countsHand":true,"countsGoldenOnly":false,"activeType":"ALL","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":100,"mode":"every","effect":"bond_layer_gain_coin"}],"desc":"刷新调度中心时,有概率使下次刷新不消耗资金(受层数影响)\n<每叠加100层>获得20资金(整备区的【奇迹】干员也可用于激活盟约)","descRaw":"刷新调度中心时,有概率使下次刷新<@ba.vup>不消耗资金<@autochess.gray>(受层数影响)\n<每叠加<@autochess.dgreen>100层>获得<@ba.vup>20资金(整备区的【奇迹】干员也可用于激活盟约)","effectId":"bondeffect_mira","effectName":"奇迹","effectDesc":"刷新调度中心时,有{0:0%}(受层数影响)概率使下次刷新不消耗资金\n<每叠加100层>获得20资金\n整备区的【奇迹】干员也可用于激活盟约","effectDescRaw":"刷新调度中心时,有<@ba.vup>{0:0%}<@ba.acrem>(受层数影响)概率使下次刷新不消耗资金\n<每叠加<@ba.vup>100层>获得<@ba.vup>20资金\n整备区的【奇迹】干员也可用于激活盟约","effectDescParams":[{"index":0,"format":"0%","base":"baseprob","perStack":"prob"}],"bb":{"probk":0.3,"prob":0.003,"baseprob":0.18,"layer":100,"count":20},"bbStr":{},"buffs":[{"key":"bond_refresh_shop_next_free","bb":{"probk":0.3,"prob":0.003,"baseprob":0.18},"bbStr":{}},{"key":"bond_layer_gain_coin","bb":{"layer":100,"count":20},"bbStr":{}}],"baseParams":["baseprob"],"perStackParams":["prob"],"members":["chess_char_1_11_a","chess_char_2_11_a","chess_char_3_01_a","chess_char_3_19_a","chess_char_4_15_a","chess_char_4_26_a","chess_char_5_04_a","chess_char_5_15_a","chess_char_5_20_a","chess_char_5_23_a","chess_char_6_07_a"],"visibleMembers":["chess_char_2_11_a","chess_char_3_01_a","chess_char_3_19_a","chess_char_4_26_a","chess_char_5_15_a","chess_char_5_20_a","chess_char_5_23_a","chess_char_6_07_a"],"spec":{"tiers":[{"need":"2 distinct (board + bench)","effect":"After each shop refresh, if the player has 0 free refreshes: with p = 0.18 + 0.003*L gain 1 free refresh."},{"need":"every 100 layers","effect":"+20 gold."}],"formulas":{"p":"min(1, 0.18 + 0.003*L)","goldPayouts":"20 * floor(L/100)"},"layerGain":"维娜·维多利亚 +2 per distinct-tier 奇迹; 录武官 获得时 +3; 伺夜 kills +1; 引星棘刺 +4 self & front; 华法琳 (奇迹 member) gives the operator in front \"开技能时 +1 own active bonds\" (data: <=7/battle, elite +2 <=14; PRTS 3/27 patch note says cap raised to 12/24).","notes":["blackboard probk = 0.3: meaning unknown (not in any description) [UNKNOWN]."]}},"investShip":{"bondId":"investShip","name":"投资人","identifier":17,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_investShip","activeCount":3,"thresholds":[3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD_AND_DECK","countsHand":true,"countsGoldenOnly":false,"activeType":"ALL","isActiveInDeck":false,"noStack":false,"weight":0,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":100,"mode":"reach","effect":"bond_layer_char_garrison_bonus"}],"desc":"干员的“获得时”类特质每次触发2次\n<达到100层>“获得时”类特质每次触发3次(整备区的【投资人】干员也可用于激活盟约)","descRaw":"干员的“获得时”类特质每次<@ba.vup>触发2次\n<达到<@autochess.dgreen>100层>“获得时”类特质每次<@ba.vup>触发3次(整备区的【投资人】干员也可用于激活盟约)","effectId":"bondeffect_invest","effectName":"投资人","effectDesc":"干员的“获得时”类特质每次触发2次\n<达到100层>“获得时”类特质每次触发3次\n整备区的【投资人】干员也可用于激活盟约","effectDescRaw":"干员的“获得时”类特质每次触发2次\n<达到<@ba.vup>100层>“获得时”类特质每次触发3次\n整备区的【投资人】干员也可用于激活盟约","effectDescParams":[],"bb":{"layer":0,"count":2},"bbStr":{"event":"SERVER_GAIN"},"buffs":[{"key":"bond_layer_char_garrison_bonus","bb":{"layer":0,"count":2},"bbStr":{"event":"SERVER_GAIN"}},{"key":"bond_layer_char_garrison_bonus","bb":{"layer":100,"count":3},"bbStr":{"event":"SERVER_GAIN"}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_16_a","chess_char_2_19_a","chess_char_3_04_a","chess_char_5_14_a","chess_char_5_17_a"],"visibleMembers":["chess_char_2_19_a","chess_char_3_04_a","chess_char_5_14_a","chess_char_5_17_a"],"spec":{"tiers":[{"need":"3 distinct (board + bench)","effect":"Every \"获得时\" (SERVER_GAIN) trait of every operator triggers 2 times."},{"need":"L >= 100","effect":"Triggers 3 times."}],"formulas":{"gainTraitRepeat":"2 if L < 100 else 3"},"layerGain":"山 休整期结束 +1 per operator gained this round; 机变 \"诗怀雅的盟誓\" +10, \"银灰的盟誓\" +8; generic sources.","howToPlay":"Pair with high \"获得时 +N 自身所属盟约\" operators (忍冬 +6, 锏 +8, 星熊 +8, 雪猎 +5) - their layers double/triple."}},"raidShip":{"bondId":"raidShip","name":"突袭","identifier":18,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_raidShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[{"layer":50,"mode":"reach","effect":"env_gbuff_new"}],"desc":"【突袭】干员10秒内未进行攻击或技能就绪时,若范围内没有敌人,则保留技力立即再部署至一名地面敌人周围,期间攻击力和生命值提升(受层数影响)\n<达到50层>所有干员攻击速度+50","descRaw":"【突袭】干员<@ba.vup>10秒内未进行攻击或技能就绪时,若范围内没有敌人,则保留技力立即<@ba.vup>再部署至一名地面敌人周围,期间<@ba.vup>攻击力和<@ba.vup>生命值提升<@autochess.gray>(受层数影响)\n<达到<@autochess.dgreen>50层>所有干员攻击速度<@ba.vup>+50","effectId":"bondeffect_raid","effectName":"突袭","effectDesc":"【突袭】干员10秒内未进行攻击或技能就绪时,若范围内没有敌人,则保留技力立即再部署至一名地面敌人周围,期间攻击力和生命值+{0:0%}(受层数影响)\n <达到50层>所有干员攻击速度+50","effectDescRaw":"【突袭】干员10秒内未进行攻击或技能就绪时,若范围内没有敌人,则保留技力立即再部署至一名地面敌人周围,期间攻击力和生命值<@ba.vup>+{0:0%}<@ba.acrem>(受层数影响)\n <达到<@ba.vup>50层>所有干员攻击速度<@ba.vup>+50","effectDescParams":[{"index":0,"format":"0%","base":"base_atk","perStack":"atk_per_stack"}],"bb":{"base_attack_speed":0,"attack_speed_per_stack":0,"base_atk":0.25,"atk_per_stack":0.01,"base_max_hp":0.25,"max_hp_per_stack":0.01,"power_bond_stack_cnt":50,"power_attack_speed":50,"no_attack_duration":10},"bbStr":{"key":"act1autochess_bond_eff_raid"},"buffs":[{"key":"env_gbuff_new","bb":{"base_attack_speed":0,"attack_speed_per_stack":0,"base_atk":0.25,"atk_per_stack":0.01,"base_max_hp":0.25,"max_hp_per_stack":0.01,"power_bond_stack_cnt":50,"power_attack_speed":50,"no_attack_duration":10},"bbStr":{"key":"act1autochess_bond_eff_raid"}}],"baseParams":["base_atk"],"perStackParams":["atk_per_stack"],"members":["chess_char_1_18_a","chess_char_2_09_a","chess_char_3_05_a","chess_char_3_12_a","chess_char_4_04_a","chess_char_4_16_a","chess_char_5_07_a","chess_char_6_15_a","chess_char_6_17_a"],"visibleMembers":["chess_char_1_18_a","chess_char_2_09_a","chess_char_3_05_a","chess_char_3_12_a","chess_char_4_04_a","chess_char_4_16_a","chess_char_5_07_a","chess_char_6_15_a","chess_char_6_17_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"If a 突袭 member has not attacked for 10 s, or its skill is ready, and no enemy is in its range: it is immediately redeployed (keeping SP) onto a tile next to a ground enemy; while in that redeployed state its ATK and maxHP x(1 + 0.25 + 0.01*L)."},{"need":"L >= 50","effect":"ALL operators ASPD +50."}],"formulas":{"atkHpMultiplier":"1.25 + 0.01*L","idleSec":"10","aspdAll(L>=50)":"50"},"layerGain":"史尔特尔 部署时 +8 (<=50/battle); 休谟斯 each 2 kills +1; 瑕光 +4/deploy; 斯卡蒂; 伊内丝 +5; 机变 \"斯卡蒂的盟誓\" +8, \"德克萨斯的盟誓\" +10.","assumed":["target enemy = the ground enemy closest to the player's objective (its own field's; another field's only while its own has none) that the member can reach; landing tile = the nearest free deployable tile within 2 tiles of it from which the member's attack range covers it. No such tile for any of the 8 most advanced -> no jump; the poll looks again every 0.25 s (GitHub issue #51 - up to 0.1.1 the idle trigger landed out of reach and hopped every 10 s; DESIGN §22.2)","the buff lasts until the operator leaves the field"]}},"indomShip":{"bondId":"indomShip","name":"不屈","identifier":19,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_indomShip","activeCount":2,"thresholds":[2,3],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":false,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"地面干员被击倒时,有概率立即重新部署(受层数影响)\n<在场3名不同【不屈】干员>地面干员被击倒时使场上所有干员技力+5","descRaw":"<@ba.vup>地面干员被击倒时,有概率立即<@ba.vup>重新部署<@autochess.gray>(受层数影响)\n<在场<@autochess.dgreen>3名不同【不屈】干员><@ba.vup>地面干员被击倒时使场上所有干员<@ba.vup>技力+5","effectId":"bondeffect_indom","effectName":"不屈","effectDesc":"地面干员被击倒时,有{0:0%}(受层数影响)概率立刻重新部署\n<在场3名不同【不屈】干员>地面干员被击倒时使场上所有干员技力+5","effectDescRaw":"<@ba.vup>地面干员被击倒时,有<@ba.vup>{0:0%}<@ba.acrem>(受层数影响)概率立刻重新部署\n<在场<@ba.vup>3名不同【不屈】干员><@ba.vup>地面干员被击倒时使场上所有干员技力<@ba.vup>+5","effectDescParams":[{"index":0,"format":"0%","base":"base_prob","perStack":"prob_per_stack"}],"bb":{"base_prob":0.18,"prob_per_stack":0.004,"power_bond_stack_cnt":0,"sp":5,"power_bond_char_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_indom"},"buffs":[{"key":"env_gbuff_new","bb":{"base_prob":0.18,"prob_per_stack":0.004,"power_bond_stack_cnt":0,"sp":5,"power_bond_char_cnt":3},"bbStr":{"key":"act1autochess_bond_eff_indom"}}],"baseParams":["base_prob"],"perStackParams":["prob_per_stack"],"members":["chess_char_1_05_a","chess_char_1_20_a","chess_char_2_03_a","chess_char_2_12_a","chess_char_3_16_a","chess_char_4_07_a","chess_char_5_06_a","chess_char_5_13_a","chess_char_6_06_a"],"visibleMembers":["chess_char_1_20_a","chess_char_2_12_a","chess_char_3_16_a","chess_char_4_07_a","chess_char_5_06_a","chess_char_5_13_a","chess_char_6_06_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"When a ground operator (地面干员 = melee position, on any tile) is knocked out / retreats / swaps 替身<->本体: with p = min(1, 0.18 + 0.004*L) it is redeployed at once (next deployment has 0 redeploy time and 0 cost). Also consumes a \"复活\" charge if it had one."},{"need":"3 distinct","effect":"When a ground (melee-position) operator is knocked out: every operator on the field +5 SP."}],"formulas":{"p":"min(1, 0.18 + 0.004*L)","reaches100%AtL":"205"},"layerGain":"雷蛇 休整期结束 +1; 砾 被击倒 +2; 归溟幽灵鲨 +5; 风笛 kills +2; 机变 \"风笛的盟誓\" +8."}},"maniShip":{"bondId":"maniShip","name":"调和","identifier":20,"isCore":false,"bondType":"REGULAR","bondOrder":1,"powerIdList":[],"iconId":"icon_maniShip","activeCount":1,"thresholds":[1],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"MANI","isActiveInDeck":false,"noStack":true,"weight":0,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"激活时使场上核心盟约的激活人数+1,【调和】干员享受已激活的核心盟约的效果","descRaw":"激活时使场上核心盟约的<@ba.vup>激活人数+1,【调和】干员享受已激活的核心盟约的效果","effectId":"bondeffect_mani","effectName":"调和","effectDesc":"激活时可以使场上核心盟约的激活人数+1,【调和】干员享受已激活的核心盟约的效果","effectDescRaw":"激活时可以使场上核心盟约的<@ba.vup>激活人数+1,【调和】干员<@ba.vup>享受已激活的核心盟约的效果","effectDescParams":[],"bb":{"count":1},"bbStr":{},"buffs":[{"key":"other_bond_add_trigger_cnt","bb":{"count":1},"bbStr":{}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_15_a","chess_char_6_11_a"],"visibleMembers":["chess_char_6_11_a"],"spec":{"tiers":[{"need":"1 调和 on board","effect":"Every core bond's member count +1; 调和 operators receive the effects of all active core bonds."}],"members":"缪尔赛思 (T6) and 盟约·辅助干员 (T1, hidden; given in round 1 by strategy Pith \"优等生\").","assumed":["+1 only for core bonds with >=1 real member","one +1 total no matter how many 调和 operators"]}},"emptyShip":{"bondId":"emptyShip","name":"协防干员","identifier":21,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_emptyShip","activeCount":2,"thresholds":[2],"maxCount":null,"thresholdTemplate":"count_threshold_upward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":true,"weight":0,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"所有干员受到的物理和法术伤害-20%,【协防干员】伤害提升至120%,精锐【协防】干员造成伤害提升至140%","descRaw":"所有干员受到的物理和法术伤害<@ba.vup>-20%,【协防干员】伤害提升至<@ba.vup>120%,精锐【协防】干员造成伤害提升至<@ba.vup>140%","effectId":"bondeffect_empty","effectName":"协防干员","effectDesc":"所有干员受到的物理和法术伤害-20%;【协防干员】伤害提升至120%,精锐【协防干员】造成伤害提升至140%","effectDescRaw":"所有干员受到的物理和法术伤害<@ba.vup>-20%;【协防干员】伤害提升至<@ba.vup>120%,精锐【协防干员】造成伤害提升至<@ba.vup>140%","effectDescParams":[],"bb":{"damage_resistance":0.2,"damage_scale_normal":1.2,"damage_scale_extra":1.4},"bbStr":{"key":"act1autochess_bond_eff_assis"},"buffs":[{"key":"env_gbuff_new","bb":{"damage_resistance":0.2,"damage_scale_normal":1.2,"damage_scale_extra":1.4},"bbStr":{"key":"act1autochess_bond_eff_assis"}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_15_a","chess_char_2_14_a","chess_char_3_10_a","chess_char_4_08_a","chess_char_4_25_a","chess_char_5_09_a","chess_char_5_10_a","chess_char_6_12_a"],"visibleMembers":["chess_char_2_14_a","chess_char_3_10_a","chess_char_4_25_a","chess_char_5_10_a","chess_char_6_12_a"],"spec":{"tiers":[{"need":"2 distinct","effect":"ALL operators take -20% physical and magic damage; 协防干员 members deal damage x1.2 (elite 协防 x1.4)."}],"meaning":"\"协防干员\" (assist operators) = fallback bond (constData.fallbackBondId). DIY/self-selected 6-star operators whose faction matches no core bond become 协防干员; some preset operators (调香师, 松果, 瑰盐, 魔王, 铃兰, 迷迭香, 盟约·辅助干员) are natively 协防.","formulas":{"damageTakenMul":"0.8","memberDamageMul":"1.2 (elite 1.4)"},"notes":["noStack=true: no layer-scaled effect, but layers are still counted (巴哈姆特)."]}},"soloShip":{"bondId":"soloShip","name":"独行","identifier":22,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_soloShip","activeCount":1,"thresholds":[1],"maxCount":1,"thresholdTemplate":"count_threshold_downward","countMode":"BOARD","countsHand":false,"countsGoldenOnly":false,"activeType":"BATTLE","isActiveInDeck":false,"noStack":true,"weight":10,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"<在场1名【独行】干员>【独行】干员攻击力和生命值+60%,初始技力+15(在场2名及以上【独行】干员时失效)","descRaw":"<在场1名【独行】干员>【独行】干员攻击力和生命值<@ba.vup>+60%,初始技力<@ba.vup>+15(在场2名及以上【独行】干员时失效)","effectId":"bondeffect_solo","effectName":"独行","effectDesc":"<在场1名【独行】干员>【独行】干员攻击力和生命值+60%,初始技力+15(在场2名及以上【独行】干员时失效)","effectDescRaw":"<在场<@ba.vup>1名【独行】干员>【独行】干员攻击力和生命值<@ba.vup>+60%,初始技力<@ba.vup>+15<@ba.acrem>(在场2名及以上【独行】干员时失效)","effectDescParams":[],"bb":{"atk":0.6,"max_hp":0.6,"sp":15},"bbStr":{"key":"act2autochess_bond_eff_solo"},"buffs":[{"key":"env_gbuff_new","bb":{"atk":0.6,"max_hp":0.6,"sp":15},"bbStr":{"key":"act2autochess_bond_eff_solo"}}],"baseParams":[],"perStackParams":[],"members":["chess_char_1_08_a","chess_char_2_17_a","chess_char_3_17_a","chess_char_4_09_a","chess_char_4_18_a","chess_char_5_11_a"],"visibleMembers":["chess_char_1_08_a","chess_char_2_17_a","chess_char_3_17_a","chess_char_4_09_a","chess_char_4_18_a","chess_char_5_11_a"],"spec":{"tiers":[{"need":"exactly 1 distinct 独行 on board","effect":"That operator ATK +60%, maxHP +60%, +15 SP when deployed. Disabled when 2+ different 独行 operators are on the board."}],"formulas":{"atkMul":"1.6","hpMul":"1.6","spOnDeploy":"15"},"notes":["noStack=true"]}},"suntShip":{"bondId":"suntShip","name":"绝技","identifier":23,"isCore":false,"bondType":"REGULAR","bondOrder":2,"powerIdList":[],"iconId":"icon_suntShip","activeCount":2,"thresholds":[2,5],"maxCount":null,"thresholdTemplate":"count_threshold_upward_golden","countMode":"BOARD_ALL_CHESS","countsHand":false,"countsGoldenOnly":true,"activeType":"BATTLE","isActiveInDeck":false,"noStack":true,"weight":0,"maxInactiveBondCount":-1,"layerMilestones":[],"desc":"<在场2名精锐状态的干员>精锐状态的干员攻击力+30%\n<在场5名精锐状态的干员>精锐状态的干员技力消耗-30%\n(所有干员的精锐状态均可激活本盟约)","descRaw":"<在场<@autochess.dgreen>2名精锐状态的干员>精锐状态的干员攻击力<@ba.vup>+30%\n<在场<@autochess.dgreen>5名精锐状态的干员>精锐状态的干员技力消耗<@ba.vup>-30%\n<@ba.acrem>(所有干员的精锐状态均可激活本盟约)","effectId":"bondeffect_sunt","effectName":"绝技","effectDesc":"<在场2名精锐状态的干员>精锐状态的干员攻击力+30%\n<在场5名精锐状态的干员>精锐状态的干员技力消耗-30%\n(所有干员的精锐状态均可激活本盟约)","effectDescRaw":"<在场<@ba.vup>2名精锐状态的干员>精锐状态的干员攻击力<@ba.vup>+30%\n<在场<@ba.vup>5名精锐状态的干员>精锐状态的干员技力消耗<@ba.vup>-30%\n<@ba.acrem>(所有干员的精锐状态均可激活本盟约)","effectDescParams":[],"bb":{"power_char_cnt":2,"ex_char_cnt":5,"power_atk":0.3,"sp_ratio":0.7},"bbStr":{"key":"act2autochess_bond_eff_sunt"},"buffs":[{"key":"env_gbuff_new","bb":{"power_char_cnt":2,"ex_char_cnt":5,"power_atk":0.3,"sp_ratio":0.7},"bbStr":{"key":"act2autochess_bond_eff_sunt"}}],"baseParams":[],"perStackParams":[],"members":[],"visibleMembers":[],"spec":{"tiers":[{"need":"2 elite (精锐) operators on board (any operators, duplicates count)","effect":"All elite operators ATK +30%."},{"need":"5 elite operators on board","effect":"At battle start every elite operator and its summons have skill SP cost x0.7 (rounded down, may become 0)."}],"formulas":{"atkMul":"1.3","spCostMul":"floor(sp*0.7)"},"notes":["isHiddenCharList=true, chessIdList empty: no member operators; elites are not \"members\" of 绝技 (PRTS).","noStack=true"]}}} diff --git a/docs/DESIGN.md b/docs/DESIGN.md index a9c3e1fa..88fb7fe9 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -442,7 +442,7 @@ S→C: temp: [ Piece | null ], // length 5 board: [ Piece & { row, col, dir } ], // dir ∈ UP|RIGHT|DOWN|LEFT (§3; bench pieces carry none) deployCap, deployCount, - bonds: [ { bondId, count, active, tier, layers, harmony? /* 调和's +1 is in count, §21.26 */, thresholds, countsHand } ], // sorted: active first, then layers desc + bonds: [ { bondId, count, active, tier, layers, harmony? /* 调和's +1 is in count, §21.26 */, thresholds, countsHand } ], // sorted: active first, then layers desc; an `off` entry (a bond the mode never activates, with members: count only, never active — the strip's grey 本局禁用 disc, bondsMeta.offBondCounts) comes last effects: [ { id, name, desc, iconKind: 'band'|'choice'|'team'|'item'|'garrison', iconId, counter?, counterText? /* a bounty: 还剩 N 场作战, §20.6 */ } ], nextEnemies: [ { enemyKey, count, tag, start? } ], // preview of the upcoming round's wave (after waves.js generation); `start` = a leader's spawn tile [row, col] on the boss field (the boss-field prep shows it standing there, community report #12) stats: { dmgDealt, kills, leaks, gold, refreshes, merges } } @@ -1111,7 +1111,7 @@ In SETTLE it is the field the last battle left on screen. In prep without watchi - `ps.bonds` / `ps.layers` are untouched. SETTLE clears the pending gains as it adds them (once), and the next round start clears them too. Since 0.1.3 the 联防 field fights with the same counts: the helpers' battle input takes its bonds from `bondsView()` (`battleInput({ reached: true })`, PRTS §联防阶段 "将以其阵地当前的状态" [ASSUMED] — it used to carry the round-start layers while the strip showed the reached ones); no other rule reads them. **Data:** -- `m.public players[].bonds = ps.alive ? bondList(gd, ps.bondsView()) : []`: every bond with members, layers or an active tier. It is the same list and order as the player's own `m.private bonds`, minus `thresholds` / `countsHand` (the client reads those from bonds.json). +- `m.public players[].bonds = ps.alive ? bondList(gd, ps.bondsView(), { off: offBondCounts(gd, ps) }) : []`: every bond with members, layers or an active tier (since 0.1.3 also the mode-off bonds with members, `off: true`, last). It is the same list and order as the player's own `m.private bonds`, minus `thresholds` / `countsHand` (the client reads those from bonds.json). - An eliminated player's list is `[]`, for these reasons: - nobody can watch them: `g.watch` refuses them and they have no field; - the result screen reads `m.result`'s own bonds; @@ -1539,7 +1539,7 @@ Public GitHub issues filed after the 0.1.1 release (2026-10-03), each triaged ag - **Now**: build-data sets `placement: 'all'` on a chess whose branch trait without module (`branchTraitText`: the trait candidate's text, else the description) contains 可以放置于远程位 — exactly 崖心, 见行者 and 歌蕾蒂娅, normal and elite (6 records, the only data change; `validateAll` allows it on a MELEE record only; module-only text never counts). `positionClass` returns 'all' for them, so the server takes them on every deployable tile — `g.move`, swaps, a merge's elite (`mergeTile`), the terrain re-check (`_evictIllegal`), invariants and audit —, and the client's `piecePosition` 'ALL' lights the 高台 while dragging; every other melee unit keeps the refusal and its text. The battle keeps position MELEE: on a ground tile they block as before; on a 高台 (`unit.ground` false) they block nothing and attack from there — the sim needed no change (act2 m01, one 萨卡兹枯朽前锋 on the lower lane, 40 s: 歌蕾蒂娅 on (10,4) facing it 2 hits, no block, on (9,5) 12 hits, blocking; 崖心 and 见行者 alike; no errors). - **Bots** read the record's own position (`basePositionClass`): they still count these units as blockers (`isBlocker`; with the widened class they would not, and on act2 m01 the planner put 歌蕾蒂娅 and 崖心 on the 高台 as non-blockers, leaving 见行者 the only blocker on the road) and plan them on the ground tiles, as in 0.1.1 [ASSUMED]: offered the 高台, the planner still chose road tiles in the cases measured, but the lineup's blocker count assumes they block and a greedy 高台 pick could take a ranged dealer's tile — not benchmarked. `tools/balance.mjs` uses the same blocker test. Tokens are unchanged; the sim's automatic placements (the 突袭 landing tile, summon / device tiles) still treat them as melee, ground tiles only [ASSUMED]. - **Players notice**: 歌蕾蒂娅 can be dragged onto a 高台 (PLAYING §4); there she attacks but blocks nothing. 崖心 and 见行者 get the same rule but are hidden chess this season (`isHidden`, never in the pool, the shop or a 突变细胞 roll), so only 歌蕾蒂娅 is reachable in play; 见行者's elite PUS-X refund (half the DP of a redeploy onto a ranged tile, kits/tier3.js `!unit.ground`) is therefore moot. -- On a 高台 she is not a 地面干员 for the effects that read the tile (`unit.ground`: the 战栗维式重锤 proc, 休谟斯 回收利用, 不屈, the 只攻击地面单位 enemy, 污染秽蚀's 高地 rate), like a ranged operator up there; position-based effects keep her 近战 (精准 tier 2, 诗怀雅's talent) [ASSUMED: the official texts may mean the position class by 地面干员]. +- On a 高台 the effects that read the tile (`unit.ground`: the 只攻击地面单位 enemy, 污染秽蚀's 高地 rate) treat her like a ranged operator up there; position-based effects keep her 近战 (精准 tier 2, 诗怀雅's talent) — since 0.1.3 the effects worded 地面干员 too (不屈, the 战栗维式重锤 proc, 休谟斯 回收利用: 地面干员 = the melee position on any tile, see the §23 「地面干员」 subsection; the tile reading 0.1.2 [ASSUMED] here was wrong). - Normative lines rewritten with it: §3 (placement), §6.6 (the bot); research 03 C2; DATA §2 (`placement`). - Tests: `test/match/feedback1-placement.test.js` (#32-4: the data rule, cross-checked against character_table when the cache exists; `g.move` onto (10,4) / (11,4) / (12,4) of 战场#01(下半) for the six records; a 重装 refused with its text; ranged unchanged; client highlights = the server's tiles; swaps; the merge's elite on the 高台; the battle input and the sim on / off the 高台; bots), `test/match/board.test.js` (`positionClass` / `basePositionClass`), `test/ui/gameLogic.test.js` (the client mirror). @@ -1569,7 +1569,7 @@ Public GitHub issues filed after the 0.1.1 release (2026-10-03), each triaged ag - **Seen** (GitHub #32, item 7): 「易拉三技能浮游单元无法造成伤害,只能造成三技能自带dot伤害」 — 荒芜拉普兰德's S3 终幕·浩劫 dealt only its once-per-second area damage. - **Official**: PRTS 荒芜拉普兰德 S3 备注, 技能流程: ① for 1.3 s after the cast or after a drone is added ("开启技能/补充浮游单元1.3s内") the drones spread evenly outward from her, one along her facing (初速度 0.1, 加速度 1.9, 最大速度 2.0); ② each then locks the target "距离自身最近>距离本体最近" anywhere on the field and flies at it (初速度 2.0, 加速度 1.0, 最大速度 4.0, 转向速度 1/6 per frame; a target that leaves or turns unselectable on the way → a new pick, the speed back to 2.0); ③ at the target it "锁定目标持续进行攻击,此状态下的攻击行为同正常浮游单元"; when that target leaves or turns unselectable it reappears at a random point of the 1.5-side square around it and picks again; with nothing selectable it circles (radius 0.9, 1.0 线速度, counter-clockwise, the circle on its left). Also: "该技能释放的浮游单元造成的伤害不属于普通攻击/技能直接伤害"; the area damage / slow has radius 0.9, does not stack and carries 头狼's 沉默. PRTS 分支特性信息 驭械术师: a drone starts at 20 % of the operator's ATK, +15 per hit on the target it hit last, up to 110 %, back to the start on a different target; drones released by a skill "不受缴械类效果制约" — the same note says they "造成技能直接伤害", which S3's own 备注 overrides for this skill. skill_table skchr_whitw2_3 at the chess levels (Lv4 / Lv7): atk +0.45 / +0.6, attack@cnt 2, attack@times 1.3 (PRTS ①'s 1.3 s), attack@move_speed −0.3 / −0.4, attack@magic_atk_scale 1, attack@fear 2, attack@range_radius 0.9, attack@projectile_turn_speed 5 (× 1/30 s = PRTS's 1/6 per frame); trait init 0.2 / 0.35 (elite: module 狼时), delta 0.15, max 1.1; 头狼 every 20 s: cap × 1.1 (PRTS 备注: 121 %), 2 s 沉默, 数量+1. - **Cause**: the S3 spec switched her attack off for the whole skill (`attack: { noAttack: true }`) and its tick only moved the drones (at attack@projectile_move_speed, 1 tile/s), feared a target the drone came within 0.9 of and dealt the area hit; no drone ever attacked. The kit's header said so ("she stops attacking while they roam"). The drones also preferred enemies no other drone held — an [ASSUMED] rule PRTS does not have. -- **Now**: her own attack stays off — every drone is out (浮游单元 +attack@cnt with her own one; +1 from 头狼 stage 3, and a drone added when stage 3 comes during the skill spreads along her facing). The drones fly ① ② ③ with PRTS's numbers (spread for attack@times s; the distance covered at the mean of the old and new speed, exact under constant acceleration; the reappearance point is drawn in her facing frame, so a battle turned with her direction plays the same). A drone that reaches its target fears it (attack@fear s) and stays on it; it attacks every attack interval of hers (her live ASPD) for ATK × its own funnel ramp (trait init, +delta per hit on the same target, the cap — raised by 头狼 stage 1 —, back to init on a new target), arts. That damage is neither a normal attack nor skill damage: no `attack` hook, `isAttack` / `isSkill` false, tag `droneAttack` — the 叙拉古 6 assassin chance ("对敌人攻击时") and the on-attack items skip it, 头狼's 沉默 ("造成伤害时") applies; 缴械 does not stop it. The once-per-second area hit and the slow are unchanged (around every drone, one hit per enemy; tags `skill` + `drone`). A wolf knocked out or withdrawn in the middle of a tick (a kill hook, say) deals nothing more in that tick. fx: `droneLock` (the wolf-eye mark) when a drone picks its target, `drone` at a drone for each of its attacks and once per second for drones still roaming; the client draws them already. +- **Now**: her own attack stays off — every drone is out (浮游单元 +attack@cnt with her own one; +1 from 头狼 stage 3, and a drone added when stage 3 comes during the skill spreads along her facing). The drones fly ① ② ③ with PRTS's numbers (spread for attack@times s; the distance covered at the mean of the old and new speed, exact under constant acceleration; the reappearance point is drawn in her facing frame, so a battle turned with her direction plays the same). A drone that reaches its target fears it (attack@fear s) and stays on it; it attacks every attack interval of hers (her live ASPD) for ATK × its own funnel ramp (trait init, +delta per hit on the same target, the cap — raised by 头狼 stage 1 —, back to init on a new target), arts. That damage is neither a normal attack nor skill damage: no `attack` hook, `isAttack` / `isSkill` false, tag `droneAttack` — the on-attack items skip it (the 叙拉古 6 chance rolls on it since 0.1.3: 普通伤害, see the §23 「叙拉古」 subsection), 头狼's 沉默 ("造成伤害时") applies; 缴械 does not stop it. The once-per-second area hit and the slow are unchanged (around every drone, one hit per enemy; tags `skill` + `drone`, + `dot` since 0.1.3: PRTS 备注 "持续法术伤害"). A wolf knocked out or withdrawn in the middle of a tick (a kill hook, say) deals nothing more in that tick. fx: `droneLock` (the wolf-eye mark) when a drone picks its target, `drone` at a drone for each of its attacks and once per second for drones still roaming; the client draws them already. - **Distance to a huge enemy** [ASSUMED] — the owner's decision of 2026-10-04: a drone measures every enemy's distance to its position (a huge enemy's centre, its 判定中心), so leader rounds stay close to 0.1.1. Considered and set aside: the sim's general convention for operator-side distance picks, the hit rectangle (body.js `bodyDist`: `targeting.js:135` `sortEnemyTargets` 'nearest' / 'farthest', `kits/tier3.js:86` `enemiesAround`, `kits/tier6.js:1108` 异客's storm chain, `kits/tier6.js:2525` / `:2549` 溯光星源's bounces and links, `kits/tier4.js:526` / `:995`; only the profession chain bounce, `ai.js:257`, takes the nearest by position) — with it a huge leader (胄, 管) was the nearest enemy of every drone around it and drew them all for the whole skill (胄 h07_01: her damage on the leader 106 309, on the other enemies 3 036, 2 deaths). A drone on a huge enemy sits at its centre; it reaches it on touching the hit rectangle. - **Players notice**: once a drone reaches a target that stays alive, its hits outweigh the area damage (3 parked 重装防御者, RES 0, the full 40 s: drone hits 38 411 of 54 640); against streams of weak enemies the area hit still does most of it (the flat stage's two lanes, 10 + 10 walkers, 40 s: drones 11 049, area 50 188 of 61 236). All drones may lock the same enemy — each takes the one nearest to itself — so against a cluster the area hit covers fewer enemies than before. Measured, old → new: parked, first 12 s normal 12 901 → 12 089 (drone hits 7 512 + area 4 578), elite 17 658 → 18 085; the whole 40 s 47 857 → 54 640 and 65 504 → 77 369; the lanes 15 481 → 61 236 (kills 1 → 14), elite 49 213 → 72 224 (9 → 18). **Leader rounds** (one elite 荒芜拉普兰德 per side, S3 at once, kept alive, 60 s; her damage on the leader / on the other enemies / enemy deaths, 0.1.1 → now): 假想敌:胄 (act1 h07_01) 32 467 / 80 186 / 9 → 84 880 / 44 391 / 6; 假想敌:管 (h07_03) 19 936 / 62 176 / 5 → 37 520 / 69 927 / 5; 假想敌:铳 (h07_02) 31 260 / 49 982 / 4 → 62 794 / 30 221 / 0; 卢西恩 (act2 h07_05) 37 957 / 58 512 / 6 → 75 094 / 40 881 / 2 (both of normal size: a drone that picks the leader because it is nearest keeps the lock, and a leader never falls); the heavy two-player 胄 scene of robustness.test.js (the review bench: 4 wolves per side, 120 extra enemies at ×20 HP, 60 s): the wolves' damage 1 315 038 → 1 291 567, on the leader 50 170 → 42 907, enemies killed 12 → 13. With the hit-rectangle distance it would have been 胄 106 309 / 3 036 / 2, 管 57 202 / 36 427 / 2 and the heavy scene 406 075 / 125 271 / 2. - [ASSUMED]: the centre distance above (the owner's decision); reading ① "补充浮游单元" as: after an addition only the added drone spreads, along her facing, while the others carry on; the turn rate (转向速度) is not modelled — a chasing drone heads straight at its target; a drone's attack clock runs all the time and its first hit lands on arrival when the clock is ready; the drones keep flying and attacking while she is stunned, frozen or silenced (PRTS only names 缴械); a drone reaches a huge enemy when it touches the hit rectangle and then sits at its position; the fear's source is her (they flee from her, as before); the area hit keeps `isSkill` (a skill DoT; PRTS's line speaks of 直接伤害). diff --git a/docs/META.md b/docs/META.md index cc0e8024..07fdbd46 100644 --- a/docs/META.md +++ b/docs/META.md @@ -431,7 +431,7 @@ otherwise locked (research 04 §2 / addendum: they leave the operator only on pr refuses them (`BAD_TARGET 'equipped items are locked'`). A second copy of an equipped normal item merges into the golden item in the hand. Every path that hands an item to the player (buy, reward, 机变, grants, equip, the equipment a sale, a promotion or `ctx.destroyPiece` returns) ends with the auto-merge (`acquireItem` / `checkItemMerges`: "已拥有2件同一初始 -装备时…自动合并"), so a player never holds two identical mergeable normal items (`test/match/feedback1b-items.test.js`). +装备时…自动合并"), so a player never holds two identical mergeable normal items (`test/match/feedback1b-items.test.js`), except an item gained while 休整期结束 is dispatching (`onPrepEnd`, including a grant nested under it): it is stowed (hand, else temp) and merges at the next prep's start, and nothing already equipped is taken off for the fight. Hand and temp both full still destroys it with 「整备区已满,获得的装备已销毁」. [ASSUMED] every such grant, not only 维多利亚's hammer (owner's decision 2026-10-04). A buy, an onPrepStart grant and a grant at any other time still merge at once (`test/match/feedback3-prep-end-item.test.js`). Built-ins (builtinMeta.js, overridable): 盟约之币 / 骑士储蓄罐 (random funds), 随身身份牌 (layers of the target's bonds), 紧急调度券 (take shop chess), 精打细算玩偶 (+funds each round), 简易通讯机 / 拟态物质 (same-bond chess), 见钱眼开玩偶 @@ -683,7 +683,9 @@ drawn set; `disabledBonds` = drawn ∪ the mode's static list), `hiddenBossId`, `combatMode` (`'client'` | `'server'`), `fields[].progress { killed, total, done }` (teammates' progress UI), `paused` (solo pause, §1.3a), `players[].autoplay`, `players[].uniteLeft` (UNITE, leakers only: their enemies still standing, uncapped — §4), -`players[].bonds` = `ps.alive ? bondList(gd, ps.bondsView()) : []` — every bond with members, layers or an active tier, the same list +`players[].bonds` = `ps.alive ? bondList(gd, ps.bondsView(), { off: offBondCounts(gd, ps) }) : []` — every bond with members, layers or an active tier +(and, last, every bond the mode never activates that the player has members of: `{ bondId, count, active: false, tier: 0, layers, off: true }`, +the strip's grey 本局禁用 disc — bondsMeta.offBondCounts, never in the battle input), the same list and order as the player's own `m.private bonds` minus `thresholds` / `countsHand` (the client reads those from bonds.json; an entry whose count holds 调和's +1 carries `harmony: 1` in both lists — the bond popup's 调和 row, DESIGN §21.26): a teammate watching the player shows it in the bond strip (DESIGN §20.15); `[]` once the player is diff --git a/docs/PLAYING.md b/docs/PLAYING.md index 7c0ad16c..5d411db5 100644 --- a/docs/PLAYING.md +++ b/docs/PLAYING.md @@ -96,12 +96,13 @@ - **核心盟约**(8 个势力:炎、萨尔贡、维多利亚、谢拉格、拉特兰、阿戈尔、叙拉古、卡西米尔):3 名激活,6 名获得强力的额外效果。 - **附加盟约**(精准、迅捷、灵巧、奥术、坚守、助力、远见、奇迹、投资人、突袭、不屈、调和、协防干员、独行、绝技):多为 2 / 3 名激活;「独行」需要场上**恰好 1 名**,「绝技」按场上的精锐数量计算,没有势力盟约的干员算「协防干员」。 +- **本局禁用**:「标准模拟」与官方相同,关闭拉特兰、阿戈尔、卡西米尔、灵巧、奥术、奇迹、投资人、突袭、独行、绝技这 10 个盟约,它们不会激活。你有这些盟约的成员时(奇迹、投资人也算整备区里的成员),盟约栏末尾显示**灰色带 ✕ 的盟约图标和「本局禁用」**,干员卡、盟约标签和盟约详情也这样标注。「远见」「奇迹」「投资人」计入整备区,盟约详情的「成员」人数也一样计入整备区里的成员(临时整备区不算)。 - **调和**:激活时,场上已有成员的核心盟约人数各 +1(只加 1 人,不论有几名调和干员)。盟约详情会写「含调和 +1」,成员列表上方列出带来这 1 人的调和干员(如缪尔赛思)。 - **炎佑**:场上 6 名以上「炎」干员时召唤炎佑(9 名时两只)。它追踪全场仇恨最高的敌人并悬停在其上方,技能「祛恶之焰」锁定 1 个目标**持续喷火**(最长 20 秒,每秒对目标周围的敌人造成法术伤害并附带灼燃,喷火时不普攻,目标死亡或被沉默时结束);场上暂时没有敌人时停在原地等待。它持有官方的「孤立」:医疗干员不会治疗它,友方的增益、光环和天赋也不会选中它(敌人照常可以攻击它)。 - **层数**:盟约通过各种效果叠加层数,层数越高效果越强(例如「炎」攻击力随层数提升、「远见」每 10 层给资金)。**层数整局保留,但只有盟约激活时才生效**,多数情况下也只有激活的盟约能叠层。每个盟约最多 **999 层**(与官方相同,取自官方客户端的常量):到 999 后再获得的层数直接作废,按层数发放的奖励(如「远见」的资金)也随之停止。作战中获得的层数在盟约栏里**实时**显示,作战结束后一直保留到结算(联防期间也不会退回去)。 - **加成怎么叠**:盟约、策略、装备、机变卡和特质给的「攻击力 / 防御力 / 生命值 +X%」与技能的「攻击力 +X%」**相加**后再乘到属性上(官方:直接乘算),例如精准 +130%、独行 +60%、一件 +40% 的装备合计 +230%,而不是 ×2.3×1.6×1.4。「伤害提升至 X%」「受到的伤害 +X%」(维多利亚、谢拉格、奥术、脆弱等)这类伤害倍率之间仍然相乘;但同名效果只算一个——同一战场两名玩家都开了「奥术」时,敌人身上只挂一层奥术易伤,取两人中较高的那一个(不再相乘);两名「灵知」的坚冰、两名「莱恩哈特」/「缄默德克萨斯」的法抗削减也一样只算最强的一个。「坚守」的反伤计入被打的那名成员(个人对领袖伤害统计里能看到)。 - 每局会随机**禁用**若干盟约(标准模拟较少),它们的干员不会出现在商店;开局的「确认本局信息」会列出,选择策略时(「查看禁用盟约与干员」)和对局中(左上角 🔍)也能再查看。 -- 两件同名装备会合成一件更强的装备;特定的装备组合可以为干员赋予额外的盟约效果:「变形同构体」与另一件盟约装备(如维式重锤)一同携带时,携带者视为该装备对应盟约的成员。对应关系见变形同构体详情卡的「天赋」一栏(本局禁用的盟约会标出;装在干员身上时,正在生效的那一组会高亮)。 +- 两件同名装备会合成一件更强的装备。休整期结束时才到手的那一件(维多利亚每 25 层发的维式重锤是这种情况)先留在整备区,已经戴在干员身上的不会为了这场战斗被卸下,合成出的进阶装备在**下一休整期开始**时出现;其他时候拿到的同名装备仍立刻合成。整备区和临时整备区都满时,这件新装备照旧销毁(「整备区已满,获得的装备已销毁」),不会换进装备栏。特定的装备组合可以为干员赋予额外的盟约效果:「变形同构体」与另一件盟约装备(如维式重锤)一同携带时,携带者视为该装备对应盟约的成员。对应关系见变形同构体详情卡的「天赋」一栏(本局禁用的盟约会标出;装在干员身上时,正在生效的那一组会高亮)。 ## 7. 最终攻势与隐秘核心 diff --git a/docs/research/02-bonds.json b/docs/research/02-bonds.json index 2ce3c8f3..0f1ff5e9 100644 --- a/docs/research/02-bonds.json +++ b/docs/research/02-bonds.json @@ -3152,7 +3152,7 @@ }, { "need": "6 distinct", - "effect": "After deployment also 隐匿 (camouflage) for the same duration. While camouflaged and for 10 s after it ends, each normal damage instance it deals may add (5000 + 50*L) true damage (source = the operator) and 恐惧 (fear) 3 s. Nominal 3% chance, implemented as pseudo-random: all 叙拉古 members share one counter; attempt n since last proc succeeds with p = 0.00139*n (guaranteed at n = 720); counter resets on proc." + "effect": "After deployment also 隐匿 (camouflage) for the same duration. While camouflaged and for 10 s after it ends, each normal damage instance (普通伤害 = attack type NORMAL: attacks, skill hits, drone attacks; not 溅射 / 持续 / 附加 — `bonds/core.js siracusaRolls`) it deals may add (5000 + 50*L) true damage (source = the operator) and 恐惧 (fear) 3 s. Nominal 3% chance, implemented as pseudo-random: all 叙拉古 members share one counter; attempt n since last proc succeeds with p = 0.00139*n (guaranteed at n = 720); counter resets on proc." } ], "formulas": { @@ -8796,11 +8796,11 @@ "tiers": [ { "need": "2 distinct", - "effect": "When a ground operator is knocked out / retreats / swaps 替身<->本体: with p = min(1, 0.18 + 0.004*L) it is redeployed at once (next deployment has 0 redeploy time and 0 cost). Also consumes a \"复活\" charge if it had one." + "effect": "When a ground operator (地面干员 = melee position, on any tile) is knocked out / retreats / swaps 替身<->本体: with p = min(1, 0.18 + 0.004*L) it is redeployed at once (next deployment has 0 redeploy time and 0 cost). Also consumes a \"复活\" charge if it had one." }, { "need": "3 distinct", - "effect": "When a ground operator is knocked out: every operator on the field +5 SP." + "effect": "When a ground (melee-position) operator is knocked out: every operator on the field +5 SP." } ], "formulas": { diff --git a/docs/research/02-bonds.md b/docs/research/02-bonds.md index 3c8f1163..f0307c0d 100644 --- a/docs/research/02-bonds.md +++ b/docs/research/02-bonds.md @@ -425,7 +425,7 @@ Members (9 chess, 9 in current shop pool; by tier in shop: {'1': 1, '2': 1, '3': **Implementable spec** - **[3 distinct]** After every deployment (incl. redeploy) a 叙拉古 member gains ASPD +(25 + 0.8*L) for (32 + 0.4*L) s. -- **[6 distinct]** After deployment also 隐匿 (camouflage) for the same duration. While camouflaged and for 10 s after it ends, each normal damage instance it deals may add (5000 + 50*L) true damage (source = the operator) and 恐惧 (fear) 3 s. Nominal 3% chance, implemented as pseudo-random: all 叙拉古 members share one counter; attempt n since last proc succeeds with p = 0.00139*n (guaranteed at n = 720); counter resets on proc. +- **[6 distinct]** After deployment also 隐匿 (camouflage) for the same duration. While camouflaged and for 10 s after it ends, each normal damage instance (普通伤害 = attack type NORMAL: attacks, skill hits, drone attacks; not 溅射 / 持续 / 附加 — `bonds/core.js siracusaRolls`) it deals may add (5000 + 50*L) true damage (source = the operator) and 恐惧 (fear) 3 s. Nominal 3% chance, implemented as pseudo-random: all 叙拉古 members share one counter; attempt n since last proc succeeds with p = 0.00139*n (guaranteed at n = 720); counter resets on proc. - Formulas: `aspd = 25 + 0.8*L`; `durationSec = 32 + 0.4*L`; `procDamage = 5000 + 50*L`; `prdStep = 0.00139` - Caps: none - How layers are gained: Shop refresh-driven: 拉普兰德 first manual refresh each round +4 (works from bench); 安洁莉娜 休整期结束 +4 per refresh this round (<=12/round); 阿罗玛 +2 叙拉古/奥术 per refresh (<=6); 伺夜 first 3 kills +2 叙拉古 +1 奇迹; 荒芜拉普兰德 each kill +2 (elite: every 叙拉古 gets this, <=100/battle); 忍冬 获得时 +6 own bonds (x2/x3 with 投资人); 机变 "德克萨斯的盟誓" +10. Strategy 贾维: every 6 manual refreshes get a free 叙拉古 (<=2/round). @@ -963,8 +963,8 @@ Members (9 chess, 9 in current shop pool; by tier in shop: {'1': 1, '2': 1, '3': **Implementable spec** -- **[2 distinct]** When a ground operator is knocked out / retreats / swaps 替身<->本体: with p = min(1, 0.18 + 0.004*L) it is redeployed at once (next deployment has 0 redeploy time and 0 cost). Also consumes a "复活" charge if it had one. -- **[3 distinct]** When a ground operator is knocked out: every operator on the field +5 SP. +- **[2 distinct]** When a ground operator (地面干员 = melee position, on any tile) is knocked out / retreats / swaps 替身<->本体: with p = min(1, 0.18 + 0.004*L) it is redeployed at once (next deployment has 0 redeploy time and 0 cost). Also consumes a "复活" charge if it had one. +- **[3 distinct]** When a ground (melee-position) operator is knocked out: every operator on the field +5 SP. - Formulas: `p = min(1, 0.18 + 0.004*L)`; `reaches100%AtL = 205` - How layers are gained: 雷蛇 休整期结束 +1; 砾 被击倒 +2; 归溟幽灵鲨 +5; 风笛 kills +2; 机变 "风笛的盟誓" +8. - Bond item (with 变形同构体 grants this bond): 不屈弹射器 `chess_item_2_01_e` (1 gold: 再部署时间-30%,生命值-30%) diff --git a/public/css/screens/game.css b/public/css/screens/game.css index 869f65ff..cb101c1a 100644 --- a/public/css/screens/game.css +++ b/public/css/screens/game.css @@ -256,6 +256,13 @@ .bslot__count.is-max { border-color: var(--mint-700); color: var(--mint-400); } .bslot.is-active .bslot__count { border-color: var(--mint-700); } .bslot.is-open .bond__core { box-shadow: 0 0 0 2px var(--mint-400), 0 0 .2rem rgba(23, 249, 183, .6); } +/* a bond the mode never activates, with members (the server's `off` entry): the briefing's grey ✕ disc, the chips' + struck name, 本局禁用 under it instead of the count */ +.bslot.is-off .bond__name { color: var(--text-dim); text-decoration: line-through; text-decoration-color: rgba(255, 84, 84, .6); } +.bslot.is-off .bslot__off { + position: static; margin-top: .02rem; font-size: .11rem; font-weight: 500; color: var(--text-dim); white-space: nowrap; + background: rgba(8, 11, 10, .85); border: 1px dashed rgba(255, 255, 255, .25); +} /* ---- team panel ------------------------------------------------------------------------------------------- */ .team { position: absolute; left: .22rem; top: 2.36rem; display: flex; flex-direction: column; gap: .14rem; pointer-events: none; } diff --git a/public/js/ui/bondStrip.js b/public/js/ui/bondStrip.js index 2f9c7fb6..2d331d72 100644 --- a/public/js/ui/bondStrip.js +++ b/public/js/ui/bondStrip.js @@ -9,14 +9,19 @@ // the +1 used to read as a miscount (GitHub issue #1, DESIGN §21.26). Opened from the detail panel's bond chips it docks // beside that panel (`beside`: the panel's side). // Research 06 §11.1: round mint discs, stack count over the disc, name below, sorted by stacks; grey = -// present but inactive; in 联防 / boss rounds the strip is dimmed ("层数叠加已禁用"). +// present but inactive; in 联防 / boss rounds the strip is dimmed ("层数叠加已禁用"). A bond the mode never activates +// that the player has members of (the server's `off` entry — server/match/bondsMeta.js offBondCounts: 标准's 投资人 奇迹 +// 突袭 独行 …) comes last as a grey disc with ✕ and 本局禁用 under it instead of its count (community reports +// 「投资人等在休整区就能生效的盟约不生效」 / 「…不会触发斯卡蒂与异德的突袭」: the bond just vanished, 0.1.3). The popup's 成员 +// header counts the hand members too for a bond that counts the hand (投资人 远见 奇迹: gameLogic memberHeadCount), as 在场 +// already did. // Watching a teammate (DESIGN §20.15, ui/watchBonds.js) the strip and the popup show THAT player's bonds and layers: // the strip carries an amber "👁 name" tag (`owner`, the observing pill's spelling, research 09 §3.1) and amber rings, // the popup a "👁 name 的盟约" line; its member list reads the teammate's operators on the field (no hand: never sent). import { html, BondDisc, Icon, MicroLabel, Tooltip } from './components.js'; import { RichText, UnitThumb, BondGlyph, GIcon } from './gameComponents.js'; -import { sortBonds, bondMembers, nextThreshold, bondTier, harmonyMembers, HARMONY_BOND } from './gameLogic.js'; +import { sortBonds, bondMembers, nextThreshold, bondTier, harmonyMembers, HARMONY_BOND, memberHeadCount, briefingBondTip } from './gameLogic.js'; import { formatBondEffect } from './richText.js'; import { bondIconUrl } from './assetUrls.js'; import { data } from '../data.js'; @@ -48,6 +53,17 @@ export function BondStrip({ bonds, layersDisabled = false, onOpen, openId = null ${shown.map((b) => { const rec = data.lookup('bonds', b.bondId); const th = Array.isArray(b.thresholds) && b.thresholds.length ? b.thresholds : rec?.thresholds || []; + if (b.off) { + // a bond the mode never activates, with members: the briefing's grey ✕ disc, no stack count, 本局禁用 under it + const name = rec?.name || b.bondId; + return html`
+ <${BondDisc} name=${name} icon=${bondIconUrl(m, b.bondId)} tier=${0} maxTier=${Math.max(1, th.length)} active=${false} + disabled=${true} size="sm" showName=${true} layersDisabled=${layersDisabled} onClick=${() => onOpen(b.bondId)} + title=${`${briefingBondTip(name, 'off')} · ${b.count ?? 0} 名成员`} /> + 本局禁用 +
`; + } const next = nextThreshold(b.count ?? 0, th); return html`
0 ? b.harmony : null} class=${cx('bslot', b.active && 'is-active', openId === b.bondId && 'is-open')}> @@ -123,7 +139,7 @@ export function BondPopup({ bondId, entry, priv, banned = [], onClose, onMember, <${RichText} as="p" text=${b.descRaw || b.desc} class="bpop__desc" />
-

成员 ${members.filter((x) => x.onBoard).length}/${members.length}

+

成员 ${memberHeadCount(members, countsHand)}/${members.length}

${harmony ? (harmonyBy.length ? html`` diff --git a/public/js/ui/gameLogic.js b/public/js/ui/gameLogic.js index b5a25cb7..d192fab1 100644 --- a/public/js/ui/gameLogic.js +++ b/public/js/ui/gameLogic.js @@ -367,8 +367,10 @@ export function activeBubbles(emotes, now, ttl = 3000) { // ---- bonds ------------------------------------------------------------------------------------------- /** - * Sort bonds for the strip: active first, then layers desc, count desc, tier desc, core first, id. - * @template {{bondId:string, active?:boolean, layers?:number, count?:number, tier?:number}} B + * Sort bonds for the strip: active first, then layers desc, count desc, tier desc, core first, id; the mode-off bonds + * (`off`: the server's entries for the bonds this mode never activates that the player has members of — + * server/match/bondsMeta.js offBondCounts) after all the others. + * @template {{bondId:string, active?:boolean, layers?:number, count?:number, tier?:number, off?:boolean}} B * @param {B[]} bonds * @param {(id:string)=>any} [getBond] * @returns {B[]} @@ -377,7 +379,8 @@ export function sortBonds(bonds, getBond = () => null) { const list = (Array.isArray(bonds) ? bonds : []).filter((b) => isObj(b) && typeof b.bondId === 'string'); const n = (v) => (Number.isFinite(v) ? v : 0); return [...list].sort((a, b) => ( - (b.active ? 1 : 0) - (a.active ? 1 : 0) + (a.off ? 1 : 0) - (b.off ? 1 : 0) + || (b.active ? 1 : 0) - (a.active ? 1 : 0) || n(b.layers) - n(a.layers) || n(b.count) - n(a.count) || n(b.tier) - n(a.tier) @@ -509,10 +512,11 @@ export function harmonyMembers(priv, getChess = () => null) { } /** - * Member rows of a bond popup: every visible member with owned / on-board / banned state, plus the player's operators - * that are members through 变形同构体 (grantedBonds; `granted: true` and `items`: the item ids of the copy that wears the - * pair — the card the row opens shows them; one row per operator — normal and elite copies are one member, like the - * count's distinct members), so "成员 x/y" agrees with the count the server reports (在场). + * Member rows of a bond popup: every visible member with owned / on-board / in-hand / banned state, plus the player's + * operators that are members through 变形同构体 (grantedBonds; `granted: true` and `items`: the item ids of the copy that + * wears the pair — the card the row opens shows them; one row per operator — normal and elite copies are one member, + * like the count's distinct members), so "成员 x/y" agrees with the count the server reports (在场; memberHeadCount). + * `inHand`: in the 整备区 (hand), not the 5 temporary slots — what BOARD_AND_DECK bonds (投资人 远见 奇迹) count. * @param {any} bond bonds.json record * @param {any} priv m.private (hand/board/temp) — or a teammate's field operators (ui/watchBonds.js ownerBoard) * @param {Set|string[]} [banned] banned base chess ids @@ -525,8 +529,9 @@ export function bondMembers(bond, priv, banned = [], getChess = () => null, getI const baseOf = (id) => getChess(id)?.baseId || (typeof id === 'string' ? id.replace(/_b$/, '_a') : id); const onBoard = new Set(); const owned = new Set(); + const inHand = new Set(); const memberSet = new Set(members); - /** base id → { on: on the board?, items: the wearer's item ids } — operators of the player that join this bond through 变形同构体 */ + /** base id → { on: on the board?, hand: in the hand?, items: the wearer's item ids } — operators of the player that join this bond through 变形同构体 */ const granted = new Map(); const grants = (p) => typeof bond?.bondId === 'string' && grantedBonds(p.items, getItem).includes(bond.bondId); const itemIds = (p) => p.items.map((it) => (typeof it === 'string' ? it : it?.id)).filter((x) => typeof x === 'string'); @@ -534,25 +539,45 @@ export function bondMembers(bond, priv, banned = [], getChess = () => null, getI if (p?.kind !== 'chess') continue; const base = baseOf(p.id); onBoard.add(base); owned.add(base); - if (!memberSet.has(base) && !granted.has(base) && grants(p)) granted.set(base, { on: true, items: itemIds(p) }); + if (!memberSet.has(base) && !granted.has(base) && grants(p)) granted.set(base, { on: true, hand: false, items: itemIds(p) }); } - for (const p of [...(Array.isArray(priv?.hand) ? priv.hand : []), ...(Array.isArray(priv?.temp) ? priv.temp : [])]) { - if (p?.kind !== 'chess') continue; - const base = baseOf(p.id); - owned.add(base); - if (!memberSet.has(base) && !granted.has(base) && grants(p)) granted.set(base, { on: false, items: itemIds(p) }); + for (const [list, hand] of [[priv?.hand, true], [priv?.temp, false]]) { + for (const p of Array.isArray(list) ? list : []) { + if (p?.kind !== 'chess') continue; + const base = baseOf(p.id); + owned.add(base); + if (hand) inHand.add(base); + if (memberSet.has(base) || !grants(p)) continue; + const g = granted.get(base); + if (!g) granted.set(base, { on: false, hand, items: itemIds(p) }); + else if (hand) g.hand = true; + } } const rows = members.map((id) => { const c = getChess(id); - return { id, tier: c?.tier ?? 0, name: c?.name ?? id, onBoard: onBoard.has(id), owned: owned.has(id), banned: bannedSet.has(id) }; + return { id, tier: c?.tier ?? 0, name: c?.name ?? id, onBoard: onBoard.has(id), owned: owned.has(id), inHand: inHand.has(id), banned: bannedSet.has(id) }; }); for (const [id, g] of granted) { const c = getChess(id); - rows.push({ id, tier: c?.tier ?? 0, name: c?.name ?? id, onBoard: g.on, owned: true, banned: false, granted: true, items: g.items }); + rows.push({ id, tier: c?.tier ?? 0, name: c?.name ?? id, onBoard: g.on, owned: true, inHand: g.hand, banned: false, granted: true, items: g.items }); } return rows.sort((a, b) => (b.onBoard - a.onBoard) || (b.owned - a.owned) || (a.tier - b.tier) || (a.id < b.id ? -1 : 1)); } +/** + * The member count of a bond popup's 成员 header: the rows on the board — and, for a bond that counts the hand + * (`countsHand`: BOARD_AND_DECK — 投资人 远见 奇迹; the server's 在场 says (含整备区)), those in the hand too (the 5 + * temporary slots never count), so the header agrees with 在场 (community report 「投资人等在休整区就能生效的盟约不生效」: + * the header said 0/n with the members in the hand while 在场 said 3/3). + * @param {Array<{ onBoard?: boolean, inHand?: boolean }>} rows bondMembers rows @param {boolean} [countsHand] + * @returns {number} + */ +export function memberHeadCount(rows, countsHand = false) { + let n = 0; + for (const r of Array.isArray(rows) ? rows : []) if (r && (r.onBoard || (countsHand && r.inHand))) n++; + return n; +} + /** * Banned-member count per bond (briefing / info drawer red badge). * @param {any[]} bonds bonds.json records @@ -603,9 +628,10 @@ export function briefingBondTip(name, state, bannedN = 0) { * The bonds a mode never activates (config.json modes[modeId].inactiveBondIds = the official modeDataDict * inactiveBondIdList: 标准模拟 leaves 拉特兰 阿戈尔 卡西米尔 灵巧 奥术 奇迹 投资人 突袭 独行 绝技 off). Operators that also carry an * enabled bond stay in the pool (server pool.js drawDisabledBonds) — 标准's 深靛 洛洛 阿罗玛 夕 圣聆初雪 still show 奥术 — and - * the server leaves such a bond out of m.private.bonds, so without a mark a card read "奥术 0/2 未激活" with three 奥术 + * the server left such a bond out of m.private.bonds, so without a mark a card read "奥术 0/2 未激活" with three 奥术 * operators deployed (player report after 0.1.0: "奥术盟约不生效"). The shop / reward cards, the detail card's bond chips - * and the bond popup mark these 本局禁用 (briefingBondTip 'off'). + * and the bond popup mark these 本局禁用 (briefingBondTip 'off'); since 0.1.3 the server also lists such a bond the player + * has members of (`off: true`, server/match/bondsMeta.js offBondCounts) and the strip shows it as a grey 本局禁用 disc. * @param {any} mode config.json modes[modeId] (data.js getMode), or null * @returns {Set} */ diff --git a/server/match/Match.js b/server/match/Match.js index 683542a4..5ae82d48 100644 --- a/server/match/Match.js +++ b/server/match/Match.js @@ -139,7 +139,7 @@ import { RealScheduler } from './scheduler.js'; import { SharedPool, drawDisabledBonds } from './pool.js'; import { PlayerState } from './PlayerState.js'; import { buildDeployMap, boardOrder, pieceDir } from './board.js'; -import { bondList } from './bondsMeta.js'; +import { bondList, offBondCounts } from './bondsMeta.js'; import { EffectDispatcher, getDefaultRegistry } from './effectsMeta.js'; import { generateDraft, applyCard, cardView, bountyBattles, isMultiRoundBounty } from './choices.js'; import { setupMatchWaves, buildNormalWave, buildBossWave, bountySpawns, withBounties, previewOf, weightedPick } from './waves.js'; @@ -892,7 +892,8 @@ export class Match { // this round's in-battle gains included once the COMBAT phase ended (PlayerState.bondsView); [] once eliminated — // nobody can watch an eliminated player (g.watch refuses them, they have no field) and the result screen reads // m.result's own bonds, so their layers would only cost every m.public bytes for the rest of the match - bonds: ps.alive ? bondList(this.gd, ps.bondsView()) : [], + // (the mode-off bonds with members included, `off: true`, as in m.private — bondsMeta.offBondCounts) + bonds: ps.alive ? bondList(this.gd, ps.bondsView(), { off: offBondCounts(this.gd, ps) }) : [], fieldId: this.fieldOf(ps), status: this.statusOf(ps), autoplay: ps.autoplay, @@ -1657,6 +1658,11 @@ export class Match { const alive = this.alivePlayers(); for (const ps of alive) { ps.ready = false; + // Items gained as the previous prep ended waited unmerged (acquireItem deferMerge). Merge them now, before + // this prep's onPrepStart grants and before the player acts — not in endPrep, which runs in the same prep + // that granted them and would take an equipped copy off for the fight about to start. + ps.checkItemMerges(); + ps.recompute(); this.dispatch(ps, 'onPrepStart', { round: this.round }); ps.recompute(); } diff --git a/server/match/PlayerState.js b/server/match/PlayerState.js index 8c2b7dc1..5349d4e1 100644 --- a/server/match/PlayerState.js +++ b/server/match/PlayerState.js @@ -75,7 +75,7 @@ import { checkLoadout, resolveLoadout } from '../../shared/protocol.js'; import { FIELD, tileKey, parseKey, inField, canPlace, positionClass, boardOrder, freeSlot, pieceDir, parseDir, mergeTile, ownerRangeKeys } from './board.js'; import { attackRangeGrid, loadoutRecord, resolveRecordLoadout } from '../../shared/loadoutRecord.js'; import { offsetTile } from '../sim/dir.js'; -import { computeBonds, bondList, bondSnapshot, activatedLayers, bondsWithGains } from './bondsMeta.js'; +import { computeBonds, bondList, bondSnapshot, activatedLayers, bondsWithGains, offBondCounts } from './bondsMeta.js'; import { itemKey } from './gamedata.js'; import { bountyText } from './choices.js'; @@ -712,12 +712,16 @@ export class PlayerState { /** * Acquire an item (buy, supply card, grant). Merges with an identical normal copy (hand/temp/equipped) into the * golden item (to the hand). Returns the owned piece or null. + * `deferMerge` (effectsMeta, while onPrepEnd is on the stack): stow it — hand, else temp — and do not merge in this + * call, even when an identical normal copy is already owned. The next prep's start runs checkItemMerges. Nothing + * already equipped is taken off for the fight about to start. Hand and temp both full keeps the 「整备区已满,获得的装备已销毁」 + * outcome. [ASSUMED] every item granted at 休整期结束, not only 维多利亚's 战栗维式重锤 (owner's decision 2026-10-04). */ - acquireItem(itemId, { source = 'grant', toTemp = false, silent = false } = {}) { + acquireItem(itemId, { source = 'grant', toTemp = false, silent = false, deferMerge = false } = {}) { const rec = this.gd.item(itemId); if (!rec) return null; let piece = this.newPiece('item', itemId); - if (this.completesItemMerge(itemId)) { + if (!deferMerge && this.completesItemMerge(itemId)) { piece = this._mergeItem(itemId, piece); if (!piece) return null; } else if (!this.stow(piece, { allowTemp: true, toTemp })) { @@ -1648,7 +1652,8 @@ export class PlayerState { board, deployCap: this.deployCap, deployCount: this.deployCount, - bonds: bondList(this.gd, this.bondsView(), { full: true }), + // + the mode-off bonds it has members of (`off: true`, the strip's grey 本局禁用 discs — bondsMeta.offBondCounts) + bonds: bondList(this.gd, this.bondsView(), { full: true, off: offBondCounts(this.gd, this) }), effects: this.effectsView(), nextEnemies: this.m.nextEnemiesFor(this), // DESIGN §16: the effective operator loadout ({ [baseChessId]: { skill, module } }; chess not listed use defaults) diff --git a/server/match/bondsMeta.js b/server/match/bondsMeta.js index c068c112..1a0c7c3a 100644 --- a/server/match/bondsMeta.js +++ b/server/match/bondsMeta.js @@ -16,7 +16,10 @@ // 助力 (deputShip): tier 1 needs `thresholds[0]` distinct operators; the upper tiers count operators that differ // in name OR elite state (PRTS 修正). // 独行 (soloShip, count_threshold_downward): active iff 1 ≤ count ≤ maxCount (distinct 独行 operators). -// Bonds in the mode's static inactive list (FUNNY) never activate and are omitted. +// Bonds in the mode's static inactive list (FUNNY) never activate and are omitted from computeBonds (the battle +// input never sees them); the views list the ones the player has members of as `off: true` +// (offBondCounts → bondList: count only, never active, after the others) so the strip can say +// 本局禁用 (community reports 「投资人…不生效」 / 「…不会触发斯卡蒂与异德的突袭」, 0.1.3). // `tier` = number of thresholds reached (downward: 1 when active); `active = tier ≥ 1`. // Layers (`ps.layers[bondId]`) persist the whole match; they are reported for every bond but only matter while active. @@ -48,17 +51,13 @@ export function pieceBonds(gd, piece) { } /** - * Compute every bond's state for a player. `harmony` (only present when it applies) = the +1 that 调和 added to `count`. - * @param {import('./gamedata.js').GameData} gd - * @param {{ board: Map, hand: Array, layers: Record, bondCountBonus?: Record }} ps - * @returns {Record} + * Who carries which bond (computeBonds' and offBondCounts' shared first step): bondId → Set(baseId) on the board / in + * the hand (the 5 temporary slots never count), bondId → Set(baseId|golden) on the board, and the elite chess on the board. */ -export function computeBonds(gd, ps) { +function membership(gd, ps) { const boardChess = []; for (const p of ps.board.values()) if (p && p.kind === 'chess') boardChess.push(p); const handChess = ps.hand.filter((p) => p && p.kind === 'chess'); - - /** bondId → Set(baseId) on board / hand; bondId → Set(baseId|golden) on board */ const onBoard = new Map(); const onBoardVariant = new Map(); const inHand = new Map(); @@ -72,14 +71,43 @@ export function computeBonds(gd, ps) { const base = gd.baseIdOf(p.id); for (const b of pieceBonds(gd, p)) add(inHand, b, base); } - const goldenOnBoard = boardChess.filter((p) => gd.isGolden(p.id)).length; + return { onBoard, onBoardVariant, inHand, goldenOnBoard: boardChess.filter((p) => gd.isGolden(p.id)).length }; +} + +/** A bond's member count by its counting mode (before 调和's +1), with the effects' per-bond count bonus. */ +function rawCount(gd, id, mem, ps) { + const bond = gd.bond(id); + let count; + if (bond.countMode === 'BOARD_ALL_CHESS' || bond.thresholdTemplate === 'count_threshold_upward_golden') { + count = mem.goldenOnBoard; + } else if (bond.countMode === 'BOARD_AND_DECK') { + const s = new Set([...(mem.onBoard.get(id) || []), ...(mem.inHand.get(id) || [])]); + count = s.size; + } else { + count = (mem.onBoard.get(id) || new Set()).size; + } + const bonus = ps.bondCountBonus || {}; + return Math.max(0, count + (Number.isInteger(bonus[id]) ? bonus[id] : 0)); +} + +const layersIn = (ps, id) => { + const v = ps.layers && ps.layers[id]; + return Number.isFinite(v) && v > 0 ? v : 0; +}; + +/** + * Compute every bond's state for a player. `harmony` (only present when it applies) = the +1 that 调和 added to `count`. + * @param {import('./gamedata.js').GameData} gd + * @param {{ board: Map, hand: Array, layers: Record, bondCountBonus?: Record }} ps + * @returns {Record} + */ +export function computeBonds(gd, ps) { + const mem = membership(gd, ps); + const { onBoard, onBoardVariant } = mem; /** @type {Record} */ const out = {}; - const layersOf = (id) => { - const v = ps.layers && ps.layers[id]; - return Number.isFinite(v) && v > 0 ? v : 0; - }; + const layersOf = (id) => layersIn(ps, id); const bonus = ps.bondCountBonus || {}; const bonusOf = (id) => (Number.isInteger(bonus[id]) ? bonus[id] : 0); @@ -87,17 +115,7 @@ export function computeBonds(gd, ps) { const raw = {}; for (const id of gd.bondIds) { if (gd.modeInactiveBonds.has(id)) continue; - const bond = gd.bond(id); - let count; - if (bond.countMode === 'BOARD_ALL_CHESS' || bond.thresholdTemplate === 'count_threshold_upward_golden') { - count = goldenOnBoard; - } else if (bond.countMode === 'BOARD_AND_DECK') { - const s = new Set([...(onBoard.get(id) || []), ...(inHand.get(id) || [])]); - count = s.size; - } else { - count = (onBoard.get(id) || new Set()).size; - } - raw[id] = Math.max(0, count + bonusOf(id)); + raw[id] = rawCount(gd, id, mem, ps); } // 调和: +1 to core bonds with ≥ 1 real board member while it is active const harmony = gd.bond(HARMONY_BOND); @@ -121,6 +139,28 @@ export function computeBonds(gd, ps) { return out; } +/** + * The bonds this mode never activates (the static inactive list — 标准模拟's 拉特兰 阿戈尔 卡西米尔 灵巧 奥术 奇迹 投资人 突袭 + * 独行 绝技) that the player has members of, counted like computeBonds would (投资人 / 奇迹 with the hand): { [bondId]: + * { count, layers } }, null when the mode switches nothing off. Only the views use it (bondList `off`) — the strip shows + * such a bond as a grey 本局禁用 disc instead of leaving the player to wonder why it does nothing (0.1.3). + * @param {import('./gamedata.js').GameData} gd + * @param {{ board: Map, hand: Array, layers: Record, bondCountBonus?: Record }} ps + * @returns {Record|null} + */ +export function offBondCounts(gd, ps) { + if (!gd.modeInactiveBonds || !gd.modeInactiveBonds.size) return null; + const mem = membership(gd, ps); + let out = null; + for (const id of gd.bondIds) { + if (!gd.modeInactiveBonds.has(id)) continue; + const count = rawCount(gd, id, mem, ps); + if (!(count > 0)) continue; + (out ??= {})[id] = { count, layers: layersIn(ps, id) }; + } + return out; +} + /** Ascending member-count thresholds of a bond (fallback: activeCount). */ export function thresholdsOf(bond) { if (Array.isArray(bond.thresholds) && bond.thresholds.length) return bond.thresholds.filter((n) => Number.isFinite(n)).sort((a, b) => a - b); @@ -149,26 +189,37 @@ export function activatedLayers(bonds) { /** * View list for m.private / m.public: bonds with members or layers, active first, then layers desc, then data order. - * An entry whose count includes 调和's +1 carries `harmony: 1` (both views; absent otherwise). + * An entry whose count includes 调和's +1 carries `harmony: 1` (both views; absent otherwise). `off` (offBondCounts): the + * mode-off bonds the player has members of follow, in data order, as `{ bondId, count, active: false, tier: 0, layers, + * off: true }` — the strip's grey 本局禁用 discs; never in computeBonds, so never in the battle input. * @param {import('./gamedata.js').GameData} gd * @param {ReturnType} bonds - * @param {{ full?: boolean }} [opts] full → include thresholds/countsHand (m.private) + * @param {{ full?: boolean, off?: ReturnType }} [opts] full → include thresholds/countsHand (m.private) */ -export function bondList(gd, bonds, { full = false } = {}) { +export function bondList(gd, bonds, { full = false, off = null } = {}) { const order = new Map(gd.bondIds.map((id, i) => [id, i])); const list = []; + const extras = (e) => { + if (!full) return e; + const bond = gd.bond(e.bondId); + e.thresholds = bond ? thresholdsOf(bond) : []; + e.countsHand = !!(bond && bond.countMode === 'BOARD_AND_DECK'); + return e; + }; for (const [bondId, b] of Object.entries(bonds || {})) { if (!(b.count > 0 || b.layers > 0 || b.active)) continue; const e = { bondId, count: b.count, active: b.active, tier: b.tier, layers: b.layers }; if (b.harmony > 0) e.harmony = b.harmony; - if (full) { - const bond = gd.bond(bondId); - e.thresholds = bond ? thresholdsOf(bond) : []; - e.countsHand = !!(bond && bond.countMode === 'BOARD_AND_DECK'); - } - list.push(e); + list.push(extras(e)); } list.sort((a, b) => (b.active - a.active) || (b.layers - a.layers) || ((order.get(a.bondId) ?? 99) - (order.get(b.bondId) ?? 99))); + if (off) { + for (const bondId of gd.bondIds) { + const o = off[bondId]; + if (!o || !(o.count > 0) || (bonds && bonds[bondId])) continue; + list.push(extras({ bondId, count: o.count, active: false, tier: 0, layers: Number.isFinite(o.layers) && o.layers > 0 ? o.layers : 0, off: true })); + } + } return list; } diff --git a/server/match/effectsMeta.js b/server/match/effectsMeta.js index 98fcf5a4..c7c8b1d8 100644 --- a/server/match/effectsMeta.js +++ b/server/match/effectsMeta.js @@ -196,6 +196,11 @@ export class EffectDispatcher { return ev; } this.depth++; + // An item granted while 休整期结束 is on the stack (this hook, or onGain re-entering it — 维多利亚 pays the next + // milestone from the grant's onGain) is stowed and not merged until the next prep start. [ASSUMED] every such + // item, not only the 战栗维式重锤 (owner's decision 2026-10-04: "an item that arrives at 休整期结束"). + const deferItems = hook === 'onPrepEnd'; + if (deferItems) ps._deferItemMerge = (ps._deferItemMerge || 0) + 1; try { const reg = this.registry; // 0. onPrice: the priced chess's own 特质 first — 购买价格为N defines the price every other modifier acts on @@ -236,6 +241,7 @@ export class EffectDispatcher { if (h) this._call(ps, ref.key, h, hook, { kind: 'effect', key: ref.key, ref }, ev); } } finally { + if (deferItems) ps._deferItemMerge--; this.depth--; } return ev; @@ -511,7 +517,11 @@ export function makeCtx(m, ps, source, hook, ev = null) { }, grantItem: (itemId, opts = {}) => { if (!ps.alive || !gd.item(itemId)) return null; - const p = ps.acquireItem(itemId, { source: opts.source || source.key || 'effect', toTemp: !!opts.toTemp }); + const p = ps.acquireItem(itemId, { + source: opts.source || source.key || 'effect', + toTemp: !!opts.toTemp, + deferMerge: ps._deferItemMerge > 0, + }); return p ? view(p) : null; }, /** Random chess id from the shared pool (copy-weighted). opts: { maxTier, tier, bond, filter(id) } */ diff --git a/server/sim/content/bands/battle.js b/server/sim/content/bands/battle.js index a1fc8d91..2f11d47e 100644 --- a/server/sim/content/bands/battle.js +++ b/server/sim/content/bands/battle.js @@ -129,7 +129,7 @@ const BY_KEY = { }); }, - // 休谟斯 回收利用 + // 休谟斯 回收利用 ("地面干员技能结束时…": a melee-position operator on any tile — support isGroundOp) act1autochess_band18_buff(battle, ps, p, bandId) { const sp = num(p.sp); if (!(sp > 0)) return; diff --git a/server/sim/content/bonds/addon/battle.js b/server/sim/content/bonds/addon/battle.js index ff2888d2..3d80e69c 100644 --- a/server/sim/content/bonds/addon/battle.js +++ b/server/sim/content/bonds/addon/battle.js @@ -441,6 +441,8 @@ export function install(battle) { // next time she leaves the field (knocked out, withdrawn) she is back at once and free (`u.mem.indomFreeDeploy`) // [ASSUMED: one such deployment at a time, spent by her next deployment whatever brings it]. Tier 2 (+sp SP to every // operator on the field) stays a knock-out effect: its own line ("地面干员被击倒时使场上所有干员技力+5") was not corrected. + // Both lines take a 地面干员 = a melee-position operator on any tile (support isGroundOp: 歌蕾蒂娅 on a 高台 counts, a + // ranged operator on a melee tile does not — community report 「不屈盟约效果高台干员也错误的吃到了」, 0.1.3). if (has(ID.indom)) { const INDOM_EXITS = new Set(['killed', 'retreat', 'merchant']); const stOf = (u) => { const st = isGroundOp(u) ? byPid[u.ownerId] : null; return st && st.tiers[ID.indom] ? st : null; }; diff --git a/server/sim/content/bonds/core.js b/server/sim/content/bonds/core.js index 0236c174..6eea7878 100644 --- a/server/sim/content/bonds/core.js +++ b/server/sim/content/bonds/core.js @@ -19,8 +19,8 @@ // 5: the first max_free_respawn_cnt members by position (the devour's order, fixed at battle // start) each redeploy at once (free) on their first knock-out // 叙拉古 siracusaShip every member deployment: ASPD +(base + per·L) for (base_duration + per·L) s; 6: 隐匿 for the same -// time, and while hidden / end_duration s after, attacks proc (PRD, nominal `prob`) base_damage + -// damage_per_stack·L true damage + fear `fear` s +// time, and while hidden / end_duration s after, every 普通伤害 hit (siracusaRolls) procs (PRD, +// nominal `prob`) base_damage + damage_per_stack·L true damage + fear `fear` s // 卡西米尔 kazimierzShip every deployment of one of the player's operators (initial ones included): members ATK // +atk_when_born, total ≤ base_max_atk_when_born + max_atk_when_born_per_stack·L; 6: blocking // members pulse damage_atk_scale×ATK true damage + stun around them every damage_interval s, @@ -476,6 +476,29 @@ function installEgir(battle, pid, bb, members) { // ===================================================================================================================== // 叙拉古 +/** + * Does a member's damage instance try the tier-6 proc? PRTS 盟约记录 叙拉古: "※仅在造成普通伤害时尝试造成来源为干员自身的 + * 真实附加伤害和恐惧", "每次造成普通伤害时尝试触发" — 普通伤害 is the attack type NORMAL (PRTS 伤害分类: the default type, + * group damage included unless it is 溅射), not "a normal attack" (community report 「叙拉古盟约真伤概率数值没有正确递增 + * 成长」, GitHub #79: it rolled on normal attacks only). So skill hits roll — 德克萨斯 剑雨, 缄默德克萨斯's bursts and + * sword rain, 阿罗玛 S1 / S2, 忍冬 S1 / S2, 伺夜 S3 — and so do 荒芜拉普兰德's S3 drone attacks (PRTS 备注 "不属于普通攻击/ + * 技能直接伤害": neither an attack nor skill damage, still 普通伤害). Not: 溅射 (`isSplash`); 持续伤害 (tags dot / periodic: + * 荒芜拉普兰德's S3 pulse, PRTS 备注 "持续法术伤害"; 缄默德克萨斯 S1, "伤害分类为法术持续伤害"); 附加伤害 (tag `addition`: + * 拉普兰德's module, 忍冬's 追凶 — PRTS "法术附加伤害"; item procs and the bonds' riders, own proc included [ASSUMED: 附加, + * PRTS gives no class]); element damage; 无来源 damage (坚守's thorns); 流失. + */ +function siracusaRolls(dmg) { + if (!dmg || dmg.isSplash || dmg.sourceless || dmg.type === 'element' || dmg.type === 'elemental') return false; + const tags = dmg.tags; + if (!Array.isArray(tags)) return true; + for (let i = 0; i < tags.length; i++) { + const t = tags[i]; + if (t === 'dot' || t === 'periodic' || t === 'addition' || t === 'item' || t === 'hpLoss') return false; + if (typeof t === 'string' && t.startsWith('bond:')) return false; + } + return true; +} + function installSiracusa(battle, pid, bb, members) { const memberSet = new Set(members); const six = reached(battle, pid, 'siracusaShip', bb.power_bond_char_cnt); @@ -497,7 +520,7 @@ function installSiracusa(battle, pid, bb, members) { const st = { n: 0 }; const onDmg = (ctx) => { const u = ctx.source, t = ctx.target, dmg = ctx.dmg; - if (!dmg || !dmg.isAttack || dmg.isSplash || !isEnemyTarget(t) || ownTag(dmg, 'bond:siracusa')) return; + if (!isEnemyTarget(t) || !siracusaRolls(dmg)) return; const hidden = u.s.flags.stealth || battle.time <= num(u.mem.siraStealthEnd, -Infinity) + end + 1e-9; if (!hidden) return; st.n++; @@ -609,6 +632,8 @@ export function payHammers(ctx) { ctx.setCounter(VICTORIA_COUNTER, paid + 1); for (let i = 0; i < count; i++) { const id = ctx.rollItem({ pool: p.pool }); + // onPrepEnd: grantItem stows this and does not merge until the next prep start, so a second copy does not + // take an equipped hammer off for the fight (effectsMeta _deferItemMerge). [ASSUMED] every item that hook grants. if (id && ctx.grantItem(id, { source: 'bond:victoriaShip' })) granted++; } } diff --git a/server/sim/content/items/battle.js b/server/sim/content/items/battle.js index 0cce0b4b..34e16f63 100644 --- a/server/sim/content/items/battle.js +++ b/server/sim/content/items/battle.js @@ -299,7 +299,7 @@ function hammerAcquire(battle, rt, u) { const m = hammerMul(battle, rt, u, hs, 'burn'); if (m > 0) battle.dealDamage(u, c.target, { type: 'element', element: 'burn', amount: c.amount * num(p.damage_scale) * m, tags: procTags('hammer_burn') }); }); - // 战栗: ground carrier, on attack prob × m ⇒ 战栗 disarmed_duration s + // 战栗: 地面干员 carrier (melee position, any tile — support isGroundOp), on attack prob × m ⇒ 战栗 disarmed_duration s S.on('attack', (c) => { if (c.attacker !== u || !isGroundOp(u)) return; const p = hammerParams(hs, 'tremble'); diff --git a/server/sim/content/kits/tier2.js b/server/sim/content/kits/tier2.js index 20fbb41b..a5434da6 100644 --- a/server/sim/content/kits/tier2.js +++ b/server/sim/content/kits/tier2.js @@ -40,7 +40,7 @@ function onDefaultSkill(chess) { * `liftoff` (no ground enemy blocked — Battle._blockerFor; 对地规避 — targeting.js evadesGround: no ground enemy selects * her, while what selects nobody still lands — 无视无法选择 abilities, direct picks, flying units' blasts, 无来源 damage, the * ticks of a debuff already on her) and `blockFly` (blocks flyers at the air radius). She stays a ground unit on her tile (PRTS 行动方式 "起飞的 - * 干员仍然是地面单位": `unit.ground` unchanged — 隐德来希's 血镰, 地面干员 bonds / items still count her). + * 干员仍然是地面单位": `unit.ground` unchanged — 隐德来希's 血镰 still counts her; 地面干员 bonds / items read her position). */ const LIFTOFF_FLAGS = Object.freeze({ blockFly: true, liftoff: true }); /** 蒂比 take-off: the ground enemies she blocked walk on. */ @@ -721,7 +721,8 @@ export default { if (num(t.duration) > 0) trait.onHitStatus = { key: 'silence', duration: num(t.duration) }; if (num(tb.atk_scale_m) > 0) { trait.afterHit = (battle, u, target) => { - if (target && target.alive && target.side === 'enemy') battle.dealDamage(u, target, { amount: u.s.atk * num(tb.atk_scale_m), type: 'arts', tags: ['module'] }); + // PRTS 特性备注 "造成预计算的法术附加伤害": 附加伤害 (tag addition — no 叙拉古 6 roll) + if (target && target.alive && target.side === 'enemy') battle.dealDamage(u, target, { amount: u.s.atk * num(tb.atk_scale_m), type: 'arts', tags: ['module', 'addition'] }); }; } return { diff --git a/server/sim/content/kits/tier3.js b/server/sim/content/kits/tier3.js index 835ce819..d8c315e2 100644 --- a/server/sim/content/kits/tier3.js +++ b/server/sim/content/kits/tier3.js @@ -1389,7 +1389,8 @@ const KITS = { if (t == null) { marks.set(e.id, battle.time); return; } if (battle.time - t <= num(t0.interval, 10) + 1e-9 && e.alive) { busy = true; - try { battle.dealDamage(unit, e, { amount: unit.s.atk * num(t0.atk_scale), type: 'arts', canDodge: false, tags: ['talent', 'vulpisHunt'] }); } finally { busy = false; } + // PRTS 备注 "伤害类型为法术附加伤害": tag addition (no 叙拉古 6 roll) + try { battle.dealDamage(unit, e, { amount: unit.s.atk * num(t0.atk_scale), type: 'arts', canDodge: false, tags: ['talent', 'vulpisHunt', 'addition'] }); } finally { busy = false; } } }, { owner: unit }); battle.on('kill', (ctx) => { if (ctx.killer === unit && unit.skill?.active) unit.mem.vulpisKill = true; }, { owner: unit }); diff --git a/server/sim/content/kits/tier6.js b/server/sim/content/kits/tier6.js index eddbd1c3..43502699 100644 --- a/server/sim/content/kits/tier6.js +++ b/server/sim/content/kits/tier6.js @@ -2972,11 +2972,13 @@ function whitw2(bb, chess, def) { // 信息 驭械术师 "浮游单元攻击不同目标…时,上述的伤害立刻恢复至初始值"). That damage is arts and neither a normal attack // nor skill damage (PRTS S3 备注 "该技能释放的浮游单元造成的伤害不属于普通攻击/技能直接伤害", which for this skill // overrides the branch note "通过技能释放的浮游单元造成技能直接伤害": no 'attack' hook, isAttack / isSkill false — the - // 叙拉古 6 assassin proc and the on-attack items skip it), and 缴械 does not stop it (PRTS 驭械术师 "…不受缴械类效果 + // on-attack items skip it; it is still 普通伤害, so the 叙拉古 6 proc rolls on it, bonds/core.js siracusaRolls), and + // 缴械 does not stop it (PRTS 驭械术师 "…不受缴械类效果 // 制约"); [ASSUMED] nor do her stun, freeze or silence (PRTS names only 缴械) — the skill ticks on and so do the drones. // Around every drone (attack@range_radius): move speed attack@move_speed and, once per second, attack@magic_atk_scale // × ATK arts (不叠加: one hit per enemy whatever the number of drones); [ASSUMED] that area hit keeps `isSkill` (a skill - // DoT — the 备注 speaks of 直接伤害). A knocked-out / withdrawn wolf (onEnd cleared the drones mid-tick, e.g. from a + // DoT — the 备注 speaks of 直接伤害) and is 持续伤害 (tag dot: PRTS 备注 "持续法术伤害" — no 叙拉古 6 roll, 锡人's + // 凋敝魂灵 raises it). A knocked-out / withdrawn wolf (onEnd cleared the drones mid-tick, e.g. from a // kill hook) deals nothing more in that tick. skill: { kind: 'duration', @@ -3009,7 +3011,7 @@ function whitw2(bb, chess, def) { unit.mem.droneAcc -= 1; for (const e of near) { if (gone()) return; - if (e.alive) battle.dealDamage(unit, e, { amount: unit.s.atk * dmgScale, type: 'arts', isSkill: true, tags: ['skill', 'drone'] }); + if (e.alive) battle.dealDamage(unit, e, { amount: unit.s.atk * dmgScale, type: 'arts', isSkill: true, tags: ['skill', 'drone', 'dot'] }); } // (a drone on its target already pulses with each of its attacks) for (const d of D) if (d.phase !== 'lock') battle.fx('drone', { x: d.x, y: d.y, id: unit.id }); diff --git a/server/sim/content/support/index.js b/server/sim/content/support/index.js index c1d18c64..dd247cbc 100644 --- a/server/sim/content/support/index.js +++ b/server/sim/content/support/index.js @@ -151,8 +151,14 @@ export function tierOf(u) { if (u.ownerUnit) return tierOf(u.ownerUnit); return 1; } -/** Operator standing on a ground (LOW, not elevated) tile — "地面干员" (engine flag set at deployment). */ -export const isGroundOp = (u) => isOp(u) && u.ground === true; +/** + * "地面干员": a melee-position (地面位, deploy class MELEE) operator, whatever tile it stands on — the official vocabulary + * names the deploy class, not the tile (game data: this mode's map card 「可以部署高台干员和地面干员的地面」, 「可将高台干员 + * 部署于其上」, 「所有地面干员阻挡数+2」; PRTS corrected 琴柳's 地面干员 to 地面位干员). Read by 不屈, the 战栗维式重锤 proc and + * 休谟斯 回收利用 (community report 「不屈盟约效果高台干员也错误的吃到了」, 0.1.3). The tile (`unit.ground`) stays what the + * enemies' 地面单位 targeting reads. + */ +export const isGroundOp = (u) => isOp(u) && u.def?.position === 'MELEE'; /** Base (normal) chess id of an operator (normal and elite share it). */ export const baseChessId = (u) => String(u?.def?.baseId ?? u?.defId ?? '').replace(/_b$/, '_a'); diff --git a/test/content/bonds_addon.test.js b/test/content/bonds_addon.test.js index a43e79f9..a1e5fe0f 100644 --- a/test/content/bonds_addon.test.js +++ b/test/content/bonds_addon.test.js @@ -412,7 +412,7 @@ test('突袭 #51: the most advanced enemy out of reach → the jump goes to the checkInvariants(h.b); }); -test('不屈: knocked-out ground operator redeploys (p=1 at high L); tier 2 every operator +5 SP; inactive / elevated → no', () => { +test('不屈: knocked-out 地面干员 (melee position) redeploys (p=1 at high L); tier 2 every operator +5 SP; inactive / ranged → no', () => { const bb = bondBb('indomShip'); const sk = { spCost: 50, initSp: 0 }; const defs = { chess: { i_g: op('i_g', ['indomShip']), i_o: chessRec({ id: 'i_o', bonds: [], skill: sk }) } }; @@ -441,12 +441,21 @@ test('不屈: knocked-out ground operator redeploys (p=1 at high L); tier 2 ever close(o1.skill.sp, s1, 'tier 1: no SP'); checkInvariants(t1.b); + // 地面干员 = the melee position, whatever the tile: up on a 高台 it still counts; a ranged operator on a melee tile never const hi = makeBattle({ defs, units: [{ chessId: 'i_g', row: 10, col: 2 }], bonds: { indomShip: bond(1, 300) } }); hi.step(2); const hg = hi.unit('i_g'); assert.equal(hg.ground, false, 'elevated tile'); hi.b.dealDamage(null, hg, { amount: 1e9, type: 'true' }); - assert.equal(hg.alive, false, 'not a ground operator'); + assert.ok(hg.alive && hg.deployed, 'a melee operator on a 高台 is a 地面干员'); + const rd = { chess: { i_r: ranged('i_r', ['indomShip']), i_o: chessRec({ id: 'i_o', bonds: [], skill: sk }) } }; + const lo = makeBattle({ defs: rd, units: [{ chessId: 'i_r', row: 10, col: 4 }, { chessId: 'i_o', row: 12, col: 6 }], bonds: { indomShip: bond(2, 300, 3) } }); + lo.step(2); + const lr = lo.unit('i_r'), lsp = lo.unit('i_o').skill.sp; + assert.equal(lr.ground, true, 'a melee (ground) tile'); + lo.b.dealDamage(null, lr, { amount: 1e9, type: 'true' }); + assert.equal(lr.alive, false, 'a ranged operator on a melee tile is not a 地面干员'); + close(lo.unit('i_o').skill.sp, lsp, 'no tier 2 SP either'); }); test('协防干员: all operators take ×0.8 phys/arts; members deal ×1.2 (elite ×1.4)', () => { diff --git a/test/content/feedback3-ground-ops.test.js b/test/content/feedback3-ground-ops.test.js new file mode 100644 index 00000000..91d98283 --- /dev/null +++ b/test/content/feedback3-ground-ops.test.js @@ -0,0 +1,98 @@ +// test/content/feedback3-ground-ops.test.js — 「地面干员」 is the melee position (地面位), not the tile (0.1.3; community +// report 「不屈盟约效果高台干员也错误的吃到了」). Game data words the deploy class this way (this mode's map card +// 「可以部署高台干员和地面干员的地面」, 「可将高台干员部署于其上」, 「所有地面干员阻挡数+2」); PRTS corrected 琴柳's 地面干员 to +// 地面位干员. The three effects worded 地面干员 — 不屈 (both lines), the 战栗维式重锤 proc and 休谟斯 回收利用 — read +// support isGroundOp = def.position MELEE: 歌蕾蒂娅 on a 高台 counts, a ranged operator on a melee tile does not. +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/battleHarness.js'; +import { isGroundOp } from '../../server/sim/content/support/index.js'; + +const close = (a, b, msg, eps = 1e-6) => assert.ok(Math.abs(a - b) <= eps, `${msg}: ${a} ≠ ${b}`); +const RANGE5 = [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]]; +const op = (id, o = {}) => chessRec({ + id, profession: o.profession ?? 'WARRIOR', bonds: o.bonds ?? [], rangeGrid: RANGE5, + stats: { maxHp: 2000, atk: 500, def: 200, res: 10, aspd: 100, bat: 1, respawnTime: 20, spRecovery: 1, blockCnt: 2 }, + skill: { spCost: 60, duration: 5, initSp: 0 }, +}); +const DUMMY = enemyRec({ key: 'e_d', hp: 1e7, speed: 0 }); +function forceRng(h, v) { const orig = h.b.rng; h.b.rng = Object.assign(() => v, orig); } + +// act2autochess_m01 (战场#01(下半)): (9,4) a melee tile on the road, (10,4) a 高台 +const PROVENCE = 'chess_char_1_07_a'; // 普罗旺斯 狙击 RANGED, 不屈 +const GLADIIA = 'chess_char_4_12_a'; // 歌蕾蒂娅 钩索师 MELEE (placement 'all': may stand on a 高台) +const CUORA = 'chess_char_3_16_a'; // 蛇屠箱: takes the tier-2 SP +const INDOM = { indomShip: { count: 3, active: true, tier: 2, layers: 210 } }; // p = min(1, 0.18 + 0.004 × 210) = 1 + +test('不屈 (real chess): 歌蕾蒂娅 knocked out on a 高台 is back at once with the tier-2 SP; 普罗旺斯 on a melee tile stays down', () => { + const run = (id, row, col) => { + const h = makeBattle({ + stageId: 'act2autochess_m01', seed: 4, timeLimit: 60, autoFinish: false, bonds: INDOM, + units: [{ chessId: id, row, col, dir: 'RIGHT' }, { chessId: CUORA, row: 12, col: 6, dir: 'RIGHT' }], + }); + h.step(2); + const u = h.unit(id), other = h.unit(CUORA); + const sp0 = other.skill.sp; + h.b.kill(u, null); + const back = u.alive && u.deployed; + const sp = other.skill.sp - sp0; + checkInvariants(h.b); + return { u, back, sp }; + }; + const g = run(GLADIIA, 10, 4); + assert.equal(g.u.ground, false, '歌蕾蒂娅 stands on the 高台'); + assert.equal(g.u.def.position, 'MELEE'); + assert.ok(isGroundOp(g.u), 'a 地面干员 up there'); + assert.ok(g.back, '不屈 brings her back at once'); + close(g.sp, 5, '不屈 tier 2: every operator on the field +5 SP'); + const p = run(PROVENCE, 9, 4); + assert.equal(p.u.ground, true, '普罗旺斯 stands on a melee tile'); + assert.ok(!isGroundOp(p.u), 'not a 地面干员'); + assert.ok(!p.back, '不屈 does not bring a ranged operator back'); + close(p.sp, 0, 'no tier-2 SP for her knock-out'); + const g2 = run(GLADIIA, 9, 4); + assert.ok(g2.back && g2.sp === 5, '歌蕾蒂娅 on the ground: as before'); +}); + +test('战栗维式重锤: the 战栗 proc takes a melee carrier on a 高台, never a ranged carrier on a melee tile', () => { + const ops = { t_m: op('t_m', { bonds: ['victoriaShip'] }), t_r: op('t_r', { bonds: ['victoriaShip'], profession: 'SNIPER' }) }; + const tremble = (id, row, col) => { + const h = makeBattle({ + defs: { chess: ops, enemies: { e_d: DUMMY } }, timeLimit: 999, autoFinish: false, + units: [{ chessId: id, row, col, items: ['chess_item_2_03_e_a'] }], enemies: [{ key: 'e_d', pos: [10, 5] }], + }); + forceRng(h, 0.05); // under the 10 % chance + h.runUntil(() => h.hooksOf('attack').length >= 1, 5); + assert.ok(h.hooksOf('attack').length >= 1, `${id} attacked`); + const u = h.unit(id); + return { ground: u.ground, hit: !!h.b.enemies[0].findBuff('tremble') }; + }; + const m = tremble('t_m', 10, 2); + assert.equal(m.ground, false, 'the melee carrier on the 高台'); + assert.ok(m.hit, '战栗 from a melee carrier on a 高台'); + const r = tremble('t_r', 10, 4); + assert.equal(r.ground, true, 'the ranged carrier on a melee tile'); + assert.ok(!r.hit, 'no 战栗 from a ranged carrier'); +}); + +test('休谟斯 回收利用: a melee operator\'s skill end on a 高台 feeds a neighbour 3 SP; a ranged one\'s on a melee tile does not', () => { + const ops = { t_m: op('t_m'), t_r: op('t_r', { profession: 'SNIPER' }), t_n: op('t_n') }; + const recycle = (id, row, col, nRow, nCol) => { + const h = makeBattle({ + defs: { chess: ops, enemies: { e_d: DUMMY } }, bandId: 'band_humus', timeLimit: 999, autoFinish: false, + units: [{ chessId: id, row, col }, { chessId: 't_n', row: nRow, col: nCol }], + }); + h.step(1); + const u = h.unit(id), n = h.unit('t_n'); + const n0 = n.skill.sp; + u.skill.activate('test', { free: true }); + u.skill.end('test'); + return { ground: u.ground, gain: n.skill.sp - n0 }; + }; + const m = recycle('t_m', 10, 2, 10, 3); + assert.equal(m.ground, false); + close(m.gain, 3, 'melee on the 高台: neighbour +3'); + const r = recycle('t_r', 10, 4, 11, 4); + assert.equal(r.ground, true); + close(r.gain, 0, 'ranged on a melee tile: nothing'); +}); diff --git a/test/content/feedback3-siracusa-rolls.test.js b/test/content/feedback3-siracusa-rolls.test.js new file mode 100644 index 00000000..fd06dce9 --- /dev/null +++ b/test/content/feedback3-siracusa-rolls.test.js @@ -0,0 +1,93 @@ +// test/content/feedback3-siracusa-rolls.test.js — 叙拉古 6's true-damage proc rolls on every 普通伤害 hit of a member +// (0.1.3; community report 「叙拉古盟约真伤概率数值没有正确递增成长」, GitHub #79 「咬了一整个技能也没出」). PRTS 盟约记录 +// 叙拉古: "※仅在造成普通伤害时尝试…", "每次造成普通伤害时尝试触发"; PRTS 伤害分类: 普通伤害 = attack type NORMAL, the +// default (group damage too unless it is 溅射); 溅射 / 持续 (BUFF) / 附加 (ADDITION) are other types. With the battle rng +// forced to 0 every roll hits, so the procs count the hits that rolled (the PRD rule and the amounts are unchanged). +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { makeBattle, chessRec, enemyRec, checkInvariants } from '../helpers/battleHarness.js'; + +const L = 20; +const SIRA6 = { siracusaShip: { count: 6, active: true, tier: 2, layers: L } }; +const dummy = (key) => enemyRec({ key, hp: 1e9, speed: 0, def: 0, res: 0 }); +const ENEMIES = { e_dummy: dummy('e_dummy'), e_dummy2: dummy('e_dummy2') }; +function forceRng(h, v) { const orig = h.b.rng; h.b.rng = Object.assign(() => v, orig); } +const isProc = (c) => !!(c.dmg && c.dmg.tags && c.dmg.tags.includes('bond:siracusa')); +const hasTag = (c, t) => !!(c.dmg && c.dmg.tags && c.dmg.tags.includes(t)); + +test('叙拉古 6: which damage rolls — attacks, skill hits, drone attacks yes; 溅射, 持续, 附加, item procs, element, 无来源 no', () => { + const h = makeBattle({ + defs: { chess: { r0_a: chessRec({ id: 'r0_a', bonds: ['siracusaShip'], skill: null }) }, enemies: ENEMIES }, + units: [{ chessId: 'r0_a', row: 10, col: 3 }], enemies: [{ key: 'e_dummy', pos: [12, 9] }], // out of her range + bonds: SIRA6, autoFinish: false, timeLimit: 300, + }); + h.step(1); + const a = h.unit('r0_a'), e = h.enemies()[0]; + assert.ok(a.s.flags.stealth, '隐匿 after the deployment'); + forceRng(h, 0); + let procs = 0; + h.b.on('damaged', (c) => { if (isProc(c)) procs++; }); + const rolls = (d) => { const n0 = procs; h.b.dealDamage(a, e, { amount: 1, ...d }); return procs - n0; }; + const cases = [ + ['a normal attack', { type: 'phys', isAttack: true }, 1], + ['a skill hit (剑雨-like)', { type: 'arts', isSkill: true, tags: ['skill'] }, 1], + ['a drone attack (neither attack nor skill)', { type: 'arts', tags: ['droneAttack'] }, 1], + ['a module / talent hit with no class', { type: 'arts', tags: ['talent'] }, 1], + ['溅射', { type: 'phys', isAttack: true, isSplash: true }, 0], + ['持续 (the S3 pulse, 缄默德克萨斯 S1)', { type: 'arts', isSkill: true, tags: ['skill', 'drone', 'dot'] }, 0], + ['持续 (periodic)', { type: 'true', canDodge: false, tags: ['dot', 'periodic'] }, 0], + ['附加 (拉普兰德 module, 忍冬 追凶)', { type: 'arts', tags: ['module', 'addition'] }, 0], + ['an item proc', { type: 'true', canDodge: false, tags: ['item', 'item:pegasus'] }, 0], + ['another bond\'s rider', { type: 'true', canDodge: false, tags: ['bond:kazimierz'] }, 0], + ['element damage', { type: 'element', element: 'burn' }, 0], + ['无来源 damage', { type: 'arts', canDodge: false, sourceless: true }, 0], + ]; + for (const [label, d, want] of cases) assert.equal(rolls(d), want, label); + checkInvariants(h.b); +}); + +test('叙拉古 6: 荒芜拉普兰德 S3 — every drone attack rolls, the per-second pulse (持续法术伤害) does not', () => { + const log = []; + const h = makeBattle({ + defs: { enemies: ENEMIES }, seed: 7, timeLimit: 120, autoFinish: false, bonds: SIRA6, + units: [{ chessId: 'chess_char_6_18_a', row: 10, col: 3, carryState: { sp: 69 } }], + enemies: [{ key: 'e_dummy', pos: [12, 9] }], + setup(b) { b.on('damaged', (c) => log.push(c), { priority: -999 }); }, + }); + const u = h.unit('chess_char_6_18_a'); + assert.ok(h.runUntil(() => u.skill.active, 10), 'S3 cast'); + forceRng(h, 0); + const t0 = h.b.time, from = log.length; + h.run(10); + assert.ok(u.skill.active && u.s.flags.stealth, 'still in S3 and 隐匿'); + const mine = log.slice(from).filter((c) => c.source === u); + const drones = mine.filter((c) => hasTag(c, 'droneAttack')).length; + const pulses = mine.filter((c) => hasTag(c, 'drone')); + const procs = mine.filter(isProc).length; + assert.ok(drones >= 5, `drone attacks ${drones}`); + assert.ok(pulses.length >= 5 && pulses.every((c) => hasTag(c, 'dot')), `pulses ${pulses.length}, 持续伤害`); + assert.equal(mine.filter((c) => c.dmg?.isAttack).length, 0, 'no attack of her own during S3'); + assert.equal(procs, drones, `one roll per drone attack, none per pulse (t ${t0.toFixed(1)}–${h.b.time.toFixed(1)})`); + checkInvariants(h.b); +}); + +test('叙拉古 6: 德克萨斯 S2 剑雨 — both hits on every enemy around roll', () => { + const log = []; + const h = makeBattle({ + defs: { enemies: ENEMIES }, seed: 3, timeLimit: 60, autoFinish: false, bonds: SIRA6, + units: [{ chessId: 'chess_char_1_08_a', row: 10, col: 3, carryState: { sp: 40 } }], + // inside the skill's diamond, outside her attack range (her tile and the one in front) + enemies: [{ key: 'e_dummy', pos: [10, 5] }, { key: 'e_dummy2', pos: [11, 4] }], + setup(b) { b.on('damaged', (c) => log.push({ c, t: b.time }), { priority: -999 }); }, + }); + forceRng(h, 0); + const u = h.unit('chess_char_1_08_a'); + const rainHit = (x) => x.c.source === u && x.c.dmg?.isSkill && !isProc(x.c); + assert.ok(h.runUntil(() => log.some(rainHit), 5), '剑雨 cast'); + const T = log.find(rainHit).t; + const mine = log.filter((x) => x.c.source === u && x.t === T).map((x) => x.c); + assert.equal(mine.filter((c) => c.dmg?.isSkill && !isProc(c)).length, 4, 'two hits on each of the two enemies'); + assert.equal(mine.filter((c) => c.dmg?.isAttack).length, 0, 'no attack hit in that tick'); + assert.equal(mine.filter(isProc).length, 4, 'every 剑雨 hit rolled (rng 0: each roll hits)'); + checkInvariants(h.b); +}); diff --git a/test/match/feedback3-off-bonds.test.js b/test/match/feedback3-off-bonds.test.js new file mode 100644 index 00000000..b0e63df2 --- /dev/null +++ b/test/match/feedback3-off-bonds.test.js @@ -0,0 +1,91 @@ +// Mode-off bonds stay out of the battle (computeBonds) and show in the views when the player has members +// (offBondCounts → bondList `off: true`, the strip's grey 本局禁用 discs). 标准模拟's inactiveBondIdList +// (activity_table mode_single_funny): 投资人 and 奇迹 count the hand (BOARD_AND_DECK); 突袭 counts the board. +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { GameData } from '../../server/match/gamedata.js'; +import { computeBonds, bondList, bondSnapshot, offBondCounts } from '../../server/match/bondsMeta.js'; +import { DATA } from './harness.js'; + +const funny = new GameData(DATA, 'mode_single_funny'); +const open = new GameData(DATA, 'mode_multi_normal'); +let uid = 1; +const piece = (id) => ({ uid: uid++, kind: 'chess', id, items: [] }); +const state = ({ board = [], hand = [], layers = {}, bondCountBonus } = {}) => { + const b = new Map(); + board.forEach((p, i) => b.set(`${9 + (i % 4)},${2 + Math.floor(i / 4)}`, p)); + const h = new Array(10).fill(null); + hand.forEach((p, i) => { h[9 - i] = p; }); + return { board: b, hand: h, layers, bondCountBonus }; +}; +const members = (bond, n) => Object.values(DATA.chess) + .filter((c) => c.visible && !c.isGolden && c.bonds.includes(bond)) + .slice(0, n) + .map((c) => c.chessId); + +const INVESTOR = members('investShip', 2); +const RAIDER = members('raidShip', 1); +const YAN = members('yanShip', 1); + +test('标准模拟: an 投资人 member in hand and a 突袭 member on the board are off entries, never in computeBonds', () => { + assert.equal(INVESTOR.length, 2); + assert.equal(RAIDER.length, 1); + const ps = state({ + board: [piece(RAIDER[0]), piece(YAN[0])], + hand: [piece(INVESTOR[0])], + layers: { investShip: 12, raidShip: 4, lateranoShip: 9 }, + }); + const bonds = computeBonds(funny, ps); + assert.ok(!('investShip' in bonds), '投资人 stays out of the battle input'); + assert.ok(!('raidShip' in bonds), '突袭 stays out of the battle input'); + assert.ok(!('lateranoShip' in bonds)); + assert.equal(bondSnapshot(bonds).investShip, undefined); + assert.ok(bonds.yanShip, 'an enabled bond is unchanged'); + + const off = offBondCounts(funny, ps); + assert.equal(off.investShip.count, 1, 'a hand member counts for 投资人'); + assert.equal(off.investShip.layers, 12); + assert.equal(off.raidShip.count, 1); + assert.equal(off.raidShip.layers, 4); + assert.ok(!('lateranoShip' in off), 'an inactive bond with zero members is omitted, layers or not'); + + const list = bondList(funny, bonds, { full: true, off }); + const invest = list.find((x) => x.bondId === 'investShip'); + const raid = list.find((x) => x.bondId === 'raidShip'); + assert.deepEqual( + { count: invest.count, active: invest.active, tier: invest.tier, layers: invest.layers, off: invest.off, countsHand: invest.countsHand }, + { count: 1, active: false, tier: 0, layers: 12, off: true, countsHand: true }, + ); + assert.equal(raid.off, true); + assert.equal(raid.active, false); + assert.equal(raid.tier, 0); + assert.equal(raid.countsHand, false); + assert.ok(list.findIndex((x) => x.off) > list.findIndex((x) => x.bondId === 'yanShip'), 'off entries follow the live bonds'); + assert.ok(list.slice(list.findIndex((x) => x.off)).every((x) => x.off), 'the off entries are a suffix'); + const pub = bondList(funny, bonds, { off }); + assert.equal(pub.find((x) => x.bondId === 'investShip').off, true); + assert.equal('countsHand' in pub.find((x) => x.bondId === 'investShip'), false, 'm.public omits countsHand'); +}); + +test('a BOARD_AND_DECK off bond counts the hand, not the temporary slots, and not twice', () => { + const [a, b] = INVESTOR; + const handOnly = offBondCounts(funny, state({ hand: [piece(a), piece(b)] })); + assert.equal(handOnly.investShip.count, 2); + assert.ok(!('raidShip' in (handOnly || {})), '突袭 in nobody\'s hand: a board bond with no board member is omitted'); + const raidHand = offBondCounts(funny, state({ hand: [piece(RAIDER[0])] })); + assert.equal(raidHand, null, '突袭 does not count a hand member'); + const both = offBondCounts(funny, state({ board: [piece(a)], hand: [piece(a), piece(DATA.chess[a].goldenId)] })); + assert.equal(both.investShip.count, 1, 'normal and elite of one operator, board and hand, count once'); + const tempOnly = { board: new Map(), hand: new Array(10).fill(null), layers: {}, temp: [piece(a)] }; + assert.equal(offBondCounts(funny, tempOnly), null, 'the 5 temporary slots never count'); +}); + +test('a mode with an empty inactive set returns null, and those bonds stay in computeBonds', () => { + assert.equal(open.modeInactiveBonds.size, 0); + const ps = state({ board: [piece(RAIDER[0])], hand: [piece(INVESTOR[0])] }); + assert.equal(offBondCounts(open, ps), null); + const bonds = computeBonds(open, ps); + assert.equal(bonds.investShip.count, 1); + assert.equal(bonds.raidShip.count, 1); + assert.equal(bondList(open, bonds).some((x) => x.off), false); +}); diff --git a/test/match/feedback3-prep-end-item.test.js b/test/match/feedback3-prep-end-item.test.js new file mode 100644 index 00000000..81557572 --- /dev/null +++ b/test/match/feedback3-prep-end-item.test.js @@ -0,0 +1,156 @@ +// An item that arrives at 休整期结束 waits in the hand and merges at the next prep start (owner's decision 2026-10-04). +// 维多利亚 pays 战栗维式重锤 on onPrepEnd; merging in that call used to detach the equipped copy before the fight. +// [ASSUMED] every grant while that dispatch is on the stack, not only this hammer. +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { createRegistry } from '../../server/match/effectsMeta.js'; +import { registerMeta as coreRegisterMeta } from '../../server/sim/content/bonds/core.js'; +import { makeMatch, give, giveItem, legalTileFor } from './harness.js'; +import { FakeBattle } from './fakeBattle.js'; +import { tileKey } from '../../server/match/board.js'; + +const HAMMER = 'chess_item_2_03_e_a'; // 战栗维式重锤 +const GOLDEN = 'chess_item_2_03_e_b'; +const FILLER = 'chess_item_1_01_e_a'; +const OPS = ['chess_char_1_06_a', 'chess_char_2_05_a', 'chess_char_3_08_a']; + +function copies(ps, id) { + let n = 0; + const see = (p) => { if (p && p.kind === 'item' && p.id === id) n++; }; + for (const p of ps.hand) see(p); + for (const p of ps.temp) see(p); + for (const c of ps.board.values()) if (c && c.kind === 'chess') for (const it of c.items || []) see(it); + return n; +} + +function fresh() { + const reg = createRegistry({ content: false }); + coreRegisterMeta(reg); + const h = makeMatch({ mode: 'solo', seed: 5, registry: reg, fake: true }).start(); + h.toPrep(1); + const orig = h.m.rollItemId.bind(h.m); + h.m.rollItemId = (opts = {}) => (opts.pool === 'pool_equip_vict' ? HAMMER : orig(opts)); + return h; +} + +/** Bond inactive while the layers land, then three 维多利亚 operators. One wears the hammer when `equip`. */ +function arm(h, { layers, equip = true, fill = false } = {}) { + const ps = h.ps('p_0'); + assert.equal(ps.setReady(false).ok, true); + for (const p of [...ps.board.values(), ...ps.hand.filter(Boolean), ...ps.temp.filter(Boolean)]) { + if (p && p.kind === 'chess') ps.returnCopies(p); + } + ps.board.clear(); + ps.hand.fill(null); + ps.temp.fill(null); + ps._tempDue.clear(); + ps.recompute(); + assert.equal(ps.bonds.victoriaShip?.active ?? false, false); + if (layers > 0) assert.equal(ps.addLayers('victoriaShip', layers), layers); + assert.equal(ps.counters['bond:victoria:hammers'] || 0, 0, 'inactive: the milestones are owed, not paid'); + const used = new Set(); + const ops = OPS.map((id) => { + const t = legalTileFor(h.m, ps, id, used); + used.add(tileKey(t[0], t[1])); + return give(h.m, ps, id, 'board', t); + }); + assert.equal(ps.bonds.victoriaShip.active, true); + let equipped = null; + if (equip) { + equipped = giveItem(h.m, ps, HAMMER); + const eq = ps.equip(equipped.uid, ops[0].uid); + assert.equal(eq.ok, true, eq.error || eq.detail); + assert.equal(ops[0].items[0].uid, equipped.uid); + } + if (fill) { + for (let i = 0; i < ps.hand.length; i++) if (!ps.hand[i]) giveItem(h.m, ps, FILLER, 'hand', i); + for (let i = 0; i < ps.temp.length; i++) if (!ps.temp[i]) giveItem(h.m, ps, FILLER, 'temp', i); + assert.ok(ps.hand.every(Boolean) && ps.temp.every(Boolean)); + } + return { ps, carrier: ops[0], equipped }; +} + +test('维多利亚 pays a 战栗维式重锤 at prep end: the equipped copy stays for the fight, and they merge at the next prep', () => { + const h = fresh(); + const { ps, carrier, equipped } = arm(h, { layers: 25 }); + assert.equal(ps.setReady(true).ok, true); + h.m.endPrep(); + assert.equal(h.m.phase, 'COMBAT'); + assert.equal(carrier.items.length, 1); + assert.equal(carrier.items[0].uid, equipped.uid, 'the equipped hammer was not taken off'); + assert.equal(carrier.items[0].id, HAMMER); + assert.equal(copies(ps, HAMMER), 2, 'the new copy is in hand or temp'); + assert.equal(copies(ps, GOLDEN), 0, 'no golden yet'); + const input = FakeBattle.instances.at(-1).opts.players[0]; + const unit = input.units.find((u) => u.uid === carrier.uid); + assert.ok(unit && unit.items.includes(HAMMER), 'the fight is built with the hammer still equipped'); + h.toPrep(2); + assert.equal(h.m.phase, 'PREP'); + assert.equal(copies(ps, GOLDEN), 1, 'the pair merged when the next prep started'); + assert.equal(copies(ps, HAMMER), 0); + h.invariants(); + h.m.dispose(); +}); + +test('two milestones owed at prep end both wait: no golden before the fight; the next prep merges the hand copies and leaves the equipped one', () => { + const h = fresh(); + const { ps, carrier, equipped } = arm(h, { layers: 50 }); + assert.equal(ps.setReady(true).ok, true); + h.m.endPrep(); + assert.equal(carrier.items[0].uid, equipped.uid); + assert.equal(copies(ps, HAMMER), 3, 'equipped + two stowed, the nested onGain grant included'); + assert.equal(copies(ps, GOLDEN), 0); + h.toPrep(2); + assert.equal(copies(ps, GOLDEN), 1); + assert.equal(copies(ps, HAMMER), 1); + assert.equal(carrier.items[0] && carrier.items[0].uid, equipped.uid, 'the hand copies merged with each other; the equipped one stayed'); + h.m.dispose(); +}); + +test('hand and temp full at prep end: the new hammer is destroyed, the equipped one stays, and the next prep does not put a golden in the slot', () => { + const h = fresh(); + const { ps, carrier, equipped } = arm(h, { layers: 50, fill: true }); + h.m.endPrep(); + assert.equal(carrier.items.length, 1); + assert.equal(carrier.items[0].uid, equipped.uid); + assert.equal(carrier.items[0].id, HAMMER); + assert.equal(copies(ps, GOLDEN), 0); + assert.equal(copies(ps, HAMMER), 1); + const toasts = h.sent.filter(([, msg]) => msg.t === 'm.toast').map(([, msg]) => msg.text); + assert.equal(toasts.filter((t) => t === '整备区已满,获得的装备已销毁').length, 2); + const input = FakeBattle.instances.at(-1).opts.players[0]; + assert.ok(input.units.find((u) => u.uid === carrier.uid).items.includes(HAMMER)); + h.toPrep(2); + assert.equal(carrier.items[0].uid, equipped.uid, 'nothing was merged into the slot'); + assert.equal(copies(ps, GOLDEN), 0); + assert.equal(copies(ps, HAMMER), 1); + h.m.dispose(); +}); + +test('a buy during prep still merges at once', () => { + const h = fresh(); + const ps = h.ps('p_0'); + assert.equal(ps.setReady(false).ok, true); + giveItem(h.m, ps, HAMMER); + ps.funds = 50; + ps.shop.slots[0] = { kind: 'item', id: HAMMER, price: 1, basePrice: 1, sold: false }; + assert.equal(ps.buy(0).ok, true); + assert.equal(h.m.phase, 'PREP'); + assert.equal(copies(ps, HAMMER), 0); + assert.equal(copies(ps, GOLDEN), 1); + h.m.dispose(); +}); + +test('a grant after the prep has ended (onLayers during combat) still merges at once', () => { + const h = fresh(); + const { ps, carrier, equipped } = arm(h, { layers: 0 }); + assert.equal(ps.setReady(true).ok, true); + h.m.endPrep(); + assert.equal(h.m.phase, 'COMBAT'); + assert.equal(carrier.items[0].uid, equipped.uid); + assert.equal(ps.addLayers('victoriaShip', 25), 25); + assert.equal(copies(ps, HAMMER), 0, 'the equipped copy was merged immediately'); + assert.equal(copies(ps, GOLDEN), 1); + assert.equal(h.m.phase, 'COMBAT'); + h.m.dispose(); +}); diff --git a/test/ui/feedback1b-bonds.test.js b/test/ui/feedback1b-bonds.test.js index fc30b409..3a1cc7c0 100644 --- a/test/ui/feedback1b-bonds.test.js +++ b/test/ui/feedback1b-bonds.test.js @@ -3,8 +3,9 @@ // of the modes whose official modeDataDict inactiveBondIdList switches 奥术 off (with 拉特兰 阿戈尔 卡西米尔 灵巧 奇迹 投资人 // 突袭 独行 绝技), yet 深靛 洛洛 阿罗玛 夕 圣聆初雪 stay in the pool through their other bond (server pool.js) and their cards // showed 奥术 like any bond: the detail card's chip read "奥术 0/2 未激活" with three 奥术 operators deployed (the server -// leaves an inactive bond out of m.private.bonds) and the bond popup "在场 0/2 未激活". The cards, chips and popup now say -// 本局禁用 for a bond the mode never activates (gameLogic modeOffBonds over config.modes[modeId].inactiveBondIds). +// used to leave an inactive bond out of m.private.bonds) and the bond popup "在场 0/2 未激活". The cards, chips and popup +// say 本局禁用 for a bond the mode never activates (gameLogic modeOffBonds over config.modes[modeId].inactiveBondIds); +// since 0.1.3 the view also lists it (`off: true`) so the strip can draw the grey disc — still never in ps.bonds. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; @@ -63,13 +64,15 @@ test('a real 标准 match: 奥术 operators are buyable, three on the board neve const used = new Set(); for (const id of members.slice(0, 3)) { const t = legalTileFor(m, ps, id, used); used.add(tileKey(t[0], t[1])); give(m, ps, id, 'board', t); } ps.recompute(); - assert.equal(ps.bonds.arcaneShip, undefined, 'official: the mode never activates 奥术'); + assert.equal(ps.bonds.arcaneShip, undefined, 'official: the mode never activates 奥术 — not in the battle state'); const priv = ps.privateView(); - assert.equal(priv.bonds.find((b) => b.bondId === 'arcaneShip'), undefined, 'no 奥术 entry in m.private.bonds'); + const arc = priv.bonds.find((b) => b.bondId === 'arcaneShip'); + assert.ok(arc && arc.off === true && arc.active === false && arc.tier === 0 && arc.count === 3, 'the view lists the members as a grey 本局禁用 disc'); + assert.ok(priv.bonds.slice(priv.bonds.findIndex((b) => b.off)).every((b) => b.off), 'off entries come last'); const off = modeOffBonds(getMode(m.modeId)); - // before: the chip computed 0 members from the missing entry — "奥术:在场 0/2,未激活" with 3 deployed - const before = chipOf(BondChips({ bondIds: DATA.chess[members[0]].bonds, bonds: priv.bonds }), 'arcaneShip'); - assert.match(before.props.title, /在场 0\/2,未激活/); + // without the mode's off set the chip would read the new entry as an ordinary inactive bond (在场 3/3,未激活) + const bare = chipOf(BondChips({ bondIds: DATA.chess[members[0]].bonds, bonds: priv.bonds }), 'arcaneShip'); + assert.match(bare.props.title, /在场 3\/3,未激活/); const chip = chipOf(BondChips({ bondIds: DATA.chess[members[0]].bonds, bonds: priv.bonds, off }), 'arcaneShip'); assert.ok(hasClass(chip, 'is-off') && !hasClass(chip, 'is-active')); assert.equal(chip.props.title, '奥术:本局禁用(该盟约不会激活)'); diff --git a/test/ui/gameLogic.test.js b/test/ui/gameLogic.test.js index b089f727..39fd36dc 100644 --- a/test/ui/gameLogic.test.js +++ b/test/ui/gameLogic.test.js @@ -9,7 +9,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { phaseMode, phaseBanner, isCombatPhase, isBossPhase, countdownState, phaseTotalSeconds, sortBonds, bondTier, nextThreshold, - bondMembers, bannedPerBond, priceTone, mergeProgress, shopBlockReason, deploySets, indexPieces, placementContext, canPlace, + bondMembers, memberHeadCount, bannedPerBond, priceTone, mergeProgress, shopBlockReason, deploySets, indexPieces, placementContext, canPlace, boardTargets, dropIntent, normalizeDraft, normalizeSp, groupEnemies, factionTypes, snapHud, bossFrac, attackInterval, fmtNum, rangeGridBox, shortcutFor, sanitizeSettings, DEFAULT_SETTINGS, normalizeResult, cycleField, fieldLabel, homeFieldId, activeBubbles, sortedPlayers, tileKey, prepCapsuleLabel, prepCamera, dropFailureReason, @@ -138,9 +138,46 @@ describe('bonds', () => { assert.equal(byId.get(m2).owned, true, 'golden in hand counts as owned base'); assert.equal(byId.get(m2).onBoard, false); assert.equal(byId.get(m3).banned, true); + assert.equal(byId.get(m2).inHand, true, 'a golden copy in the hand marks the base in hand'); assert.equal(rows[0].id, m1, 'on-board first'); assert.equal(rows.length, b.visibleMembers.length); }); + test('memberHeadCount: the hand counts only for a bond that counts the hand, once per row', () => { + const rows = [ + { id: 'a', onBoard: true, inHand: true }, + { id: 'b', onBoard: false, inHand: true }, + { id: 'c', onBoard: false, inHand: false }, + null, + ]; + assert.equal(memberHeadCount(rows, false), 1, 'board only'); + assert.equal(memberHeadCount(rows, true), 2, 'board or hand, one row once'); + assert.equal(memberHeadCount(null, true), 0); + assert.equal(memberHeadCount(undefined), 0); + const invest = bonds.investShip; + assert.equal(invest.countsHand, true); + const [m1, m2] = invest.visibleMembers; + const priv = privWith({ + board: [{ ...piece(m1), row: 9, col: 3 }], + hand: [piece(m2)], + temp: [piece(invest.visibleMembers[2] || m2)], + }); + const got = bondMembers(invest, priv, [], getChess); + const byId = new Map(got.map((r) => [r.id, r])); + assert.equal(byId.get(m1).onBoard, true); + assert.equal(byId.get(m2).inHand, true); + assert.equal(byId.get(m2).onBoard, false); + if (invest.visibleMembers[2]) assert.equal(byId.get(invest.visibleMembers[2]).inHand, false, 'a temporary-slot copy is not in hand'); + assert.equal(memberHeadCount(got, true), 2, 'the board member and the hand member, not the temporary slot'); + assert.equal(memberHeadCount(got, false), 1, 'without countsHand the hand member is left out'); + }); + test('sortBonds puts a mode-off bond after every live bond', () => { + const sorted = sortBonds([ + { bondId: 'investShip', off: true, active: false, layers: 99, count: 3, tier: 0 }, + { bondId: 'yanShip', active: true, layers: 1, count: 3, tier: 1 }, + { bondId: 'raidShip', off: true, layers: 0, count: 1 }, + ], (id) => bonds[id]).map((b) => b.bondId); + assert.deepEqual(sorted, ['yanShip', 'investShip', 'raidShip']); + }); test('bannedPerBond counts banned visible members', () => { const b = bonds.deputShip; const per = bannedPerBond(Object.values(bonds), [b.visibleMembers[0], b.visibleMembers[1], 'nope']);