feedback3 WH: 叙拉古 6's true-damage chance rolls on every 普通伤害 hit of a member, not only on normal attacks — 荒芜拉普兰德's S3 drone bites, 德克萨斯 剑雨 and other skill hits now roll; 溅射, 持续 (the S3 per-second hit), 附加 and item procs still do not (community report 「叙拉古盟约真伤概率数值没有正确递增成长」, GitHub #79)

This commit is contained in:
sganggs committed 2026-10-04 20:08:01 +08:00
1 parent d77148962b
commit e444bc3c3f
9 files changed
+132 -12

No files matched your search

+1 -1
View File
@@ -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 rouLine truncated
{"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 rouLine truncated
+1 -1
View File
@@ -1567,7 +1567,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 直接伤害).
+1 -1
View File
@@ -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": {
+1 -1
View File
@@ -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).
+26 -3
View File
@@ -18,8 +18,8 @@
// 阿戈尔 egirShip members max HP +(base_max_hp + max_hp_per_stack·L) (直接乘算); battle start devour (see devour());
// 5: the first max_free_respawn_cnt members knocked out for the first time redeploy at once (free)
// 叙拉古 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,
@@ -451,6 +451,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);
@@ -472,7 +495,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++;
+2 -1
View File
@@ -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 {
+2 -1
View File
@@ -1381,7 +1381,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 });
+5 -3
View File
@@ -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 });
@@ -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);
});