Allow Advanced advisors to use the physical Ornithopter

Adopt the supplied advisor/city distinction: advisors do not grant city access, but both printed physical-card modes permit advisor groups. Retain native stance/arrival/locks and distinct original cohorts; use shared advisor-aware paths and entry for minimal bot candidates. Add persistent guidance and genuine paid-acquisition/native-advisor regressions.

Validation: frozen10-file87/87, types/lint/build and three original-action/rendered-table programmes. Actual host/setup, cache1 purchase, foreign shipment/accompaniment and paid BG reinforcement cover range3, two groups and leaving the last city fighter. Eight minimal policy proposals remain legal; controlled geometry and UI checks are separate. No wider combinations, complete modes, final assurance or browser/deployed acceptance claimed. No saved-room/reset/restart/deployment operation.
This commit is contained in:
Quintine committed 2026-10-18 12:58:54 +11:00
1 parent 884a09fa92
commit 7fe84ffbbd
14 files changed
+634 -36

No files matched your search

+2 -3
View File
@@ -67,12 +67,11 @@ void test('played card escrow, owner-only remaining quotas and ended movement su
assert.equal(ended.active,'q');
});
void test('invalid source, blocked route, committed card and explicitly unresolved combinations are immutable',()=>{
for(const change of ['range','storm','prior','advisor','gift','wrongMode'] as const){
const g=fixture(change==='advisor'?'beneGesserit':'emperor',change==='advisor');
for(const change of ['range','storm','prior','gift','wrongMode'] as const){
const g=fixture();
let key=destination(g,origin,3);const extra:Partial<Action>={movementCard:card,ornithopter:'range3'};
if(change==='range')key=destination(g,origin,4);if(change==='storm')g.storm=splitLocation(key).sector;
if(change==='prior')g.players[0].moved=1;
if(change==='advisor'){g.players[0].advisors={red_chasm:{}};g.players[1].forces={[origin]:1};}
if(change==='wrongMode')extra.ornithopter='both';
if(change==='gift')g.pendingRicheseGift={event:'reserved',intent:{owner:'p',recipient:'q',cardId:card},turn:g.turn,phase:g.phase,resume:{response:null,decision:null,pendingKarama:null,phaseOpening:null}} as Game['pendingRicheseGift'];
const before=structuredClone(g);assert.throws(()=>move(g,key,extra),change);assert.deepEqual(g,before);