Wire the Tleilaxu Ambassador force return
The last unimplemented Ambassador effect is now reachable. A placed Tleilaxu token gives its beneficiary — the Ecaz owner or its ally — a private ecazAmbassador decision at the new revival stage: one to four physical counters return from the Tanks to reserves at zero cost, quoted by the existing game/tleilaxu-ambassador-forces.ts, which also enforces the shared Fedaykin/Sardaukar one-per-turn counter and keeps Ixian cyborgs uncapped. The player view projects the maximum, Tanks and elite inventory and current elite usage to the beneficiary only; the entry control offers a per-count button and an explicit "Return no forces" decline; all four AI profiles choose a legal return from the decision owner's own view or decline when the Tanks are empty. Player-facing coverage text now lists Tleilaxu. Kept gated exactly as recorded: the printed leader alternative, ordinary force/free/leader allowance accounting around this independent grant, dead-twice eligibility, and Tleilaxu free-income repeat scope. No ordinary revival allowance, price, phase or income path changes. Evidence: tests/tleilaxu-ambassador-engine.test.ts drives a genuine arrival into a placed token and asserts the beneficiary-only projection, the typed return with unchanged spice, the shared elite limit, malformed/over-maximum rejection with immutability, the ordinary-only return, the decline path and the rendered control. The four-profile ecaz-entry-bots loop now covers tleilaxu, and the former unsupported-effect and copy-list pins were updated to the supported behaviour rather than re-pinned. Offline suite 7,797/7,797 with typecheck and lint clean. No game, seat, saved state or deployment changes.
This commit is contained in:
1 parent
07c20ae806
commit
0e1a442dca
11 files changed
+503
-27
No files matched your search
@@ -123,6 +123,7 @@ void test('all four profiles legally resolve each supported ordinary effect from
|
||||
'harkonnen',
|
||||
'choam',
|
||||
'ixians',
|
||||
'tleilaxu',
|
||||
] as const) {
|
||||
const initial = enter(fixture(effect));
|
||||
for (const id of ['entrant', 'ally'])
|
||||
@@ -166,19 +167,22 @@ void test('all four profiles legally resolve each supported ordinary effect from
|
||||
}
|
||||
});
|
||||
|
||||
void test('unsupported effects are explicitly declined without consuming the placed token at every difficulty', () => {
|
||||
for (const difficulty of DIFFICULTIES)
|
||||
for (const effect of ['tleilaxu'] as const) {
|
||||
const entered = enter(fixture(effect));
|
||||
const { action, next } = choose(entered, difficulty);
|
||||
assert.equal(action.decline, true);
|
||||
assert.equal(next.pendingAmbassador, null);
|
||||
assert.equal(
|
||||
next.ecazAmbassadors!.tokens.find((t) => t.effect === effect)!.zone,
|
||||
'placed',
|
||||
);
|
||||
assert.equal(next.players[0].spice, 10);
|
||||
}
|
||||
void test('the Tleilaxu force return is offered and declined when the beneficiary has nothing in the Tanks', () => {
|
||||
for (const difficulty of DIFFICULTIES) {
|
||||
const entered = enter(fixture('tleilaxu'));
|
||||
const offered = choose(entered, difficulty).next;
|
||||
assert.equal(offered.pendingAmbassador?.stage, 'revival');
|
||||
assert.equal(offered.decision?.kind, 'ecazAmbassador');
|
||||
const { action, next } = choose(offered, difficulty);
|
||||
assert.equal(action.decline, true);
|
||||
assert.equal(next.pendingAmbassador, null);
|
||||
assert.equal(
|
||||
next.ecazAmbassadors!.tokens.find((t) => t.effect === 'tleilaxu')!.zone,
|
||||
'used',
|
||||
);
|
||||
assert.equal(next.players[0].spice, 10);
|
||||
assert.equal(next.players[0].tanks, 0);
|
||||
}
|
||||
});
|
||||
|
||||
void test('Bene Gesserit copies choose only supported projected effects and complete without another acknowledgement', () => {
|
||||
|
||||
Reference in new issue
Block a user