feedback1e WR: real-wave test counts the enemies each attack damages; AoE source wording

The act2 m01 round 10 test now checks the damage itself: every attack of
卡涅利安 S2/S3 damages each enemy on her range, under the same attack id.
SIM.md, the CASTER comment and the test header name the primary source
for the 轰击术师 (PRTS 作战机制: 伊芙利特's next-attack skill 炎爆 is a
锁定攻击范围 AoE), mark Terra Wiki as secondary for the 阵法术师 and treat
the missing PRTS 溅射半径一览 row as supporting evidence only.
This commit is contained in:
sganggs committed 2026-10-03 06:12:34 +08:00
1 parent f3a73fec6b
commit 165e7255f8
3 files changed
+30 -15

No files matched your search

+2 -2
View File
@@ -899,7 +899,7 @@ table: `hitSleep` (targets and damages sleeping enemies — "可以攻击沉睡
| closerange, underminer, primcaster, corecaster, ritualist, summoner, counsellor, pioneer, fearless, fighter, protector, guardian, primprotector, executor, duelist | plain profile (numbers from data; skills/talents via kits). underminer module: weaken 10 % ATK 2 s on hit |
| longrange | lowest DEF first |
| aoesniper / splashcaster | splash 1.1 tiles around the struck target at full damage (PRTS 溅射半径一览: 扩散术师 1.1; Arknights Terra Wiki, Splash Caster). [OPEN] the same table gives 炮手 1.0 (none in the pool) and 格雷伊 1.0 |
| blastcaster | `rangeAoe`: every selectable enemy on its line at once, the same damage near and far, instant (`'beam'`) — "超远距离的群体法术伤害" is the whole line, not a splash (PRTS 溅射半径一览 lists no splash for it; Terra Wiki, Blast Caster; PRTS 作战机制 §AOE伤害判定: 伊芙利特's 炎爆 is a 锁定攻击范围 AoE; community report E3). A stealthed enemy is not struck unless it is revealed or blocked (a 锁定范围 AoE cannot hit a 隐匿 unit, PRTS 作战机制) |
| blastcaster | `rangeAoe`: every selectable enemy on its line at once, the same damage near and far, instant (`'beam'`) — "超远距离的群体法术伤害" is the whole line, not a splash (primary: PRTS 作战机制 §AOE伤害判定 names 伊芙利特's 炎爆 a 锁定攻击范围 AoE, and 炎爆 is her next-attack skill "下次攻击造成…" (PRTS 伊芙利特 S2), so a 轰击术师 normal attack; secondary: Terra Wiki, Blast Caster; supporting: PRTS 溅射半径一览 documents no splash radius for it; community report E3). A stealthed enemy is not struck unless it is revealed or blocked (a 锁定范围 AoE cannot hit a 隐匿 unit, PRTS 作战机制) |
| bombarder | ground-only splash 1.0 + aftershock(s) at 50 % ATK (bb append_atk_scale / times). [OPEN] PRTS 溅射半径一览 gives 投掷手 0.9 |
| hunter | 8 bullets (bb value), ×1.2 ATK (bb atk_scale), reloads 1/s after 1 s without attacking; can't attack when empty |
| loopshooter | 回环射手 (user playtest #3): every attack throws a boomerang (`ai.js throwBoomerang`, projectile `'boomerang'`) out to the target at 15 tiles/s — it hits on arrival — and back to the thrower's current position at 3.75 tiles/s without damage (PRTS 跃跃 "投射物飞行速度15,返回时飞行速度3.75"); attacks only while holding it (every boomerang thrown caught — "必须回收全部回旋投掷物才可以进行下一次攻击", `unit.trait.boomerangsOut`) and with the attack cooldown ready, so the real interval is the longer of the two; a target dead mid-flight is not hit (it still flies to the last position and back); knocked out / withdrawn ⇒ lost, a redeployed thrower holds a fresh one; 跃跃 S2's extra boomerangs share the one flight (cnt hits) |
@@ -907,7 +907,7 @@ table: `hitSleep` (targets and damages sleeping enemies — "可以攻击沉睡
| chain | chain N (trait text/bb max_target) with −15 % per jump (bb chain.atk_scale), 1.8-tile jumps, sluggish on each hit. [OPEN] PRTS 溅射半径一览 gives 链术师 1.7 |
| funnel | drone damage 20 % → +15 %/hit on the same target → 110 % (bb init/delta/max) |
| mystic | stores up to 3 (bb times) attacks while idle, fires them all at once |
| phalanx | no attack & DEF +200 %, RES +20 (bb) while the skill is off; while on, `rangeAoe`: each attack strikes every selectable enemy on its range at once (blocked enemies included; a stealthed one only when revealed or blocked), the same damage near and far, instant (`'beam'`) — "群体法术伤害" (PRTS 溅射半径一览 lists no splash for it; Terra Wiki, Phalanx Caster: "attacks hit all enemies within their range"; PRTS 林 S3 备注 "单次普攻最多触发1次效果"; community report E3: it used to be one bolt + a 1.1 splash). 卡涅利安's charged S1 keeps the skill-off trait, 不攻击 included (kit `canAttack`, PRTS 备注) |
| phalanx | no attack & DEF +200 %, RES +20 (bb) while the skill is off; while on, `rangeAoe`: each attack strikes every selectable enemy on its range at once (blocked enemies included; a stealthed one only when revealed or blocked), the same damage near and far, instant (`'beam'`) — "群体法术伤害" (secondary: Terra Wiki, Phalanx Caster: "attacks hit all enemies within their range"; supporting: PRTS 林 S3 备注 "单次普攻最多触发1次效果" — one normal attack can kill several — the same 锁定攻击范围 shape as the 轰击术师, and PRTS 溅射半径一览 documents no splash radius for it (it omits the 撼地者 too, so this is not proof); no primary source states a target cap; community report E3: it used to be one bolt + a 1.1 splash). 卡涅利安's charged S1 keeps the skill-off trait, 不攻击 included (kit `canAttack`, PRTS 备注) |
| physician | heal the lowest HP% injured ally in range (a skill `targeting.maxTargets` widens any heal profile) |
| ringhealer | heal 3 allies |
| chainhealer | heal bounces 3× (−25 %, bb chain.*) within 2.5 tiles |
+6 -4
View File
@@ -302,10 +302,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 (PRTS 溅射半径一览 — which lists
// no splash for the 阵法术师 / 轰击术师 — and 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
// "群体法术伤害" names two shapes: the 扩散术师 splash 1.1 tiles around the struck target (PRTS 溅射半径一览; Arknights
// Terra Wiki, Splash Caster), while the 轰击术师 ("超远距离的群体法术伤害") and the 阵法术师 strike every enemy inside the
// attack range at once, the same damage near and far — community report E3 after 0.1.0. Primary for the 轰击术师: PRTS
// 作战机制 §AOE伤害判定 names 伊芙利特's 炎爆 a 锁定攻击范围 AoE, and 炎爆 is her next-attack skill ("下次攻击造成…",
// PRTS 伊芙利特 S2); for the 阵法术师: Terra Wiki, Phalanx Caster (secondary) and PRTS 林 S3 备注. PRTS 溅射半径一览
// documents no splash radius for either (supporting only: it omits the 撼地者 too)
splashcaster: P({ splashRadius: 1.1 }),
blastcaster: P({ rangeAoe: true }),
chain: P({ chain: { count: 3, falloff: 0.15, radius: 1.8, sluggish: 0.5 } }),
+22 -9
View File
@@ -3,10 +3,11 @@
// enemies within their range … equal damage to all enemies in range, regardless of distance"; PRTS 作战机制 §AOE伤害判定
// "对攻击范围内的每个可以被选中的敌人进行判定"; PRTS 林 S3 备注 "单次普攻最多触发1次效果" — one normal attack can kill
// several), not one target plus a 1.1-tile splash. The same holds for the 轰击术师 line ("超远距离的群体法术伤害": every
// enemy on the line — Terra Wiki Blast Caster; PRTS 作战机制: 伊芙利特's 炎爆 is a 锁定攻击范围 AoE), while the 扩散术师
// "群体法术伤害" stays a splash of 1.1 tiles around the struck target (PRTS 溅射半径一览 — no row for the 阵法术师 /
// 轰击术师 — and Terra Wiki Splash Caster). Real battles with the real chess (every selectable attacking skill, normal +
// elite), counting the enemies each attack damages. Her kit per PRTS 卡涅利安 备注: a charged S1 keeps the skill-off trait
// enemy on the line — PRTS 作战机制: 伊芙利特's 炎爆, her next-attack skill, is a 锁定攻击范围 AoE; Terra Wiki Blast
// Caster), while the 扩散术师 "群体法术伤害" stays a splash of 1.1 tiles around the struck target (PRTS 溅射半径一览, which
// documents no splash radius for the 阵法术师 / 轰击术师 — supporting only — and Terra Wiki Splash Caster). Real
// battles with the real chess (every selectable attacking skill, normal + elite), counting the enemies each attack
// damages. Her kit per PRTS 卡涅利安 备注: a charged S1 keeps the skill-off trait
// (不攻击 + the guard), the charged S3 mark stacks before the damage and is one buff per enemy (the setter's bonus); a
// 流形 copy takes no attack shape ('beam' → bolt); `rangeAoe` from any source means every enemy in range, instant.
import { test } from 'node:test';
@@ -128,7 +129,7 @@ test('E3 audit: a 扩散术师 still splashes 1.1 tiles around its target — no
}
});
test('E3 real stage + real wave: 卡涅利安 targets every enemy on her range with each attack (act2 m01, round 10)', () => {
test('E3 real stage + real wave: 卡涅利安 targets AND damages every enemy on her range with each attack (act2 m01, round 10)', () => {
const data = getData({ log: { warn() {}, error() {}, info() {} } });
const mode = data.config.modes.mode_multi_normal;
const round = '10';
@@ -150,19 +151,31 @@ test('E3 real stage + real wave: 卡涅利安 targets every enemy on her range w
});
const u = h.unit(id);
const rows = [];
// (beforeAttack, after every content hook: the targets of the attack and the enemies on her range at that moment)
const hit = new Map(); // attackId → the enemies its damage reached
// (beforeAttack, after every content hook: the targets of the attack and the enemies on her range at that moment;
// the attack that follows takes the next attackId)
h.b.on('beforeAttack', (c) => {
if (c.attacker !== u) return;
const p = effectiveProfile(u);
const want = new Set(h.b.enemiesInKeys(u.rangeKeys, u, p));
for (const e of h.b.blockedTargets(u, p)) want.add(e);
rows.push({ got: c.targets.length, want: want.size, all: [...want].every((e) => c.targets.includes(e)) });
rows.push({ attackId: h.b._attackSeq + 1, got: c.targets.length, want, all: [...want].every((e) => c.targets.includes(e)) });
}, { priority: -2000 });
h.b.on('damaged', (c) => {
if (c.source !== u || !c.dmg?.isAttack) return;
if (!hit.has(c.dmg.attackId)) hit.set(c.dmg.attackId, new Set());
hit.get(c.dmg.attackId).add(c.target);
}, { priority: -2000 });
h.runToEnd(rc.combatTimeLimit + 5);
assert.equal(h.b.errors.length, 0, JSON.stringify(h.b.errors[0]));
const crowded = rows.filter((r) => r.want >= 3);
const crowded = rows.filter((r) => r.want.size >= 3);
assert.ok(crowded.length >= 1, `S${skillIndex + 1}: attacks into a crowd (${crowded.length}/${rows.length})`);
for (const r of rows) assert.ok(r.all && r.got === r.want, `S${skillIndex + 1}: ${r.got} targets of ${r.want} enemies on her range`);
for (const r of rows) {
assert.ok(r.all && r.got === r.want.size, `S${skillIndex + 1}: ${r.got} targets of ${r.want.size} enemies on her range`);
// the damage itself: one instant hit on every one of them, in the same attack (no projectile, no splash)
const got = hit.get(r.attackId) ?? new Set();
assert.ok(got.size === r.want.size && [...r.want].every((e) => got.has(e)), `S${skillIndex + 1}: attack ${r.attackId} damaged ${got.size} of the ${r.want.size} enemies on her range`);
}
}
});