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:
1 parent
017390c93f
commit
5d3ca339e4
3 files changed
+67
-15
No files matched your search
@@ -40,8 +40,8 @@ export default {
|
||||
// ---- 3_04 琳琅诗怀雅 · 行商 — S2 “见面礼” (passive): with a coin and a free tile of range x-6 her attack's turn
|
||||
// throws a champagne bomb instead (onto an enemy's tile when one stands there; installS2);
|
||||
// 大买家: coin at skill start + coin & ATK stack per trait payment; 破财消灾: DP-paid revive (cost doubles)
|
||||
// S1 仗义疏财 (passive, 2 coins): a coin heals the most injured ally (< 70 % HP) of the 8 surrounding tiles for
|
||||
// attack@heal_scale × ATK — on her attack, or with no enemy to attack on her own attack timer (owner's decision
|
||||
// S1 仗义疏财 (passive, 2 coins): a coin heals the most injured ally (< 70 % HP) of the 3×3 around her — herself
|
||||
// included — for attack@heal_scale × ATK — on her attack, or with no enemy to attack on her own attack timer (owner's decision
|
||||
// 2026-10-04, against the official 「下一次攻击会为…」; installS1). S3 千金一掷 (持续时间无限): attacks hit twice, kills give a coin;
|
||||
// closing it spends every coin on random ground enemies of range 2-4 in front and those she blocks (atk_scale phys +
|
||||
// a small push, radial despite the text's 向前 — PRTS 备注 "推开效果为径向推动"; client charpack char_1033_swire2:
|
||||
@@ -96,10 +96,13 @@ export default {
|
||||
* 仗义疏财 — official text 「消耗一枚金币,下一次攻击会为周围八格内血量不足70%的一名友方单位恢复相当于攻击力40%的生命」: the heal rides on an
|
||||
* attack, so with no enemy around she never healed (community report #5 「琳琅诗怀雅1技能不会主动奶身边受伤的干员」). Owner's
|
||||
* decision 2026-10-04 (a deliberate deviation, like §21.29's 重装 casts): she heals an injured ally beside her whether
|
||||
* she attacks or not. Same target (the lowest HP ratio below 70 % of the 8 surrounding tiles, no 禁疗 / 孤立 unit, no
|
||||
* she attacks or not. Same target (the lowest HP ratio below 70 % of the 3×3 around her, no 禁疗 / 孤立 unit, no
|
||||
* device), coin and heal_scale × ATK. Cadence [ASSUMED]: at most one heal per attack cycle (her attack interval, ASPD
|
||||
* included) — while she attacks, on the attack as before; when her last attack attempt found no target, on her own
|
||||
* timer (the 'tick' hook runs after the attacks, so an attack due in the same tick takes it).
|
||||
* 「周围八格」 includes herself: 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. Until 0.2.0 she was
|
||||
* left out and never healed herself (community report of 2026-10-06 「琳琅诗怀雅不会治疗自己」).
|
||||
*/
|
||||
const installS1 = (battle, unit) => {
|
||||
const hs = num(bb['attack@heal_scale'], num(bb.heal_scale, 0));
|
||||
@@ -107,9 +110,10 @@ export default {
|
||||
const healTarget = () => {
|
||||
let best = null;
|
||||
for (const a of battle.allyUnits) {
|
||||
if (a === unit || !alive(a) || a.hidden || a.kind === 'device' || a.hpRatio >= healRatio) continue;
|
||||
if (a.s.flags.noHeal || a.profile?.noHeal) continue; // 禁疗 / 孤立: never a heal target
|
||||
if (Math.max(Math.abs(a.tileR - unit.tileR), Math.abs(a.tileC - unit.tileC)) !== 1) continue; // 周围八格
|
||||
if (!alive(a) || a.hidden || a.kind === 'device' || a.hpRatio >= healRatio) continue;
|
||||
if (a !== unit && (a.s.flags.noHeal || a.profile?.noHeal)) continue; // 禁疗 / 孤立: never a heal target
|
||||
if (a === unit && a.s.flags.healFree) continue; // her own 禁疗 (HEAL_FREE) stops a heal of herself too
|
||||
if (Math.max(Math.abs(a.tileR - unit.tileR), Math.abs(a.tileC - unit.tileC)) > 1) continue; // x-4: the 3×3, her tile too
|
||||
if (!best || a.hpRatio < best.hpRatio || (a.hpRatio === best.hpRatio && a.deploySeq < best.deploySeq)) best = a;
|
||||
}
|
||||
return best;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
@@ -1692,25 +1692,25 @@
|
||||
"time": 170,
|
||||
"ticks": 5100,
|
||||
"reason": "timeout",
|
||||
"killed": 30,
|
||||
"killed": 31,
|
||||
"total": 53,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 140,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {
|
||||
"p1": {"killed":30,"total":53,"perfect":false,"leaks":23,"leaksUncounted":0,"coins":4,"dmg":375198,"bossDmg":0,"heal":14642,"deaths":9,"layerGains":{"raidShip":18}}
|
||||
"p1": {"killed":31,"total":53,"perfect":false,"leaks":22,"leaksUncounted":0,"coins":4,"dmg":381570,"bossDmg":0,"heal":20570,"deaths":8,"layerGains":{"raidShip":18}}
|
||||
},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_3_06_b",0,"none",0,0,2,0,952,6276,0,10,1],
|
||||
["p1",2,"op","chess_char_3_12_b",0,"uniequip_003_blemsh",0,0,14,5,31951,14072,11110,46,21],
|
||||
["p1",3,"op","chess_char_3_02_b",0,"none",0,0,6,0,15577,2291,0,37,12],
|
||||
["p1",4,"op","chess_char_3_03_b",0,"none",0,0,8,0,3718,1778,0,35,1],
|
||||
["p1",5,"op","chess_char_3_04_b",0,"uniequip_003_swire2",0,0,59,4,48389,6778,3531,66,0],
|
||||
["p1",5,"op","chess_char_3_04_b",0,"uniequip_003_swire2",1913.64,1,59,5,55982,7885,9460,73,0],
|
||||
["p1",6,"op","chess_char_3_05_b",0,"uniequip_003_skadi",0,0,12,2,26200,12824,0,29,1],
|
||||
["p1",7,"op","chess_char_3_21_a",0,null,506.83,1,10,0,8795,857,0,35,14],
|
||||
["p1",8,"op","chess_char_3_01_b",0,"uniequip_003_angel",470.41,1,11,1,38052,1246,0,75,32],
|
||||
["p1",9,"op","chess_char_3_08_b",0,"none",233.39,1,1,7,80992,3015,0,23,4],
|
||||
["p1",9,"op","chess_char_3_08_b",0,"none",233.39,1,1,7,79772,3015,0,23,4],
|
||||
["p1",10,"op","chess_char_3_09_b",0,"none",0,0,3,0,12044,1534,0,13,4],
|
||||
["p1",11,"op","chess_char_3_10_b",0,"none",0,0,5,4,54938,2120,0,24,7],
|
||||
["p1",12,"op","chess_char_3_11_b",0,"none",0,0,7,6,53591,1610,0,19,10]
|
||||
@@ -1726,12 +1726,12 @@
|
||||
"enemy_1283_sgkill_2": [1,0,1,8304,8764],
|
||||
"enemy_1425_lrcmra": [1,0,1,1808,10651],
|
||||
"enemy_2008_flking": [1,0,1,7980,4818],
|
||||
"enemy_9006_actoxi": [12,5,5,4229,136218]
|
||||
"enemy_9006_actoxi": [12,6,5,5082,142471]
|
||||
},
|
||||
"hooks": [1,67,5100,528,528,1936,1936,28,39,60,107,108,0,7439,40,31,53,19,1,41,3,0,0],
|
||||
"events": {"atk":733,"bounty":2,"deploy":14,"die":41,"dmg":1871,"engage":12,"fx":110,"heal":28,"layer":3,"leak":19,"skill":217,"spawn":65,"status":185},
|
||||
"fx": {"blink":1,"buff":1,"coin":18,"explode":25,"garrison":3,"revive":2,"shield":20,"shieldBreak":1,"strike":10,"volley":7,"zone":22},
|
||||
"snaps": "96282387 24613d95 49d36ca6 4e91020f f1d25080 9e767196 bdb45ea5 0f508e6f c1c13843 91b6d342 0d44ebac 29e98739 a430c9be c8c5ec6c 2fd74d54 48089465 456f6920"
|
||||
"hooks": [1,67,5100,536,536,1944,1944,36,39,60,107,107,0,7439,40,31,53,19,1,39,3,0,0],
|
||||
"events": {"atk":740,"bounty":2,"deploy":14,"die":41,"dmg":1879,"engage":12,"fx":125,"heal":36,"layer":3,"leak":19,"skill":217,"spawn":65,"status":185},
|
||||
"fx": {"blink":1,"buff":1,"coin":34,"explode":25,"garrison":3,"shield":20,"shieldBreak":1,"strike":10,"volley":7,"zone":23},
|
||||
"snaps": "96282387 24613d95 49d36ca6 4e91020f f1d25080 9e767196 bdb45ea5 0f508e6f c1c13843 91b6d342 0d44ebac 29e98739 5de387ca e01250d2 66bd1e5b 4aa99d1f 8cb0a6a5"
|
||||
},
|
||||
"roster-028": {
|
||||
"about": "pass 1 band 4: chess_char_3_16_b chess_char_4_01_a chess_char_3_18_b chess_char_4_04_a chess_char_3_13_b chess_char_3_14_b chess_char_3_17_b chess_char_3_19_b chess_char_3_20_b chess_char_3_21_b chess_char_4_02_a chess_char_4_06_a token_10028_vigil_wolf",
|
||||
|
||||
Reference in new issue
Block a user