Files
ark-stronghold-protocol/test/match/feedback3-off-bonds.test.js
T

92 lines
4.8 KiB
JavaScript

// Mode-off bonds stay out of the battle (computeBonds) and show in the views when the player has members
// (offBondCounts → bondList `off: true`, the strip's grey 本局禁用 discs). 标准模拟's inactiveBondIdList
// (activity_table mode_single_funny): 投资人 and 奇迹 count the hand (BOARD_AND_DECK); 突袭 counts the board.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { GameData } from '../../server/match/gamedata.js';
import { computeBonds, bondList, bondSnapshot, offBondCounts } from '../../server/match/bondsMeta.js';
import { DATA } from './harness.js';
const funny = new GameData(DATA, 'mode_single_funny');
const open = new GameData(DATA, 'mode_multi_normal');
let uid = 1;
const piece = (id) => ({ uid: uid++, kind: 'chess', id, items: [] });
const state = ({ board = [], hand = [], layers = {}, bondCountBonus } = {}) => {
const b = new Map();
board.forEach((p, i) => b.set(`${9 + (i % 4)},${2 + Math.floor(i / 4)}`, p));
const h = new Array(10).fill(null);
hand.forEach((p, i) => { h[9 - i] = p; });
return { board: b, hand: h, layers, bondCountBonus };
};
const members = (bond, n) => Object.values(DATA.chess)
.filter((c) => c.visible && !c.isGolden && c.bonds.includes(bond))
.slice(0, n)
.map((c) => c.chessId);
const INVESTOR = members('investShip', 2);
const RAIDER = members('raidShip', 1);
const YAN = members('yanShip', 1);
test('标准模拟: an 投资人 member in hand and a 突袭 member on the board are off entries, never in computeBonds', () => {
assert.equal(INVESTOR.length, 2);
assert.equal(RAIDER.length, 1);
const ps = state({
board: [piece(RAIDER[0]), piece(YAN[0])],
hand: [piece(INVESTOR[0])],
layers: { investShip: 12, raidShip: 4, lateranoShip: 9 },
});
const bonds = computeBonds(funny, ps);
assert.ok(!('investShip' in bonds), '投资人 stays out of the battle input');
assert.ok(!('raidShip' in bonds), '突袭 stays out of the battle input');
assert.ok(!('lateranoShip' in bonds));
assert.equal(bondSnapshot(bonds).investShip, undefined);
assert.ok(bonds.yanShip, 'an enabled bond is unchanged');
const off = offBondCounts(funny, ps);
assert.equal(off.investShip.count, 1, 'a hand member counts for 投资人');
assert.equal(off.investShip.layers, 12);
assert.equal(off.raidShip.count, 1);
assert.equal(off.raidShip.layers, 4);
assert.ok(!('lateranoShip' in off), 'an inactive bond with zero members is omitted, layers or not');
const list = bondList(funny, bonds, { full: true, off });
const invest = list.find((x) => x.bondId === 'investShip');
const raid = list.find((x) => x.bondId === 'raidShip');
assert.deepEqual(
{ count: invest.count, active: invest.active, tier: invest.tier, layers: invest.layers, off: invest.off, countsHand: invest.countsHand },
{ count: 1, active: false, tier: 0, layers: 12, off: true, countsHand: true },
);
assert.equal(raid.off, true);
assert.equal(raid.active, false);
assert.equal(raid.tier, 0);
assert.equal(raid.countsHand, false);
assert.ok(list.findIndex((x) => x.off) > list.findIndex((x) => x.bondId === 'yanShip'), 'off entries follow the live bonds');
assert.ok(list.slice(list.findIndex((x) => x.off)).every((x) => x.off), 'the off entries are a suffix');
const pub = bondList(funny, bonds, { off });
assert.equal(pub.find((x) => x.bondId === 'investShip').off, true);
assert.equal('countsHand' in pub.find((x) => x.bondId === 'investShip'), false, 'm.public omits countsHand');
});
test('a BOARD_AND_DECK off bond counts the hand, not the temporary slots, and not twice', () => {
const [a, b] = INVESTOR;
const handOnly = offBondCounts(funny, state({ hand: [piece(a), piece(b)] }));
assert.equal(handOnly.investShip.count, 2);
assert.ok(!('raidShip' in (handOnly || {})), '突袭 in nobody\'s hand: a board bond with no board member is omitted');
const raidHand = offBondCounts(funny, state({ hand: [piece(RAIDER[0])] }));
assert.equal(raidHand, null, '突袭 does not count a hand member');
const both = offBondCounts(funny, state({ board: [piece(a)], hand: [piece(a), piece(DATA.chess[a].goldenId)] }));
assert.equal(both.investShip.count, 1, 'normal and elite of one operator, board and hand, count once');
const tempOnly = { board: new Map(), hand: new Array(10).fill(null), layers: {}, temp: [piece(a)] };
assert.equal(offBondCounts(funny, tempOnly), null, 'the 5 temporary slots never count');
});
test('a mode with an empty inactive set returns null, and those bonds stay in computeBonds', () => {
assert.equal(open.modeInactiveBonds.size, 0);
const ps = state({ board: [piece(RAIDER[0])], hand: [piece(INVESTOR[0])] });
assert.equal(offBondCounts(open, ps), null);
const bonds = computeBonds(open, ps);
assert.equal(bonds.investShip.count, 1);
assert.equal(bonds.raidShip.count, 1);
assert.equal(bondList(open, bonds).some((x) => x.off), false);
});