feedback1e WR: 阵法术师 / 轰击术师 strike every enemy in range (卡涅利安 E3)
Community report E3 "卡涅利安的攻击不是真群攻" was real: the phalanx trait "技能开启时攻击造成群体法术伤害" was read as one bolt at the priority target plus a 1.1-tile splash, so spread enemies took one hit per attack (act2 m01, round 10: 2.3 of 12.4 enemies on her range per attack, never all). Officially a 阵法术师 attack hits every enemy inside the attack range at once, the same damage near and far (Arknights Terra Wiki, Phalanx Caster; PRTS 林 S3 note; PRTS 作战机制 AOE), and so does the 轰击术师 line (Terra Wiki, Blast Caster; PRTS 作战机制: 伊芙利特's 炎爆 is a range-locked AoE). The 扩散术师 keep their 1.1-tile splash around the target. - professions.js: phalanx and blastcaster get allInRange + rangeAoe (instant 'beam' hits, no projectile) instead of the 1.1 splash. - 卡涅利安 S3 食噬之印: ATK climbs in 1 s steps to the full bonus at 20 s (PRTS note) instead of continuously over the 21 s duration. - fx.js: phalanx / blastcaster leave the splash-ring list. - Tests: real battles counting damaged enemies per attack for every phalanx skill, both blast casters, a splash-caster guard, a real stage and wave, the S3 ramp; opt-in headless-Chrome check of the strikes. - SIM.md profession rows and kit comments updated.
This commit is contained in:
1 parent
7f134737ce
commit
27181d88bd
8 files changed
+332
-25
No files matched your search
@@ -768,10 +768,11 @@ const KITS = {
|
||||
return kit;
|
||||
},
|
||||
|
||||
// ---- 3_08 薄绿 · 阵法术师 — S2 聚能涡旋: each hit pushes the target towards her (splash arts), end-of-skill burst on
|
||||
// ---- 3_08 薄绿 · 阵法术师 — S2 聚能涡旋: each attack strikes every enemy on her range (the trait's 群体法术伤害) and
|
||||
// pushes each one towards her, end-of-skill burst on
|
||||
// every enemy in range; 地质学者: DEF aura (skill off) / less likely targeted (skill on);
|
||||
// 精锐 module PLX-X: keeps part of the guard (DEF/RES) while the skill runs
|
||||
// S1 风语: wider range (skill grid), attacks at attack@atk_scale (群体 arts splash of the trait). Auto-cast: the data
|
||||
// S1 风语: wider range (skill grid), attacks every enemy on it at attack@atk_scale. Auto-cast: the data
|
||||
// rule SEARCH is the 阵法术师 row (PRTS 卫戍协议/帮助 "不受基础策略影响,在初始攻击范围内存在敌人时释放技能"; it
|
||||
// covers every MANUAL skill of the class — user playtest #6) = an enemy inside her INITIAL range — the engine's
|
||||
// DEFAULT rule, checked every tick for a unit that does not attack while its skill is off — not any enemy on the
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
// groupId `abyssal` (data/chess.json has no groupId: charIds from docs/research/03-operators.json).
|
||||
// - "友方干员" effects touch operators only (summons/devices excluded); SP gifts skip units whose timed skill runs
|
||||
// (AK: no SP gain during a skill — the engine's gainSp enforces it too; the kits skip such units when picking).
|
||||
// - On-hit statuses of AoE skill attacks (卡涅利安) apply to every enemy the attack damages (a SkillSpec
|
||||
// `attack.onHit` only sees the main target), via a `damaged` hook.
|
||||
// - On-hit statuses of 卡涅利安's attacks apply to every enemy the attack damages — the 阵法术师 trait strikes every
|
||||
// enemy on her range at once (professions.js `allInRange`, community report E3) — via a `damaged` hook.
|
||||
// - Dodge from a skill that adds to other dodge sources (焰尾 S3) is rolled independently in a `hit` hook, so the
|
||||
// sources combine as 1 − Π(1 − p) (the same rule the engine now applies to stacked dodge mods).
|
||||
// - Operator loadouts (DESIGN §16): every selectable non-default skill of the 22 visible chess is authored in the kit's
|
||||
@@ -37,6 +37,8 @@ const AURA = 0.2; // aura refresh period (s)
|
||||
const AURA_DUR = 0.25; // aura buff lifetime (s): lapses ~1 tick after the source stops refreshing it
|
||||
const ABYSSAL = new Set(['char_143_ghost', 'char_263_skadi', 'char_474_glady', 'char_4145_ulpia', 'char_1023_ghost2']);
|
||||
const LINE = Object.freeze(Array.from({ length: COLS }, (_, i) => Object.freeze([0, i])));
|
||||
/** 卡涅利安 S3 食噬之印: the ATK bonus climbs in 1 s steps over 20 s (PRTS 备注; the blackboard has no ramp time). */
|
||||
const BILLRO_S3_RAMP = 20;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
// helpers
|
||||
@@ -834,7 +836,7 @@ const kits = {
|
||||
kind: instantKind(def),
|
||||
attack: {
|
||||
atkScale: num(bb.atk_scale, 1.5),
|
||||
onEachHit({ battle, unit, target }) { // every victim of the blast (main + splash) that flies
|
||||
onEachHit({ battle, unit, target }) { // every enemy of her line the blast strikes that flies
|
||||
if (target && target.alive && target.isFlying) battle.dealDamage(unit, target, { amount: unit.s.atk * num(bb.atk_scale_to_fly, 0.55), type: 'arts', isSkill: true, tags: ['skill', 'antiAir'] });
|
||||
},
|
||||
},
|
||||
@@ -1712,11 +1714,12 @@ const kits = {
|
||||
};
|
||||
},
|
||||
|
||||
// ===== 卡涅利安 (phalanx) S2 沙缚镣锁 — faster AoE, 0.3 s sluggish; charged: ATK +10 % and bind; talents
|
||||
// ===== 卡涅利安 (phalanx) S2 沙缚镣锁 — faster attacks on every enemy in range (the trait's 群体法术伤害), 0.3 s
|
||||
// sluggish on each; charged: ATK +10 % and bind; talents
|
||||
// S1 沙暴守卫 (SEARCH: ATK/DEF up; charged — cast with every charge stored — the trait's DEF/RES guard stays on);
|
||||
// S3 食噬之印 (wider range, ATK ramps to +140 %/+200 % over the skill; charged: every hit marks the target, +20 %
|
||||
// damage from her per mark, ≤ 5, until the skill ends). Talent 生命之餐 heals on every skill; module PLX-X keeps
|
||||
// part of the guard during any skill, PLX-Y (乡音): +3 % damage per enemy in range (≤ 5)
|
||||
// S3 食噬之印 (wider range, ATK +0 % → +140 %/+200 % in 1 s steps over 20 s — PRTS 备注; charged: every hit marks
|
||||
// its target, +20 % damage from her per mark, ≤ 5, until the skill ends). Talent 生命之餐 heals on every skill;
|
||||
// module PLX-X keeps part of the guard during any skill, PLX-Y (乡音): +3 % damage per enemy in range (≤ 5)
|
||||
chess_char_4_24_a: (bb, chess, def) => {
|
||||
const t0 = tbb(def, 0), t1 = tbb(def, 1), mb = moduleBb(def);
|
||||
const tb = def.traitBb || {};
|
||||
@@ -1748,10 +1751,11 @@ const kits = {
|
||||
battle.addBuff(unit, { key: 'billro:s3atk', mods: { atkPct: 0 } });
|
||||
battle.fx('devour', { x: unit.x, y: unit.y, id: unit.id });
|
||||
},
|
||||
onTick({ unit, skill, dt }) { // 攻击力逐渐增至+N% (linear over the skill duration)
|
||||
onTick({ unit, dt }) { // 攻击力逐渐增至+N%: PRTS 备注 "从+0%开始在20秒内线性增加,攻击力每1秒更新1次"
|
||||
unit.mem.billroRamp = (unit.mem.billroRamp ?? 0) + dt;
|
||||
const steps = Math.min(BILLRO_S3_RAMP, Math.floor(unit.mem.billroRamp + 1e-9));
|
||||
const b = unit.findBuff('billro:s3atk');
|
||||
if (b) { b.mods = { atkPct: num(bb.atk) * Math.min(1, unit.mem.billroRamp / Math.max(0.1, skill.duration)) }; unit.markDirty(); }
|
||||
if (b && b.mods.atkPct !== num(bb.atk) * steps / BILLRO_S3_RAMP) { b.mods = { atkPct: num(bb.atk) * steps / BILLRO_S3_RAMP }; unit.markDirty(); }
|
||||
},
|
||||
onEnd({ battle, unit }) {
|
||||
battle.removeBuff(unit, 'billro:s3atk');
|
||||
@@ -1817,8 +1821,7 @@ const kits = {
|
||||
}, { owner: unit });
|
||||
}
|
||||
if (!S2) return;
|
||||
// "每次攻击对目标造成0.3秒停顿" (charged: 束缚): every enemy damaged by her AoE skill attack — the splash victims
|
||||
// too (a SkillSpec attack.onHit only sees the main target)
|
||||
// "每次攻击对目标造成0.3秒停顿" (charged: 束缚): every enemy her attack damages — each one on her range
|
||||
battle.on('damaged', (c) => {
|
||||
const e = c.target;
|
||||
if (c.source !== unit || !c.dmg || !c.dmg.isAttack || e.side !== 'enemy' || !e.alive || !skillActive(unit)) return;
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
// data fields (dmgType/attackKind/projectile/canHitFly/targetPriority from data/chess.json) → kit.trait overrides.
|
||||
// Profile fields:
|
||||
// attack 'melee'|'ranged' dmgType 'phys'|'arts'|'true'|'heal'|'none'
|
||||
// projectile 'none'|'arrow'|'bolt'|'bomb'|'lob'|'orb'|'drone'|'boomerang' ('boomerang': out to the target and back to
|
||||
// the thrower, ai.js throwBoomerang) boomerang bool (回环射手: keeps 'boomerang')
|
||||
// projectile 'none'|'beam'|'arrow'|'bolt'|'bomb'|'lob'|'orb'|'drone'|'boomerang' ('beam': an instant hit drawn as a
|
||||
// line; 'boomerang': out to the target and back to the thrower, ai.js throwBoomerang)
|
||||
// boomerang bool (回环射手: keeps 'boomerang')
|
||||
// canHitFly bool maxTargets n (≥1) hitAllBlocked bool (attack every blocked enemy)
|
||||
// allInRange bool splashRadius tiles splashScale (× damage for splash victims)
|
||||
// allInRange bool (every enemy on the range at once) splashRadius tiles (around the struck target)
|
||||
// rangeAoe bool (a 锁定攻击范围 AoE without a projectile: allInRange, instant 'beam' hits)
|
||||
// splashScale (× damage for splash victims)
|
||||
// splashOthersOnly bool groundOnly bool hits n (damage instances per attack)
|
||||
// chain {count, falloff, radius, sluggish} heal {mode:'single'|'multi'|'chain', count, falloff, farMul, elementHealRatio}
|
||||
// priority 'fly'|'lowDef'|'ranged'|'lowestHp'|'highestHp'|'nearest'|'farthest'|'notBurst'|null
|
||||
@@ -297,8 +300,12 @@ export const SUB = Object.freeze({
|
||||
return front ? (unit.profile.frontScale ?? 1.5) : 1;
|
||||
} }),
|
||||
// --- CASTER
|
||||
// "群体法术伤害" names two shapes: the 扩散术师 splash 1.1 tiles around the struck target (Arknights Terra Wiki, Splash
|
||||
// Caster), while the 轰击术师 ("超远距离的群体法术伤害") and the 阵法术师 strike every enemy inside the attack range at
|
||||
// once, the same damage near and far (Terra Wiki, Blast / Phalanx Caster; PRTS 作战机制 §AOE伤害判定: 伊芙利特's 炎爆 is a
|
||||
// 锁定攻击范围 AoE) — community report E3 after 0.1.0
|
||||
splashcaster: P({ splashRadius: 1.1 }),
|
||||
blastcaster: P({ splashRadius: 1.1, projectile: 'bomb' }),
|
||||
blastcaster: P({ allInRange: true, rangeAoe: true }),
|
||||
chain: P({ chain: { count: 3, falloff: 0.15, radius: 1.8, sluggish: 0.5 } }),
|
||||
funnel: P({ projectile: 'drone', install: installFunnel,
|
||||
dmgMul: (battle, unit, target) => {
|
||||
@@ -309,7 +316,7 @@ export const SUB = Object.freeze({
|
||||
} }),
|
||||
mystic: P({ install: installMystic,
|
||||
hitsFn: (battle, unit) => { const n = 1 + (unit.trait.stored ?? 0); unit.trait.stored = 0; return n; } }),
|
||||
phalanx: P({ noAttackUnlessSkill: true, splashRadius: 1.1, install: installPhalanx }),
|
||||
phalanx: P({ noAttackUnlessSkill: true, allInRange: true, rangeAoe: true, install: installPhalanx }),
|
||||
primcaster: P({}),
|
||||
corecaster: P({}),
|
||||
// --- MEDIC
|
||||
@@ -476,6 +483,10 @@ export function resolveProfile(def, kitTrait = null) {
|
||||
// a boomerang thrower (回环射手) always throws its boomerang: the data's generic ranged projectile ('arrow', a
|
||||
// build-data default) would turn the out-and-back flight into a plain shot
|
||||
if (p.boomerang && p.attack === 'ranged') p.projectile = 'boomerang';
|
||||
// a 锁定攻击范围 AoE (阵法术师, 轰击术师) has no projectile: every enemy on the range is struck at the same moment
|
||||
// ('beam' = instant hits, drawn as a line to each victim — PRTS 作战机制 "在攻击前摇结束时选取范围内的全体目标,同时
|
||||
// 造成伤害"); the data's generic ranged projectile ('bolt') would land them one by one
|
||||
if (p.rangeAoe && p.attack === 'ranged') p.projectile = 'beam';
|
||||
if (def.type === 'token') {
|
||||
if (p.dmgType === 'heal') p.heal = p.heal || { mode: 'single' };
|
||||
if (def.stats.atk <= 0) p.noAttack = true;
|
||||
|
||||
Reference in new issue
Block a user