Resume printed native specials through Semuta cost and cashout stages
This commit is contained in:
1 parent
44c2bf0da4
commit
8a2df97be8
14 files changed
+656
-35
No files matched your search
+132
-25
@@ -1416,6 +1416,15 @@ export type Game = {
|
||||
resume: NonNullable<Game['pendingNullentropy']>['resume'];
|
||||
stateSignature: string;
|
||||
}
|
||||
| {
|
||||
kind: 'specialKaramaDiscard';
|
||||
player: string;
|
||||
card: string;
|
||||
intent: SpecialKaramaIntent;
|
||||
stage: 'effect' | 'complete' | 'cashout';
|
||||
resume: NonNullable<Game['pendingNullentropy']>['resume'];
|
||||
stateSignature: string;
|
||||
}
|
||||
| {
|
||||
kind: 'choamSaleDiscard';
|
||||
owner: string;
|
||||
@@ -5555,6 +5564,64 @@ function karamaShipmentPriceDiscardSignature(g: Game, c: KaramaShipmentPriceDisc
|
||||
opportunity: karamaOpportunitySignature(g, { owner: c.player, use: c.use }),
|
||||
});
|
||||
}
|
||||
type SpecialKaramaDiscardContinuation = Extract<
|
||||
NonNullable<Game['pendingTreacheryDiscard']>['continuation'],
|
||||
{ kind: 'specialKaramaDiscard' }
|
||||
>;
|
||||
function specialKaramaDiscardSignature(g: Game, c: SpecialKaramaDiscardContinuation) {
|
||||
return JSON.stringify({
|
||||
player: c.player, card: c.card, intent: c.intent, stage: c.stage,
|
||||
parent: nullentropyParentSignature(g, c.resume, `specialKarama:${c.intent.kind}:${c.card}`),
|
||||
status: g.status, turn: g.turn, phase: g.phase, advanced: g.advanced,
|
||||
active: g.active, order: g.order, ready: g.ready,
|
||||
movementRemaining: g.movementRemaining, battle: g.battle,
|
||||
lastBattle: g.lastBattleContext, homeworlds: g.homeworlds,
|
||||
occupation: g.homeworldOccupationHistory, mobile: g.mobileStronghold,
|
||||
tech: g.techTokens, skills: g.leaderSkills, strongholds: g.strongholdCards,
|
||||
price: g.karamaShipping, spice: g.spice, storm: g.storm,
|
||||
stormResolution: g.stormResolution, spiceWindow: g.spiceWindow,
|
||||
spiceResolution: g.spiceResolution, summoned: g.summonedWorm,
|
||||
rides: g.wormRides, nexus: g.nexusCards,
|
||||
emperorPurchases: g.nexusEmperorPurchaseHistory,
|
||||
auction: g.auction, sale: g.currentAuctionSale,
|
||||
richeseAuction: g.richeseAuction, richeseBidding: g.richeseBidding,
|
||||
cache: g.richeseCache?.map(card => card.id),
|
||||
deck: g.deck.map(card => card.id), revivalPrevention: g.revivalPrevention,
|
||||
players: g.players.map(p => ({
|
||||
id: p.id, faction: p.faction, ally: p.ally,
|
||||
hand: p.hand.map(card => card.id), spice: p.spice,
|
||||
forces: p.forces, reserves: p.reserves, tanks: p.tanks,
|
||||
elites: p.elites, leaders: p.leaders, noField: p.noField,
|
||||
noFieldEvent: p.noFieldEvent, advisors: p.advisors,
|
||||
shipped: p.shipped, moved: p.moved, revived: p.revived,
|
||||
specialKaramaUsed: p.specialKaramaUsed,
|
||||
})),
|
||||
});
|
||||
}
|
||||
function stageSpecialKaramaCost(
|
||||
g: Game, intent: SpecialKaramaIntent, card: Card, complete: boolean,
|
||||
): boolean {
|
||||
if (!g.semutaPreview || card.effect !== 'karama') return false;
|
||||
return stageSpecialKaramaDiscard(g, intent,
|
||||
[{ card, discardedBy: intent.owner, publicFace: true }], complete ? 'complete' : 'effect');
|
||||
}
|
||||
function stageSpecialKaramaDiscard(
|
||||
g: Game, intent: SpecialKaramaIntent, entries: FreshDiscardBatch['entries'],
|
||||
stage: SpecialKaramaDiscardContinuation['stage'],
|
||||
): boolean {
|
||||
const continuation: SpecialKaramaDiscardContinuation = {
|
||||
kind: 'specialKaramaDiscard', player: intent.owner, card: intent.card, intent, stage,
|
||||
resume: { response: g.response, decision: g.decision,
|
||||
pendingKarama: g.pendingKarama, phaseOpening: g.phaseOpening },
|
||||
stateSignature: '',
|
||||
};
|
||||
if (!semutaOfferSupported(g, continuation, entries)) return false;
|
||||
g.response = null; g.decision = null; g.pendingKarama = null; g.phaseOpening = null;
|
||||
continuation.stateSignature = specialKaramaDiscardSignature(g, continuation);
|
||||
stageTreacheryDiscard(g, stage === 'cashout' ? 'specialKarama:choamCashout'
|
||||
: `specialKarama:${intent.kind}`, entries, continuation);
|
||||
return true;
|
||||
}
|
||||
type ChoamSaleDiscardContinuation = Extract<
|
||||
NonNullable<Game['pendingTreacheryDiscard']>['continuation'],
|
||||
{ kind: 'choamSaleDiscard' }
|
||||
@@ -6386,6 +6453,28 @@ function treacheryDiscardIntegrity(g: Game) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} else if (continuation?.kind === 'specialKaramaDiscard') {
|
||||
const c = continuation, entry = batch.entries[0], owner = getPlayer(g, c.player);
|
||||
const emperor = c.intent.kind === 'emperorLeader' || c.intent.kind === 'emperorForces';
|
||||
const faction = emperor ? 'emperor' : c.intent.kind === 'guildHomeworld' ? 'guild' : c.intent.kind;
|
||||
const cashout = c.stage === 'cashout' && c.intent.kind === 'choam' ? c.intent.cards : null;
|
||||
requireRule(
|
||||
g.advanced && !g.response && !g.decision && !g.pendingKarama && !g.phaseOpening &&
|
||||
c.player === c.intent.owner && c.card === c.intent.card &&
|
||||
c.intent.turn === g.turn && c.intent.phase === g.phase &&
|
||||
owner.faction === faction &&
|
||||
(c.stage === 'complete' ? emperor && owner.specialKaramaUsed === true
|
||||
: cashout ? owner.specialKaramaUsed === true : c.stage === 'effect' && !emperor && !owner.specialKaramaUsed) &&
|
||||
(cashout
|
||||
? batch.cause === 'specialKarama:choamCashout' && batch.entries.length === cashout.length &&
|
||||
batch.entries.every((entry, index) => !entry.publicFace && entry.discardedBy === c.player &&
|
||||
entry.card.id === cashout[index] && entry.card.id !== c.card)
|
||||
: batch.cause === `specialKarama:${c.intent.kind}` && batch.entries.length === 1 &&
|
||||
entry.card.id === c.card && entry.card.effect === 'karama' &&
|
||||
entry.publicFace && entry.discardedBy === c.player) &&
|
||||
c.stateSignature === specialKaramaDiscardSignature(g, c),
|
||||
'The spent special Karama no longer matches its original native activation.',
|
||||
);
|
||||
} else if (continuation?.kind === 'karamaShipmentPriceDiscard') {
|
||||
const c = continuation, entry = batch.entries[0];
|
||||
requireRule(
|
||||
@@ -7223,6 +7312,7 @@ function semutaOfferSupported(
|
||||
continuation.kind !== 'karamaIncomeDiscard' &&
|
||||
continuation.kind !== 'karamaShipmentDiscard' &&
|
||||
continuation.kind !== 'karamaShipmentPriceDiscard' &&
|
||||
continuation.kind !== 'specialKaramaDiscard' &&
|
||||
continuation.kind !== 'kaitainDiscard' &&
|
||||
continuation.kind !== 'tupileCleanupDiscard' &&
|
||||
continuation.kind !== 'karamaPurchaseDiscard' &&
|
||||
@@ -7257,6 +7347,7 @@ function semutaOfferSupported(
|
||||
continuation.kind !== 'karamaIncomeDiscard' &&
|
||||
continuation.kind !== 'karamaShipmentDiscard' &&
|
||||
continuation.kind !== 'karamaShipmentPriceDiscard' &&
|
||||
continuation.kind !== 'specialKaramaDiscard' &&
|
||||
continuation.kind !== 'ordinaryCardDiscard' &&
|
||||
continuation.kind !== 'nullentropyDiscard' &&
|
||||
continuation.kind !== 'distransDiscard' &&
|
||||
@@ -7325,7 +7416,8 @@ function semutaOfferSupported(
|
||||
return g.semutaPreview === true && g.status === 'playing' &&
|
||||
g.players.some(p => p.faction === 'richese') &&
|
||||
entries.length > 0 &&
|
||||
(continuation.kind === 'kaitainDiscard' || continuation.kind === 'tupileCleanupDiscard'
|
||||
(continuation.kind === 'kaitainDiscard' || continuation.kind === 'tupileCleanupDiscard' ||
|
||||
(continuation.kind === 'specialKaramaDiscard' && continuation.stage === 'cashout')
|
||||
? entries.every(entry => !entry.publicFace)
|
||||
: continuation.kind === 'ixAllyCard' || continuation.kind === 'terrorDiscard' ||
|
||||
continuation.kind === 'nexusChoamBetrayal' || choamCunningDiscard(continuation)
|
||||
@@ -7359,6 +7451,7 @@ function semutaOfferSupported(
|
||||
(!g.response || JSON.stringify(g.response) === JSON.stringify(continuation.resume.response))
|
||||
: true) &&
|
||||
(continuation.kind === 'battleCleanup' ||
|
||||
continuation.kind === 'specialKaramaDiscard' ||
|
||||
continuation.kind === 'winnerMandatoryDiscard' ||
|
||||
continuation.kind === 'battleResolved' ||
|
||||
continuation.kind === 'kaitainDiscard' ||
|
||||
@@ -7386,8 +7479,9 @@ function semutaOfferSupported(
|
||||
(continuation.kind === 'amalDiscard'
|
||||
? continuation.resume.phaseOpening?.passed.length === 0
|
||||
: !continuation.resume.phaseOpening)))) &&
|
||||
(continuation.kind === 'karamaShipmentDiscard' || !g.karamaShipping) &&
|
||||
(continuation.kind === 'ixAllyCard'
|
||||
(continuation.kind === 'karamaShipmentDiscard' ||
|
||||
continuation.kind === 'specialKaramaDiscard' || !g.karamaShipping) &&
|
||||
(continuation.kind === 'specialKaramaDiscard' || (continuation.kind === 'ixAllyCard'
|
||||
? !!g.currentAuctionSale && continuation.sale.origin === g.currentAuctionSale.origin &&
|
||||
(continuation.sale.origin === 'normal'
|
||||
? !!g.auction && !g.richeseAuction
|
||||
@@ -7400,12 +7494,13 @@ function semutaOfferSupported(
|
||||
continuation.use.response.kind === 'emperorIncome'
|
||||
? !!g.currentAuctionSale && (g.currentAuctionSale.origin === 'normal'
|
||||
? !!g.auction && !g.richeseAuction : !!g.richeseAuction && !g.auction)
|
||||
: !g.auction) &&
|
||||
(continuation.kind === 'saphoAuctionDiscard' ||
|
||||
: !g.auction)) &&
|
||||
(continuation.kind === 'specialKaramaDiscard' || continuation.kind === 'saphoAuctionDiscard' ||
|
||||
continuation.kind === 'ixAllyCard' ||
|
||||
(continuation.kind === 'karamaIncomeDiscard' &&
|
||||
continuation.use.response.kind === 'emperorIncome') || !g.richeseAuction) &&
|
||||
(continuation.kind === 'saphoAggressorDiscard' ||
|
||||
continuation.kind === 'specialKaramaDiscard' ||
|
||||
continuation.kind === 'residualPoisonDiscard' ||
|
||||
continuation.kind === 'truthtranceDiscard' ||
|
||||
continuation.kind === 'nullentropyDiscard' ||
|
||||
@@ -7429,6 +7524,7 @@ function semutaOfferSupported(
|
||||
!g.pendingExchange && !g.pendingIxAlly && !g.pendingNullentropy &&
|
||||
!g.pendingAmbassador && !g.pendingTerrorEntry &&
|
||||
(continuation.kind === 'karamaShipmentDiscard' ||
|
||||
continuation.kind === 'specialKaramaDiscard' ||
|
||||
(!g.pendingShipment && !g.pendingHomeworldShipment)) &&
|
||||
!g.pendingRicheseGift &&
|
||||
((continuation.kind === 'karamaIncomeDiscard' &&
|
||||
@@ -7656,6 +7752,13 @@ function finishTreacheryDiscard(g: Game, claim?: { player: string; card: string
|
||||
const battle = g.battle!;
|
||||
if (battle.preLeader && !battle.preLeader.closed)
|
||||
battle.preLeader.ready = battle.preLeader.ready.filter(id => id !== next.player);
|
||||
} else if (next.kind === 'specialKaramaDiscard') {
|
||||
g.response = next.resume.response;
|
||||
g.decision = next.resume.decision;
|
||||
g.pendingKarama = next.resume.pendingKarama;
|
||||
g.phaseOpening = next.resume.phaseOpening;
|
||||
if (next.stage === 'effect')
|
||||
resolveSpecialKaramaEffect(g, getPlayer(g, next.player), pending.batch.entries[0].card, next.intent);
|
||||
} else if (next.kind === 'karamaShipmentPriceDiscard') {
|
||||
g.response = next.resume.response;
|
||||
g.decision = next.resume.decision;
|
||||
@@ -28913,15 +29016,30 @@ export function executeSpecialKaramaIntent(
|
||||
g,
|
||||
`${p.name} used the physical Truthtrance as Karama for their special faction power.`,
|
||||
);
|
||||
if (intent.kind === 'ecaz') {
|
||||
if (intent.kind !== 'emperorLeader' && intent.kind !== 'emperorForces') {
|
||||
if (intent.kind === 'richese' && intent.nexusEvent) {
|
||||
const receipt = nexusRule(() => createEmperorNexusSpecialPurchase(g, p.id, card.id, intent.acquire));
|
||||
requireRule(receipt.event === intent.nexusEvent,
|
||||
'The original joint special-purchase source changed before disposal.');
|
||||
g.nexusCards!.cards = nexusRule(() => discardNexusCard(g.nexusCards!.cards!, p.id, g.players));
|
||||
(g.nexusEmperorPurchaseHistory ??= []).push(receipt);
|
||||
(g.nexusEmperorPurchaseEvents ??= []).push(receipt.event);
|
||||
}
|
||||
discard(g, p, card.id);
|
||||
if (stageSpecialKaramaCost(g, intent, card, false)) return;
|
||||
}
|
||||
resolveSpecialKaramaEffect(g, p, card, intent);
|
||||
}
|
||||
|
||||
/** Only the validated original activation or its authenticated cost receipt calls this. */
|
||||
function resolveSpecialKaramaEffect(g: Game, p: Player, card: Card, intent: SpecialKaramaIntent): void {
|
||||
if (intent.kind === 'ecaz') {
|
||||
p.specialKaramaUsed = true;
|
||||
g.battle!.ecazSpecialKarama = { owner: p.id, card: card.id, event: intent.event };
|
||||
log(g, `${p.name} declared the once-game unarmed Ecaz special Karama. The revealed disc-value difference adds provisional virtual dial strength, without additional physical losses.`,
|
||||
{ faction: 'ecaz', name: 'Special Karama' });
|
||||
} else if (intent.kind === 'moritani') {
|
||||
const pending = g.moritaniSpecialKarama!;
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
const winner = getPlayer(g, intent.source.opponent);
|
||||
pending.optional = pending.cards.filter(id => !intent.keep.includes(id) && !intent.discard.includes(id));
|
||||
@@ -28939,15 +29057,6 @@ export function executeSpecialKaramaIntent(
|
||||
} else resumeMoritaniSpecialKarama(g);
|
||||
} else if (intent.kind === 'richese') {
|
||||
const selected = g.richeseCache!.findIndex((c) => c.id === intent.acquire);
|
||||
if (intent.nexusEvent) {
|
||||
const receipt = nexusRule(() => createEmperorNexusSpecialPurchase(g, p.id, card.id, intent.acquire));
|
||||
requireRule(receipt.event === intent.nexusEvent,
|
||||
'The original joint special-purchase source changed before disposal.');
|
||||
g.nexusCards!.cards = nexusRule(() => discardNexusCard(g.nexusCards!.cards!, p.id, g.players));
|
||||
(g.nexusEmperorPurchaseHistory ??= []).push(receipt);
|
||||
(g.nexusEmperorPurchaseEvents ??= []).push(receipt.event);
|
||||
}
|
||||
discard(g, p, card.id);
|
||||
if (!intent.nexusEvent) p.spice -= 3;
|
||||
p.hand.push(...g.richeseCache!.splice(selected, 1));
|
||||
p.specialKaramaUsed = true;
|
||||
@@ -28982,17 +29091,20 @@ export function executeSpecialKaramaIntent(
|
||||
}
|
||||
} else if (intent.kind === 'choam') {
|
||||
const selected = intent.cards;
|
||||
discard(g, p, card.id);
|
||||
for (const id of selected) discard(g, p, id);
|
||||
const entries: FreshDiscardBatch['entries'][number][] | null = g.semutaPreview ? [] : null;
|
||||
for (const id of selected) {
|
||||
const used = discard(g, p, id);
|
||||
entries?.push({ card: used, discardedBy: p.id, publicFace: false });
|
||||
}
|
||||
p.spice += selected.length * 3;
|
||||
p.specialKaramaUsed = true;
|
||||
log(
|
||||
g,
|
||||
`${p.name} used special Karama to discard ${selected.length} cards and gain ${selected.length * 3} spice.`,
|
||||
);
|
||||
if (entries?.length) stageSpecialKaramaDiscard(g, intent, entries, 'cashout');
|
||||
} else if (intent.kind === 'ixians') {
|
||||
const route = intent.route;
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
relocateMobileStronghold(g, {
|
||||
player: p.id,
|
||||
@@ -29002,7 +29114,6 @@ export function executeSpecialKaramaIntent(
|
||||
});
|
||||
} else if (intent.kind === 'tleilaxu') {
|
||||
const target = intent.target;
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
g.revivalPrevention = { player: target, turn: g.turn };
|
||||
if (g.pendingRevival?.nexusEmperorEvent)
|
||||
@@ -29017,7 +29128,6 @@ export function executeSpecialKaramaIntent(
|
||||
);
|
||||
} else if (intent.kind === 'fremen') {
|
||||
const t = intent.territory;
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
g.summonedWorm = {
|
||||
territory: t,
|
||||
@@ -29051,7 +29161,6 @@ export function executeSpecialKaramaIntent(
|
||||
} else if (intent.kind === 'atreides') {
|
||||
const b = g.battle!,
|
||||
target = intent.target;
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
b.fullPlan = { owner: p.id, target };
|
||||
g.decision = null;
|
||||
@@ -29061,7 +29170,6 @@ export function executeSpecialKaramaIntent(
|
||||
);
|
||||
} else if (intent.kind === 'guildHomeworld') {
|
||||
const shipper = getPlayer(g, intent.target);
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
if (g.pendingHomeworldShipment?.guildNexusEvent) finishGuildCunningShipment(g,shipper.id,'homeworld',g.pendingHomeworldShipment,'stopped');
|
||||
shipper.shipped = true;
|
||||
@@ -29072,7 +29180,6 @@ export function executeSpecialKaramaIntent(
|
||||
log(g, `${p.name} used special Karama to stop ${shipper.name}’s interplanetary shipment. No forces arrive or spice is paid; their shipment is used and movement remains available.`);
|
||||
} else if (intent.kind === 'guild') {
|
||||
const shipper = getPlayer(g, intent.target);
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
if (g.pendingShipment?.source === 'ambassador') {
|
||||
currentGuildAmbassador(g, g.pendingShipment.ambassadorEvent);
|
||||
@@ -29119,10 +29226,10 @@ export function executeSpecialKaramaIntent(
|
||||
techIncome(g, 'axlotl', p);
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
stageSpecialKaramaCost(g, intent, card, true);
|
||||
} else if (intent.kind === 'harkonnen') {
|
||||
const target = getPlayer(g, intent.target),
|
||||
count = intent.amount;
|
||||
discard(g, p, card.id);
|
||||
p.specialKaramaUsed = true;
|
||||
const taken = shuffle(target.hand).slice(0, count);
|
||||
target.hand = target.hand.filter((c) => !taken.some((t) => t.id === c.id));
|
||||
|
||||
+7
-5
@@ -1203,6 +1203,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
'A printed Karama canceling original paid Guild shipment income, non-Ambassador Emperor auction income or Richese special-purchase income also offers its exact public cost before the native denial. The price and physical transaction have already committed: claim or Continue cannot refund spice, re-ship forces, undo cache acquisition or replay a purchase. Original Movement, next-lot inspection or the Richese purchase’s suspended controls resume once. A winner may spend the very Karama it just bought; claiming that identity does not reverse its payment. Homeworld and Ambassador payment compositions remain separate.',
|
||||
'A printed Karama canceling native Guild transport permission or shipment rate now offers that exact public cost while the original reserve, cross/return or typed Homeworld declaration remains unpaid. Claim or Continue restores and applies that cancellation once. Recovering the cost never restores a denied route, retains the native discount, finances an unfunded group or repeats shipment. Ordinary movement and legal replacements remain; independent price grants stay distinct.',
|
||||
'A printed Karama buying another active player’s shipment price also offers its exact fresh cost before that same original grant activates. Claim or Continue preserves the original beneficiary, creator and half-normal bank-paid price. Physical recovery ends the provisional stop-refund eligibility for that cost, even if the claimant later discards it again. Guild can spend that very recovered card for an actual special stop without also refunding it to the former owner. Unclaimed original costs retain their older refund; this is selected source composition, not a publisher worked example.',
|
||||
'Printed native special-Karama costs now offer Semuta at their original disposal point. Recovery or Continue resumes the same committed native effect once even when its physical cost changed hands. Emperor revival already happened before its native disposal and is not repeated. CHOAM has a separate later private batch for its selected cashout cards after one earned credit: commit before inspection and recover one fresh card, never the old activation or one per discarded card. Original once-use, typed sources and refund remain; Advanced E3 entry and converted costs keep their separate gates.',
|
||||
'The separate fresh semuta --homeworlds entry retains original Richese/CHOAM and classic Homeworld occupation setup with exact CHOAM and no other modules. Paid Box search, clean Distrans transfer, definite Truthtrance answers, used ordinary specials, paid Kaitain disposal, Tupile cleanup and printed Karama canceling native Guild/Emperor/Richese-purchase income offer Semuta. Native printed Kulon, Baliset, La La La, Trip to Gamont and Jubba costs also pause before their original effect: claim/pass adds one movement bonus, denies free allowance without charging/moving forces, stops the uncommitted Baliset move, returns one original board counter before the same CHOAM close, or applies protection before the same recorded storm moves. Printed Karama canceling these powers pauses separately before denial; the retained Worthless fuel is not a candidate. A canceled reactive Baliset resumes its original declared move once; canceled Kulon/La La La/Gamont/Jubba do not apply their effects. A recovered card grants no other faction CHOAM power. Kaitain private groups require commitment before selection; each Tupile holder has a separate cost. Native income denial retains payment and the original occupied-share allocation. Basic unresolved epochs, Kull, other producers and public starts remain guarded.',
|
||||
'Legal completed CHOAM market sales also offer their used card in the Homeworld profile. Worthless cashout keeps its original two-spice credit; a non-Worthless duplicate keeps its three-spice credit and the original same-name witness stays held. The high-Tupile Worthless-sale prohibition still applies, including duplicate Worthless sales. Claim/pass cannot repeat payout, undo the actual reserve shipment or replace the original market close; no new bank-income interpretation is made.',
|
||||
'Final Ornithopter disposal also offers its used card in the Homeworld profile after the one-group range-three or original two-group movement completes, including an early end with no useful original group. Claim/pass cannot move those counters again or replay the paid native shipment; prior-move/Hajr, advisor and Homeworld-transfer boundaries remain. Clean Sapho Once Around and unstarted Movement first/last costs likewise offer after reordering the finite unacted queue. Earlier bids/funding and physical storm order stay committed, and the same next bidder or combined turn resumes once. Cyclic auctions, partly completed turns, first-versus-Guild and late battle timing are not opened.',
|
||||
@@ -1227,31 +1228,31 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
area: 'Implementation' as const,
|
||||
status: 'Partial' as const,
|
||||
detail:
|
||||
'The Richese preview interrupts clean ordinary-card, paid Box, Ornithopter, Distrans, Truthtrance, four Sapho scopes, pre-leader Residual Poison, printed Karama canceling clean CHOAM Charity, Inflation or Bene Gesserit Charity or settling a normal auction purchase or winning bid, a completed CHOAM sale, clean Kulon, proactive or reactive La La La/Baliset and ordinary Trip to Gamont Worthless use, accepted printed Jubba before storm protection, Ix-deck Thumper/Amal and three battle discard stages, including before native Advanced Harkonnen capture. A private normal-auction or Black Market Ixian ally replacement pauses before its draw with a neutral, face-hidden offer; original payment and seller income settle once. Cache purchases retain their native allied-replacement prohibition. Ordinary definite Truthtrance answers pause whether or not another question remains reserved, and also when the answer bound a supported shipment or unsubmitted battle-plan promise. CHOAM sale income is committed before its neutral offer and the same market resumes once; Kulon adds one movement range, La La La blocks one target’s free revival, Baliset restricts the chosen player’s movement, ordinary Trip returns one selected force, and Jubba protects one CHOAM territory only after their offers. Karama’s physical cost is discarded before its neutral offer; the original response is canceled or the reserved lot settles once. Residual Poison commits one random leader death; Sapho commits its finite priority. Thumper waits before worm/spice draw; Amal restores an already-halved opening. Owner-only candidates and one physical Semuta transfer retain privacy. The user-approved full-hand exchange preserves final hand count and incoming reservations. Other Karama uses, other reactive Worthless uses, other private discards, nested responses and other pending rewards remain unfinished. Printed native Guild permission/rate costs now use a dedicated unpaid shipment continuation for reserve, cross/return and typed Homeworld sources; claim/pass applies the same denial/repricing once without delivery replay or invented funding. Printed shipment-price activation now has its own continuation: claim/decline creates the same original price once. Recovered physical cost retains the beneficiary/creator but loses provisional refund eligibility even after rediscard; the same recovered card can pay a real stop without being returned to its former owner.',
|
||||
'The Richese preview interrupts clean ordinary-card, paid Box, Ornithopter, Distrans, Truthtrance, four Sapho scopes, pre-leader Residual Poison, printed Karama canceling clean CHOAM Charity, Inflation or Bene Gesserit Charity or settling a normal auction purchase or winning bid, a completed CHOAM sale, clean Kulon, proactive or reactive La La La/Baliset and ordinary Trip to Gamont Worthless use, accepted printed Jubba before storm protection, Ix-deck Thumper/Amal and three battle discard stages, including before native Advanced Harkonnen capture. A private normal-auction or Black Market Ixian ally replacement pauses before its draw with a neutral, face-hidden offer; original payment and seller income settle once. Cache purchases retain their native allied-replacement prohibition. Ordinary definite Truthtrance answers pause whether or not another question remains reserved, and also when the answer bound a supported shipment or unsubmitted battle-plan promise. CHOAM sale income is committed before its neutral offer and the same market resumes once; Kulon adds one movement range, La La La blocks one target’s free revival, Baliset restricts the chosen player’s movement, ordinary Trip returns one selected force, and Jubba protects one CHOAM territory only after their offers. Karama’s physical cost is discarded before its neutral offer; the original response is canceled or the reserved lot settles once. Residual Poison commits one random leader death; Sapho commits its finite priority. Thumper waits before worm/spice draw; Amal restores an already-halved opening. Owner-only candidates and one physical Semuta transfer retain privacy. The user-approved full-hand exchange preserves final hand count and incoming reservations. Other Karama uses, other reactive Worthless uses, other private discards, nested responses and other pending rewards remain unfinished. Printed native Guild permission/rate costs now use a dedicated unpaid shipment continuation for reserve, cross/return and typed Homeworld sources; claim/pass applies the same denial/repricing once without delivery replay or invented funding. Printed shipment-price activation now has its own continuation: claim/decline creates the same original price once. Recovered physical cost retains the beneficiary/creator but loses provisional refund eligibility even after rediscard; the same recovered card can pay a real stop without being returned to its former owner. Printed native special costs now resume one committed native effect through effect/complete/cashout stages. Original Emperor post-revival disposal is preserved; CHOAM selected cards are a later private simultaneous batch after one credit. Existing native once-use, joint ordering and typed parent remain.',
|
||||
},
|
||||
{
|
||||
area: 'Player controls' as const,
|
||||
status: 'Partial' as const,
|
||||
detail:
|
||||
'All seats can Continue at the neutral fresh-discard boundary; only the actual holder sees Commit. In a mixed-owner battle batch, a committed holder can inspect and select only cards discarded by another player; nonholders receive no candidates. Normal Richese starts remain gated. Earlier four original-action390px native cost/continuation journeys exercise full4 reserve claim, denied cross plus ordinary1, typed full2 all-seat decline, and poor2/full4 release then one-force full2. No overflow/browser/application error; one tool-only stale-node race was resolved with fresh evidence, not replay. Four new original-action390px journeys start at actual price activation: bank3 allowance while Guild holds the cost, same-card reserve stop, typed bank2 after all-seat decline, and same-card typed stop followed by real ordinary movement. No overflow/browser/application errors; two tool-only stale-node races were resolved without replay.',
|
||||
'All seats can Continue at the neutral fresh-discard boundary; only the actual holder sees Commit. In a mixed-owner battle batch, a committed holder can inspect and select only cards discarded by another player; nonholders receive no candidates. Normal Richese starts remain gated. Earlier four original-action390px native cost/continuation journeys exercise full4 reserve claim, denied cross plus ordinary1, typed full2 all-seat decline, and poor2/full4 release then one-force full2. No overflow/browser/application error; one tool-only stale-node race was resolved with fresh evidence, not replay. Earlier four original-action390px price journeys start at actual activation: bank3 allowance while Guild holds the cost, same-card reserve stop, typed bank2 after all-seat decline, and same-card typed stop followed by real ordinary movement. No overflow/browser/application errors; two tool-only stale-node races were resolved without replay. Four current390px journeys cover original reserve/typed Guild prevention claim/decline and controlled CHOAM private Kulon selection plus Emperor post-revival cost claim. Two original/two controlled; actual native movement/public force inspectors, no overflow/browser/application errors.',
|
||||
},
|
||||
{
|
||||
area: 'AI' as const,
|
||||
status: 'Partial' as const,
|
||||
detail:
|
||||
'All four AI profiles use their own projected hand to commit or pass the exact current event, and can choose only privately projected committed candidates. This is minimal legal participation, not tuned strategy. For both new native permission and rate cost parents, all four actual original-state profiles recover the exact cost through legal actions and preserve the original denial/repricing. No tuning or calibration. All four original-state profiles claim the price cost; a subsequent real owner action executes the retained bank-paid shipment. This is legal source participation, not a new strategy preference or calibration.',
|
||||
'All four AI profiles use their own projected hand to commit or pass the exact current event, and can choose only privately projected committed candidates. This is minimal legal participation, not tuned strategy. For both new native permission and rate cost parents, all four actual original-state profiles recover the exact cost through legal actions and preserve the original denial/repricing. No tuning or calibration. All four original-state profiles claim the price cost; a subsequent real owner action executes the retained bank-paid shipment. This is legal source participation, not a new strategy preference or calibration. All four existing profiles recover the original Guild stop cost via legal private actions, and the native prevention then executes once. No new preference, tuning or calibration.',
|
||||
},
|
||||
{
|
||||
area: 'Documentation' as const,
|
||||
status: 'Partial' as const,
|
||||
detail:
|
||||
'The guide distinguishes clean public ordinary-card, paid Box, Ornithopter, Distrans, definite ordinary Truthtrance answers (including queued questions, supported shipment promises and battle answers before or after plan submission/reveal), four Sapho scopes, pre-leader Residual Poison, printed Karama cancellation of CHOAM Charity, Inflation or Bene Gesserit Charity or clean normal-auction purchase or winning-bid payment, completed CHOAM card sales, clean Kulon/proactive La La La/Baliset/ordinary Trip to Gamont Worthless and accepted printed Jubba Cloak, Ix-deck Thumper/Amal and three battle batches from a private normal-auction or Black Market Ixian ally replacement, the cache replacement prohibition, privacy-neutral acknowledgements, the user-approved atomic full-hand exchange and remaining discard sources. The native Guild followup distinguishes unpaid transport from completed income and keeps existing denial/no-debt interpretations. Both original cards are actually auctioned; two extra active-price probes explicitly disclose controlled second-card acquisition. Printed price-cost activation is connected below; converted and special costs remain separate. The printed price-cost continuation and claimed-cost nonduplication extension are explicit. Unclaimed original refunds remain provisional and unchanged; recovery does not transfer or repeat the price benefit. Converted and other special-Karama discard sources remain separate.',
|
||||
'The guide distinguishes clean public ordinary-card, paid Box, Ornithopter, Distrans, definite ordinary Truthtrance answers (including queued questions, supported shipment promises and battle answers before or after plan submission/reveal), four Sapho scopes, pre-leader Residual Poison, printed Karama cancellation of CHOAM Charity, Inflation or Bene Gesserit Charity or clean normal-auction purchase or winning-bid payment, completed CHOAM card sales, clean Kulon/proactive La La La/Baliset/ordinary Trip to Gamont Worthless and accepted printed Jubba Cloak, Ix-deck Thumper/Amal and three battle batches from a private normal-auction or Black Market Ixian ally replacement, the cache replacement prohibition, privacy-neutral acknowledgements, the user-approved atomic full-hand exchange and remaining discard sources. The native Guild followup distinguishes unpaid transport from completed income and keeps existing denial/no-debt interpretations. Both original cards are actually auctioned; two extra active-price probes explicitly disclose controlled second-card acquisition. Printed price-cost activation is connected below; converted and special costs remain separate. The printed price-cost continuation and claimed-cost nonduplication extension are explicit. Unclaimed original refunds remain provisional and unchanged; recovery does not transfer or repeat the price benefit. Converted costs and wider E3 entries remain separate; printed special costs are connected below. Printed special costs and CHOAM cashout stages follow native disposal order without a new publisher timing ruling. Eight original and18 controlled paths plus2 original/2 controlled surfaces are explicit. Advanced E3 entry, converted costs and full assurance remain separate.',
|
||||
},
|
||||
{
|
||||
area: 'Verification' as const,
|
||||
status: 'Partial' as const,
|
||||
detail:
|
||||
'Genuine setup, custody, hidden-hand parity, saved JSON, authenticated SQLite continuation and legal AI participation cover clean ordinary-card, paid Box, Ornithopter, Distrans, Truthtrance, four Sapho scopes, pre-leader Residual Poison, printed Karama cancellation of CHOAM Charity, Inflation or Bene Gesserit Charity or clean normal-auction purchase or winning-bid payment, completed CHOAM card sales, clean Kulon/proactive La La La/Baliset/ordinary Trip to Gamont Worthless and accepted printed Jubba Cloak, Ix-deck Thumper/Amal, a private normal-auction Ixian ally replacement and three battle discard stages. Other private producers, Karama uses, other reactive Worthless uses, pending rewards, full games and live deployment remain unverified. Earlier thirteen-file158/158 passes, including12 new cases. Thirty-two original-action runtime/policy paths and four original-action390px journeys pass; two separately controlled cross/typed active-price probes retain the original independent grant. No worker/D1/real-room/deployed assurance or complete-mode claim. New eighteen-file234/234 passes, including8 new cases. Fourteen original-action runtime/policy paths and four actual original-action390px journeys pass; two explicitly controlled extra-stop-card acquisitions prove unclaimed refunds. The original same-card stop uses no extra card or staged acquisition. No worker/D1/saved/deployed or complete-mode assurance.',
|
||||
'Genuine setup, custody, hidden-hand parity, saved JSON, authenticated SQLite continuation and legal AI participation cover clean ordinary-card, paid Box, Ornithopter, Distrans, Truthtrance, four Sapho scopes, pre-leader Residual Poison, printed Karama cancellation of CHOAM Charity, Inflation or Bene Gesserit Charity or clean normal-auction purchase or winning-bid payment, completed CHOAM card sales, clean Kulon/proactive La La La/Baliset/ordinary Trip to Gamont Worthless and accepted printed Jubba Cloak, Ix-deck Thumper/Amal, a private normal-auction Ixian ally replacement and three battle discard stages. Other private producers, Karama uses, other reactive Worthless uses, pending rewards, full games and live deployment remain unverified. Earlier thirteen-file158/158 passes, including12 new cases. Thirty-two original-action runtime/policy paths and four original-action390px journeys pass; two separately controlled cross/typed active-price probes retain the original independent grant. No worker/D1/real-room/deployed assurance or complete-mode claim. Earlier eighteen-file234/234 passes, including8 new cases. Fourteen original-action runtime/policy paths and four actual original-action390px journeys pass; two explicitly controlled extra-stop-card acquisitions prove unclaimed refunds. The original same-card stop uses no extra card or staged acquisition. No worker/D1/saved/deployed or complete-mode assurance. Current sixteen-file224/224 passes with13 new behavior cases. Twenty-six runtime/policy paths pass:8 original-action Guild paths including4 profiles,18 explicitly controlled native-effect paths. Four actual390px journeys pass (2 original/2 controlled). Existing income/refund consumers use actual neutral passes. No worker/D1/saved/deployed or complete-mode claim.',
|
||||
evidence: [
|
||||
'tests/semuta-engine.test.ts',
|
||||
'tests/semuta-recovery.test.ts',
|
||||
@@ -1305,6 +1306,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
'tests/semuta-homeworld-choam-battle-karama.test.ts',
|
||||
'tests/semuta-guild-transport.test.ts',
|
||||
'tests/semuta-shipment-price.test.ts',
|
||||
'tests/semuta-special-karama.test.ts',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user