Support Ecaz renewal of temporary Duke tenure
This commit is contained in:
1 parent
4e55ab9e86
commit
69bbb09dcf
12 files changed
+314
-21
No files matched your search
@@ -11,7 +11,7 @@ export type EcazDukeContext = Omit<Partial<FactionModuleProfile>, 'players'> & {
|
||||
players: readonly { id: string; faction: FactionId; ally?: string | null }[];
|
||||
dukeVidal?: DukeState;
|
||||
};
|
||||
type Failure = 'context' | 'custody' | 'table' | 'alreadyControlled';
|
||||
type Failure = 'context' | 'custody' | 'table' | 'alreadyControlled' | 'sameHolderTable';
|
||||
export class EcazDukeAcquisitionError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
@@ -32,9 +32,11 @@ const whole = (n: unknown): n is number =>
|
||||
Number.isSafeInteger(n) && (n as number) >= 0;
|
||||
const tableBlock =
|
||||
'Duke Vidal acquisition with Advanced Harkonnen is still being implemented.';
|
||||
const sameHolderTableBlock =
|
||||
'Same-holder Duke acquisition with Advanced Harkonnen is not available in this preview.';
|
||||
const alreadyBlock =
|
||||
'Acquiring Duke Vidal when Ecaz already controls him is still being implemented.';
|
||||
const allyAlreadyBlock = 'The chosen beneficiary already controls Duke Vidal.';
|
||||
'Ecaz already controls Duke Vidal through its Ambassador.';
|
||||
const allyAlreadyBlock = 'The chosen beneficiary already controls Duke Vidal through the Ambassador.';
|
||||
const unavailable = 'Duke Vidal is unavailable for this acquisition.';
|
||||
|
||||
/** Ordinary Ambassador acquisition for Ecaz or its current reciprocal ally.
|
||||
@@ -91,15 +93,21 @@ export function quoteEcazDukeAcquisition(
|
||||
whole(duke.leader.deaths),
|
||||
'The shared Duke Vidal disc has invalid physical identity or history.',
|
||||
);
|
||||
// Harkonnen may privately capture Duke without changing his public prior
|
||||
// controller. Keep same-holder availability independent of that hidden
|
||||
// custody until a public-safe capture continuation is implemented.
|
||||
requireDuke(duke.controller !== recipientId || !g.advanced ||
|
||||
!g.players.some(player => player.faction === 'harkonnen'),
|
||||
sameHolderTableBlock, 'sameHolderTable');
|
||||
// A direct Ambassador grant is already in force for this recipient. Other
|
||||
// sources may be converted to this until-battle tenure without moving or
|
||||
// recreating the disc. Check public tenure before private custody details.
|
||||
requireDuke(duke.controller !== recipientId || duke.source !== 'ecaz',
|
||||
recipientId === ownerId ? alreadyBlock : allyAlreadyBlock, 'alreadyControlled');
|
||||
requireDuke(
|
||||
!duke.leader.concealed,
|
||||
'Duke Vidal cannot be acquired from unresolved concealed custody.',
|
||||
);
|
||||
// This explicit unfinished case is public controller information. Check it
|
||||
// before private capture/ghola details so its projected reason cannot vary
|
||||
// with an undisclosed custody marker.
|
||||
requireDuke(duke.controller !== recipientId,
|
||||
recipientId === ownerId ? alreadyBlock : allyAlreadyBlock, 'alreadyControlled');
|
||||
requireDuke(
|
||||
duke.controller === null
|
||||
? duke.acquiredTurn === null && duke.source === null
|
||||
@@ -131,6 +139,7 @@ export function ecazDukeAcquisitionBlock(
|
||||
} catch (error) {
|
||||
if (error instanceof EcazDukeAcquisitionError) {
|
||||
if (error.reason === 'table') return tableBlock;
|
||||
if (error.reason === 'sameHolderTable') return sameHolderTableBlock;
|
||||
if (error.reason === 'alreadyControlled')
|
||||
return recipientId === ownerId ? alreadyBlock : allyAlreadyBlock;
|
||||
}
|
||||
|
||||
+1
-1
@@ -25122,7 +25122,7 @@ function decideAmbassador(g: Game, p: Player, action: Action) {
|
||||
g.dukeVidal = acquiredDuke;
|
||||
log(
|
||||
g,
|
||||
`${beneficiary.name} acquired Duke Prad Vidal${previous ? ` from ${getPlayer(g, previous).name}` : ''} through the Ecaz Ambassador. ${beneficiary.name} keeps the shared Duke until battle use or another rule takes him away; the entrant’s remaining actions resume.`,
|
||||
`${beneficiary.name} ${previous === beneficiary.id ? 'renewed control of' : 'acquired'} Duke Prad Vidal${previous && previous !== beneficiary.id ? ` from ${getPlayer(g, previous).name}` : ''} through the Ecaz Ambassador. ${beneficiary.name} keeps the shared Duke until battle use or another rule takes him away; the entrant’s remaining actions resume.`,
|
||||
{ faction: owner.faction, name: 'Ecaz Ambassador — Duke Vidal' },
|
||||
);
|
||||
finishAmbassador(g);
|
||||
|
||||
+1
-1
@@ -4054,7 +4054,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
'Duke Vidal is separate from both factions’ five ordinary leaders. His Ecaz identity does not mean Ecaz currently controls him. Inspect the shared disc to see its current controller, whether it is set aside, or whether it is in the Tanks.',
|
||||
'At the end of Shipping and Movement, Moritani gains Vidal if it faces battles in at least two strongholds, excluding battles involving Ecaz, and Vidal is not in the Tanks. The printed rule takes him from the current controller. Moritani has him for one battle; it may acquire him again on a later turn by meeting the condition again. At turn end, set him aside unless he is in the Tanks or captured.',
|
||||
'Karama can prevent Moritani from acquiring Vidal. That cancellation does not remove him once Moritani already controls him.',
|
||||
'Ecaz may acquire Vidal through a triggered Ambassador for itself or its current reciprocal ally outside Tanks/captured/ghola custody. Ordinary acquisition lasts until battle use, including unused control across turns; this shared tenure is provisional. The alternative forms a consensual alliance while both factions are unallied. Basic can then lend Duke optionally; the supplied Advanced physical p30 adds an available Duke to the new ally automatically and sets an unused disc aside at turn end.',
|
||||
'Ecaz may acquire Vidal through a triggered Ambassador for itself or its current reciprocal ally outside Tanks/captured/ghola custody. Ordinary acquisition lasts until battle use, including unused control across turns; this shared tenure is provisional. A current recipient under a different temporary tenure may provisionally renew control through the Ambassador; Advanced Harkonnen same-holder cases remain guarded. The alternative forms a consensual alliance while both factions are unallied. Basic can then lend Duke optionally; the supplied Advanced physical p30 adds an available Duke to the new ally automatically and sets an unused disc aside at turn end.',
|
||||
'Only Ecaz may revive Vidal, including with Ghola Treachery. Ecaz may revive him for five spice regardless of how many of its leaders are in the Tanks. Five spice is his special revival cost; his printed battle strength is six. Ecaz may begin ordinary leader revival when five leaders are in the Tanks, counting Vidal, even if it still holds another leader.',
|
||||
'Ordinary Ecaz returns now use an explicit provisional native cohort. Five actual Tanked discs including Duke, or the existing unavailable-native-roster exception, opens it; completed native IDs preserve the remainder and later openings. A late first death can join a later cohort. Independent Duke deaths do not set or hold its ordinary number, and a real Duke resurrection preserves an already satisfied opening. Original native prices and one ordinary leader slot remain.',
|
||||
'An unallied native Ecaz holder may spend its actual Ecaz Nexus at a quiet boundary in any phase to take Duke for the current turn, including original captured custody or the set-aside disc in Tanks. Finish committed interactions first. One battle or unused turn expiry sets him aside. Nexus liberation permanently clears captivity; it does not return him to a former captor. Actual Ecaz Ghola returns him alive and set aside before a separate Cunning play.',
|
||||
|
||||
Reference in new issue
Block a user