- co-op leaders died within seconds: leader HP is the official data (40 values pinned); bond / strategy / item / 机变 / 特质 "+X%" bonuses now add up (PRTS 直接乘算) instead of compounding; a same-named enemy debuff keeps one (strongest) instance per target (奥术 across a pair field); leader parts pass damage 1:1; fixed co-op pool (the user's call) - official limits read from the client: each bond stops at 999 layers (MAX_GARRISON_STACK); a leader hit of 300000+ in boss / hidden battles is cancelled (MAX_BATTLE_DAMAGE, 限伤) — shared/constants.js switches, research 11 - a merge that consumes a deployed copy puts the elite on that tile and facing (user-confirmed); gold target highlight, promotion effect - 假想敌:胄 per PRTS: one shell, shells within range, any drone death costs 2 % max HP, 剑/锤 sorties and 瘫痪 - DESIGN §20.10–§20.14; 2842 unit tests, all 28 browser suites green; Chrome = Node on boss fields
47 lines
2.4 KiB
JavaScript
47 lines
2.4 KiB
JavaScript
// Bond layer cap (user report after playtest #6, DESIGN §20.10 / §20.12): a bond holds at most BOND_LAYER_CAP — 999, the
|
|
// client's AutoChessBattleConst.MAX_GARRISON_STACK (research 11 §1; the community also never names a count above 999:
|
|
// 巴哈姆特 12534 "每把都能999层", 12316 "999謝"). v2.5 had no cap, so per-layer bonuses kept growing past anything the
|
|
// official game reaches. Prep-side gains (PlayerState.addLayers: items, choices, bands, garrisons) and the IN_BATTLE gains
|
|
// merged at settlement both stop there (shared/constants.js layerGainRoom, the one implementation).
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { PHASE, BOND_LAYER_CAP } from '../../shared/constants.js';
|
|
import { MetaRegistry } from '../../server/match/effectsMeta.js';
|
|
import { registerBuiltins } from '../../server/match/builtinMeta.js';
|
|
import { DATA, makeMatch, checkInvariants } from './harness.js';
|
|
|
|
test('prep-side layer gains stop at 999; a gain at the cap adds nothing and fires no onLayers', () => {
|
|
assert.equal(BOND_LAYER_CAP, 999);
|
|
const reg = registerBuiltins(new MetaRegistry(), DATA);
|
|
const seen = [];
|
|
reg.global('watch', { onLayers: (ctx, ev) => { seen.push([ev.bondId, ev.from, ev.to]); } });
|
|
const h = makeMatch({ mode: 'solo', seed: 81, registry: reg, fake: true }).start();
|
|
h.toPrep(1);
|
|
const ps = h.ps('p_0');
|
|
ps.layers.yanShip = 990;
|
|
assert.equal(ps.addLayers('yanShip', 20, { reason: 'test' }), 9, 'only the room left under the cap');
|
|
assert.equal(ps.layers.yanShip, 999);
|
|
assert.equal(ps.addLayers('yanShip', 5, { reason: 'test' }), 0, 'at the cap: nothing');
|
|
assert.equal(ps.layers.yanShip, 999);
|
|
assert.deepEqual(seen, [['yanShip', 990, 999]], 'one onLayers, with the clamped value');
|
|
assert.equal(ps.addLayers('sargonShip', 40, { reason: 'test' }), 40, 'other bonds unaffected');
|
|
checkInvariants(h.m);
|
|
h.m.dispose();
|
|
});
|
|
|
|
test('IN_BATTLE gains merged at settlement stop at 999 too; below the cap they apply in full', () => {
|
|
const h = makeMatch({
|
|
mode: 'coop', humans: 2, seed: 82, fake: true,
|
|
script: (b) => (b.round === 1 ? { layerGains: { p_0: { yanShip: 50 }, p_1: { yanShip: 50 } } } : {}),
|
|
}).start();
|
|
const m = h.m;
|
|
h.toPrep(1);
|
|
const [a, b] = [h.ps('p_0'), h.ps('p_1')];
|
|
a.layers.yanShip = 980;
|
|
h.drive(() => m.phase === PHASE.SETTLE);
|
|
assert.equal(a.layers.yanShip, 999, '980 + 50 stops at 999');
|
|
assert.equal(b.layers.yanShip, 50);
|
|
checkInvariants(m);
|
|
m.dispose();
|
|
});
|