diff --git a/components/ecaz-ambassadors.tsx b/components/ecaz-ambassadors.tsx index e01d8e9d..68523f11 100644 --- a/components/ecaz-ambassadors.tsx +++ b/components/ecaz-ambassadors.tsx @@ -23,7 +23,7 @@ import { TERRITORIES } from '@/game/board'; import { faction } from '@/game/catalog'; export const AMBASSADOR_COVERAGE = - 'Development coverage: Ambassador placement, Ecaz’s direct Duke acquisition and consensual alliance, Emperor, Atreides, Harkonnen, CHOAM, Ixian, Richese, Fremen, Guild and Tleilaxu entry effects are supported, plus Bene Gesserit copies. The Tleilaxu effect offers physical force returns or a first-death own-leader revival. Basic offers an optional new-ally Duke loan; Advanced automatically grants the available Duke after accepted alliance consent. One-battle loan tenure is provisional; an unused living loan is set aside at turn end. Ordinary revival accounting, repeat-death/shared-leader cases and competing arrivals remain for refinement; full Ecaz starts remain disabled.'; + 'Development coverage: Ambassador placement, Ecaz’s direct Duke acquisition and consensual alliance, Emperor, Atreides, Harkonnen, CHOAM, Ixian, Richese, Fremen, Guild and Tleilaxu entry effects are supported, plus Bene Gesserit copies. The Tleilaxu effect offers physical forces or a first-death own leader, including Atreides’ separate Kwisatz Haderach token. Basic offers an optional new-ally Duke loan; Advanced automatically grants the available Duke after accepted alliance consent. One-battle loan tenure is provisional; an unused living loan is set aside at turn end. Ordinary revival accounting, repeat-return/shared-leader cases and competing arrivals remain for refinement; full Ecaz starts remain disabled.'; function tokenLocation(token: AmbassadorToken) { if (token.zone === 'placed') return `Placed in ${TERRITORIES.find((t) => t.id === token.location)?.name ?? 'a stronghold'}`; diff --git a/components/ecaz-entry.tsx b/components/ecaz-entry.tsx index 931c625b..020b29dd 100644 --- a/components/ecaz-entry.tsx +++ b/components/ecaz-entry.tsx @@ -283,10 +283,11 @@ export function EcazEntry({ ) : entry.stage === 'revival' ? ( <>
- Revive one eligible own leader, or return up to {entry.revival?.maximum ?? 0} - {' '}physical forces from the Tanks for free. This independent grant - leaves ordinary allowances and income unchanged provisionally. - Repeat-death and shared-leader interactions remain unfinished. + Revive one eligible first-death own leader, including Atreides’ first + killed Kwisatz Haderach, or return up to {entry.revival?.maximum ?? 0} + {' '}physical forces for free. This independent grant leaves ordinary + allowances and income unchanged provisionally. Repeat-return and + shared-leader interactions remain unfinished.
{entry.revival?.blocked && ({entry.revival.blocked}
diff --git a/docs/CURRENT_STATUS.md b/docs/CURRENT_STATUS.md index fe968abb..22d4d01e 100644 --- a/docs/CURRENT_STATUS.md +++ b/docs/CURRENT_STATUS.md @@ -29,6 +29,22 @@ optional skill bands, combinations and public expansion starts remain open. Rules implementation continues; comprehensive assurance and administration remain deferred until all rules are implemented. +**Tleilaxu Ambassador first-death Kwisatz Haderach — 11 October.** +The source-supported separate KH identity (base p17) now appears in the +private native or Bene Gesserit-copied Tleilaxu grant. It is not appended to +the five ordinary native leaders; battle losses, wallets, force pools and +ordinary leader usage are unchanged, while its original activation and +first-kill cycle1 record are required. Every existing KH return advances the +same cycle marker; a prior return stays guarded by the pending repeat-death +interpretation. Two native before programs with real seven-loss combat, a +KH Lasgun/Shield death and an actual placed-token arrival offered no KH and +rejected it. Four native/copied human/Easy programs now return that same +token and resume the original entrant. Six consumer cases and all four legal +bot profiles pass; the frozen six-file union passes44/44 with types/lint +clean. Styled390px humans use the native button, inspect awakened10-loss +private status and explicitly select the legal copied effect. No +repeat-return, shared-leader or revival-income ruling changes. + **Semuta / Homeworld income costs and retained printed shares — 11 October.** The existing `karamaIncomeDiscard` now also covers the same source-qualified Guild, Emperor auction and Richese special-purchase income in the original diff --git a/docs/IMPLEMENTATION_STATUS.md b/docs/IMPLEMENTATION_STATUS.md index e7a62eda..2582c351 100644 --- a/docs/IMPLEMENTATION_STATUS.md +++ b/docs/IMPLEMENTATION_STATUS.md @@ -1,5 +1,37 @@ # Dune implementation status +## 11 October 2026 — source-supported first-death KH Ambassador return + +The Tleilaxu Ambassador's own-leader alternative excluded Atreides' +separate Kwisatz Haderach token even though base p17 revives KH like a +leader without adding it to the ordinary roster. Two native before programs +with genuine seven-loss combat, an actual KH Lasgun/Shield death, a real +worm alliance and a real placed-token arrival offered no KH choice and +rejected it. + +Shared `tleilaxu-ambassador-leaders.ts` now supplies the private eligibility +list and validates the submitted identity for native and Bene Gesserit +copied grants. KH requires Advanced Atreides, seven battle losses, its own +dead state and the original cycle1 marker; foreign discs, living KH and a +prior return marker remain excluded. No response/decision shape, ordinary +roster, wallet, force or quota calculation changed. + +Returning KH clears its dead/battle-use state and advances the same cycle +marker used by original Ghola and ordinary KH returns. It does not reset +battle losses, add a physical disc, spend the ordinary leader allowance, +charge spice or alter force pools. Four native/copied human/Easy runtime +programs return the same token and resume the original Guild entrant once. +Six consumer cases cover both paths, owner/stale/exclusive errors, living and +prior-return exclusion and all four minimal legal bots. The fixture's battle +preparation and physical Ghola descriptor were corrected during development; +no engine rule was changed for those fixture errors. Styled390px humans use +the native button, inspect awakened10-loss status and select the legal +copied effect before returning KH. + +No repeat-return, shared-leader or revival-income interpretation is settled; +those remain the recorded policy questions. Types/lint and the frozen +six-file Ambassador union pass44/44; no broad-suite or deployed acceptance. + ## 11 October 2026 — Homeworld income cost before original printed share Seven source-qualified before programs lacked Semuta for Basic/Advanced low diff --git a/docs/RULE_DECISIONS.md b/docs/RULE_DECISIONS.md index f4a2e9b0..bac2b5ce 100644 --- a/docs/RULE_DECISIONS.md +++ b/docs/RULE_DECISIONS.md @@ -27,7 +27,7 @@ They supersede earlier software-absence claims only within their named scope. | --- | --- | --- | | Odd-force Ecaz Occupy | Main paragraph: ceiling contribution/loss, floor survivors; conflicting FAQ remains unresolved. | [Occupy](ECAZ_OCCUPY_RULES.md) | | New-ally Duke loan | Optional existing-disc loan after Ambassador alliance consent; one battle and unused turn-end set-aside. | [Duke acquisition](ECAZ_DUKE_ACQUISITION.md) | -| Tleilaxu Ambassador leader alternative | First-death own native leader revives free instead of forces, independently of ordinary revival allowance. | [Ambassador](TLEILAXU_AMBASSADOR_RULES.md) | +| Tleilaxu Ambassador leader alternative | First-death own native leader, or Atreides' source-supported separate first-killed KH, revives free instead of forces. Ordinary allowance independence remains provisional; repeat returns/shared custody stay separate. | [Ambassador](TLEILAXU_AMBASSADOR_RULES.md) | | Ordinary allied shipment transit | Depart during the shipper's turn; excess new physical visitors still present at ending go to Tanks, even when exit was prevented. Old co-occupation timing is separate. | [Allied transit](ALLIED_TRANSIT_RULES.md) | | Ordinary mixed No-Field battle | Private pool is physical forces plus reserve-limited token materialization; both plans seal before one reveal. Advanced now shares this provisional policy; combined Occupy remains separate. | [No-Field](RICHESE_NO_FIELD_RULES.md) | | Guild-recipient allied No-Field | Rounded one-force Guild fee: one spice to bank, even when Richese funds it; no Guild self-shipment income. | [Allied No-Field payment](RICHESE_ALLIED_SHIPMENT_AUDIT.md) | diff --git a/docs/TLEILAXU_AMBASSADOR_RULES.md b/docs/TLEILAXU_AMBASSADOR_RULES.md index 580af055..9103eef7 100644 --- a/docs/TLEILAXU_AMBASSADOR_RULES.md +++ b/docs/TLEILAXU_AMBASSADOR_RULES.md @@ -2,6 +2,30 @@ Primary-source review, 2026-09-07, with later runtime checkpoints below. This document supplements the [Ambassador effects audit](ECAZ_AMBASSADOR_EFFECTS_AUDIT.md) and [runtime readiness review](TLEILAXU_AMBASSADOR_RUNTIME_READINESS.md). Recorded source questions remain distinct from the Basic-first implementation choices. +## First-death own Kwisatz Haderach — 11 October 2026 + +The source-supported separate KH identity below now appears in Atreides' +private native or Bene Gesserit-copied Tleilaxu grant. Its original advanced +activation and first-kill cycle1 record are required. It is not appended to +the five ordinary native leaders and does not inherit foreign/shared custody. + +The return clears its dead/battle-use state and advances the same cycle +marker used by original Ghola and ordinary KH returns. Battle losses, +ordinary roster identities, wallets, force pools and ordinary leader usage +remain unchanged; quota independence retains the existing first-version +qualification. A prior return marker stays guarded by the pending repeat-death +interpretation rather than gaining a new exception. + +Two native before programs recorded real seven-loss combat followed by a +KH Lasgun/Shield death, real worm alliance and Ambassador placement/arrival, +but offered no KH and rejected its choice. Four native/copied human/Easy +programs now return the same token and source entrant once. Six consumer +cases include both paths, owner/stale/exclusive errors, living/prior-return +exclusion and all four minimal legal bot profiles. Styled390px humans use +the native button, inspect awakened10-loss status, and explicitly select the +legal copied Tleilaxu effect before returning KH; original Guild Movement +still finishes. This does not settle the three policy questions below. + ## First-version leader alternative — 8 October 2026 The beneficiary may now revive one first-death own leader for free instead of diff --git a/game/engine.ts b/game/engine.ts index 6b2e7d7d..e8c206c0 100644 --- a/game/engine.ts +++ b/game/engine.ts @@ -15,6 +15,7 @@ import { } from './leader-skill-combat'; import { quoteSukPhysicalRescue, quoteSukRescue, SukPhysicalRescueError, sukReceiptSignature, sukRescueOptions, type SukForceGroup, type SukPhysicalRescueQuote, type SukPhysicalRescueReceipt, type SukReserveDestinations, type SukRescueOption, type SukRescueReceipt } from './suk-graduate'; import { quoteTleilaxuAmbassadorForces, TleilaxuAmbassadorForceError } from './tleilaxu-ambassador-forces'; +import { tleilaxuAmbassadorLeaderChoices, tleilaxuAmbassadorLeaderSelection } from './tleilaxu-ambassador-leaders'; import { leaderSkillStrongholdCount, sandmasterVictorySpice, sandmasterVictoryPiles, type SandmasterVictorySpiceOffer } from './leader-skill-battle-board'; import { beginRihani, chooseRihaniDraw, finishRihani, validateRihani, type RihaniReceipt, type RihaniSkill } from './rihani-decipherer'; import { planetologistMovementModeSupported, planetologistLeader, planetologistRange, selectedOriginElites, groundMovementRange, type PlanetologistMovement } from './planetologist-movement'; @@ -16675,8 +16676,8 @@ function resolveAmbassadorEffect(g: Game) { return; } if (effect === 'tleilaxu') { - // Initial leader path: first-death own discs, independent of ordinary quota. - // Repeat-death and shared-disc interactions remain explicit refinement work. + // First-death own identities include KH's separate token under base p17. + // Repeat returns, shared discs and ordinary-quota policy stay separate. entry.stage = 'revival'; g.decision = { kind: 'ecazAmbassador', player: p.id }; log( @@ -16879,13 +16880,21 @@ function decideAmbassador(g: Game, p: Player, action: Action) { if (action.leader !== undefined) { requireRule(action.forces === undefined && action.elite === undefined, 'Choose a leader or forces, not both.'); - const leader = p.leaders.find(l => l.id === action.leader && - l.faction === p.faction && l.dead && l.deaths === 1 && - !l.capturedBy && !l.gholaBy); - requireRule(leader, 'Choose a first-death own leader from the Tanks.'); - leader.dead = false; - delete leader.usedAt; - log(g, `${p.name} revived ${leader.name} for free through the Tleilaxu Ambassador. The ordinary leader allowance is unchanged.`, + const selected = tleilaxuAmbassadorLeaderSelection(g, p, action.leader); + requireRule(selected, 'Choose an eligible first-death own leader or Kwisatz Haderach from the Tanks.'); + let name: string; + if (selected === 'kwisatz') { + const kwisatz = p.kwisatz!; + kwisatz.dead = false; + delete kwisatz.usedAt; + kwisatz.revivalCycle = Math.max(p.revivalCycle, kwisatz.revivalCycle ?? 1) + 1; + name = 'Kwisatz Haderach'; + } else { + selected.dead = false; + delete selected.usedAt; + name = selected.name; + } + log(g, `${p.name} revived ${name} for free through the Tleilaxu Ambassador. The ordinary leader allowance is unchanged.`, { faction: 'tleilaxu', name: 'Tleilaxu Ambassador' }); finishAmbassador(g); return; @@ -32730,9 +32739,7 @@ export function viewGame(state: Game, id: string) { tanks: me.tanks, eliteTanks: me.elites?.tanks ?? 0, eliteRevived: me.elites?.revived ?? 0, - leaders: me.leaders.filter(l => l.faction === me.faction && - l.dead && l.deaths === 1 && !l.capturedBy && !l.gholaBy) - .map(l => ({ id: l.id, name: l.name, strength: l.strength })), + leaders: tleilaxuAmbassadorLeaderChoices(g, me), blocked: ambassadorEffectBlock( g, diff --git a/game/reference.ts b/game/reference.ts index 07c17bbb..889057e6 100644 --- a/game/reference.ts +++ b/game/reference.ts @@ -1368,7 +1368,7 @@ export const RULE_TOPICS: RuleTopic[] = [ 'The Guild Ambassador grants an immediate free shipment of zero through four physical reserve forces for Ecaz or its ally, including typed elites. Choose a clear territory and sector; this does not spend ordinary shipment or movement, ally aid or a retained rate card. Fremen may use destinations outside their ordinary reinforcement radius, but their southern reserves stay on-planet and this effect never permits storm entry. Only Ixians may ship directly into their placed mobile stronghold.', 'During Shipment and Movement, Guild can use its special Karama to stop another eligible off-planet Ambassador shipment before forces arrive; it does not stop this grant during a phase-one worm sequence. A successful off-planet shipment may invite Bene Gesserit accompaniment and accrues applicable phase-five Heighliner income once. BG can accompany Ixians into the mobile stronghold. Projected accompaniment choices show blocked sectors and keep Polar Sink and decline available when legal. Intrusion, separate Terror and accompanying fighter-triggered Ambassadors finish before the original entrant or worm rider resumes.', 'No-Field substitution into the free four-force grant remains unavailable. In bounded classic plus Ecaz/Moritani games, a shared Ambassador/Terror entry gives both owners saved optional prompts in current storm order without repeating the committed entry; this is a provisional table order, not a printed publisher priority. A Terror entry now waits for the arrival’s own interaction — Guild income, a Bene Gesserit fighter Intrusion or advisor choice, or Fremen storm protection — and then opens without replaying payment or force transfer. Ambassador-created Fremen/Guild child arrivals remain gated. Atomics Aftermath, Homeworlds, Nexus and Discovery combinations do not gain coverage from this overlap path.', - 'The Tleilaxu Ambassador offers one first-death own-leader revival or up to four physical forces for free. These are exclusive choices; the beneficiary sees its own eligible leaders privately. The ordinary allowance remains unchanged provisionally. Repeat-death, shared-leader and revival-income interactions remain for refinement.', + 'The Tleilaxu Ambassador offers one first-death own-leader revival or up to four physical forces for free. Atreides may choose its separate first-killed Kwisatz Haderach under the base leader-revival rule; this does not add a disc to the ordinary roster, reset battle losses or spend the ordinary leader allowance. Native and Bene Gesserit copied grants share the same private eligibility. Every existing KH return advances its original cycle marker; a prior return remains outside this first-death preview. The force/leader choices are exclusive and ordinary allowance independence stays provisional. Repeat-return, shared-leader and revival-income interpretations remain separate.', 'All eleven effect guides are readable. Emperor, Atreides, Harkonnen, CHOAM, Ixian, Richese, Fremen and Guild entry effects are integrated, together with Bene Gesserit copies of those eight effects and direct Duke acquisition or consensual alliance through the reusable Ecaz token. Advanced combined Occupy has a separate bounded Development Verified guide, and Basic even-force Occupy now composes the same shared controls. Remaining effects, exceptional Duke custody and complete Ecaz rules remain unfinished. Mobile stronghold placement is gated. Full Ecaz starts remain disabled.', ], checklist: [ @@ -1412,6 +1412,8 @@ export const RULE_TOPICS: RuleTopic[] = [ 'tests/ecaz-alliance-engine.test.ts', 'tests/ecaz-alliance-recovery.test.ts', 'tests/ecaz-entry-bots.test.ts', + 'game/tleilaxu-ambassador-leaders.ts', + 'tests/kwisatz-ambassador.test.ts', 'tests/ecaz-entry-continuations.test.ts', 'tests/ecaz-entry-recovery.test.ts', 'tests/richese-ambassador.test.ts', diff --git a/game/tleilaxu-ambassador-leaders.ts b/game/tleilaxu-ambassador-leaders.ts new file mode 100644 index 00000000..ece343a0 --- /dev/null +++ b/game/tleilaxu-ambassador-leaders.ts @@ -0,0 +1,36 @@ +import type { Game, Player } from './engine'; +import type { Leader } from './cards'; + +type Context = Pick