Offer Karama against mandatory advisor ground conversions

Keep completed moves while allowing native advisor-to-fighter conversion to be prevented after empty arrival or the last outsider's ground departure. Bind each queued response to its actual whole group and movement. Shared settlement honors the explicit provisional continuously-alone cancellation duration; setup remains automatic and non-ground producers remain open.

Validation: 16 related files199/199, types/lint/build, five native move/response/GameTable SSR journeys and eight legal existing-profile paths. Native34/36-action public Advanced sources earn original setup/counters/Karama. Existing standard controls render; no new component-callback, browser/deployed or full-mode certificate. No saved-room/D1/restart/deployment operation.
This commit is contained in:
Quintine committed 2026-10-24 19:44:12 +11:00
1 parent 1a505525a8
commit 3aca64412f
15 files changed
+874 -34

No files matched your search

+9 -3
View File
@@ -199,7 +199,7 @@ void test('moving fighters into existing advisors matches their stance, and the
assert.equal(isAdvisor(g.players[1], 'arrakeen'), false);
assert.equal(fighterCount(g.players[1], 'arrakeen'), 3);
});
void test('advisors moving to an empty territory become fighters; optional occupied-territory flips can be canceled after movement', () => {
void test('empty and occupied advisor arrivals offer conversion cancellation after the committed movement', () => {
const g = fixture();
g.players[0].hand = [baseDeck().find((c) => c.effect === 'karama')!];
army(g, 'a', { 'arrakeen:10': 1 });
@@ -217,8 +217,14 @@ void test('advisors moving to an empty territory become fighters; optional occup
assert.equal(isAdvisor(allow(moved).players[1], 'imperial_basin'), false);
g.players[2].forces = {};
const empty = move(g, 'b', 'arrakeen:10', 'imperial_basin', 10, 2);
assert.equal(isAdvisor(empty.players[1], 'imperial_basin'), false);
assert.equal(empty.response, null);
assert.equal(isAdvisor(empty.players[1], 'imperial_basin'), true);
assert.equal(empty.response?.kind, 'advisorFlip');
assert.ok(empty.response?.automaticAdvisorFlip);
assert.equal(isAdvisor(allow(empty).players[1], 'imperial_basin'), false);
const held = cancel(empty);
assert.equal(isAdvisor(held.players[1], 'imperial_basin'), true);
assert.ok(held.players[1].advisors?.imperial_basin.aloneFlipHold);
assert.equal(held.players[1].moved, 1);
});
void test('intrusion without advisor accompaniment restores the same decision and private views', () => {
const g = fixture();