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:
sganggs committed 2026-10-06 16:52:11 +08:00
commit e2bb090f44
60 files changed
+6888 -6103

No files matched your search

+16 -1
View File
@@ -27,7 +27,7 @@
// counter {id} · crit {id} · dp {n, id} · heal {id} · taunt {id} · summon {id, token} · pull {id} · sonic {radius} ·
// shield {id} · overload {id} · takeoff {id} · sleep {id} · buff {id, kind} · reveal {id} · dodge (engine kind).
import { COLS } from '../../../constants.js';
import { COLS, TICK } from '../../../constants.js';
import { absoluteRangeKeys, sortEnemyTargets } from '../../../targeting.js';
import { offsetTile } from '../../../dir.js';
import { bodyInKeys, bodyTileReach } from '../../../body.js';
@@ -94,6 +94,21 @@ export function onDamagedOn(battle, unit, fn, priority = 0) {
return battle.on('damaged', (ctx) => { if (ctx.target === unit) fn(ctx); }, { owner: unit, priority });
}
/**
* 庇护 (gamedata_const ba.protect "受到的物理和法术伤害降低相应比例(同名效果取最高)"; PRTS 术语释义 庇护): ONE effect per unit
* whoever grants it — battle.applyStrongest under this key, the strongest value holds and a weaker one resumes when it
* outlasts it. (遥's bubbles are a separate key, the client's damage_resistance[bonus] — they multiply with it.)
*/
export const PROTECT = 'protect';
/** The mods of a 庇护 value: physical and arts damage taken ×(1 − v). */
export const protectMods = (v) => ({ physTakenMul: 1 - v, artsTakenMul: 1 - v });
/** A hold that outlives one tick and lapses in the next: refreshed every tick while its condition lasts. */
export const PROTECT_TICK_HOLD = 1.5 * TICK;
/** Hold 庇护 `value` on `target` for `duration` s (the shared PROTECT effect). */
export function holdProtect(battle, target, value, duration, source = null) {
if (value > 0) battle.applyStrongest(target, PROTECT, { duration, value, mods: protectMods, source });
}
/** Targetable enemies inside `grid` (relative to the unit; null ⇒ current range), best targets first. */
export function enemiesInGrid(battle, unit, grid, { n = 0, priority = null, canHitFly = true, groundOnly = false } = {}) {
const keys = grid ? absoluteRangeKeys(grid, unit.tileR, unit.tileC, unit.dir, 0) : unit.rangeKeys;
+8 -2
View File
@@ -146,10 +146,16 @@ function pullToFront(battle, unit, e, force) {
}
/** Physician module trait (录武官, 华法琳 elites): heals on allies below hp_ratio are ×heal_scale. */
function installLowHpHealBonus(battle, unit, tb) {
/**
* The module trait "治疗生命值低于50%的友方单位时治疗量提升15%" (heal_scale, hp_ratio): the client's module buff filters the
* target's HP before the heal with its own comparison — `atOrBelow` for the template heal_scale_up[hpratio][LE] (华法琳's
* PHY-X), strictly below otherwise (录武官's reckpr_e_002_tr: LT). [ASSUMED as before: not on herself]
*/
function installLowHpHealBonus(battle, unit, tb, { atOrBelow = false } = {}) {
const s = num(tb.heal_scale, 0), r = num(tb.hp_ratio, 0);
if (!(s > 0) || !(r > 0)) return;
battle.on('heal', (c) => { if (c.source === unit && c.target !== unit && c.target.hpRatio < r) c.amount *= s; }, { owner: unit });
const low = atOrBelow ? (t) => t.hpRatio <= r + 1e-9 : (t) => t.hpRatio < r;
battle.on('heal', (c) => { if (c.source === unit && c.target !== unit && low(c.target)) c.amount *= s; }, { owner: unit });
}
// DESIGN §5.6 documents `(bb, chess)`; content/index.js also passes the normalised def — rebuild it when absent.
+8 -3
View File
@@ -150,13 +150,18 @@ function burstDamageUp(battle, unit, mul) {
}, { owner: unit });
}
/** Modules PHY-X / GUA-X: heals on allies below hp_ratio ×heal_scale. */
function lowHpHealUp(battle, unit, tb) {
/**
* Modules PHY-X / GUA-X "治疗生命值低于50%的友方单位时治疗量提升15%": heals on allies below hp_ratio ×heal_scale. The client's
* module buff picks its comparison: `atOrBelow` for heal_scale_up[hpratio][LE] (华法琳's PHY-X), strictly below for 塞雷娅's
* GUA-X (set_heal_scale_by_hpratio: LT) and 录武官's PHY-X (reckpr_e_002_tr: LT).
*/
function lowHpHealUp(battle, unit, tb, { atOrBelow = false } = {}) {
const mul = num(tb.heal_scale), thr = num(tb.hp_ratio);
if (!(mul > 1) || !(thr > 0)) return;
const low = atOrBelow ? (t) => t.hpRatio <= thr + 1e-9 : (t) => t.hpRatio < thr;
battle.on('heal', (c) => {
if (c.source !== unit || c.opts?.regen || !c.target || c.target.side !== 'ally') return;
if (c.target.hpRatio < thr) c.amount *= mul;
if (low(c.target)) c.amount *= mul;
}, { owner: unit });
}