Fix: 深巡 / 雷蛇 S2 fire with an enemy in range, not only when hit
Both 哨戒铁卫 S2s (深巡 行动能力剥夺, 雷蛇 反击电弧) are OFFENSIVE skills but waited for a hit: the official 技能策略 row `TANK | | | 0 | TAKE_DAMAGE` is documented for skillIndex 0, and reading it as a wildcard for every index handed TAKE_DAMAGE to these two skillIndex-1 skills (issue #4). The mode's rule (docs/research/03-operators.md §1.4, quoting the in-game help) is "offensive skills activate when an enemy is in their skill range; defensive skills activate when the unit is receiving damage", so both take the basic strategy instead. - kits/tier1.js: `trigger: 'DEFAULT'` on 深巡's default S2 and on 雷蛇's. Only the rule changes — spCost / initSp / spType still come from data. The defensive S1s (深巡 侵袭破坏应对, 雷蛇 充能防御) keep theirs. - tests: the two 雷蛇 tests that pinned the hit-gated cast now assert the basic strategy, and their enemy stands two tiles away so it never touches her; 深巡's test drops its forced dealDamage hit; a new test covers all four records (normal + elite of both). node --test: 2888 tests, 2871 pass, 0 fail, 17 skipped.
This commit is contained in:
1 parent
7f134737ce
commit
60db22ed67
3 files changed
+35
-6
No files matched your search
@@ -673,11 +673,12 @@ test('1_20 雷蛇 反击电弧: attack interval +70 % of the base (PRTS 增大(+
|
||||
for (const id of pair('20')) {
|
||||
const bb = raw(id).skill.bb;
|
||||
assert.equal(raw(id).skill.skillId, 'skchr_liskam_2');
|
||||
// 重装 S2: TAKE_DAMAGE (the enemy has to hit her)
|
||||
const h = run({ defs: { enemies: { e: dummy('e', { atk: 300, bat: 1 }) }, chess: noGarrison(id) }, units: [{ chessId: id, row: 9, col: 4, carryState: READY }], enemies: [{ key: 'e', pos: [9, 4] }] });
|
||||
// 重装 S2 反击电弧 is an OFFENSIVE skill: the basic strategy casts it with an enemy in the skill range (issue #4) —
|
||||
// the enemy here stands two tiles ahead and, being a speed-0 dummy, never touches her
|
||||
const h = run({ defs: { enemies: { e: dummy('e', { atk: 300, bat: 1 }) }, chess: noGarrison(id) }, units: [{ chessId: id, row: 9, col: 4, carryState: READY }], enemies: [{ key: 'e', pos: [9, 6] }] });
|
||||
const u = h.unit(id);
|
||||
assert.ok(h.runUntil(() => u.skill.active, 5));
|
||||
assert.equal(started(h, u)[0].reason, 'TAKE_DAMAGE');
|
||||
assert.equal(started(h, u)[0].reason, 'DEFAULT');
|
||||
approx(u.s.interval, u.base.bat * (1 + bb.base_attack_time) * 100 / u.s.aspd, `${id} interval ×${1 + bb.base_attack_time}`);
|
||||
h.runUntil(() => !u.skill.active, 30);
|
||||
approx(u.s.interval, u.base.bat * 100 / u.s.aspd, 'restored');
|
||||
|
||||
@@ -132,9 +132,11 @@ test('1_04 深巡: fin darts pierce attack@max_target enemies on the line + 1 s
|
||||
});
|
||||
const u = h.unit(id);
|
||||
h.step();
|
||||
h.b.dealDamage(h.enemies()[0], u, { amount: 10, type: 'phys' }); // 重装: TAKE_DAMAGE
|
||||
// 技能策略 (issue #4): an enemy inside her initial 2-2 range is enough — the basic strategy casts it, no hit required
|
||||
assert.equal(u.skill.rule, 'DEFAULT', '行动能力剥夺 is an offensive ranged skill, not a 重装 TAKE_DAMAGE one');
|
||||
h.run(3.5);
|
||||
assert.ok(u.skill.active);
|
||||
assert.equal(h.hooksOf('skillStart').find((c) => c.unit === u).reason, 'DEFAULT', 'cast by the basic strategy');
|
||||
approx(u.s.atk, u.base.atk * (1 + bb.atk));
|
||||
const firstAtk = h.hooksOf('attack').find((c) => c.attacker === u && c.isSkill);
|
||||
assert.equal(firstAtk.targets.length, bb['attack@max_target'], 'hits every enemy of the line');
|
||||
@@ -147,6 +149,20 @@ test('1_04 深巡: fin darts pierce attack@max_target enemies on the line + 1 s
|
||||
done(h);
|
||||
});
|
||||
|
||||
test('1_04 深巡 / 1_20 雷蛇 S2 技能策略: both 哨戒铁卫 S2s cast with an enemy in range, no hit needed (issue #4)', () => {
|
||||
// both S2s are offensive (深巡: range up + ATK/ASPD + piercing darts; 雷蛇: ATK +125 % + arts on 3 + stun), and the
|
||||
// mode's rule is "offensive skills activate when an enemy is in their skill range". The 重装 TAKE_DAMAGE row is
|
||||
// documented for skillIndex 0 only — reading it as a wildcard made both wait for a hit.
|
||||
for (const id of ['chess_char_1_04_a', 'chess_char_1_04_b', 'chess_char_1_20_a', 'chess_char_1_20_b']) {
|
||||
const h = run({ units: [{ chessId: id, row: 9, col: 4, carryState: READY }], enemies: [{ key: 'e', pos: [9, 6] }] });
|
||||
const u = h.unit(id);
|
||||
assert.equal(u.skill.rule, 'DEFAULT', `${id}: an offensive skill, not the 重装 TAKE_DAMAGE row`);
|
||||
assert.ok(h.runUntil(() => u.skill.activations >= 1, 5), `${id}: casts while an enemy is in range and untouched`);
|
||||
assert.equal(h.hooksOf('skillStart').find((c) => c.unit === u).reason, 'DEFAULT', `${id}: cast by the basic strategy`);
|
||||
done(h);
|
||||
}
|
||||
});
|
||||
|
||||
test('1_04 深巡 / 1_20 雷蛇 elite module: stealthed enemies inside the range are revealed', () => {
|
||||
for (const id of ['chess_char_1_04_b', 'chess_char_1_20_b']) {
|
||||
const h = run({ defs: { enemies: { e: dummy('e') } }, units: [{ chessId: id, row: 9, col: 4 }], enemies: [{ key: 'e', pos: [9, 6] }] });
|
||||
@@ -590,7 +606,7 @@ test('1_20 雷蛇: 反击电弧 arts on up to 3 enemies, self-stun `stun` s afte
|
||||
const u = h.unit(id);
|
||||
h.run(3);
|
||||
assert.ok(u.skill.active);
|
||||
assert.equal(h.hooksOf('skillStart').find((c) => c.unit === u).reason, 'TAKE_DAMAGE', '重装: cast by the hit');
|
||||
assert.equal(h.hooksOf('skillStart').find((c) => c.unit === u).reason, 'DEFAULT', 'an offensive skill: cast with an enemy in range');
|
||||
approx(u.s.atk, u.base.atk * (1 + bb.atk));
|
||||
approx(u.s.interval, u.base.bat * (1 + bb.base_attack_time) * 100 / u.s.aspd, 'attack interval +70 % (PRTS 增大(+70%): a ratio, not +0.7 s)');
|
||||
const a0 = h.hooksOf('attack').find((c) => c.attacker === u && c.isSkill);
|
||||
|
||||
Reference in new issue
Block a user