PRTS 分支特性信息 强攻手 / 重剑手 / 推击手 "普通攻击最大目标数等于阻挡数(不会低于1)"; PRTS 作战机制 §AOE "锁定人数的无弹道AOE攻击 (例如近卫分支“强攻手”)…在抬手时选取范围内的全体目标(不超过其攻击目标上限)"; PRTS 忍冬 S3 备注 "可对空". The client's selectors of the branch traits and of every kit skill marked hitAllBlocked carry _limitedMaxTargetNumToBlockedCnt (_allowZeroBlockCntLimit off) — charpacks extracted 2026-10-06. - ai.js: hitAllBlocked no longer returns just the blocked enemies; targetCount = max(1, block count) (+ maxTargets mods) of targets from the range and the blocked enemies, blocked first. Mon3tr S3 drops maxTargets 1; 凯尔希's Mon3tr under S2 picks its targets the same way. [ASSUMED] maxTargets mods add; 忍冬 S3's range-only note not modelled. Golden: 52 scenarios, each with a hitAllBlocked attacker (probe-checked) — roster-001, -003, -004, -007, -009, -011, -013, -014, -015, -016, -020, -022, -023, -024, -030, -032, -038, -040, -041, -042, -043, -049; bond-sargonShip-high, bond-soloShip-low, bond-soloShip-high, bond-yanShip-low; boss-boss_4-solo, boss-boss_6-solo, boss-boss_7-solo, hidden-boss_9-solo, hidden-boss_10-solo; matches solo-NORMAL-1, solo-ABYSS-1, coop3-ABYSS-5, coop4-FUNNY-6, coop4-ABYSS-7, coop2-NORMAL-70-diy; diy-013, -014, -033, -034, -035, -037, -038, -039, -051, -053, -076, -078, -109, -127, -130. standins unchanged. Tests: test/sim/feedback5-block-targets.test.js (new, 2). Updated on purpose: feedback1-transform.test.js (its real round relied on 百炼嘉维尔 — a 强攻手 — falling; the ember-walks-on check is now a deterministic sub-test). test/content and test/sim pass. Docs: SIM.md centurion row, professions.js header.
49 lines
3.1 KiB
JavaScript
49 lines
3.1 KiB
JavaScript
// test/sim/feedback5-block-targets.test.js — "同时攻击阻挡的所有敌人" takes up to the block count of targets (the queued 0.2.0
|
|
// question; PRTS 分支特性信息 强攻手 / 重剑手 / 推击手 "普通攻击最大目标数等于阻挡数(不会低于1)", PRTS 作战机制 §AOE伤害判定 "锁定人数的无
|
|
// 弹道AOE攻击(例如近卫分支“强攻手”)…在抬手时选取范围内的全体目标(不超过其攻击目标上限)"; the client's selector flag
|
|
// _limitedMaxTargetNumToBlockedCnt) — server/sim/ai.js acquireTargets / targetCount (`hitAllBlocked`). Until 0.2.0 it struck
|
|
// the enemies it blocked only (one in range when it blocked none).
|
|
// Run: node --test test/sim/feedback5-block-targets.test.js
|
|
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { makeBattle, enemyRec, chessRec, checkInvariants } from '../helpers/battleHarness.js';
|
|
|
|
// a 强攻手 (block 3) whose range is its tile and the three ahead
|
|
const CENT = chessRec({ id: 't_cent', subProfessionId: 'centurion', stats: { maxHp: 1e6, atk: 100, def: 1e4, blockCnt: 3, bat: 1 }, skill: null, rangeGrid: [[0, 0], [0, 1], [0, 2], [0, 3]] });
|
|
const dummy = (key) => enemyRec({ key, hp: 1e9, speed: 0, atk: 0 });
|
|
|
|
/** The targets of its first attack, with enemies at `at` ([row, col] each). */
|
|
function firstAttack(at, setup = null) {
|
|
const h = makeBattle({
|
|
defs: { chess: { t_cent: CENT }, enemies: { e: dummy('e') } }, units: [{ chessId: 't_cent', row: 10, col: 5 }],
|
|
enemies: at.map((pos) => ({ key: 'e', pos })), content: 'none', autoFinish: false, timeLimit: 30, hooks: ['attack'], captureNoisy: true,
|
|
setup,
|
|
});
|
|
const u = h.unit('t_cent');
|
|
assert.ok(h.runUntil(() => h.hooksOf('attack').some((c) => c.attacker === u), 3));
|
|
const atk = h.hooksOf('attack').find((c) => c.attacker === u);
|
|
checkInvariants(h.b);
|
|
return { h, u, targets: atk.targets };
|
|
}
|
|
|
|
test('blocking one enemy with two more in its range: one attack strikes all three (up to its block count, the blocked one first)', () => {
|
|
const { u, targets } = firstAttack([[10, 5], [10, 6], [10, 7]]);
|
|
assert.equal(u.blocking.length, 1, 'it blocks the one on its tile');
|
|
assert.equal(targets.length, 3);
|
|
assert.equal(targets[0], u.blocking[0], 'the blocked enemy first');
|
|
});
|
|
|
|
test('blocking none: up to its block count from the range; never more than the block count; never fewer than 1', () => {
|
|
const free = firstAttack([[10, 6], [10, 7], [10, 8]]);
|
|
assert.equal(free.u.blocking.length, 0);
|
|
assert.equal(free.targets.length, 3, 'three in range, none blocked: three targets');
|
|
const crowd = firstAttack([[10, 5], [10, 6], [10, 6], [10, 7], [10, 7], [10, 8]]);
|
|
assert.equal(crowd.targets.length, 3, 'six in reach: its block count of them');
|
|
assert.ok(crowd.u.blocking.every((e) => crowd.targets.includes(e)), 'every enemy it blocks among them');
|
|
const zero = firstAttack([[10, 6], [10, 7]], (b) => {
|
|
b.on('deploy', (c) => { if (c.unit.defId === 't_cent') b.addBuff(c.unit, { key: 'test:noBlock', mods: { blockCnt: -99 } }); });
|
|
});
|
|
assert.equal(zero.targets.length, 1, 'block count 0: still one target (不会低于1)');
|
|
});
|