灵巧's knocked-out aura counts only knocked-out operators; hidden-layer bonds hide their layers in the UI only (#66)
A knocked-out 灵巧 operator gives its neighbours the aura once more; a player retreat, a merchant exit or a 联防 forced exit no longer counts, and a redeploy restores it. 调和, 协防干员, 独行 and 绝技 hide their layer counts in the UI while the real layers stay for saving, settlement and support ranking. Contributed by @sunstricken.
This commit is contained in:
1 parent
8747f45bba
commit
85b91b9013
7 files changed
+305
-10
No files matched your search
@@ -83,7 +83,7 @@ test('迅捷 / 不屈 proc chances: p = min(1, base + per·L) at each layer coun
|
||||
close(procChance(ind, 1000), 1, 'capped');
|
||||
});
|
||||
|
||||
test('灵巧: aura on members + 4 neighbours (once), 8 tiles at ≥40 layers, follows death and relocation', () => {
|
||||
test('灵巧: aura on members + 4 neighbours (once), 8 tiles at ≥40 layers, survives death and follows relocation', () => {
|
||||
const defs = { chess: { k_1: op('k_1', ['skillfulShip']), k_2: op('k_2', ['skillfulShip']), k_n: op('k_n', []), k_d: op('k_d', []), k_f: op('k_f', []) } };
|
||||
const h = makeBattle({
|
||||
defs, bonds: { skillfulShip: bond(1, 5) },
|
||||
@@ -107,7 +107,117 @@ test('灵巧: aura on members + 4 neighbours (once), 8 tiles at ≥40 layers, fo
|
||||
assert.equal(a('k_n'), 100, 'relocated out of the aura');
|
||||
h.b.dealDamage(null, h.unit('k_1'), { amount: 1e9, type: 'true' });
|
||||
h.step(2);
|
||||
assert.equal(a('k_d'), 100, 'aura source died');
|
||||
assert.equal(a('k_d'), 150, 'downed aura source still buffs neighbours');
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
|
||||
for (const layers of [5, 40]) {
|
||||
test(`灵巧: downed sources keep one aura at ${layers} layers, update live layers and restore it on redeploy`, () => {
|
||||
const defs = { chess: {
|
||||
k_1: op('k_1', ['skillfulShip']), k_2: op('k_2', ['skillfulShip']),
|
||||
k_n: op('k_n', []), k_d: op('k_d', []),
|
||||
} };
|
||||
const h = makeBattle({
|
||||
defs, bonds: { skillfulShip: bond(1, layers) },
|
||||
units: [
|
||||
{ chessId: 'k_1', row: 10, col: 4 }, { chessId: 'k_2', row: 10, col: 6 },
|
||||
{ chessId: 'k_n', row: 10, col: 5 }, { chessId: 'k_d', row: 11, col: 5 },
|
||||
],
|
||||
});
|
||||
h.step();
|
||||
const first = h.unit('k_1'), second = h.unit('k_2'), neighbour = h.unit('k_n'), diagonal = h.unit('k_d');
|
||||
assert.equal(neighbour.s.aspd, 110 + layers, 'overlapping sources buff once');
|
||||
h.b.kill(first);
|
||||
assert.ok(h.b.isDown(first));
|
||||
assert.equal(neighbour.s.aspd, 110 + layers, 'no attack speed drop on death');
|
||||
h.b.kill(second);
|
||||
assert.ok(h.b.isDown(second));
|
||||
h.run(1);
|
||||
assert.equal(neighbour.s.aspd, 110 + layers, 'all sources down: polling keeps the aura');
|
||||
assert.equal(diagonal.s.aspd, layers >= 40 ? 110 + layers : 100, '4 / 8 tile range still applies');
|
||||
assert.equal(neighbour.buffs.filter((b) => b.key === 'bond:skillfulShip').length, 1);
|
||||
|
||||
gainLayers(h.b, { playerId: 'p1', bonds: 'skillfulShip', n: 40 - layers + 2 });
|
||||
h.step(2);
|
||||
assert.equal(neighbour.s.aspd, 152, 'downed sources use live layer values');
|
||||
assert.equal(diagonal.s.aspd, 152, 'downed sources widen their aura at 40 layers');
|
||||
h.b.kill(neighbour);
|
||||
assert.ok(h.b.redeploy(neighbour, { free: true }));
|
||||
assert.equal(neighbour.s.aspd, 152, 'recipient redeployed next to a downed source');
|
||||
assert.ok(h.b.redeploy(first, { free: true }));
|
||||
assert.equal(first.s.aspd, 152, 'source regains its own bonus on redeploy');
|
||||
assert.equal(neighbour.s.aspd, 152, 'redeploy does not stack the aura');
|
||||
h.b.retreat(first);
|
||||
assert.equal(neighbour.s.aspd, 152, 'remaining downed source still covers the recipient');
|
||||
assert.ok(h.b.redeploy(second, { free: true }));
|
||||
h.b.retreat(second);
|
||||
assert.equal(neighbour.s.aspd, 100, 'withdrawn sources no longer provide an aura');
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
}
|
||||
|
||||
test('灵巧: a downed source provides its aura around the body tile when it returns home after death', () => {
|
||||
const defs = { chess: {
|
||||
k_1: op('k_1', ['skillfulShip']), k_2: op('k_2', ['skillfulShip']),
|
||||
k_home: op('k_home', []), k_away: op('k_away', []), k_tile: op('k_tile', []),
|
||||
} };
|
||||
const h = makeBattle({
|
||||
defs, bonds: { skillfulShip: bond(1, 5) },
|
||||
units: [
|
||||
{ chessId: 'k_1', row: 10, col: 4 }, { chessId: 'k_2', row: 12, col: 3 },
|
||||
{ chessId: 'k_home', row: 10, col: 5 }, { chessId: 'k_away', row: 10, col: 8 },
|
||||
{ chessId: 'k_tile', row: 10, col: 7 },
|
||||
],
|
||||
});
|
||||
h.step();
|
||||
h.b.retreat(h.unit('k_tile'), { permanent: true });
|
||||
assert.ok(h.b.relocate(h.unit('k_1'), 10, 7));
|
||||
h.run(0.4);
|
||||
assert.equal(h.unit('k_home').s.aspd, 100);
|
||||
assert.equal(h.unit('k_away').s.aspd, 115);
|
||||
h.b.kill(h.unit('k_1'));
|
||||
assert.deepEqual(h.unit('k_1').body, [10, 4]);
|
||||
assert.equal(h.unit('k_home').s.aspd, 115, 'aura follows the downed body back home');
|
||||
assert.equal(h.unit('k_away').s.aspd, 100, 'last living tile no longer provides an aura');
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
|
||||
for (const reason of ['retreat', 'forcedExit', 'merchant']) {
|
||||
test(`灵巧: ${reason} leaves a down model without preserving the killed-source aura`, () => {
|
||||
const h = makeBattle({
|
||||
defs: { chess: { k_1: op('k_1', ['skillfulShip']), k_n: op('k_n', []) } },
|
||||
bonds: { skillfulShip: bond(1, 5) },
|
||||
units: [{ chessId: 'k_1', row: 10, col: 4 }, { chessId: 'k_n', row: 10, col: 5 }],
|
||||
});
|
||||
h.step();
|
||||
const source = h.unit('k_1'), recipient = h.unit('k_n');
|
||||
assert.equal(recipient.s.aspd, 115);
|
||||
h.b.retreat(source, { reason });
|
||||
assert.ok(h.b.isDown(source), 'a down model is not proof of being killed');
|
||||
assert.equal(source.removeReason, reason);
|
||||
assert.equal(recipient.s.aspd, 100, 'aura stops immediately on retreat');
|
||||
assert.ok(h.b.redeploy(source, { free: true }));
|
||||
assert.equal(recipient.s.aspd, 115, 'the living source restores its aura');
|
||||
h.b.kill(source);
|
||||
assert.equal(recipient.s.aspd, 115, 'a subsequent real kill keeps the aura');
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
}
|
||||
|
||||
test('灵巧: unite carry-down forcedExit starts without an aura and restores it on redeploy', () => {
|
||||
const h = makeBattle({
|
||||
kind: 'unite',
|
||||
defs: { chess: { k_1: op('k_1', ['skillfulShip']), k_n: op('k_n', []) } },
|
||||
bonds: { skillfulShip: bond(1, 40) },
|
||||
units: [{ chessId: 'k_1', row: 10, col: 4, carryState: { down: true } }, { chessId: 'k_n', row: 11, col: 5 }],
|
||||
});
|
||||
h.step();
|
||||
const source = h.unit('k_1'), recipient = h.unit('k_n');
|
||||
assert.equal(source.removeReason, 'forcedExit');
|
||||
assert.ok(h.b.isDown(source));
|
||||
assert.equal(recipient.s.aspd, 100, 'forcedExit is not a kill in this battle');
|
||||
assert.ok(h.b.redeploy(source, { free: true }));
|
||||
assert.equal(recipient.s.aspd, 150, 'the redeployed source covers all eight neighbours');
|
||||
checkInvariants(h.b);
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user