feedback1e WP: live attack range on the battle card; 烛煌 S3 splash 1.7

Community report "干员烛煌开启3技能时候攻击范围不会变". The sim already attacked
with S3's 4-11 while it ran (real matches, and every attack-range change of
the mode); what stayed the same was the battle detail card: its 攻击范围
mini-map kept the base 3-1 grid while the live stats beside it moved.

- Battle._refreshRange keeps the relative grid behind rangeKeys as
  unit.liveRangeGrid (targeting.js extendedGrid: rangeExtend grown on);
  shared/protocol.js unitStatsEntry carries it as `range`; the detail card
  draws it (cardRangeGrid) in battle and in the prep preview, and names a
  whole-field range (纯烬艾雅法拉 S3) 全场 instead of drawing it.
- 烛煌 S3 "攻击变为群体攻击" is one target + a 1.7 splash (PRTS 技能3 备注
  "攻击溅射半径1.7"), not every enemy inside 4-11; the burst bonus hits
  every enemy of the attack; a burn burst's +2 ammo stops at the skill's
  ammo ("补充后的弹药数量无法超过上限").
- Tests: test/sim/feedback1e-skillrange.test.js (S3 range, splash, ammo
  cap, live grid, the audit of every attack-range change, a real spec),
  test/ui/feedback1e-range.test.js (the card).
This commit is contained in:
sganggs committed 2026-10-03 05:03:07 +08:00
1 parent 7f134737ce
commit 8b0e672bb8
10 files changed
+471 -20

No files matched your search

+10 -3
View File
@@ -193,16 +193,22 @@ const statView = (x) => ({
* or the last ones the sim computed) next to its own `unit.base` (no buffs) — max HP, ATK, DEF, RES, attack interval
* (s), block, move speed — rounded for display (the sim keeps floats), plus the current HP. The shape of the
* `m.unitStats` units (Match.unitStats: what the board's units start their next battle with) and of the browser
* runner's live battle stats (public/js/battle/runner.js unitStats).
* @param {{ id?: number, uid?: number|null, defId?: string, hp?: number, alive?: boolean, base?: any } | null} u
* runner's live battle stats (public/js/battle/runner.js unitStats). An ally with a range also carries `range`: the grid
* (`[dRow, dCol]`, facing RIGHT) it attacks with now — a running skill's range, rangeExtend included (the sim's
* `unit.liveRangeGrid`, Battle._refreshRange; community report E1 after 0.1.0: 烛煌 S3's 4-11 never reached the card).
* @param {{ id?: number, uid?: number|null, defId?: string, hp?: number, alive?: boolean, base?: any, liveRangeGrid?: any } | null} u
* @param {any} [s] aggregated stats (missing ⇒ the base)
* @returns {{ id: number|null, uid: number|null, defId: string|null, hp: number, alive: boolean, maxHp: number, atk: number,
* def: number, res: number, interval: number|null, blockCnt: number, moveSpeed: number,
* base: { maxHp: number, atk: number, def: number, res: number, interval: number|null, blockCnt: number, moveSpeed: number } }}
* base: { maxHp: number, atk: number, def: number, res: number, interval: number|null, blockCnt: number, moveSpeed: number },
* range?: Array<[number, number]> }}
*/
export function unitStatsEntry(u, s = null) {
const base = u && u.base && typeof u.base === 'object' ? u.base : {};
const cur = s && typeof s === 'object' ? s : base;
const range = u?.side !== 'enemy' && Array.isArray(u?.liveRangeGrid)
? u.liveRangeGrid.filter((p) => Array.isArray(p) && Number.isInteger(p[0]) && Number.isInteger(p[1])).map((p) => [p[0], p[1]])
: null;
return {
id: Number.isInteger(u?.id) ? u.id : null,
uid: Number.isInteger(u?.uid) ? u.uid : null,
@@ -211,6 +217,7 @@ export function unitStatsEntry(u, s = null) {
alive: u?.alive !== false,
...statView(cur),
base: statView(base),
...(range ? { range } : {}),
};
}