Connect owned Sandmaster ground pile selection
This commit is contained in:
1 parent
5544b69d7e
commit
24863480cb
10 files changed
+155
-89
No files matched your search
@@ -78,26 +78,9 @@ function markup(game: Game, viewer = 'p', busy = false) {
|
||||
);
|
||||
}
|
||||
|
||||
void test('the owner sees exact default routes, per-pile opt-out and explicit route editing controls', () => {
|
||||
void test('Sandmaster controls remain absent from other seats and unsupported module profiles', () => {
|
||||
const game = fixture();
|
||||
const html = markup(game);
|
||||
assert.match(html, /Sandmaster movement/);
|
||||
assert.match(
|
||||
html,
|
||||
/False Wall West, sector 16 → Wind Pass, sector 16 · 1 \/ 1 territories/,
|
||||
);
|
||||
assert.match(
|
||||
html,
|
||||
/Collect 1 spice in Wind Pass, sector 15 \(3 on the pile\)/,
|
||||
);
|
||||
assert.match(html, /type="checkbox" checked=""/);
|
||||
assert.match(html, /Remove last route step/);
|
||||
assert.match(html, /Reset route to source/);
|
||||
assert.match(html, /Use shortest route/);
|
||||
assert.match(html, />Move with Sandmaster<\/button>/);
|
||||
assert.match(html, /normal Move forces button to decline Sandmaster/);
|
||||
assert.equal(markup(game, 'o'), '');
|
||||
assert.ok((markup(game, 'p', true).match(/disabled=""/g) ?? []).length >= 4);
|
||||
|
||||
const combined = fixture();
|
||||
combined.expansions = ['ix'];
|
||||
@@ -108,18 +91,12 @@ void test('drafts preserve the ordinary move, accept a connected alternate and a
|
||||
const game = fixture();
|
||||
const view = viewGame(game, 'p');
|
||||
const standard = sandmasterMoveDraft(view, move);
|
||||
assert.equal(standard.blocked, null);
|
||||
assert.deepEqual(standard.choice, {
|
||||
routes: { [source]: [source, destination] },
|
||||
collect: [spicePile],
|
||||
});
|
||||
assert.deepEqual(standard.action, {
|
||||
...move,
|
||||
sandmaster: standard.choice,
|
||||
});
|
||||
const collected = applyAction(structuredClone(game), 'p', standard.action!);
|
||||
assert.equal(collected.players[0].spice, game.players[0].spice + 1);
|
||||
assert.equal(collected.spice[spicePile], 2);
|
||||
assert.equal(collected.players[0].forces[source] ?? 0, 0);
|
||||
assert.equal(collected.players[0].forces[destination], 2);
|
||||
assert.equal(collected.players[0].moved, 1);
|
||||
|
||||
assert.ok(GRAPH[source].includes(location('wind_pass', 17)));
|
||||
assert.ok(GRAPH[location('wind_pass', 17)].includes(destination));
|
||||
@@ -165,10 +142,11 @@ void test('all four bot profiles add legal collection only to ordinary single-so
|
||||
action.ornithopterEvent === undefined,
|
||||
),
|
||||
);
|
||||
assert.doesNotThrow(
|
||||
() => applyAction(game, 'p', candidates[0]),
|
||||
`${difficulty} emitted an illegal Sandmaster move`,
|
||||
);
|
||||
const completed = applyAction(game, 'p', candidates[0]);
|
||||
const selected = (candidates[0].sandmaster as { collect: string[] }).collect;
|
||||
assert.equal(completed.players[0].moved, 1, difficulty);
|
||||
assert.equal(completed.players[0].spice, game.players[0].spice + selected.length, difficulty);
|
||||
for (const key of selected) assert.equal(completed.spice[key], game.spice[key] - 1, difficulty);
|
||||
|
||||
const combined = viewGame(fixture(), 'p');
|
||||
combined.players.find((player) => player.id === 'p')!.bot = difficulty;
|
||||
|
||||
@@ -87,7 +87,32 @@ void test('Sandmaster can decline each territory or the entire effect; legacy mo
|
||||
g.players[0].spice,
|
||||
);
|
||||
});
|
||||
void test('Sandmaster rejects disconnected, overlong, storm, duplicate and ambiguous collection choices without mutation', () => {
|
||||
|
||||
void test('Sandmaster chooses either positive sector pile but never collects twice from one entered territory', () => {
|
||||
for (const advanced of [false, true]) {
|
||||
const game = sandmasterMovementGame('emperor', advanced);
|
||||
const action = sandmasterMove(game);
|
||||
const choice = action.sandmaster as SandmasterChoice;
|
||||
const original = choice.collect.find(key => territory(splitLocation(key).territory).sectors.some(
|
||||
sector => sector !== splitLocation(key).sector && sector !== game.storm));
|
||||
assert.ok(original);
|
||||
const at = splitLocation(original);
|
||||
const sector = territory(at.territory).sectors.find(value => value !== at.sector && value !== game.storm)!;
|
||||
const alternate = `${at.territory}:${sector}`;
|
||||
game.spice[alternate] = 2;
|
||||
unchanged(game, { ...action, sandmaster: { ...choice, collect: [...choice.collect, alternate] } });
|
||||
const collect = choice.collect.map(key => key === original ? alternate : key);
|
||||
const done = applyAction(restored(game), 'p', { ...action, sandmaster: { ...choice, collect } });
|
||||
assert.equal(done.spice[original], game.spice[original]);
|
||||
assert.equal(done.spice[alternate], 1);
|
||||
assert.equal(done.players[0].spice, game.players[0].spice + collect.length);
|
||||
assert.equal(done.players[0].moved, 1);
|
||||
const defaults = sandmasterDefaultChoice(viewGame(game, 'p'), 'p', action)!;
|
||||
assert.equal(new Set(defaults.collect.map(key => splitLocation(key).territory)).size, defaults.collect.length);
|
||||
conserved(done, game);
|
||||
}
|
||||
});
|
||||
void test('Sandmaster rejects disconnected, overlong, storm and duplicate collection choices without mutation', () => {
|
||||
const g = sandmasterMovementGame(),
|
||||
action = sandmasterMove(g),
|
||||
choice = action.sandmaster as SandmasterChoice;
|
||||
@@ -117,22 +142,6 @@ void test('Sandmaster rejects disconnected, overlong, storm, duplicate and ambig
|
||||
delete tooFar.players[0].forces['arrakeen:10'];
|
||||
tooFar.players[0].reserves++;
|
||||
unchanged(tooFar, action);
|
||||
const id = splitLocation(choice.collect[0]).territory;
|
||||
const second = territory(id).sectors.find(
|
||||
(s) => `${id}:${s}` !== choice.collect[0],
|
||||
);
|
||||
if (second !== undefined) {
|
||||
const ambiguous = restored(g);
|
||||
ambiguous.spice[`${id}:${second}`] = 2;
|
||||
unchanged(ambiguous, action);
|
||||
const decline = {
|
||||
...choice,
|
||||
collect: choice.collect.filter((key) => key !== choice.collect[0]),
|
||||
};
|
||||
assert.doesNotThrow(() =>
|
||||
applyAction(ambiguous, 'p', { ...action, sandmaster: decline }),
|
||||
);
|
||||
}
|
||||
});
|
||||
void test('Fremen Sandmaster waits for movement permission and cancellation releases untouched spice', () => {
|
||||
const g = sandmasterMovementGame('fremen'),
|
||||
|
||||
Reference in new issue
Block a user