feedback5 WC: a MANUAL skill whose running attack range strictly contains the own range casts as soon as an enemy is inside it (ACTIVE_RANGE, the owner's rule of 2026-10-05)
A deliberate deviation from the official 技能策略 (community report: skills with a larger range waited for the normal range). tools/build-data.mjs resolveTrigger: a MANUAL operator skill still on the basic strategy (no class row, no TRIGGER_DEVIATIONS entry) whose running range (its rangeId grid, or the own range grown by ability_range_forward_extend; never 被动效果:攻击范围扩大) strictly contains the operator's range gets rule ACTIVE_RANGE, customRangeGrid = that range, rawRule the official DEFAULT; validateAll checks it. server/sim/skills.js: ACTIVE_RANGE checks the DEFAULT condition (a targetable enemy or a blocked one; a heal skill an injured ally) on that range, grown by the permanent rangeExtend, every tick. Data rebuilt offline: only skills[].trigger changed (33 skills, 66 chess records, 9 stand-in form records). 深巡 S2 (§21.29), 重装 TAKE_DAMAGE, the SEARCH / CUSTOM_RANGE / SP_FULL rows, 烛煌 S2 / S3 (not containing her 3-1) and 引星棘刺 S3 keep their rule. Docs: DESIGN §5.6, DATA, SIM, PLAYING, kits README, notes. Tests: new test/sim/feedback5-active-range.test.js; data, playtest6-skills (银灰 S3), kits_alt_t2 (蒂比 S1), kits_t5 (百炼嘉维尔 S2) updated; feedback1-transform's fixtures move 莫斯提马 one tile (her S3 now casts on its 3-15). Golden: 27 roster, 25 bond, 21 field and 14 match scenarios moved — every one fields an operator with one of the 33 skills, which now casts when an enemy enters its running range instead of the initial range.
This commit is contained in:
1 parent
ebfda7e657
commit
01fddd3021
23 files changed
+1921
-1708
No files matched your search
+18
-6
@@ -14,6 +14,10 @@
|
||||
// too), checked every tick, no attack needed. Kit option `trigger.allies` (+ `hpAtMost`, default 1): a healable,
|
||||
// injured ally of the grid whose HP ratio is at most that instead (an AUTO heal skill's own rule — 古米 S1 waits in
|
||||
// its heal mode until it has healed);
|
||||
// ACTIVE_RANGE — the owner's rule (2026-10-05, a deliberate deviation): a MANUAL skill on the basic strategy whose attack
|
||||
// range while it runs strictly contains the unit's own range checks the DEFAULT condition on that larger range
|
||||
// (trigger grid = the running range, grown by the unit's permanent rangeExtend unless the skill ignores 攻击距离), every
|
||||
// tick, no attack needed — an enemy the unit can target there (or one it blocks), a heal skill an injured ally;
|
||||
// TAKE_DAMAGE (ready + just took a hit: 重装 "不受技能范围影响,受到伤害时释放技能"), SP_FULL/ALWAYS (as soon as ready),
|
||||
// CUSTOM_RANGE (enemy inside the custom trigger grid), SEARCH (an enemy inside the INITIAL range, checked every tick
|
||||
// without waiting for an attack: "不受基础策略影响,在初始攻击范围内存在敌人时释放技能" — not any enemy on the field,
|
||||
@@ -44,7 +48,7 @@
|
||||
import { absoluteRangeKeys, canTargetEnemy } from './targeting.js';
|
||||
import { AUTO_OP_COOLDOWN, COLS, ROWS } from './constants.js';
|
||||
|
||||
const TICK_RULES = new Set(['SP_FULL', 'SEARCH', 'CUSTOM_RANGE', 'SKILL_RANGE', 'GDGLOW_SKILL_2']);
|
||||
const TICK_RULES = new Set(['SP_FULL', 'SEARCH', 'CUSTOM_RANGE', 'SKILL_RANGE', 'ACTIVE_RANGE', 'GDGLOW_SKILL_2']);
|
||||
/** True when a SkillSpec `targeting` changes the unit's range while the skill runs (Battle._refreshRange). */
|
||||
const changesRange = (tg) => !!(tg && (tg.rangeGrid || tg.rangeExtend || tg.noRangeExtend));
|
||||
/** Enemies that satisfy a content trigger range (any targetable enemy, flyers included). */
|
||||
@@ -325,15 +329,21 @@ export class SkillRuntime {
|
||||
/** Public form of the operation cooldown, for kits with their own automatic cast of a MANUAL skill. */
|
||||
get opCooling() { return this._opCooling(); }
|
||||
|
||||
/** Absolute tile keys of the trigger grid at the unit's current tile and direction (cached, with their Set). */
|
||||
/**
|
||||
* Absolute tile keys of the trigger grid at the unit's current tile and direction (cached, with their Set). ACTIVE_RANGE
|
||||
* grows it by the unit's permanent rangeExtend (the range the skill would run with — Battle._refreshRange) unless the
|
||||
* skill's range ignores 攻击距离 (targeting.noRangeExtend).
|
||||
*/
|
||||
_triggerKeys() {
|
||||
const u = this.unit;
|
||||
const tile = u.tileR * COLS + u.tileC;
|
||||
if (!this._trigKeys || this._trigTile !== tile || this._trigDir !== u.dir) {
|
||||
this._trigKeys = absoluteRangeKeys(this.triggerGrid, u.tileR, u.tileC, u.dir, 0);
|
||||
const ext = this.rule === 'ACTIVE_RANGE' && !this.spec.targeting?.noRangeExtend ? (u.s.baseRangeExtend || 0) : 0;
|
||||
if (!this._trigKeys || this._trigTile !== tile || this._trigDir !== u.dir || this._trigExt !== ext) {
|
||||
this._trigKeys = absoluteRangeKeys(this.triggerGrid, u.tileR, u.tileC, u.dir, ext);
|
||||
this._trigSet = new Set(this._trigKeys);
|
||||
this._trigTile = tile;
|
||||
this._trigDir = u.dir;
|
||||
this._trigExt = ext;
|
||||
}
|
||||
return this._trigKeys;
|
||||
}
|
||||
@@ -364,6 +374,7 @@ export class SkillRuntime {
|
||||
if (!this.triggerGrid) return this._defaultCondition();
|
||||
return b.anyEnemyInKeys(this._triggerKeys());
|
||||
}
|
||||
if (this.rule === 'ACTIVE_RANGE') return this._defaultCondition(this.triggerGrid ? this._triggerKeys() : null);
|
||||
// GDGLOW_SKILL_2 "全场存在可选目标时释放技能": a targetable enemy anywhere (heal skill: an ally that needs healing)
|
||||
if (this.rule === 'GDGLOW_SKILL_2') {
|
||||
if (this.healSkill) return b.injuredAlliesInKeys(ALL_TILES, u, !!u.profile?.heal?.elementHealRatio).length > 0;
|
||||
@@ -375,12 +386,13 @@ export class SkillRuntime {
|
||||
/**
|
||||
* DEFAULT rule condition: an enemy (or injured ally for heal skills) inside the initial range (baseRangeKeys: own
|
||||
* grid + permanent rangeExtend), or an enemy inside a content trigger range (addTriggerRange; not for heal skills).
|
||||
* `range` (ACTIVE_RANGE): those absolute tile keys instead of the initial range.
|
||||
*/
|
||||
_defaultCondition() {
|
||||
_defaultCondition(range = null) {
|
||||
const b = this.battle;
|
||||
const u = this.unit;
|
||||
if (b.rangeChanged(u)) b._refreshRange(u);
|
||||
const keys = u.baseRangeKeys || u.rangeKeys;
|
||||
const keys = range || u.baseRangeKeys || u.rangeKeys;
|
||||
if (keys) {
|
||||
if (this.healSkill) return b.injuredAlliesInKeys(keys, u).length > 0;
|
||||
if (b.enemiesInKeys(keys, u, u.profile).length > 0) return true;
|
||||
|
||||
Reference in new issue
Block a user