feedback7 R22-GHSIM: a 速射手 (优先攻击空中单位) blocking a ground enemy shoots a flyer in its range first; every other attacker keeps its blocked enemy first (GitHub #220, the owner's decision of 2026-10-08); golden: roster-026, roster-037 move
The owner's decision (relayed 2026-10-08): only the 速射手 air priority outranks the attacker's own blocked enemy — PRTS 索敌的概念 「阻挡(近战限定)→特殊优先级→…」 — while the user's playtest #6 rule 「阻挡了就一定要能打到」 keeps 'blocked first' for every other attacker and priority. PR #220 by TsangAsuna (for #205) moved every special priority ahead of the block; re-implemented for priority 'fly' only (targeting.js sortEnemyTargets: the fly key, then blocked, then the rest as before) — the trait's priority and a skill's targeting priority 'fly' (新约能天使) alike. Seen (repro): 能天使 on a melee tile blocking a walker kept shooting it with a flyer in range; now the flyer, and 远牙 (神射手, lowest DEF first) still hits the enemy it blocks over a softer or a flying one. Docs: SIM.md (blocking), design/engine.md, PLAYING.md 阻挡. Golden: roster-026 (流星, 速射手) and roster-037 (新约能天使's priority 'fly') now shoot flyers in range while blocking.
This commit is contained in:
1 parent
895653fc10
commit
4bd154e326
6 files changed
+89
-51
No files matched your search
@@ -66,6 +66,36 @@ test('#1 the user\'s case: ground-only operators never hit a 近地悬浮 enemy
|
||||
}
|
||||
});
|
||||
|
||||
test('#220 (the owner\'s decision of 2026-10-08): a 速射手 blocking a ground enemy shoots a flyer in its range; a 神射手 keeps hitting the enemy it blocks', () => {
|
||||
const defs = { enemies: {
|
||||
e_walker: enemyRec({ key: 'e_walker', hp: 1e8, atk: 0, def: 800, speed: 1 }),
|
||||
e_soft: enemyRec({ key: 'e_soft', hp: 1e8, atk: 0, def: 0, speed: 0 }),
|
||||
e_bat: enemyRec({ key: 'e_bat', hp: 1e8, atk: 0, def: 0, speed: 0, motion: 'FLY' }),
|
||||
} };
|
||||
const shots = (chessId, other) => {
|
||||
const h = makeBattle({ seed: 3, autoFinish: false, timeLimit: 120, captureNoisy: true, defs, units: [{ chessId, row: 10, col: 4 }] });
|
||||
h.step();
|
||||
const u = h.unit(chessId);
|
||||
h.b.addBuff(u, { key: 'test:mute', flags: { silence: true } });
|
||||
const walker = h.spawn('e_walker', { pos: [10, 7], routeIndex: 0, route: { motion: 'WALK', start: [10, 7], end: [10, 0], checkpoints: [] } });
|
||||
assert.ok(h.runUntil(() => walker.blockedBy === u, 10), `${u.name} on a melee tile blocks the walker`);
|
||||
const o = h.spawn(other, { pos: [10, 6], routeIndex: 0, route: { motion: other === 'e_bat' ? 'FLY' : 'WALK', start: [10, 6], end: [10, 6], checkpoints: [] } });
|
||||
h.step();
|
||||
assert.ok(h.b.enemiesInKeys(u.rangeKeys, u, u.profile).includes(o), `${other} in range`);
|
||||
const n0 = h.hooksOf('damaged').length;
|
||||
h.run(4);
|
||||
const hits = (t) => h.hooksOf('damaged').slice(n0).filter((c) => c.source === u && c.target === t).length;
|
||||
checkInvariants(h.b);
|
||||
return { blocked: hits(walker), other: hits(o) };
|
||||
};
|
||||
const exu = shots('chess_char_3_01_a', 'e_bat'); // 能天使 (速射手: 优先攻击空中单位)
|
||||
assert.ok(exu.other > 0 && exu.blocked === 0, `速射手: the flyer over her own blocked enemy (${JSON.stringify(exu)})`);
|
||||
for (const other of ['e_soft', 'e_bat']) {
|
||||
const far = shots('chess_char_4_20_a', other); // 远牙 (神射手: 优先攻击防御力最低)
|
||||
assert.ok(far.blocked > 0 && far.other === 0, `神射手: still the enemy it blocks, not ${other} (${JSON.stringify(far)})`);
|
||||
}
|
||||
});
|
||||
|
||||
test('#1 ground-only splash spares a hovering enemy next to its ground target (迷迭香 + aftershocks)', () => {
|
||||
const h = makeBattle({ units: [{ chessId: 'chess_char_6_12_a', row: 10, col: 3 }], seed: 3, autoFinish: false, timeLimit: 120, captureNoisy: true, defs: SYN });
|
||||
h.step();
|
||||
|
||||
Reference in new issue
Block a user