Files
ark-stronghold-protocol/server/sim/content/kits/ops/chess_char_3_11-snhunt.js
T
sganggs 37e45e362e feedback7 R22-OSIM: 白铁's 铁钳号·原型机 counts like an enemy for a non-heal skill's automatic start; golden: unchanged
Community report relayed by the owner: 圣约送葬人 hitting 白铁's device spent no bullet and gained no layer.
Our attacks already selected the device (Battle.setAllyTarget, damage cancelled), but every skill start
condition counted enemies only, so her MANUAL ammo skill (DEFAULT) never opened. The owner's rule of
2026-10-08: a registered ally target in range counts like an enemy for a non-heal skill's auto start.

- skills.js `_allyTargetIn`: DEFAULT (about to attack, the initial range; SEARCH / ACTIVE_RANGE through
  it), CUSTOM_RANGE, SKILL_RANGE, GDGLOW_SKILL_2 (anywhere) and the content trigger ranges. Heal skills
  never count it (禁疗). It stays out of enemiesInKeys / canTargetEnemy.
- 雪猎's empty-magazine S2 cast counts it too; allyTargetsInKeys takes a Set of tile keys.
- 白铁™多功能平台 stays no target. Kits whose own selectors pick enemies (陈 S3, 艾丽妮 S2 guards,
  蕾缪安 S3 locks) are unchanged.

Tests: test/sim/feedback7-allytarget-cast.test.js (4; 3 fail on the parent).
2026-10-08 19:36:35 +08:00

77 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// server/sim/content/kits/ops/chess_char_3_11-snhunt.js — 雪猎 (char_4211_snhunt) kit, tier 3.
// Conventions of the tier-3 kits: ../shared/tier3.js; kit contract and rules: ../README.md.
import {
num, defOf, talentBb, traitBb, selectedId, altSkills, instantKindOf, alive, fx, textNum, enemiesOn,
} from '../shared/tier3.js';
export default {
// ---- 3_11 雪猎 · 猎手 — S2 风雪连弩: instant special-bullet double shot (higher vs non-moving targets), charges;
// 裂云一击: the skill also sends 裂云兽 (ATK% phys + cold); 精锐 module HUN-X: reload from empty adds extra rounds
// S1 强力击·β型: next attack ×atk_scale (a normal shot: needs a round); 裂云兽 hits the enemy it is cast on
chess_char_3_11_a: (bb, chess, def) => {
const d = defOf(chess, def);
const t0 = talentBb(d, 0);
const tb = traitBb(d);
const sel = selectedId(chess, d);
const S2 = 'skchr_snhunt_2';
const s1 = num(bb.atk_scale_1, 1), s2 = num(bb.atk_scale_2, s1);
const charges = Math.max(1, Math.floor(num(d.skill?.maxCharges, num(bb.ct, 1))));
const shots = textNum(d.skill?.description, /(\d+|[一二两三四五])连击/, 2);
const still = (e) => !!(e.blockedBy || e.s.flags.stun || e.s.flags.noMove || !e.moving);
const extra = num(tb.extra_add, 0);
return {
skill: {
kind: charges > 1 ? 'charges' : 'instant',
onStart({ battle, unit }) {
const t = enemiesOn(battle, unit, unit.rangeKeys, 1, unit.profile)[0] ?? null;
unit.mem.snTarget = t;
if (!t) return;
battle.addProjectile({
from: unit, target: t, speed: 16, visual: 'arrow', source: unit,
onHit: ({ target }) => {
if (!target || !target.alive) return;
const sc = still(target) ? s2 : s1;
for (let i = 0; i < shots && target.alive; i++) battle.dealDamage(unit, target, { amount: unit.s.atk * sc, type: 'phys', isSkill: true, tags: ['skill', 'snhunt'] });
},
});
fx(battle, 'volley', unit, { target: t.id, skill: 'snhunt_2' });
},
},
skills: altSkills(chess, d, bb, {
skchr_snhunt_1: (s) => ({ kind: instantKindOf(s), attack: { atkScale: num(s.bb.atk_scale, 1) } }),
}),
talents: [{ install(battle, unit) {
battle.on('skillStart', (ctx) => {
if (ctx.unit !== unit) return;
// S2 aims its special bullets itself (mem.snTarget); another skill is cast on the enemy about to be shot
const t = sel === S2 || sel == null ? unit.mem.snTarget : (enemiesOn(battle, unit, unit.rangeKeys, 1, unit.profile)[0] ?? null);
if (!t || !t.alive) return;
battle.dealDamage(unit, t, { amount: unit.s.atk * num(t0.atk_scale, 1), type: 'phys', isSkill: true, tags: ['talent', 'cloudbeast'] });
if (t.alive) battle.applyStatus(t, 'cold', { duration: num(t0.cold, 3), source: unit });
fx(battle, 'strike', t, { src: unit.id, talent: 'snhunt_beast' });
}, { owner: unit });
} }],
install(battle, unit) {
// special bullets (S2 only): the skill also fires while the magazine is empty (the attack loop cannot run then)
if (sel === S2 || sel == null) {
battle.on('tick', () => {
const sk = unit.skill;
if (!alive(unit) || !unit.canAct || !sk || !sk.ready || sk.opCooling || unit.s.flags.silence || (unit.trait.ammo ?? 1) > 0) return;
// (白铁's 铁钳号·原型机, an ally target, counts like an enemy — skills.js `_allyTargetIn`)
const keys = unit.baseRangeKeys || unit.rangeKeys;
if (battle.enemiesInKeys(keys, unit, unit.profile).length || battle.allyTargetsInKeys(keys, unit).length) sk.activate('DEFAULT');
}, { owner: unit });
}
if (extra > 0) {
battle.on('tick', () => {
const a = unit.trait.ammo ?? 0;
if (unit.mem.prevAmmo === 0 && a === 1) unit.trait.ammo = Math.min(Math.max(1, unit.profile.ammoMax ?? 8), a + extra);
unit.mem.prevAmmo = unit.trait.ammo;
}, { owner: unit });
}
},
};
},
};