Compose native Stone and Mirror with phase modules
This commit is contained in:
1 parent
4a67e8c7be
commit
ccdcfe2c4d
14 files changed
+359
-29
No files matched your search
@@ -29,6 +29,23 @@ optional skill bands, combinations and public expansion starts remain open.
|
||||
Rules implementation continues; comprehensive assurance and administration
|
||||
remain deferred until all rules are implemented.
|
||||
|
||||
**Native Stone/Mirror with phase modules — 16 October.** Selected Ix/CHOAM
|
||||
retains original Tech/Advanced Strongholds in ordinary47 or independent50
|
||||
setups; mixed E3 with these modules and Homeworlds/Skills/Nexus/Discovery/
|
||||
Sandtrout remain guarded. Keep public allocation safety and the existing
|
||||
provisional Stone-before-Tooth, printed copy-first and physical retention.
|
||||
Genuine cache acquisition, paid marker shipment, earned Habbanya and next-turn
|
||||
typed attack precede each new battle; no force/wallet/owner/phase is assigned.
|
||||
Two actual mobile journeys/20 actions reach Collection with native typed losses,
|
||||
one reserve fee and physical Stone/Mirror retention. Habbanya alone decides
|
||||
the Advanced3-versus3 physical tie; without it, +2 R cannot save the same game.
|
||||
Four policies complete32 original47/independent50 programmes,870 validated
|
||||
candidates and256 continuations. All take a naturally held Traitor; normal
|
||||
physical results are separate Node/UI proof. Related18-file union passes115/115;
|
||||
final three rule cases also pass after fixture decision narrowing. Types/lint,
|
||||
build and actual prototype help pass, with existing build warnings. No
|
||||
complete-mode, calibration or deployed claim.
|
||||
|
||||
**Independent cards with original phase modules — 16 October.** Fresh clean
|
||||
classic/selected Ix/CHOAM profiles retain original unused Tech3–6 Basic/Advanced
|
||||
and/or Strongholds2–6 Advanced, with independent cards before genuine setup.
|
||||
|
||||
@@ -1,5 +1,48 @@
|
||||
# Dune implementation status
|
||||
|
||||
## 16 October 2026 — Native Stone/Mirror with original phase modules
|
||||
|
||||
Genuine cache/earned-Habbanya programmes reproduced the blanket Ix Tech/
|
||||
Stronghold rejection before a plan changed. Extend only selected Ix/CHOAM;
|
||||
retain mixed E3 plus these modules and existing Homeworld/Nexus/Skills/
|
||||
Discovery/Sandtrout guards. No optional module is retrofitted or public start
|
||||
opened. Existing public typed allocation and original/uncopied/copy ordering
|
||||
remain: provisional original Stone-first, printed copy-first and user-selected
|
||||
winning physical retention, not a new priority ruling.
|
||||
|
||||
New programme uses genuine original47 or independent50 setup, native HMS,
|
||||
original unbid-cache acquisition, paid marker shipment, actual end-Mentat
|
||||
Habbanya and a paid next-turn typed attack. Only physical card positioning is
|
||||
explicit conserved staging. Real opening3+3 dials fix Ix-before-Richese order;
|
||||
the native later Storm Deck remains original. No board, wallet, module owner,
|
||||
phase or history assignments. Shared setup helper selects the original native
|
||||
initializer when independent cards are absent, never a flag removal after setup.
|
||||
|
||||
Three behavioral cases cover original Stone-before-Tooth, independent copied/
|
||||
original choices and retention, and earned-Habbanya versus genuine Tech-only
|
||||
counterfactual. Remove the obsolete blanket module-profile table rather than
|
||||
re-pinning it. Public winner-changing allocation rejection remains exercised.
|
||||
|
||||
Two actual390px journeys/20 actions reach Collection. Original Basic Stone
|
||||
compares4 against3, pays R once into reserves12/Tanks4, keeps physical Stone
|
||||
and bounty6/spice10. Advanced copied Stone ignores first, original independently
|
||||
kills; actual Habbanya wins3-versus3, reserves12/Tanks5/spice8 and physical Mirror
|
||||
retained. Both native selected leaders die once, Ix loses three including one
|
||||
cyborg, HMS6/elite3 stays, original winner Tech and phase opening finish.
|
||||
Browser app-error query empty; no horizontal overflow. Owned host/tab/scaffolds
|
||||
removed; evidence is under `/tmp/dune-native-stone-modules-*-proof.json`.
|
||||
|
||||
Original47 programmes retain15 reserves/Tanks1 or2 without inventing an R fee.
|
||||
Strongholds-only original47 Mirror also finishes without Tech. Four policies
|
||||
complete32 programmes/870 validated candidates/256 continuations. Every policy
|
||||
uses its naturally held Traitor; normal physical results are separate Node/UI
|
||||
evidence. No Tleilaxu/Face Dance route, complete mode, strategy/calibration,
|
||||
broader assurance or deployed acceptance is claimed.
|
||||
Related18-file union passes115/115; final three physical rule cases also pass
|
||||
after adding real decision discriminants for TypeScript and removing redundant
|
||||
fixture assertions. Types/lint, build and actual prototype help pass. Existing
|
||||
module-register deprecation, large-chunk and dynamic-route warnings remain.
|
||||
|
||||
## 16 October 2026 — Independent cards with original phase modules
|
||||
|
||||
Original valid three-seat native ready lobbies rejected independent cards plus
|
||||
|
||||
@@ -4,6 +4,47 @@ Audited 6 September 2026 as a proposed contract. The 28 September bounded runtim
|
||||
|
||||
**28 September ruling and runtime:** the user selected ordinary winner retention for the physical Mirror even when its copy activates Tooth or Artillery. This is an explicit product interpretation, not a located GF9 clarification. `game/effective-weapons.ts` keeps physical identity apart from copied attacks; the engine now connects copied Tooth/Stone choices, Stone comparison, custody, battle controls and legal AI in the bounded configuration.
|
||||
|
||||
## Original phase-module composition — 16 October 2026
|
||||
|
||||
Selected Ix/CHOAM now preserves original Tech3+ and/or Advanced Strongholds2+
|
||||
for original Stone and physical Mirror, in ordinary47 or independently selected
|
||||
50-card setups with the separate ten-card cache. Reuse the existing public
|
||||
physical-allocation guard, provisional original Stone-before-Tooth, printed
|
||||
copy-first and user-selected winning physical retention. This closes a profile
|
||||
gap, not a new publisher priority or a reason to inspect a hidden plan.
|
||||
|
||||
Keep Homeworlds, Nexus, Skills, Discovery, Sandtrout and mixed E3 with these
|
||||
phase modules guarded. Existing non-Ix bands and public/played-save gates stay.
|
||||
Original setup, first-Storm Tech, delayed income and actual end-Mentat custody
|
||||
remain; no module owner, force, wallet, phase or history is assigned.
|
||||
|
||||
The genuine programme acquires Stone through its original unbid-cache producer,
|
||||
pays a concealed marker shipment, earns Habbanya at end-Mentat, then receives a
|
||||
real next-turn typed Ixian attack. Legal opening dials3+3 keep Ix before Richese;
|
||||
the later native Storm Deck remains original. Tooth/Mirror/Reinforcements and
|
||||
the acquired Stone transfer for the Mirror case are explicit conserved physical
|
||||
staging, not a claimed natural card trade.
|
||||
|
||||
Normal Node/UI outcomes compare4 versus3 in Basic and an earned3-versus3
|
||||
Advanced tie. Without the held Habbanya in a separate genuine Tech-only game,
|
||||
the same tie loses despite +2 Reinforcements. The original fee still pays once:
|
||||
Richese reserves12/Tanks4 or5 with R, versus15/Tanks1 or2 in original47.
|
||||
Ix loses three actual counters including one cyborg; original HMS6/elite3 stays.
|
||||
Winning Stone/Mirror stays physical, both selected leaders die once in kill
|
||||
programmes, and original Tech reward/Collection continue. Strongholds-only
|
||||
original47 Mirror also reaches Collection without creating Tech.
|
||||
|
||||
Two actual390px journeys/20 actions complete ordinary Stone-before-Tooth and
|
||||
earned-Habbanya copied Stone, independent choices, Traitor declines and owner
|
||||
retention into Collection. No horizontal overflow or browser app error observed.
|
||||
Four policies complete32 programmes/870 validated candidates/256 continuations
|
||||
across original47/independent50 and both modes. All naturally use a held Traitor;
|
||||
normal physical results are separate human/Node evidence. No Tleilaxu/Face Dance,
|
||||
new elite-revival, complete mode, strategy/calibration or deployed proof is claimed.
|
||||
Frozen related18-file union passes115/115; final three cases pass after fixture
|
||||
decision narrowing. Types/lint, build and actual prototype help pass, with
|
||||
existing Node deprecation, chunk-size and dynamic-route classification warnings.
|
||||
|
||||
## Clean selected Ix composition — 16 October 2026
|
||||
|
||||
Clean CHOAM/Ix profiles now admit original Stone and physical Mirror with
|
||||
@@ -24,9 +65,9 @@ copy-first is separately printed on its physical face and remains unchanged.
|
||||
The public profile and physical allocation guards never inspect an opposing
|
||||
hand or sealed plan. Winner-changing typed allocation remains blocked, even
|
||||
when the actual hidden plan would happen to make it finishable. New clean-Ix
|
||||
admission excludes Homeworlds, Nexus, Leader Skills, Discoveries, active
|
||||
Sandtrout, Tech Tokens and Stronghold Cards. The existing non-Ix Tech/Stronghold
|
||||
band is intentionally unchanged. Other combinations remain separate.
|
||||
admission excludes Homeworlds, Nexus, Leader Skills, Discoveries and active
|
||||
Sandtrout. Original Tech/Advanced Strongholds use the phase-module composition
|
||||
above; mixed E3 with those modules remains guarded. Other bands stay separate.
|
||||
|
||||
Physical Mirror retention still follows the user's28 September interpretation;
|
||||
the original Tooth/Artillery retain their actual mandatory-discard rules.
|
||||
|
||||
@@ -667,7 +667,7 @@ dedicated retrieved worked FAQs. [Contract and remaining limits](HOMEWORLD_OCCUP
|
||||
| Reinforcements / classic Homeworlds | Under standing choose-recommended, seal exact native normal-first sources for the existing three-reserve/all-outcome fee. Ambiguous omission rejects; a unique source may derive. Native reserves on an own World are also its army, so that fee cannot fund the same physical dial/casualties; an off-World fee leaves the pool. Keep original pre-fee traits/printed face, including explosion loss choices across a threshold, then typed Tanks, Harass return and original casualties. This is explicit provisional physical-pool composition, not a new FAQ or own-World ban. Source-aware full/complying plan reviews and named independent-card conditions use canonical names and actual combat locations. Other rosters/overlays/public starts remain gated. | [Native sources and exact proof](REINFORCEMENTS_RUNTIME.md#classic-homeworld-reserve-fees--16-october-2026) |
|
||||
| Reinforcements / clean selected Ix and CHOAM | Admit original independent cards with clean selected native/base Basic/Advanced rosters and no optional modules/overlays. Reuse existing provisional normal-first/all-outcome payment, original No-Field materialization before the fee, then successful Harass return; physical Stone ignores +2. Native cyborg substitution uses its own casualty origins, not a duplicate reserve fee. This closes admission consistency, not a new numerical ruling or public expansion gate. | [Profile and bounded proof](REINFORCEMENTS_RUNTIME.md#clean-selected-ixchoam-families--16-october-2026) |
|
||||
| Independent Treachery / original phase modules | Printed E3 shared variant independence permits original unused Tech3–6 Basic/Advanced and/or Strongholds2–6 Advanced with clean classic/selected Ix/CHOAM native/base rosters. Keep original setup, actual phase triggers/delayed income and earned end-Mentat custody. Reuse provisional R fee-before-Harass; returned counters are not free Revival/shipment and +2 is not supported force. No Homeworlds, Skills, Nexus, Discovery, E3 mixture or unrelated preview; existing Stone/Mirror guards remain. | [Source and composition](ECAZ_TREACHERY_RULES.md#original-phase-module-composition--16-october-2026) |
|
||||
| Clean Ix Stone / Tooth / Mirror | Reuse the existing CHOAM prototype order: original Stone first, then uncopied Tooth. The earlier priority question is unanswered; standing choose-recommended extends that order provisionally, not as a publisher ruling or user answer. Printed Mirror copy-first and user-selected physical retention stay independent. Clean selected Ix/Richese supports native Ixians/Tleilaxu in both modes; Ecaz/Moritani stays Advanced-only. Typed winner ambiguity, new Ix Tech/Stronghold and other module bands remain guarded. | [Source and profile distinction](MIRROR_WEAPON_ENGINE_AUDIT.md#clean-selected-ix-composition--16-october-2026) |
|
||||
| Clean Ix Stone / Tooth / Mirror | Reuse existing provisional original Stone-first/uncopied-Tooth order; the earlier priority question stays unanswered. Printed Mirror copy-first and user-selected physical retention remain independent. Selected Ix/CHOAM now retains original Tech3+ and Advanced Strongholds2+, original47/independent50 plus separate cache, with genuine earned custody. No numerical ruling changes. Typed winner ambiguity, mixed E3 with these phase modules and other overlays stay guarded; existing Ecaz/Moritani combinations remain Advanced-only. | [Source and profile distinction](MIRROR_WEAPON_ENGINE_AUDIT.md#clean-selected-ix-composition--16-october-2026), [phase-module proof](MIRROR_WEAPON_ENGINE_AUDIT.md#original-phase-module-composition--16-october-2026) |
|
||||
| Expansion-faction setup | Selecting Ecaz/Moritani factions does not select their independent three-card variant. Ordinary decks contain 33/35/47 cards; Richese's ten-card cache stays separate. Ecaz allocates six total forces within Imperial Basin sectors 9–11, retaining fourteen reserves. Flexible sector allocation is the literal printed territory constraint; Fremen→Ecaz→Advanced BG order is an implementation inference, while Moritani-last is printed. | [Source and profile contract](EXPANSION_FACTIONS_PROTOTYPE.md) |
|
||||
| Ixian Technology on Richese lots | Superseded 8 October by the authorized supplied Advanced physical p34, which expressly excludes Richese auctions from Ixian Technology. Richese cache/Black Market lots now open directly; the once-per-round Technology use remains for ordinary lots. The temporary per-lot decline scaffolding and its tests were deleted. | [Auction source boundary](RICHESE_AUCTION_RULES.md#13-september-saved-per-lot-technology-decline--superseded-8-october) |
|
||||
| Spice Banker battle spending | Secret own-spice commitment is separate from support; only the surviving selected disc gains strength. Core Battle Plan payment rules spend it on death/loss and waive it for a sole traitor-call winner. This payment composition is explicit; upper deferred-income custody remains pending. | [Source contract and prototype](SPICE_BANKER_RUNTIME.md) |
|
||||
|
||||
@@ -60,7 +60,9 @@ See the [exact profile and source distinction](MIRROR_WEAPON_ENGINE_AUDIT.md#cle
|
||||
Public precommit still quantifies over every feasible opposing force/dial/
|
||||
support possibility, never a hidden already-sealed plan. Original typed force,
|
||||
support, death, bounty, substitution and retention paths remain native.
|
||||
New Ix Tech/Stronghold and other combined-module bands remain guarded.
|
||||
Original selected Ix/CHOAM Tech and Advanced Strongholds now follow the
|
||||
[genuine phase-module composition](MIRROR_WEAPON_ENGINE_AUDIT.md#original-phase-module-composition--16-october-2026).
|
||||
Public typed allocation, mixed E3 phase-module and other overlay guards stay.
|
||||
|
||||
## Primary evidence and exact effect
|
||||
|
||||
|
||||
@@ -94,9 +94,9 @@ export function cardPresentation(card: VisibleCard): CardPresentation {
|
||||
: richese.card.effect === 'semutaDrug'
|
||||
? 'The explicit Semuta development preview offers neutral responses after clean public ordinary-card discards, paid Box disposal, retired Ornithopter movement (including a following Bene Gesserit Intrusion), Distrans, ordinary and queued definite Truthtrance answers, four Sapho scopes, unready pre-leader Residual Poison, printed Karama cancelling CHOAM Charity/Inflation/Bene Gesserit Charity, native capture/Auditor/battle-income/Ix-substitution/Basic allied-retention powers, or settling a normal-auction purchase or winning bid, a completed CHOAM sale, clean Kulon, proactive or reactive La La La/Baliset, proactive/final-Mentat Trip to Gamont with an ordinary/elite force or concealed No-Field, accepted Jubba Cloak before storm protection, Ix-deck Thumper/Amal, three battle discard stages (including before original Tech award, native Advanced capture, Face Dance, quoted CHOAM income or Auditor) and private normal-auction or Black Market Ixian ally replacements. Acquiring a printed cancellation cost never restores its canceled effect. Tech requires a supported fresh 3–6-seat CHOAM/optional-Ix profile. Native Ixian casualty substitution keeps its original before-Tooth order. Native Basic Moritani cleanup offers only unkept played cards after the original choice and Karama response, preserving its kept card and unchanged original retention pool. The Basic Richese/Moritani CHOAM/Ecaz entry also adds private Sabotage and Robbery overflow after clean shipment/movement arrivals, preserving the original victim/draw and arrival suffix. Commitment is owner-only; the approved full-hand exchange spends Semuta without increasing your completed hand. Other pending rewards, producers, nested responses and normal expansion starts remain unfinished.'
|
||||
: richese.card.effect === 'mirrorWeapon'
|
||||
? 'Mirror Weapon works in supported CHOAM/Richese-deck tables, including clean selected Ix profiles and Advanced native Ecaz/Moritani. Copied Tooth or Stone chooses before its original; a winning physical Mirror may be kept after copied Tooth or Artillery under the user-selected retention interpretation. Original Stone/Tooth uses the visibly provisional Stone-first order. Other profile/module and full-start gates remain.'
|
||||
? 'Mirror Weapon works in supported CHOAM/Richese-deck tables, including selected Ix/CHOAM with original Tech3+ and Advanced Strongholds2+, or existing Advanced native Ecaz/Moritani. Copied Tooth or Stone chooses before its original; a winning physical Mirror may be kept after copied Tooth or Artillery under the user-selected retention interpretation. Original Stone/Tooth uses provisional Stone-first. Typed public allocation safety, mixed E3 phase-module and other profile/full-start guards remain.'
|
||||
: richese.card.effect === 'stoneBurner'
|
||||
? 'Stone Burner has development controls, including clean selected CHOAM/Ix profiles. Original Stone provisionally chooses before uncopied Tooth; Mirror copies still choose first as printed. Winner-changing physical allocations and other profile/module boundaries remain guarded; full expansion starts stay disabled.'
|
||||
? 'Stone Burner has development controls, including selected CHOAM/Ix with original Tech3+ and Advanced Strongholds2+. Earned Habbanya may decide a physical-token tie; +2 Reinforcements does not. Original Stone provisionally chooses before uncopied Tooth; Mirror copies still choose first as printed. Winner-changing physical allocations, mixed E3 phase modules and other profile/full-start limits remain guarded.'
|
||||
: 'Richese effect integration and verification are incomplete. Karama, Distrans, Nullentropy Box, Ornithopter, Residual Poison, Portable Snooper, Stone Burner and Mirror Weapon have bounded card handlers; full expansion starts remain disabled.',
|
||||
topics: RULE_TOPICS.filter(
|
||||
(topic) =>
|
||||
|
||||
+1
-1
@@ -21143,7 +21143,7 @@ function stonePublicPools(
|
||||
function stoneTimingBlock(g: Game): string | null {
|
||||
if (!g.expansions.includes('ix')) return null;
|
||||
return mirrorWeaponModeBlock(g)
|
||||
? 'Stone Burner with Ix needs the clean selected CHOAM/Ix profile without combined optional modules; the public allocation guard still applies.'
|
||||
? 'Stone Burner with Ix needs a supported selected CHOAM/Ix family and module profile; the public allocation guard still applies.'
|
||||
: null;
|
||||
}
|
||||
function stoneOccupyContext(g: Game): StoneBurnerContext | undefined {
|
||||
|
||||
@@ -24,8 +24,8 @@ export function mirrorWeaponModeBlock(g: {
|
||||
(g.expansions.includes('ecaz') && g.advanced !== true) ||
|
||||
g.players.some((p) => !supported.has(p.faction)))
|
||||
return 'Mirror Weapon needs selected CHOAM/Richese with supported native factions; Ecaz/Moritani combinations require Advanced.';
|
||||
if (g.expansions.includes('ix') && (g.techTokens || g.strongholdCards))
|
||||
return 'Ix-deck Stone/Mirror with Tech Tokens or Stronghold Cards remains outside this clean profile.';
|
||||
if (g.expansions.includes('ix') && g.expansions.includes('ecaz') && (g.techTokens || g.strongholdCards))
|
||||
return 'Mixed E3 Stone/Mirror with Tech Tokens or Stronghold Cards remains outside this profile.';
|
||||
if (g.homeworlds || g.nexusCards || g.leaderSkills || g.discoveries || g.sandtrout)
|
||||
return 'Mirror Weapon with combined optional modules is still being integrated.';
|
||||
return null;
|
||||
|
||||
+6
-3
@@ -1123,11 +1123,11 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
steps: [
|
||||
'Any faction holding canonical Stone Burner may commit it as a Weapon / Special. It is a named special weapon for Voice, not a poison or projectile weapon. Prescience reveals its actual card identity while other plan elements stay private.',
|
||||
'After both plans reveal, choose to kill both leaders or ignore the strength of leaders who otherwise survive. Neither leader strength nor Kwisatz Haderach strength determines this battle. The choice affects deaths and bounty, not which undialed-force comparison is used. Ignoring strength supplies no protection against another weapon.',
|
||||
'Compare the number of physical force tokens not dialed into battle. The aggressor wins a tie. Dialed losses and spice support still follow their normal rules; elite strength is not an extra physical token.',
|
||||
'Compare the number of physical force tokens not dialed into battle. The aggressor wins a tie unless the actual held Habbanya Ridge Sietch advantage decides it. Dialed losses and spice support still follow their normal rules; elite strength is not an extra physical token.',
|
||||
'With Harass & Withdraw, this prototype provisionally compares undialed tokens remaining after successful withdrawal. An opposing successful Traitor cancels the return and decides the outcome instead. In Occupy, only the card user’s pool returns; original fixed Ecaz commitment and the other ally’s undialed counters remain. This timing is an explicit implementation interpretation, not a publisher ruling.',
|
||||
'In the existing native Advanced Occupy prototype, Reinforcements still pays its original own-reserve cost with same-plan, opposing or Mirror-copied Stone. Its +2 normal-score bonus adds no physical undialed tokens, dial, support or on-board casualties. Original mode choices, Traitor precedence and physical Stone/Mirror retention remain unchanged; other profile/module boundaries stay.',
|
||||
'The plan editor checks dial/support against every public opposing force possibility, never a hidden plan or No-Field value. Winner-changing physical allocations remain guarded. Clean selected CHOAM/Ix profiles now reuse the existing provisional original Stone-first, then uncopied Tooth order; Mirror copies still choose before their originals as printed. The earlier priority question remains unanswered.',
|
||||
'Clean Ix admission excludes Homeworlds, Nexus, Leader Skills, Discoveries, active Sandtrout, Tech Tokens and Stronghold Cards. Native Ecaz/Moritani combinations remain Advanced-only. Other non-Ix profile behavior and full expansion/public-start gates are unchanged.',
|
||||
'Clean selected Ix/CHOAM retains original Tech3+ and/or Advanced Strongholds2+, using genuine setup, delayed income and earned end-Mentat custody. Original47 and independent50 decks keep the separate Richese cache. Homeworlds, Nexus, Skills, Discoveries, active Sandtrout and mixed E3 with these phase modules stay guarded. Native Ecaz/Moritani combinations remain Advanced-only; other non-Ix behavior and public starts are unchanged.',
|
||||
'Traitor and Lasgun–shield explosion precedence remain intact. Ordinary bounty applies unless another effect suppresses it. Stone Burner uses the general winning battle-card retention rule: a winner may keep it, and a losing played card is discarded. Normal Moritani ally retention may apply.',
|
||||
'The post-reveal choice is bound to the current battle event and cannot be repeated after refresh. Review both revealed plans and select one mode; there is no separate victim or death confirmation.',
|
||||
],
|
||||
@@ -1166,7 +1166,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
area: 'Verification',
|
||||
status: 'Partial',
|
||||
detail:
|
||||
'Pure, engine, independent review, bot and recovery scenarios cover the supported slice; browser and complete expansion-game certification are separate.',
|
||||
'Earlier pure/engine/review/recovery evidence remains separate. Genuine native cache acquisition, paid marker/typed attack and earned Habbanya now cover physical fees/losses and original/copied retention. Two mobile journeys/20 actions reach Collection;32 legal policy programmes validate870 candidates/256 continuations. All32 naturally call a held Traitor; normal physical outcomes are separate Node/UI proof, not complete modes or calibration.',
|
||||
evidence: [
|
||||
'tests/stone-burner.test.ts',
|
||||
'tests/stone-burner-engine.test.ts',
|
||||
@@ -1179,6 +1179,9 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
'tests/stone-reinforcements.test.ts',
|
||||
'tests/ix-revealed-weapons.test.ts',
|
||||
'tests/fixture-ix-revealed-weapons.ts',
|
||||
'tests/native-stone-modules.test.ts',
|
||||
'tests/fixture-native-stone-modules.ts',
|
||||
'tests/fixture-independent-card-modules.ts',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
applyAction, createGame, initializeEcazTreacheryGameForAudit, joinGame, newPlayer,
|
||||
type Action, type Game,
|
||||
applyAction, createGame, initializeEcazTreacheryGameForAudit, initializeFactionExpansionsGameForAudit,
|
||||
initializeStrongholdFactionsGameForAudit, joinGame, newPlayer, type Action, type Game,
|
||||
} from '../game/engine';
|
||||
import type { FactionId } from '../game/catalog';
|
||||
import { createTechTokens } from '../game/tech-tokens';
|
||||
@@ -15,6 +15,8 @@ export type IndependentCardModulesOptions = {
|
||||
expansions?: Game['expansions'];
|
||||
tech?: boolean;
|
||||
strongholds?: boolean;
|
||||
/** False keeps the original native deck for revealed-card comparisons. */
|
||||
independent?: boolean;
|
||||
};
|
||||
|
||||
/** Select original modules and independent cards before the undealt native setup.
|
||||
@@ -40,7 +42,10 @@ export function createIndependentCardModulesFixture(options: IndependentCardModu
|
||||
new Uint8Array(array.buffer, array.byteOffset, array.byteLength).fill(255);
|
||||
return array;
|
||||
};
|
||||
try { game = initializeEcazTreacheryGameForAudit(game); }
|
||||
try {
|
||||
game = options.independent !== false ? initializeEcazTreacheryGameForAudit(game) :
|
||||
options.strongholds ? initializeStrongholdFactionsGameForAudit(game) : initializeFactionExpansionsGameForAudit(game);
|
||||
}
|
||||
finally {
|
||||
if (descriptor) Object.defineProperty(crypto, 'getRandomValues', descriptor);
|
||||
else Reflect.deleteProperty(crypto, 'getRandomValues');
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { applyAction, viewGame, type Game } from '../game/engine';
|
||||
import type { Card } from '../game/cards';
|
||||
import { createIndependentCardModulesFixture, type IndependentCardModulesStep } from './fixture-independent-card-modules';
|
||||
import { nextRicheseStrongholdsNativeStep } from './fixture-richese-strongholds';
|
||||
|
||||
export const NATIVE_MODULE_STONE = 'richese-stone-burner';
|
||||
export const NATIVE_MODULE_MIRROR = 'richese-mirror-weapon';
|
||||
export const NATIVE_MODULE_TOOTH = 'ix-poison-tooth';
|
||||
export const NATIVE_MODULE_REINFORCEMENTS = 'ecaz-reinforcements';
|
||||
export type NativeStoneModulesStep = IndependentCardModulesStep;
|
||||
export type NativeStoneModulesOptions = {
|
||||
advanced?: boolean;
|
||||
tech?: boolean;
|
||||
strongholds?: boolean;
|
||||
kind?: 'original' | 'mirror';
|
||||
independent?: boolean;
|
||||
};
|
||||
export const nativeStoneModulesClean = (game: Game) =>
|
||||
!game.phaseOpening && !game.response && !game.decision && !game.pendingTreacheryDiscard;
|
||||
export function nativeStoneModulesPlayer(game: Game, actor: string) {
|
||||
const player = game.players.find(p => p.id === actor); assert.ok(player); return player;
|
||||
}
|
||||
export function advanceNativeStoneModules(game: Game, until: (state: Game) => boolean,
|
||||
steps: NativeStoneModulesStep[] = []): Game {
|
||||
for (let count = 0; count < 1800; count++) {
|
||||
if (until(game)) return game;
|
||||
assert.notEqual(game.status, 'finished', 'Original native programme ended before its requested boundary');
|
||||
const step = nextRicheseStrongholdsNativeStep(game);
|
||||
assert.ok(step, 'Supply the real unsealed battle plans');
|
||||
// Real opening dials put Storm at7; every later native distance leaves
|
||||
// Ix before Richese in battle order. Habbanya can then decide their tie.
|
||||
if (game.turn === 1 && step.action.type === 'stormDial') step.action.amount = 3;
|
||||
steps.push(structuredClone(step)); game = applyAction(game, step.actor, step.action);
|
||||
}
|
||||
throw Error('Original native Stone module programme did not reach its requested boundary');
|
||||
}
|
||||
function positionPhysicalCard(game: Game, actor: string, id: string, staging: string[]) {
|
||||
const player = nativeStoneModulesPlayer(game, actor);
|
||||
if (player.hand.some(card => card.id === id)) return;
|
||||
const zones: { label: string; cards: Card[] }[] = [
|
||||
{ label: 'remaining original deck', cards: game.deck },
|
||||
{ label: 'original discard', cards: game.discard },
|
||||
{ label: 'separate original Richese cache', cards: game.richeseCache ?? [] },
|
||||
...game.players.filter(p => p.id !== actor).map(p => ({ label: `${p.id}'s hand`, cards: p.hand })),
|
||||
];
|
||||
const source = zones.find(zone => zone.cards.some(card => card.id === id));
|
||||
assert.ok(source, `Missing original physical ${id}`);
|
||||
assert.ok(player.hand.length < 4, 'The native physical hand must retain its printed limit');
|
||||
player.hand.push(source.cards.splice(source.cards.findIndex(card => card.id === id), 1)[0]);
|
||||
staging.push(`Conserved physical ${id}: ${source.label} → ${actor}'s hand; not a new purchase or face.`);
|
||||
}
|
||||
|
||||
/** Original selected setup/cache acquisition → paid concealed shipment → earned
|
||||
* END-Mentat custody → next-turn paid typed attack → actual native battle.
|
||||
* Only explicitly recorded physical cards move outside the real action trail. */
|
||||
export function createNativeStoneModulesFixture(options: NativeStoneModulesOptions = {}) {
|
||||
const advanced = options.advanced ?? true;
|
||||
const strongholds = options.strongholds ?? advanced;
|
||||
const kind = options.kind ?? 'original';
|
||||
const source = createIndependentCardModulesFixture({ advanced, tech: options.tech ?? true,
|
||||
strongholds, independent: options.independent, factions: ['ixians', 'richese', 'atreides'], expansions: ['ix', 'choam'] });
|
||||
let game = source.game;
|
||||
const initial = source.initial, afterSetup = structuredClone(game);
|
||||
const steps = source.steps, staging: string[] = [];
|
||||
const owner = 'richese', opponent = 'ixians';
|
||||
const territory = 'habbanya_ridge_sietch', sector = 17;
|
||||
const act = (step: NativeStoneModulesStep): Game => {
|
||||
steps.push(structuredClone(step)); game = applyAction(game, step.actor, step.action); return game;
|
||||
};
|
||||
const advance = (until: (state: Game) => boolean) => {
|
||||
game = advanceNativeStoneModules(game, until, steps);
|
||||
};
|
||||
advance(g => g.decision?.kind === 'richeseCache');
|
||||
const acquisitionBefore = structuredClone(game);
|
||||
const acquisitionStart = steps.length;
|
||||
advance(g => nativeStoneModulesPlayer(g, owner).hand.some(c => c.id === NATIVE_MODULE_STONE));
|
||||
const acquisition = { before: acquisitionBefore, after: structuredClone(game), steps: steps.slice(acquisitionStart) };
|
||||
advance(g => g.turn === 1 && g.phase === 5 && g.active === owner && nativeStoneModulesClean(g));
|
||||
const token = nativeStoneModulesPlayer(game, owner).noField!.tokens.find(t => t.value === 5)!;
|
||||
const beforeShipment = structuredClone(game);
|
||||
const shipmentStep: NativeStoneModulesStep = { actor: owner, action: { type: 'ship', territory, sector,
|
||||
noField: token.id, event: nativeStoneModulesPlayer(game, owner).noFieldEvent } };
|
||||
act(shipmentStep);
|
||||
advance(g => g.turn === 1 && g.phase === 8 && nativeStoneModulesClean(g));
|
||||
let beforeMentat: Game | undefined, mentatStep: NativeStoneModulesStep | undefined;
|
||||
for (let count = 0; game.turn === 1 && count < 100; count++) {
|
||||
const next = nextRicheseStrongholdsNativeStep(game); assert.ok(next);
|
||||
const before = structuredClone(game), after = act(next);
|
||||
if (after.turn === 2) { beforeMentat = before; mentatStep = next; }
|
||||
}
|
||||
assert.ok(beforeMentat && mentatStep);
|
||||
if (strongholds) assert.equal(game.strongholdCards!.owners[territory], owner);
|
||||
const afterMentat = structuredClone(game);
|
||||
advance(g => g.turn === 2 && g.phase === 5 && g.active === opponent && nativeStoneModulesClean(g));
|
||||
const beforeAttack = structuredClone(game);
|
||||
const attackStep: NativeStoneModulesStep = { actor: opponent,
|
||||
action: { type: 'ship', territory, sector, amount: 3, elite: 1 } };
|
||||
act(attackStep);
|
||||
advance(g => g.phase === 6 && nativeStoneModulesClean(g));
|
||||
const beforeBattle = structuredClone(game);
|
||||
const choice = viewGame(game, game.active!).battleChoices.find(b => b.territory === territory);
|
||||
assert.ok(choice);
|
||||
const battleStep: NativeStoneModulesStep = { actor: choice.chooser, action: { type: 'chooseBattle', territory,
|
||||
target: choice.attacker === choice.chooser ? choice.defender : choice.attacker } };
|
||||
act(battleStep);
|
||||
advance(g => !!g.battle && !g.battle.preparation && (!g.battle.preLeader || g.battle.preLeader.closed) && nativeStoneModulesClean(g));
|
||||
if (game.ecazTreachery) positionPhysicalCard(game, owner, NATIVE_MODULE_REINFORCEMENTS, staging);
|
||||
if (kind === 'mirror') {
|
||||
positionPhysicalCard(game, opponent, NATIVE_MODULE_STONE, staging);
|
||||
positionPhysicalCard(game, owner, NATIVE_MODULE_MIRROR, staging);
|
||||
} else positionPhysicalCard(game, opponent, NATIVE_MODULE_TOOTH, staging);
|
||||
const strongest = nativeStoneModulesPlayer(game, owner).leaders.filter(l => !l.dead)
|
||||
.sort((a, b) => b.strength - a.strength || a.id.localeCompare(b.id))[0];
|
||||
const weakest = nativeStoneModulesPlayer(game, opponent).leaders.filter(l => !l.dead)
|
||||
.sort((a, b) => a.strength - b.strength || a.id.localeCompare(b.id))[0];
|
||||
assert.ok(strongest && weakest);
|
||||
const dial = advanced ? 2 : 1;
|
||||
const plans: NativeStoneModulesStep[] = [
|
||||
{ actor: owner, action: { type: 'battlePlan', dial, support: advanced ? dial : 0,
|
||||
leader: strongest.id, weapon: kind === 'mirror' ? NATIVE_MODULE_MIRROR : NATIVE_MODULE_STONE,
|
||||
defense: game.ecazTreachery ? NATIVE_MODULE_REINFORCEMENTS : null } },
|
||||
{ actor: opponent, action: { type: 'battlePlan', dial: 0, support: 0, leader: weakest.id,
|
||||
weapon: kind === 'mirror' ? NATIVE_MODULE_STONE : NATIVE_MODULE_TOOTH } },
|
||||
];
|
||||
return { initial, afterSetup, acquisition, beforeShipment, shipmentStep, beforeMentat, mentatStep,
|
||||
afterMentat, beforeAttack, attackStep, beforeBattle, battleStep, game, owner, opponent,
|
||||
territory, location: `${territory}:${sector}`, kind, advanced, plans, steps, staging };
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {applyAction, viewGame} from '../game/engine';
|
||||
import {mirrorWeaponModeBlock} from '../game/mirror-weapon-mode';
|
||||
import {STONE_CARD, MIRROR_CARD, stoneHarassOccupyFixture, takeStoneHarassCard,
|
||||
sealStoneHarassPlans, finishStoneHarassBattle} from './fixture-stone-harass';
|
||||
import {IX_TOOTH, ixRevealedWeaponFixture, revealIxWeapons,
|
||||
@@ -92,18 +91,6 @@ void test('Ix public precommit still rejects winner-changing cyborg allocations
|
||||
assert.equal(messages[0], messages[1]);
|
||||
});
|
||||
|
||||
void test('new Ix admission leaves optional-module and Basic Ecaz limits closed while retaining the existing non-Ix band', () => {
|
||||
const source = ixRevealedWeaponFixture().game;
|
||||
assert.equal(mirrorWeaponModeBlock(source), null);
|
||||
for (const moduleName of ['homeworlds', 'nexusCards', 'leaderSkills', 'discoveries', 'techTokens', 'strongholdCards'] as const)
|
||||
assert.notEqual(mirrorWeaponModeBlock({...source, [moduleName]: {}}), null);
|
||||
assert.notEqual(mirrorWeaponModeBlock({...source, sandtrout: true}), null);
|
||||
assert.notEqual(mirrorWeaponModeBlock({...source, expansions: ['ix']}), null);
|
||||
assert.notEqual(mirrorWeaponModeBlock({...source, expansions: ['ix', 'choam', 'ecaz'], advanced: false}), null);
|
||||
assert.equal(mirrorWeaponModeBlock({expansions: ['choam'], advanced: true,
|
||||
players: [{faction: 'emperor'}, {faction: 'richese'}, {faction: 'guild'}], techTokens: {}, strongholdCards: {}}), null);
|
||||
});
|
||||
|
||||
void test('native Ixian or Tleilaxu Occupy keeps fixed remainder, copied Stone queue and actual card-user reserve cost separate', () => {
|
||||
for (const allyFaction of ['ixians', 'tleilaxu'] as const) for (const lead of ['ecaz', 'ally'] as const) {
|
||||
const source = stoneHarassOccupyFixture({allyFaction, lead, harass: false, stone: 'opponent', mirror: true,
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { applyAction, viewGame, type Game } from '../game/engine';
|
||||
import {
|
||||
advanceNativeStoneModules, createNativeStoneModulesFixture, nativeStoneModulesClean,
|
||||
nativeStoneModulesPlayer, NATIVE_MODULE_MIRROR, NATIVE_MODULE_REINFORCEMENTS,
|
||||
NATIVE_MODULE_STONE, NATIVE_MODULE_TOOTH,
|
||||
} from './fixture-native-stone-modules';
|
||||
|
||||
type Fixture = ReturnType<typeof createNativeStoneModulesFixture>;
|
||||
function reveal(fixture: Fixture): Game {
|
||||
let game = fixture.game;
|
||||
for (const step of fixture.plans) game = applyAction(game, step.actor, step.action);
|
||||
return game;
|
||||
}
|
||||
function finish(game: Game): Game {
|
||||
for (const actor of viewGame(game, game.host).battle!.traitorVoters)
|
||||
game = applyAction(game, actor, { type: 'traitorCall', call: false });
|
||||
return advanceNativeStoneModules(game, state => !state.battle && nativeStoneModulesClean(state));
|
||||
}
|
||||
function assertPhysicalOutcome(fixture: Fixture, game: Game) {
|
||||
assert.equal(game.lastBattleContext?.winner, fixture.owner);
|
||||
const owner = nativeStoneModulesPlayer(game, fixture.owner);
|
||||
assert.equal(owner.reserves, 12, 'Five native counters materialize before the original three-reserve fee');
|
||||
assert.equal(owner.tanks, fixture.advanced ? 5 : 4, 'Only the real dialed counters and original fee reach Tanks');
|
||||
assert.equal(owner.forces[fixture.location], fixture.advanced ? 3 : 4);
|
||||
const opponent = nativeStoneModulesPlayer(game, fixture.opponent);
|
||||
assert.equal(opponent.tanks, 3);
|
||||
assert.equal(opponent.elites!.tanks, 1, 'The real opposing cyborg retains its typed loss');
|
||||
assert.equal(opponent.forces['hidden_mobile_stronghold:0'], 6);
|
||||
assert.equal(opponent.elites!.forces['hidden_mobile_stronghold:0'], 3);
|
||||
for (const step of fixture.plans) {
|
||||
const leader = nativeStoneModulesPlayer(game, step.actor).leaders.find(l => l.id === step.action.leader)!;
|
||||
assert.equal(leader.dead, true, 'The original kill choice kills each actual selected disc once');
|
||||
}
|
||||
assert.equal(game.discard.filter(card => card.id === NATIVE_MODULE_REINFORCEMENTS).length, 1);
|
||||
const lostTokens = Object.entries(fixture.game.techTokens!).filter(([, token]) => token.owner === fixture.opponent);
|
||||
assert.equal(lostTokens.length, 1);
|
||||
assert.equal(game.techTokens![lostTokens[0][0] as keyof NonNullable<Game['techTokens']>].owner, fixture.owner);
|
||||
const faces = (state: Game) => [...state.deck, ...state.discard, ...(state.richeseCache ?? []),
|
||||
...(state.richeseRemoved ?? []), ...state.players.flatMap(p => p.hand)].map(card => card.id).sort();
|
||||
assert.deepEqual(faces(game), faces(fixture.afterSetup));
|
||||
}
|
||||
|
||||
void test('original native Stone chooses before Tooth with genuine Tech and earned Advanced custody, keeping physical costs and typed losses', () => {
|
||||
for (const advanced of [false, true]) {
|
||||
const fixture = createNativeStoneModulesFixture({ advanced });
|
||||
let game = reveal(fixture);
|
||||
assert.equal(game.decision?.kind, 'stoneBurner');
|
||||
assert.equal(game.decision?.player, fixture.owner);
|
||||
game = applyAction(game, fixture.owner, { type: 'decision', event: game.decision!.event, mode: 'kill' });
|
||||
assert.equal(game.decision?.kind, 'poisonTooth');
|
||||
assert.equal(game.decision?.physicalId, NATIVE_MODULE_TOOTH);
|
||||
game = applyAction(game, fixture.opponent, { type: 'decision', event: game.decision!.event, activate: false });
|
||||
game = finish(game);
|
||||
assertPhysicalOutcome(fixture, game);
|
||||
assert.ok(nativeStoneModulesPlayer(game, fixture.owner).hand.some(c => c.id === NATIVE_MODULE_STONE));
|
||||
}
|
||||
});
|
||||
|
||||
void test('physical native Mirror chooses copied Stone first, retains independent original mode and winning physical custody', () => {
|
||||
for (const advanced of [false, true]) {
|
||||
const fixture = createNativeStoneModulesFixture({ advanced, kind: 'mirror' });
|
||||
let game = reveal(fixture);
|
||||
assert.equal(game.decision?.kind, 'stoneBurner');
|
||||
assert.equal(game.decision?.player, fixture.owner);
|
||||
assert.equal(game.decision?.physicalId, NATIVE_MODULE_MIRROR);
|
||||
const copiedChoice = { type: 'decision' as const, event: game.decision!.event, mode: 'ignore' as const };
|
||||
game = applyAction(game, fixture.owner, copiedChoice);
|
||||
assert.equal(game.decision?.kind, 'stoneBurner');
|
||||
assert.equal(game.decision?.player, fixture.opponent);
|
||||
assert.equal(game.decision?.physicalId, NATIVE_MODULE_STONE);
|
||||
const before = structuredClone(game);
|
||||
assert.throws(() => applyAction(game, fixture.owner, copiedChoice));
|
||||
assert.deepEqual(game, before, 'Replaying the copy cannot consume the original owner’s choice');
|
||||
game = applyAction(game, fixture.opponent, { type: 'decision', event: game.decision!.event, mode: 'kill' });
|
||||
game = finish(game);
|
||||
assertPhysicalOutcome(fixture, game);
|
||||
assert.ok(nativeStoneModulesPlayer(game, fixture.owner).hand.some(c => c.id === NATIVE_MODULE_MIRROR));
|
||||
assert.equal(game.discard.filter(c => c.id === NATIVE_MODULE_MIRROR).length, 0);
|
||||
assert.equal(game.discard.filter(c => c.id === NATIVE_MODULE_STONE).length, 1);
|
||||
}
|
||||
});
|
||||
|
||||
void test('genuinely earned Habbanya decides the native physical tie, while the same Tech-only battle loses despite Reinforcements', () => {
|
||||
for (const strongholds of [false, true]) {
|
||||
const fixture = createNativeStoneModulesFixture({ strongholds });
|
||||
assert.equal(fixture.game.battle!.attacker, fixture.opponent);
|
||||
let game = reveal(fixture);
|
||||
assert.equal(game.decision?.kind, 'stoneBurner');
|
||||
game = applyAction(game, fixture.owner, { type: 'decision', event: game.decision!.event, mode: 'ignore' });
|
||||
assert.equal(game.decision?.kind, 'poisonTooth');
|
||||
game = applyAction(game, fixture.opponent, { type: 'decision', event: game.decision!.event, activate: false });
|
||||
game = finish(game);
|
||||
assert.equal(game.lastBattleContext?.winner, strongholds ? fixture.owner : fixture.opponent,
|
||||
'Three undialed native counters tie three; the score-only +2 cannot decide this comparison');
|
||||
const owner = nativeStoneModulesPlayer(game, fixture.owner);
|
||||
assert.equal(owner.reserves, 12, 'The original reserve fee applies to either physical result');
|
||||
assert.equal(owner.tanks, strongholds ? 5 : 8);
|
||||
if (strongholds) assert.equal(fixture.afterMentat.strongholdCards!.owners.habbanya_ridge_sietch, fixture.owner);
|
||||
}
|
||||
});
|
||||
@@ -38,6 +38,7 @@ async function main() {
|
||||
'\n--profile guild-betrayal --leader-skills composes the bounded classic native-Guild Nexus preview with original all14 skills. Original payment/physical shipment and once-per-phase Bureaucrat receipt remain; ordinary Skills use their shared quotes. Homeworlds, expansions, Tech, Strongholds, Discovery, Semuta, other overlays and conversion of played games remain excluded.',
|
||||
'\n--profile ecaz-treachery --homeworlds selects independent36-card classic2–6 Basic/Advanced Homeworld setup. Recruits doubles current native rates within seven total, provisionally rechecking separate-request thresholds/prior free use with native typed deposits/caps. Harass returns exact undialed counters through native reserves, never on an own World. Reinforcements seals exact normal-first native sources when ambiguous, pays before Harass and excludes an on-World fee from physical dial/casualties while preserving original face/support. Named-card Truthtrance and source-aware legal completion use canonical cards/locations. These are bounded provisional compositions, not full variant certification. No expansions, other overlays, public start or played-save conversion.',
|
||||
'\nWithout Homeworlds, ecaz-treachery supports clean classic or selected Ix and/or CHOAM native/base Basic/Advanced rosters with original unused Tech3+ and/or Advanced Strongholds2+; both requires Advanced3+. Original selected33/35/47 decks gain the three independent cards; Richese cache stays separate. First-Storm Tech owners/income and actual end-Mentat Stronghold ownership remain original. Recruits keeps original Axlotl triggers; Reinforcements/Harass keep physical costs/returns and earned held-card effects. Original Stone/Mirror allocation/profile guards stay. Nexus, Skills, Discovery, Sandtrout, mixed E3 and unrelated overlays remain outside this entry.',
|
||||
'\nSelected Ix/CHOAM original Stone and physical Mirror now also retain original Tech/Advanced Strongholds, in ordinary47 or independently selected50-card setups with a separate cache. Earned Habbanya decides physical ties; original Stone-before-Tooth remains provisional, printed copy-first and user-selected physical Mirror retention stay. Public winner-changing allocations, mixed E3 phase modules and other overlay/public-start guards remain.',
|
||||
'\nEcaz-occupy (--profile ecaz-occupy) opts a fresh ready2–6 native Ecaz/classic or selected Advanced native-family lobby. Basic uses exact ecaz33 and provisionally follows the main paragraph for odd/even counts: ceil contribution/loss and floor survivors; the conflicting FAQ is recorded, not adjudicated. Advanced retains original selected ecaz/ix/choam decks and native offers/HMS/Auditor/Face Dancers/cache. Explicit --ecaz-treachery independently adds three physical cards in Advanced. Native Richese ordinary, marker-only and mixed pools compose with selected leads under the provisional additive interpretation. Ordinary dial Prescience remains barred for the physical No-Field army; distinct Advanced special Karama uses the explicit complete private-plan interpretation without early token revelation. Other profile/module and public-start gates remain.' +
|
||||
'\nLeader-skills retains existing classic and Basic native entries and adds native Basic Richese/CHOAM. Advanced Ixians, Tleilaxu, CHOAM and/or Richese plus classic rosters use distinct required family decks and all fourteen skills, with original cache, Face Dancers, Auditor exclusion and typed aftermath. Foreign revival grants no new skill. Separate non-Harkonnen Advanced Moritani uses the ecaz deck and original skill-first assassination preview. Native Ecaz supports its five ordinary discs, original Ambassador/Duke custody and ecaz deck with classic opponents in Basic/Advanced; Advanced Harkonnen retains its existing Duke capture exclusion. Normal Mentat questions use a uniform private card-show step in supported Leader Skills games. Banker-income additionally supports native Richese and Ecaz, never ordinary seller/allowed Emperor income or a bank grant as a payer cost. Basic auction recipients remain unchanged. Public activation, exhausted-cache counts, native Ixian Technology on Richese lots, own mixed No-Field, captured replacement, shared-Duke assignment, combined Occupy skills and other pending module/rulings remain guarded.',
|
||||
'\nStronghold-factions additionally admits standalone Advanced Ecaz OR Moritani with classic opponents and the exact ecaz deck, six Stronghold Cards with optional unused Tech Tokens at 3–6 seats. Original setup and actual end-Mentat claims remain. Ecaz holds shared-control cards and only the actual selected holder-plan benefits. Native Moritani retains original assassination with printed bounty and one private Mentat replacement; Harkonnen is excluded there. An E3 pair, E1/E2/E3 mixtures and other modules remain separate.' +
|
||||
|
||||
Reference in new issue
Block a user