Pure move: every line of a kit, of a helper and of the tier headers is copied verbatim (only the headers' first
line names the new file); a helper used by one kit moved into that kit's file. Glue only: the generated imports,
`export default { … }` around each registry entry, `export { … }` lists in shared/tier2..6.js, and tier4's
`(bb, chess, def)` default-argument wrapper as shared/tier4.js `withDefaults` (applied in each tier-4 kit file).
kits/index.js loads every kit file with a guarded dynamic import (browser-safe, no directory listing); tierN.js
re-export the tier registry (TIER_KITS) and their old named exports (tier1 helpers + tinmanKit, tier6
PITHST_ELEMENTS). The merged registry, every tier default and named export have the same keys, order, frozenness
and function sources as before. test/docs-consistency.test.js reads the moved code at its new paths.
Golden: GOLDEN_FULL=1 node --test test/golden.test.js unchanged.
82 lines
4.6 KiB
JavaScript
82 lines
4.6 KiB
JavaScript
// server/sim/content/kits/ops/chess_char_1_20-liskam.js — 雷蛇 (char_107_liskam) kit, tier 1.
|
||
// Conventions of the tier-1 kits: ../shared/tier1.js; kit contract and rules: ../README.md.
|
||
|
||
import {
|
||
num, talentBb, talentGrid, moduleOn, up, hurtSpDamage, giveSp, onDamagedOn, alliesInGridOf, statBuff, installReveal,
|
||
skillBbOf,
|
||
} from '../shared/tier1.js';
|
||
|
||
export default {
|
||
// ---------------------------------------------------------------------------------------------------------------
|
||
// 1_20 雷蛇 反击电弧 (hurt SP): attack interval ×(1 + base_attack_time) (PRTS "攻击间隔增大(+70%)": a RATIO for this skill,
|
||
// 1.2 → 2.04 s — not +0.7 s), ATK +atk, arts attacks on up to attack@max_target enemies,
|
||
// attack@buff_prob to stun attack@stun s; afterwards 雷蛇 is stunned `stun` s.
|
||
// 技能策略 → DEFAULT (PR #12; DESIGN §21.29): 反击电弧 is an offensive skill (ATK +125 %, arts hits on up to 3 enemies,
|
||
// stun); the official 下半 TANK row (TAKE_DAMAGE for every MANUAL 重装 skill) made it — and 深巡's S2 — wait for a hit
|
||
// (GitHub issue #4). The owner's deliberate deviation from that row (2026-10-03, community feedback) gives both
|
||
// 哨戒铁卫 S2s the basic strategy; the data says DEFAULT too (rawRule keeps the official TAKE_DAMAGE).
|
||
// 战术防御: when attacked, +sp SP to herself and to one random ally in the talent grid. Elite 雷抗: RES +magic_resistance.
|
||
// Elite module (SPT-X): stealth of enemies inside the range is cancelled.
|
||
// Alternate S1 充能防御 (AUTO, hurt SP, "技能自动开启" — an AUTO skill takes no 技能策略: SP_FULL, so the hit that fills SP
|
||
// sets it off): PRTS "技能拥有8s的持续时间": for bb.duration s DEF +def, and the next damage instance taken is blocked
|
||
// (cancelled — a blocked hit "导致第一天赋无法触发": no 战术防御 SP, no hurt SP).
|
||
chess_char_1_20_a: (bb, chess) => {
|
||
const t = talentBb(chess, 0);
|
||
const grid = talentGrid(chess, 0);
|
||
const S1 = 'skchr_liskam_1';
|
||
const b1 = skillBbOf(chess, S1);
|
||
const blockKey = 'liskam:block';
|
||
return {
|
||
skills: {
|
||
[S1]: {
|
||
kind: 'duration', duration: num(b1.duration, 8), mods: { defPct: num(b1.def) }, trigger: 'SP_FULL',
|
||
onStart({ battle, unit, skill }) {
|
||
battle.addBuff(unit, { key: blockKey, duration: skill.duration + 0.05, tags: ['skill'], visible: true });
|
||
battle.fx('shield', { x: unit.x, y: unit.y, id: unit.id });
|
||
},
|
||
onEnd({ battle, unit }) { battle.removeBuff(unit, blockKey); },
|
||
},
|
||
},
|
||
install(battle, unit) {
|
||
if (moduleOn(chess) && chess.isGolden) installReveal(battle, unit);
|
||
if (unit.skill?.id !== S1) return;
|
||
battle.on('hit', (ctx) => {
|
||
if (ctx.target !== unit || ctx.dmg.cancel || !(ctx.dmg.amount > 0) || !unit.findBuff(blockKey)) return;
|
||
ctx.dmg.cancel = true;
|
||
battle.removeBuff(unit, blockKey);
|
||
battle.fx('shield', { x: unit.x, y: unit.y, id: unit.id });
|
||
}, { owner: unit, priority: 50 });
|
||
},
|
||
skill: {
|
||
trigger: 'DEFAULT',
|
||
kind: 'duration', mods: { atkPct: num(bb.atk), batPct: Math.max(0, num(bb.base_attack_time)) },
|
||
targeting: { maxTargets: Math.max(1, Math.floor(num(bb['attack@max_target'], 1))) },
|
||
attack: {
|
||
dmgType: 'arts',
|
||
onHit({ battle, unit, target }) {
|
||
if (target && target.alive && battle.rng.chance(num(bb['attack@buff_prob']))) battle.applyStatus(target, 'stun', { duration: num(bb['attack@stun']), source: unit });
|
||
},
|
||
},
|
||
onEnd({ battle, unit, reason }) {
|
||
if (reason !== 'death' && unit.alive && num(bb.stun) > 0) battle.applyStatus(unit, 'stun', { duration: num(bb.stun), source: unit });
|
||
},
|
||
},
|
||
talents: [{ install(battle, unit) {
|
||
const sp = num(t.sp);
|
||
if (sp > 0) {
|
||
// PRTS 备注 "仅伤害量不为0且能够触发受击回复的伤害才能触发此天赋": any such damage, not only an enemy attack
|
||
// (a zone tick, the 源石溶剂 drain — player report D1 audit)
|
||
onDamagedOn(battle, unit, (ctx) => {
|
||
if (!hurtSpDamage(ctx) || !up(unit)) return;
|
||
giveSp(unit, sp);
|
||
const mates = alliesInGridOf(battle, unit, grid ?? [[1, 0], [0, -1], [0, 1], [-1, 0]]).filter((a) => a !== unit && a.skill && !a.skill.noSkill);
|
||
const m = battle.rng.pick(mates);
|
||
if (m) giveSp(m, sp);
|
||
});
|
||
}
|
||
statBuff(battle, unit, 'talent:liskam', { resFlat: num(talentBb(chess, 1).magic_resistance) });
|
||
} }],
|
||
};
|
||
},
|
||
};
|