tools/build-data.mjs resolveTrigger: a MANUAL operator skill on DEFAULT (no row, or a DEFAULT entry of the deviation
tables) or on the SEARCH row ("在初始攻击范围内存在敌人时释放技能": 解放者 / 阵法术师 / 安洁莉娜 — ACTIVE_RANGE_OVER) whose
running range strictly contains its own is ACTIVE_RANGE on that range, rawRule the official row; validateAll accepts a
DEFAULT deviation resolved to ACTIVE_RANGE (chess and stand-in tables) and ACTIVE_RANGE over SEARCH. Data rebuilt
offline, JSON-compared: only skills[].trigger rule / customRangeGrid of 薄绿 S1 (x-2), 蜜蜡 S1 (x-2), 卡涅利安 S3 (x-2),
玛恩纳 S2 (2-3), 安洁莉娜 S3 (y-4) — rawRule SEARCH — and 深巡 S2 (3-2, rawRule TAKE_DAMAGE), normal + elite (32
leaves); backups.json unchanged. Kits: 薄绿 S1 drops its DEFAULT trigger and 深巡 S2 PR #12's DEFAULT line, both read the
data now (雷蛇 S2 keeps PR #12's line). The sim needs no change (SEARCH was the DEFAULT condition on the initial range
every tick; ACTIVE_RANGE is the same on the running range). Docs: DESIGN §5.6 and the §21.20 flip row, DATA, SIM,
PLAYING, kits README, shared tier comments, skills.js header.
Tests: data (78 records / 39 skills, the five from SEARCH, the SEARCH skills that stay), feedback5-active-range (安洁莉娜
S3 on its y-4, S2 keeps SEARCH), feedback1-tank-triggers and kits_t1t2 (深巡 S2 on its 3-2, before any hit), kits_alt_t3
(薄绿 S1 on its x-2), feedback1f-fence (the idle measure uses the interval of the cooldown still running: the S2 now casts
between two attacks), docs-consistency (one PR #12 kit line left).
Golden: roster-001 / 002 (深巡), roster-016 / 044 (玛恩纳, 安洁莉娜), roster-026 / 027 (薄绿), roster-041 / 042 (卡涅利安),
bond-egirShip-low / bond-suntShip-high (深巡), boss-boss_2-pair / boss-boss_6-pair (玛恩纳, 安洁莉娜), matches solo-NORMAL-1,
coop2-NORMAL-3, coop4-FUNNY-6, coop2-NORMAL-8-serverrun — each fields one of the six skills, which now casts when an
enemy enters its running range.
47 lines
3.2 KiB
JavaScript
47 lines
3.2 KiB
JavaScript
// server/sim/content/kits/ops/chess_char_1_04-udflow.js — 深巡 (char_4137_udflow) kit, tier 1.
|
|
// Conventions of the tier-1 kits: ../shared/tier1.js; kit contract and rules: ../README.md.
|
|
|
|
import { num, talentBb, moduleOn, installReveal, skillBbOf } from '../shared/tier1.js';
|
|
|
|
export default {
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// 1_04 深巡 行动能力剥夺: longer line range (skill grid), ATK +atk, ASPD +attack_speed, fin darts pierce
|
|
// attack@max_target enemies on the line and cause attack@sluggish s of 停顿.
|
|
// 技能策略 (DESIGN §21.29, PR #12): the official 下半 class row hands every MANUAL 重装 skill TAKE_DAMAGE, which makes a
|
|
// 2-2 ranged 哨戒铁卫 wait until something hits her — in practice until she blocks (GitHub issue #4). By the owner's
|
|
// deliberate deviation from that row (2026-10-03, community feedback) this offensive ranged skill takes the basic
|
|
// strategy (tools/build-data.mjs TRIGGER_DEVIATIONS: DEFAULT, rawRule keeps the official TAKE_DAMAGE), and since 0.2.0
|
|
// the owner's ACTIVE_RANGE rule on top of it (2026-10-05): its running range 3-2 strictly contains her 2-2, so it casts
|
|
// as soon as an enemy is inside the 3-2 — the data rule (rule ACTIVE_RANGE, customRangeGrid the 3-2), which this spec
|
|
// reads (PR #12's DEFAULT line is gone: it would have kept the 2-2).
|
|
// 细胞活性抑制剂: attacks inflict `damage` arts per `interval` s for `duration` s (damage_seamonster vs 【海怪】).
|
|
// Elite module (SPT-X): stealth of enemies inside the range is cancelled.
|
|
// Alternate S1 侵袭破坏应对 (重装 ⇒ TAKE_DAMAGE trigger from data): ATK +atk, DEF +def.
|
|
chess_char_1_04_a: (bb, chess, def) => {
|
|
const t = talentBb(chess, 0);
|
|
const s1 = skillBbOf(chess, 'skchr_udflow_1');
|
|
return {
|
|
skill: {
|
|
kind: 'duration', mods: { atkPct: num(bb.atk), aspd: num(bb.attack_speed) },
|
|
targeting: { rangeGrid: def?.skill?.rangeGrid ?? null, maxTargets: num(bb['attack@max_target'], 1) },
|
|
attack: { onHitStatus: { key: 'sluggish', duration: num(bb['attack@sluggish'], 1) } },
|
|
},
|
|
skills: { skchr_udflow_1: { kind: 'duration', mods: { atkPct: num(s1.atk), defPct: num(s1.def) } } },
|
|
talents: [{ install(battle, unit) {
|
|
const dur = num(t.duration), iv = num(t.interval, 1);
|
|
if (!(dur > 0) || !(num(t.damage) > 0)) return;
|
|
battle.on('damaged', (ctx) => {
|
|
if (ctx.source !== unit || !ctx.dmg?.isAttack || ctx.target.side !== 'enemy' || !ctx.target.alive) return;
|
|
const sea = (ctx.target.def?.tags || []).includes('seamonster');
|
|
const amount = sea ? num(t.damage_seamonster, num(t.damage) * 2) : num(t.damage);
|
|
battle.addBuff(ctx.target, {
|
|
key: `udflow:dot:${unit.id}`, duration: dur, interval: iv, refresh: 'extend', source: unit, visible: false,
|
|
onTick: ({ battle: b, unit: e }) => b.dealDamage(unit, e, { amount, type: 'arts', canDodge: false, tags: ['dot'] }),
|
|
});
|
|
}, { owner: unit });
|
|
} }],
|
|
install(battle, unit) { if (moduleOn(chess) && chess.isGolden) installReveal(battle, unit); },
|
|
};
|
|
},
|
|
};
|