feedback5: merge WE1 — fidelity (sim rules): 秘术师 store at the attack check (深靛; 维伊 / 黑键 plug into it), enemy attacks land at their damage frame so a short stun / freeze / sleep / 浮空 / 缴械 / 恐惧 before it cancels the swing, 武者 heal per damage instance through 禁疗, 庇护 the strongest only, PHY-X 不高于 50 %, 链愈师 jumps in the 3×3, a summon readied at its owner's redeploy, Misery's duration skills, 伺夜 S2 in 战术点形态, centurions hit up to block-count targets; merge fixes: 黑键's kit keeps the up() import WE2's S2 cast needs (WE1 dropped it with its tick store — the first regeneration had stored 9288 swallowed errors in diy-114), the 自选 refusal names 集成战略 / 生息演算, tools/golden.mjs prints a missing value, test/golden.test.js fails on any stored engine error; golden: vs WE1 only the W4B / WE2 scenarios differ (roster-042, bond-egirShip-high, coop2-ABYSS-10-boosted, coop2-NORMAL-70-diy, diy-045 / 078 / 114 / 115 / 116)
This commit is contained in:
commit
e2bb090f44
60 files changed
+6888
-6103
No files matched your search
@@ -27,8 +27,9 @@
|
||||
// prosts_t_1[born_charge] BLOCK_CNT ×0, interval 0.1, firstTriggerInterval 1, FixedValueDamage PURE `damage` on itself);
|
||||
// buff_template_data (monstr_t_2[atk_spd] ON_OUTPUT_MODIFIER IsHeal; monstr_s_3[undead] ON_BEFORE_TRY_SET_HP_ZERO).
|
||||
// - Trait (链愈师) "恢复友方单位生命,且会在3个友方单位间跳跃,每次跳跃治疗量降低25%" — the chain is this kit's (the profession's
|
||||
// 2.5-tile chain is replaced: heal mode single + `chainFrom`), as her heal projectiles have it: after the heal on the main
|
||||
// target the heal jumps to the lowest-HP-ratio injured ally of the 3×3 around the last one healed (x-4), each jump ×
|
||||
// chain is replaced: heal mode single + `chainFrom`, its links the profession's — ai.js chainHealNext): after the heal on
|
||||
// the main target the heal jumps to the lowest-HP-ratio ally (a full-HP one too — PRTS 分支特性信息 链愈师; ties: the latest
|
||||
// deployed) of the 3×3 around the last one healed (x-4), each jump ×
|
||||
// attack@chain.atk_scale (0.75; XAH-X 0.85), up to attack@chain.max_target units healed (3). A 重构体 (and she herself while S3
|
||||
// runs: monstr[free_jump]) is a free link: healing it uses no target of the count and the next jump does not decay (XAH-X
|
||||
// stage 3: the next attack@chain.extra_cnt jumps after that neither). Her heals pass 禁疗 ("治疗效果无视禁疗"); her selection
|
||||
@@ -54,8 +55,9 @@
|
||||
// - S3 策略:熔毁 (MANUAL, data DEFAULT, 25 s; only while her 重构体 stands — the cast is refused otherwise): the 重构体 is withdrawn
|
||||
// (its piece waits: back once its tile is free again) and she 【移动】s onto its tile; meanwhile range x-4, ATK +atk, base attack
|
||||
// time base_attack_time (a flat −1.5 s on 2.85 s), block +block_cnt, max HP +max_hp (the HP ratio kept), 流失 of
|
||||
// damage_per_second HP/s (8 every 0.1 s); her attacks hit every ground enemy she blocks (one in range when she blocks none —
|
||||
// [ASSUMED] as 凯尔希's Mon3tr S2) for ATK true damage, and each attack starts a chain heal on herself at attack@heal_scale × ATK
|
||||
// damage_per_second HP/s (8 every 0.1 s); "同时攻击阻挡的所有敌人" (her selector's _limitedMaxTargetNumToBlockedCnt): each attack
|
||||
// takes up to her block count of ground enemies of her range, the blocked ones first (ai.js `hitAllBlocked`, the 强攻手 rule
|
||||
// of PRTS 分支特性信息) for ATK true damage, and each attack starts a chain heal on herself at attack@heal_scale × ATK
|
||||
// (she is a free link). 不死: a hit or 流失 that would knock her out leaves her at 1 HP, untargetable and blocking nothing, and
|
||||
// the skill ends on the next tick. At the end she 【返回】s to the tile she left (her SP emptied; the max HP drop keeps the ratio,
|
||||
// so after a fatal blow she stands at ≤ 1 HP) with 1 s of 不死. The 路标形态 marker on her tile is not modelled: should another
|
||||
@@ -63,6 +65,7 @@
|
||||
|
||||
import { num, talentBb, traitBb, skillRec, batMod, installAura, up } from '../shared/tier1.js';
|
||||
import { COLS } from '../../../constants.js';
|
||||
import { chainHealNext } from '../../../ai.js';
|
||||
|
||||
const S1 = 'skchr_monstr_1';
|
||||
const S2 = 'skchr_monstr_2';
|
||||
@@ -101,28 +104,13 @@ const prostsInRange = (battle, unit) => prostsOf(battle, unit).find((t) => up(t)
|
||||
/** `a` stands on the 3×3 around `b` (x-4: a heal jump's reach, the 重构体's aura). */
|
||||
const nearX4 = (a, b) => Math.abs(a.tileR - b.tileR) <= 1 && Math.abs(a.tileC - b.tileC) <= 1;
|
||||
|
||||
/**
|
||||
* The next link of a chain heal from `cur`: the lowest-HP-ratio injured ally of its 3×3 not healed yet by this chain (her
|
||||
* own 重构体 even at full HP when `fullProsts`); never a 禁疗 unit but her 重构体.
|
||||
*/
|
||||
function nextLink(battle, unit, cur, seen, fullProsts) {
|
||||
let best = null;
|
||||
for (const a of battle.allyUnits) {
|
||||
if (!a.alive || !a.deployed || a.hidden || a.kind === 'device' || seen.has(a.id) || !nearX4(a, cur)) continue;
|
||||
const mine = isProstsOf(a, unit);
|
||||
if (a !== unit && ((a.s.flags.noHeal && !mine) || (a.profile && a.profile.noHeal))) continue;
|
||||
if (!(a.hp < a.s.maxHp - 1e-6) && !(fullProsts && mine)) continue;
|
||||
if (!best || a.hpRatio < best.hpRatio - 1e-12 || (Math.abs(a.hpRatio - best.hpRatio) <= 1e-12 && a.deploySeq < best.deploySeq)) best = a;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* A chain heal of hers from `main` (already healed by her attack when `mainDone`): up to `count` units healed, × `step` per
|
||||
* jump; a free link (her 重构体; herself with `selfFree`) uses no target of the count and the next 1 + `extra` jumps keep the
|
||||
* amount.
|
||||
* amount. Each link is the 链愈师 one (ai.js chainHealNext — the 3×3 around the last one healed, the lowest HP ratio a
|
||||
* full-HP ally included, then the latest deployed; no 禁疗 unit but her 重构体, her `healThrough`).
|
||||
*/
|
||||
function chainFrom(battle, unit, main, base, { count, step, extra, fullProsts = false, mainDone = false, selfFree = false }) {
|
||||
function chainFrom(battle, unit, main, base, { count, step, extra, mainDone = false, selfFree = false }) {
|
||||
const free = (t) => isProstsOf(t, unit) || (selfFree && t === unit);
|
||||
let amount = base;
|
||||
if (!mainDone) battle.heal(unit, main, amount, HEAL_OPTS);
|
||||
@@ -131,7 +119,7 @@ function chainFrom(battle, unit, main, base, { count, step, extra, fullProsts =
|
||||
const seen = new Set([main.id]);
|
||||
let cur = main;
|
||||
while (counted < count) {
|
||||
const next = nextLink(battle, unit, cur, seen, fullProsts);
|
||||
const next = chainHealNext(battle, unit, cur, seen);
|
||||
if (!next) break;
|
||||
seen.add(next.id);
|
||||
if (calm > 0) calm--; else amount *= step;
|
||||
@@ -212,7 +200,7 @@ export default {
|
||||
kind: 'duration',
|
||||
mods: { atkPct: num(b3.atk), batPct: batMod(b3.base_attack_time, chess), blockCnt: num(b3.block_cnt), hpFlat: num(b3.max_hp) },
|
||||
targeting: s3?.rangeGrid ? { rangeGrid: s3.rangeGrid } : undefined,
|
||||
attack: { dmgType: 'true', attack: 'melee', projectile: 'none', canHitFly: false, groundOnly: true, hitAllBlocked: true, maxTargets: 1 },
|
||||
attack: { dmgType: 'true', attack: 'melee', projectile: 'none', canHitFly: false, groundOnly: true, hitAllBlocked: true },
|
||||
onStart({ battle, unit, skill }) {
|
||||
const r = prostsOf(battle, unit).find(up);
|
||||
if (!r) { skill.end('noToken'); skill.addCharge(1); return; } // (refused before: the activate guard)
|
||||
@@ -280,12 +268,12 @@ export default {
|
||||
const base = unit.s.atk * (prof.atkScale ?? 1) * (prof.healScale ?? 1) * unit.s.atkScaleMul;
|
||||
for (const t of c.targets || []) {
|
||||
if (!t || t.side !== 'ally') continue;
|
||||
chainFrom(battle, unit, t, base, { ...chain, count: s1on ? s1Count : chain.count, fullProsts: s2on, mainDone: true });
|
||||
chainFrom(battle, unit, t, base, { ...chain, count: s1on ? s1Count : chain.count, mainDone: true });
|
||||
// S2: 0.6 s after her attack healed her 重构体, a second chain on it (her ATK × 1)
|
||||
if (s2on && isProstsOf(t, unit)) {
|
||||
battle.after(S2_EXTRA_DELAY, () => {
|
||||
if (!unit.alive || !up(t)) return;
|
||||
chainFrom(battle, unit, t, unit.s.atk * unit.s.atkScaleMul, { ...chain, fullProsts: skillOn(unit, S2) });
|
||||
chainFrom(battle, unit, t, unit.s.atk * unit.s.atkScaleMul, chain);
|
||||
}, { owner: unit });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user