103 lines
6.0 KiB
TypeScript
103 lines
6.0 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { coalitionOf, emptyCoalitionState } from '../game/coalition-alliance';
|
|
import { coalitionBattleBeneficiary } from '../game/coalition-battle-preparation';
|
|
import { nativeBattlePowerOpportunity, type NativeBattlePowerGame } from '../game/battle-power-question';
|
|
import { applyAction, createGame, newPlayer } from '../game/engine';
|
|
|
|
/** The ledger starts staged because the lobby does not expose group play;
|
|
* the pair and unanimous third admission use real Nexus actions. */
|
|
function groupGame(): NativeBattlePowerGame {
|
|
let game = createGame('GROUPPOWER', newPlayer('bg', 'Bene Gesserit', 'beneGesserit'), false);
|
|
game.players.push(newPlayer('a', 'Atreides', 'atreides'), newPlayer('e', 'Emperor', 'emperor'),
|
|
newPlayer('h', 'Harkonnen', 'harkonnen'));
|
|
Object.assign(game, {status:'playing', phase:1, turn:2, nexus:true, order:['bg','a','e','h'],
|
|
ready:[], storm:18, response:null, decision:null, phaseOpening:null});
|
|
game.coalitionState = emptyCoalitionState();
|
|
game = applyAction(game, 'bg', {type:'alliance', target:'a'});
|
|
game = applyAction(game, 'a', {type:'alliance', target:'bg'});
|
|
const pair = coalitionOf(game.players, game.coalitionState, 'bg'); assert.ok(pair);
|
|
game = applyAction(game, 'bg', {type:'coalitionPropose', groupId:pair.id, entrant:'e',
|
|
expectedRevision:game.coalitionState!.revision});
|
|
for (const id of ['a', 'e']) {
|
|
const proposal = game.coalitionState!.proposal!;
|
|
game = applyAction(game, id, {type:'coalitionAnswer', event:proposal.event, nexus:proposal.nexus,
|
|
turn:proposal.turn, accept:true, expectedRevision:game.coalitionState!.revision});
|
|
}
|
|
assert.deepEqual(coalitionOf(game.players, game.coalitionState, 'bg')!.members, ['a','bg','e']);
|
|
return {status:'playing', phase:6, advanced:false, expansions:[], players:game.players,
|
|
coalitionState:game.coalitionState,
|
|
battle:{event:'group-battle', territory:'carthag', attacker:'e', defender:'h', revealed:false,
|
|
prepared:true, preparation:{kind:'voice', owner:'bg', beneficiary:'e'}}};
|
|
}
|
|
|
|
void test('group Voice and Prescience select either actual allied combatant against an outsider', () => {
|
|
const source = groupGame();
|
|
const before = structuredClone(source);
|
|
for (const [owner, otherAlly] of [['bg','a'], ['a','bg']] as const) {
|
|
for (const ally of [otherAlly, 'e']) {
|
|
assert.equal(coalitionBattleBeneficiary(source, owner, ally, 'h'), ally);
|
|
assert.equal(coalitionBattleBeneficiary(source, owner, 'h', ally, true), ally);
|
|
}
|
|
assert.equal(coalitionBattleBeneficiary(source, owner, owner, 'h'), owner);
|
|
}
|
|
assert.deepEqual(source, before);
|
|
});
|
|
|
|
void test('group Voice is ready now and allied Prescience remains the future owned opportunity', () => {
|
|
const source = groupGame();
|
|
assert.deepEqual(nativeBattlePowerOpportunity(source, 'bg', 'voice'), {
|
|
event:'group-battle', territory:'carthag', power:'voice', owner:'bg', beneficiary:'e', target:'h', ready:true,
|
|
});
|
|
assert.deepEqual(nativeBattlePowerOpportunity(source, 'a', 'prescience'), {
|
|
event:'group-battle', territory:'carthag', power:'prescience', owner:'a', beneficiary:'e', target:'h', ready:false,
|
|
});
|
|
source.battle!.preparation = {kind:'prescience', owner:'a', beneficiary:'e'};
|
|
assert.equal(nativeBattlePowerOpportunity(source, 'a', 'prescience')?.ready, true);
|
|
assert.equal(nativeBattlePowerOpportunity(source, 'bg', 'voice'), null);
|
|
source.response = {};
|
|
assert.equal(nativeBattlePowerOpportunity(source, 'a', 'prescience')?.ready, false);
|
|
});
|
|
|
|
void test('each group ally supplies the beneficiary for the corresponding native power', () => {
|
|
const source = groupGame();
|
|
source.battle!.attacker = 'a';
|
|
source.battle!.preparation = {kind:'voice', owner:'bg', beneficiary:'a'};
|
|
assert.equal(nativeBattlePowerOpportunity(source, 'bg', 'voice')?.beneficiary, 'a');
|
|
source.battle!.attacker = 'bg';
|
|
source.battle!.preparation = {kind:'prescience', owner:'a', beneficiary:'bg'};
|
|
assert.equal(nativeBattlePowerOpportunity(source, 'a', 'prescience')?.beneficiary, 'bg');
|
|
});
|
|
|
|
void test('unsupported group profiles and ambiguous battles cannot borrow an ally power', () => {
|
|
const source = groupGame();
|
|
for (const patch of [{advanced:true}, {expansions:['ix']}, {homeworlds:{}},
|
|
{nexusCards:{}}, {leaderSkills:{}}, {techTokens:{}}, {strongholdCards:{}},
|
|
{ecazTreachery:true}, {discoveryEnabled:true}]) {
|
|
const unsupported = {...source, ...patch};
|
|
assert.equal(coalitionBattleBeneficiary(unsupported, 'bg', 'e', 'h'), null);
|
|
assert.equal(nativeBattlePowerOpportunity(unsupported, 'bg', 'voice'), null);
|
|
}
|
|
assert.equal(coalitionBattleBeneficiary(source, 'bg', 'a', 'e'), null);
|
|
assert.equal(coalitionBattleBeneficiary(source, 'bg', 'bg', 'a'), null);
|
|
assert.equal(coalitionBattleBeneficiary(source, 'bg', 'e', 'e'), null);
|
|
source.battle!.attacker = 'a'; source.battle!.defender = 'e';
|
|
source.battle!.preparation = {kind:'voice', owner:'bg', beneficiary:'a'};
|
|
assert.equal(nativeBattlePowerOpportunity(source, 'bg', 'voice'), null);
|
|
});
|
|
|
|
void test('legacy self and reciprocal-pair selection keep their existing behavior', () => {
|
|
const pair: NativeBattlePowerGame = {status:'playing', phase:6, players:[
|
|
{id:'bg', faction:'beneGesserit', ally:'e'}, {id:'e', faction:'emperor', ally:'bg'},
|
|
{id:'h', faction:'harkonnen', ally:null},
|
|
], battle:{event:'pair', territory:'carthag', attacker:'e', defender:'h', revealed:false,
|
|
preparation:{kind:'voice', owner:'bg', beneficiary:'e'}}};
|
|
assert.equal(coalitionBattleBeneficiary(pair, 'bg', 'bg', 'h', true), 'bg');
|
|
assert.equal(coalitionBattleBeneficiary(pair, 'bg', 'e', 'h', true), 'e');
|
|
assert.equal(nativeBattlePowerOpportunity(pair, 'bg', 'voice')?.beneficiary, 'e');
|
|
pair.players = pair.players.map(player => player.id === 'e' ? {...player, ally:null} : player);
|
|
assert.equal(coalitionBattleBeneficiary(pair, 'bg', 'e', 'h'), 'e');
|
|
assert.equal(coalitionBattleBeneficiary(pair, 'bg', 'e', 'h', true), null);
|
|
assert.equal(nativeBattlePowerOpportunity(pair, 'bg', 'voice'), null);
|
|
});
|