Extend Basic Semuta poison continuation
Verify and publish checkpoint container / container (push) Canceled after 0s

This commit is contained in:
Quintine committed 2026-10-28 22:56:03 +11:00
1 parent 9c6b2d884b
commit ea3b21f92c
7 files changed
+134 -26

No files matched your search

+7 -20
View File
@@ -434,6 +434,7 @@ import {
import {
quoteSpiceCollection,
quoteBattlePhaseAdvance,
quoteCoalitionAlliedSeparation,
BoardResolutionError,
type AdvisorRelease,
type CollectionQuote,
@@ -747,7 +748,7 @@ import {
settleAdvisors,
arrivalAsAdvisor,
} from './advisors';
import { quoteAlliedSeparation, isAlliedShipmentVisit, makeBasicAlliedShipment, quoteBasicAlliedShipment,
import { isAlliedShipmentVisit, makeBasicAlliedShipment, quoteBasicAlliedShipment,
type BasicAlliedShipment } from './allied-separation';
import { casualtyOptions, maxCombatDial, maxCombatSupport, validCombatForces, type Casualties, type CombatForces } from './combat';
import { FACTIONS, faction, type FactionId } from './catalog';
@@ -9531,6 +9532,7 @@ function semutaOfferSupported(
['hajr', 'ghola', 'harvester', 'weather', 'atomics'].includes(continuation.effect) ||
continuation.kind === 'battleResolved' || continuation.kind === 'winnerMandatoryDiscard' ||
continuation.kind === 'battleCleanup' && continuation.source === 'winner' ||
continuation.kind === 'residualPoisonDiscard' ||
continuation.kind === 'nullentropyDiscard' || continuation.kind === 'distransDiscard' ||
continuation.kind === 'truthtranceDiscard' && continuation.promise === null &&
(continuation.record.question.kind === 'fact' || continuation.record.question.kind === 'freeform') ||
@@ -23093,25 +23095,10 @@ function finishMovedGroup(g: Game, move: CompletedMovement) {
}
/** Native board classification is shared by the consequence and its own-seat preview. */
function alliedSeparationTerritories(g: Game, p: Player) {
const ally = p.ally ? getPlayer(g, p.ally) : null;
return quoteAlliedSeparation({
advanced: g.advanced,
turn: g.turn,
player: p.id,
ally: ally?.id ?? null,
playerAllySinceTurn: p.allySinceTurn,
allySinceTurn: ally?.allySinceTurn,
return boardResolution(() => quoteCoalitionAlliedSeparation({
...g,
remaining: g.movementRemaining ?? g.order.slice(g.order.indexOf(p.id)),
territories: gameTerritories(g).map(terr => ({
territory: terr.id,
polar: terr.type === 'polar',
ownPresent: at(p, terr.id) > 0,
allyPresent: !!ally && at(ally, terr.id) > 0,
ownAdvisors: isAdvisor(p, terr.id),
allyAdvisors: !!ally && isAdvisor(ally, terr.id),
ecazCoexist: !!ally && sharesEcazOccupation(g, p, terr.id),
})),
});
}, p.id));
}
function alliedSeparationView(g: Game, p: Player): {territories: string[]; noField?: true} | null {
if (g.status !== 'playing' || g.phase !== 5 || g.active !== p.id ||
@@ -29999,7 +29986,7 @@ function playResidualPoison(
`${p.name} played Residual Poison against ${target.name}. ${victim.name} was randomly selected from the available leaders and sent to the Tanks. No spice is awarded, no forces are lost, and battle preparation continues.`,
{ faction: p.faction, name: 'Residual Poison' },
);
if (g.semutaPreview) {
if (g.semutaPreview || g.semutaRecruitsPreview && basicIndependentSemutaProfile(g)) {
const continuation: ResidualPoisonDiscardContinuation = {
kind: 'residualPoisonDiscard', player: p.id, target: target.id,
victim: victim.id, battleEvent: b.event!, card: used.id,
+1 -1
View File
@@ -1328,7 +1328,7 @@ export const RULE_TOPICS: RuleTopic[] = [
: definition.card.effect === 'ornithopter'
? 'Use the Ornithopter controls with one unused normal/Hajr movement and a selected group/destination. Two card groups stay distinct, while Hajr may reuse their forces afterward. A genuinely recovered Hajr may be legally replayed for another grant. Advanced needs a fresh immediate-after-movement opportunity. Kulon retains the fixed maximum three and extends both normal groups. Advisor/card and wider module combinations remain unfinished.'
: definition.card.effect === 'residualPoison'
? 'Use the Residual Poison panel before either combatant commits a leader. A shared preparation step provides an opportunity regardless of hand contents; advanced Harkonnen tables remain guarded pending the secret-captive ruling. In the explicit Semuta preview, a clean death pauses after public disposal for the neutral offer even if one combatant is already ready. The opponent’s readiness remains; the Poison player must ready again. Inspected battle commitments remain outside this reaction.'
? 'Use the Residual Poison panel before either combatant commits a leader. A shared preparation step provides an opportunity regardless of hand contents; advanced Harkonnen tables remain guarded pending the secret-captive ruling. In the explicit Semuta preview, including the supported Basic independent-card profile, a clean death pauses after public disposal for the neutral offer even if one combatant is already ready. The opponent’s readiness remains; the Poison player must ready again. Inspected battle commitments remain outside this reaction.'
: definition.card.effect === 'stoneBurner'
? 'Use Stone Burner in the weapon selector and review public dial/support feasibility before sealing. Clean selected CHOAM/Ix now uses visibly provisional original Stone-first then uncopied Tooth order; copy-first and physical allocation guards remain.'
: definition.card.effect === 'mirrorWeapon'