feedback5 R4: one file per operator kit — kits/tier1..6.js split into kits/ops/<chessId>-<codename>.js (129 kits), kits/shared/tier1..6.js (the helpers two or more kits of a tier use, and each tier's header notes) and kits/index.js (the registry, same keys in the same order); the tier files become re-export shims
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.
This commit is contained in:
1 parent
6b489b1776
commit
1169102d46
143 files changed
+12924
-11784
No files matched your search
@@ -0,0 +1,105 @@
|
||||
// server/sim/content/kits/ops/chess_char_6_12-rosmon.js — 迷迭香 (char_391_rosmon) kit, tier 6.
|
||||
// Conventions of the tier-6 kits: ../shared/tier6.js; kit contract and rules: ../README.md.
|
||||
|
||||
import { sortEnemyTargets } from '../../../targeting.js';
|
||||
import { summonToken } from '../../tokens.js';
|
||||
import { num, tbb, live, opsOf, selectedSkill, batOf } from '../shared/tier6.js';
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------
|
||||
// 迷迭香 chess_char_6_12 (投掷手) — S2 末梢阻断; 歼灭战装备; 感知稳定
|
||||
|
||||
/** S2 末梢阻断 "溅射范围扩大": radius 1.5 (PRTS 溅射半径一览, 技能: 迷迭香 末梢阻断 1.5; ×1.3 [ASSUMED] until 0.1.1). */
|
||||
const ROSMON_S2_SPLASH = 1.5;
|
||||
|
||||
function rosmon(bb, chess, def) {
|
||||
const t0 = tbb(def, 0), t1 = tbb(def, 1);
|
||||
const sid = selectedSkill(chess, def);
|
||||
const prob = num(bb['attack@prob']), stun = num(bb['attack@stun']);
|
||||
const gearId = (chess?.tokens || []).find((t) => /rosmon_shield/.test(String(t))) || 'token_10012_rosmon_shield';
|
||||
const skills = {
|
||||
// S1 思维膨大 (attack SP): the next attack also deals extra_atk_scale × ATK arts to every enemy it hits
|
||||
skchr_rosmon_1: {
|
||||
kind: 'instant',
|
||||
attack: {
|
||||
onEachHit({ battle, unit, target, kind }) {
|
||||
if (!target || !target.alive || (kind !== 'main' && kind !== 'splash')) return;
|
||||
battle.dealDamage(unit, target, { amount: unit.s.atk * num(bb.extra_atk_scale, 1), type: 'arts', isSkill: true, tags: ['skill'] });
|
||||
},
|
||||
},
|
||||
},
|
||||
// S3 “如你所愿”: base attack time ×0.5 (akdata: 乘算负数), ATK +atk, 2 targets but blocked enemies only (install);
|
||||
// two 战术装备 on melee tiles of her range (the token kit: appear stun, blocked enemies DEF −160, lifetime)
|
||||
skchr_rosmon_3: {
|
||||
kind: 'duration',
|
||||
mods: { batPct: batOf(bb.base_attack_time, def, true), atkPct: num(bb.atk) },
|
||||
targeting: { maxTargets: Math.max(1, Math.floor(num(bb['attack@max_target'], 2))) },
|
||||
onStart({ battle, unit }) {
|
||||
let n = 0;
|
||||
for (let i = 0; i < 2; i++) if (summonToken(battle, unit, gearId, 'melee')) n++;
|
||||
battle.fx('summon', { x: unit.x, y: unit.y, id: unit.id, n });
|
||||
},
|
||||
},
|
||||
};
|
||||
return {
|
||||
skills,
|
||||
install(battle, unit) {
|
||||
if (sid !== 'skchr_rosmon_3') return;
|
||||
battle.on('beforeAttack', (ctx) => { // "仅选择被阻挡的敌人作为目标"
|
||||
if (ctx.attacker !== unit || !unit.skill?.active) return;
|
||||
// her range, plus the enemies she blocks herself — always her targets (Battle.blockedTargets, DESIGN §20.3)
|
||||
const c = battle.enemiesInKeys(unit.rangeKeys, unit, ctx.profile);
|
||||
for (const e of battle.blockedTargets(unit, ctx.profile)) if (!c.includes(e)) c.push(e);
|
||||
for (let i = c.length - 1; i >= 0; i--) if (!c[i].blockedBy) c.splice(i, 1);
|
||||
sortEnemyTargets(battle, unit, c, ctx.profile?.priority ?? null);
|
||||
ctx.targets = c.slice(0, Math.max(1, Math.floor(num(ctx.profile?.maxTargets, 2))));
|
||||
}, { owner: unit });
|
||||
},
|
||||
skill: {
|
||||
kind: 'duration',
|
||||
mods: { batPct: batOf(bb.base_attack_time, def), atkPct: num(bb.atk) },
|
||||
onStart({ unit }) {
|
||||
const p = unit.profile;
|
||||
unit.mem.rosSaved = { r: p.splashRadius, n: p.shockTimes };
|
||||
p.splashRadius = Math.max(num(p.splashRadius, 0.9), ROSMON_S2_SPLASH);
|
||||
p.shockTimes = num(p.shockTimes, 2) + Math.floor(num(bb.add_times));
|
||||
},
|
||||
onEnd({ unit }) {
|
||||
const s = unit.mem.rosSaved;
|
||||
if (s) { unit.profile.splashRadius = s.r; unit.profile.shockTimes = s.n; }
|
||||
unit.mem.rosSaved = null;
|
||||
},
|
||||
},
|
||||
talents: [
|
||||
{ install(battle, unit) { // S2: attack & aftershock stun chance
|
||||
battle.on('damaged', (ctx) => {
|
||||
if (ctx.source !== unit || !unit.skill?.active || !(stun > 0) || !ctx.target.alive || ctx.target.side !== 'enemy') return;
|
||||
if (!ctx.dmg?.isAttack && !ctx.dmg?.tags?.includes('aftershock')) return;
|
||||
if (battle.rng() < prob) battle.applyStatus(ctx.target, 'stun', { duration: stun, source: unit });
|
||||
}, { owner: unit });
|
||||
} },
|
||||
{ install(battle, unit) { // 歼灭战装备
|
||||
const v = num(t0.def_penetrate_fixed);
|
||||
if (v) battle.addBuff(unit, { key: 'rosmon:pierce', mods: { defIgnoreFlat: v }, persist: true, allowDead: true });
|
||||
} },
|
||||
{ install(battle, unit) { // 感知稳定
|
||||
const atk = num(t1.atk);
|
||||
battle.on('deploy', ({ unit: u }) => {
|
||||
if (u !== unit || !atk) return;
|
||||
battle.after(0, () => {
|
||||
if (!live(unit)) return;
|
||||
const casters = opsOf(battle, unit.ownerId).filter((a) => a.def?.profession === 'CASTER');
|
||||
const pick = battle.rng.pick(casters);
|
||||
if (!pick) return;
|
||||
battle.addBuff(unit, { key: 'rosmon:stable', mods: { atkPct: atk } });
|
||||
battle.addBuff(pick, { key: 'rosmon:stable', mods: { atkPct: atk } });
|
||||
battle.fx('link', { x: pick.x, y: pick.y, id: pick.id, src: unit.id });
|
||||
}, { owner: unit });
|
||||
}, { owner: unit });
|
||||
} },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
chess_char_6_12_a: rosmon,
|
||||
};
|
||||
Reference in new issue
Block a user