Connect expansion faction setup and saved Ixian auction decline
Add a local faction-only prototype profile for all seven nonempty expansion selections, genuine Basic/Advanced initialization and existing private setup, controls, AI and saved continuation. Ecaz allocates six forces across Imperial Basin sectors and retains fourteen reserves before later setup; preserve Fremen, Advanced BG and Moritani ordering with printed and inferred boundaries explicit. Keep optional Ecaz Treachery cards separate, ordinary deck counts 33/35/47, and Richese cache separate. Public start and publication gates remain closed. Replace the Advanced Ixian/Richese pre-offer stop with an explicit per-lot Ixian decline. Bind the saved original offer to its round, turn, owner, independent event, exact card custody and terms before view/action/normalization. Decline resumes that unchanged lot once without using Technology; later normal lots still offer the exchange. Protect reserved cards across transfers, spending and random Harkonnen exchange, and preserve legitimate Gift/Truthtrance interruptions. The actual special-lot exchange still awaits replacement-custody interpretation. Validation: focused setup, rules, UI/bot, private JSON/SQLite reload and concurrent CAS tests and independent custody/persistence review passed. Typecheck, lint, 4573 offline tests, production build and 43 HTTP tests passed. Browser Ecaz setup rejected an incomplete total, saved a 2/2/2 split, and refreshed to fourteen reserves and unchanged private cards. A separate genuine Advanced QA game restored the Ixian choice; explicit decline opened the unchanged cache lot with legal bidding and retained private hand, spice, pool count and unused Technology after refresh. Five of six genuine four-profile samples finish: CHOAM Basic 1054 actions/28 JSON restores, CHOAM Advanced 225/6, Ecaz Basic 91/2, Ecaz Advanced 523/14, all-three Basic 476/12. Combined Advanced passes three former auction stops and reaches turn three/action614 with 16 restores, then hits an existing CHOAM movement/Ambassador arrival guard. Ecaz samples also include guarded arrival candidates with legal alternatives. Full combined play is not certified; arrival integration is the next gap. Retain initial failed logs, including a corrected private harness sold-card receipt alias. After the outage, all 597 opening rooms and original seat/recovery records were preserved (632 after QA/HTTP). A stale development module cache required restart after a fresh 598-room backup; all 598 matched afterward and the QA seat restored. Final integrity and foreign keys passed. No database reset, recurring automation or publication. Verified source tree: 5e2ff244a1167f2834bb46d609b8de914a34f7049ff7b06046243068c0935131
This commit is contained in:
1 parent
f067950f5e
commit
cab2f1c42d
26 files changed
+3001
-58
No files matched your search
@@ -320,34 +320,42 @@ void test('normal paid auctions after a cache sale route income to Emperor witho
|
||||
assert.equal(g.auction!.index, 1);
|
||||
});
|
||||
|
||||
void test('advanced unused Ixian Technology explicitly fences special lots when Ixians hold a replacement', () => {
|
||||
void test('advanced unused Ixian Technology pauses special lots for an explicit per-lot decline', () => {
|
||||
let g = fixture(true);
|
||||
g.players[2].faction = 'ixians';
|
||||
g.players[2].hand = [g.deck.shift()!];
|
||||
reject(
|
||||
g,
|
||||
'r',
|
||||
{
|
||||
type: 'decision',
|
||||
event: g.richeseBidding!.event,
|
||||
card: g.players[0].hand[0].id,
|
||||
method: 'silent',
|
||||
},
|
||||
/Ixian Technology/,
|
||||
);
|
||||
const blackMarket = applyAction(g, 'r', {
|
||||
type: 'decision',
|
||||
event: g.richeseBidding!.event,
|
||||
card: g.players[0].hand[0].id,
|
||||
method: 'silent',
|
||||
});
|
||||
assert.equal(blackMarket.decision?.kind, 'ixRicheseTechnology');
|
||||
assert.equal(blackMarket.richeseAuction, null);
|
||||
const resumed = applyAction(blackMarket, g.players[2].id, {
|
||||
type: 'decision',
|
||||
event: blackMarket.pendingIxRicheseTechnology!.event,
|
||||
decline: true,
|
||||
});
|
||||
assert.equal(resumed.richeseAuction?.source, 'blackMarket');
|
||||
assert.equal(resumed.ixTechnologyTurn, g.ixTechnologyTurn);
|
||||
g = decision(g, { decline: true });
|
||||
g = decision(g, { position: 'first' });
|
||||
reject(
|
||||
g,
|
||||
'r',
|
||||
{
|
||||
type: 'decision',
|
||||
event: g.richeseBidding!.event,
|
||||
card: g.richeseCache![0].id,
|
||||
method: 'silent',
|
||||
},
|
||||
/Ixian Technology/,
|
||||
);
|
||||
const cache = applyAction(g, 'r', {
|
||||
type: 'decision',
|
||||
event: g.richeseBidding!.event,
|
||||
card: g.richeseCache![0].id,
|
||||
method: 'silent',
|
||||
});
|
||||
assert.equal(cache.decision?.kind, 'ixRicheseTechnology');
|
||||
assert.equal(cache.richeseAuction, null);
|
||||
const resumedCache = applyAction(cache, g.players[2].id, {
|
||||
type: 'decision',
|
||||
event: cache.pendingIxRicheseTechnology!.event,
|
||||
decline: true,
|
||||
});
|
||||
assert.equal(resumedCache.richeseAuction?.source, 'cache');
|
||||
assert.equal(resumedCache.ixTechnologyTurn, g.ixTechnologyTurn);
|
||||
g.ixTechnologyTurn = g.turn;
|
||||
g = decision(g, { card: g.richeseCache![0].id, method: 'silent' });
|
||||
assert.equal(g.richeseAuction!.source, 'cache');
|
||||
|
||||
Reference in new issue
Block a user