feedback5 CB2: 琳琅诗怀雅's S1 仗义疏财 heals herself too — the 3×3 around her includes her own tile (community report of 2026-10-06 「琳琅诗怀雅不会治疗自己」)

Official: S1 「下一次攻击会为周围八格内血量不足70%的一名友方单位恢复…」; the client charpack (char_1033_swire2, mode S1,
ability HealAlly) selects with range x-4 (the 3×3 with her tile), ally side, _excludeOwner 0, max HP ratio 0.7, one target.
Cause: kits/ops/chess_char_3_04-swire2.js healTarget skipped her (a === unit) and kept only Chebyshev distance 1.
Now: the lowest HP ratio below 70 % of the 3×3, herself included (her own 禁疗 still stops it); the owner's 2026-10-04
cadence (a heal without an attack, once per attack cycle) unchanged.

Golden: roster-027 (琳琅诗怀雅 elite S1 in band 4: she heals herself below 70 %).
Tests: test/content/feedback5-swire2-self-heal.test.js (2, fail on the parent).
This commit is contained in:
sganggs committed 2026-10-07 02:12:34 +08:00
1 parent 017390c93f
commit 5d3ca339e4
3 files changed
+67 -15

No files matched your search

@@ -0,0 +1,48 @@
// test/content/feedback5-swire2-self-heal.test.js — 琳琅诗怀雅 S1 仗义疏财 heals herself too (community report of 2026-10-06
// 「干员琳琅诗怀雅不会治疗自己」): 「下一次攻击会为周围八格内血量不足70%的一名友方单位恢复…」 — the client charpack
// (char_1033_swire2, mode S1, ability HealAlly) selects with range x-4 (the 3×3 with her own tile), ally side,
// `_excludeOwner` 0, max HP ratio 0.7, one target. kits/ops/chess_char_3_04-swire2.js used to skip her own tile.
// Run: node --test test/content/feedback5-swire2-self-heal.test.js
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { makeBattle, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
import { getDefaultSource } from '../../server/sim/simdata.js';
const ds = getDefaultSource();
const ID = 'chess_char_3_04_a', S1 = 'skchr_swire2_1';
const S1_INDEX = ds.rawChess(ID).skills.find((s) => s.skillId === S1).index;
const NEIGHBOUR = 'chess_char_3_16_a';
/** 琳琅诗怀雅 (S1) on (9, 5), an ally on (10, 5); HP ratios set after the deployment; coins to spare. */
function field(herRatio, allyRatio) {
const h = makeBattle({
defs: { enemies: { enemy_d: enemyRec({ key: 'enemy_d', hp: 1e7, speed: 0 }) } },
units: [{ chessId: ID, row: 9, col: 5, skillIndex: S1_INDEX }, { chessId: NEIGHBOUR, row: 10, col: 5 }],
timeLimit: 60, autoFinish: false, hooks: ['heal'], captureNoisy: true, flags: { dpInit: 60, dpMax: 99 },
});
h.step();
const u = h.unit(ID), ally = h.unit(NEIGHBOUR);
u.mem.coins = 2;
u.hp = u.s.maxHp * herRatio;
ally.hp = ally.s.maxHp * allyRatio;
h.run(1);
return { h, u, ally, heals: h.hooksOf('heal').filter((c) => c.source === u) };
}
test('alone below 70 %: a coin heals herself (her own tile is in the x-4 selector)', () => {
const { h, u, heals } = field(0.5, 1);
assert.equal(heals.length, 1, 'one heal');
assert.equal(heals[0].target, u, 'on herself');
assert.equal(u.mem.coins, 1, 'one coin spent');
checkInvariants(h.b);
assert.equal(h.b.errors.length, 0);
});
test('the lowest HP ratio of the 3×3 wins: herself below the neighbour, the neighbour below her; 70 % or more is never healed', () => {
assert.equal(field(0.4, 0.6).heals[0].target.defId, ID, 'she is lower: herself');
assert.equal(field(0.6, 0.4).heals[0].target.defId, NEIGHBOUR, 'the neighbour is lower: the neighbour');
const none = field(0.75, 1);
assert.equal(none.heals.length, 0, 'not below 70 %: no heal, the coin is kept');
assert.equal(none.u.mem.coins, 2);
});