Connect provisional Advanced Richese mixed battles and exchanges

This commit is contained in:
Quintine committed 2026-10-08 16:46:48 +11:00
1 parent 4ed6beb33a
commit 85729f9819
13 files changed
+127 -67

No files matched your search

+2 -2
View File
@@ -5001,8 +5001,8 @@ export function GameTable({
<p className="fine">
{ownNoField &&
g.battle.noFieldPlayers.includes(me.id)
? g.battle.basicMixedNoField
? `Provisional Basic mixed No-Field pool: ${battleForces} fighters, combining forces already here with the token's reserve-limited materialization. This estimate is private; the mixed-pool formula is not an adjudicated publisher ruling.`
? g.battle.mixedNoField
? `Provisional ${g.advanced ? 'Advanced' : 'Basic'} mixed No-Field pool: ${battleForces} fighters, combining forces already here with the token's reserve-limited materialization. This estimate is private; the mixed-pool formula is not an adjudicated publisher ruling.`
: `Your concealed No-Field can reveal ${battleForces} physical forces from your current reserves. This estimate is private.`
: occupyProfile
? `${battleForceOwnerName} supplies ${battleForces} physical fighters for the variable dial.`
+1 -1
View File
@@ -5,7 +5,7 @@ import type { Action, GameView } from '@/game/engine';
import { Button } from './ui/button';
import { CardInspector, CardRules } from './card-inspector';
const fullHandPolicy = 'Provisional Basic full-hand exchange: retrieval and the played Box discard settle atomically, leaving your final hand at its limit. The printed intermediate-capacity timing remains unresolved.';
const fullHandPolicy = 'Provisional full-hand exchange: retrieval and the played Box discard settle atomically, leaving your final hand at its limit. The printed intermediate-capacity timing remains unresolved.';
type BoxProps = {
game: GameView;
+10 -2
View File
@@ -102,8 +102,16 @@ both public progress and actual turn-ten victory. Basic stays Tabr-only;
solitary Ecaz and third-party blockers remain. One before/after native ending
smoke and three Habbanya contract cases pass; no broad suite was run.
**Advanced Richese first-version follow-up.** Ordinary mixed No-Field battles,
Guild/active-Karama allied rates and full-hand Box exchange now share the
visibly provisional Basic policies. Native Advanced support and Guild-stop
timing remain connected. Four direct scenarios cover unsupported/supported
mixed battles, actual allied shipment settlement and private Box exchange;
GameTable SSR surfaces were observed in Chromium. Types/lint and one affected
bot contract pass. Combined Occupy, whole-plan inspection and Guild-refund
boundaries remain; no broad suite or deployed acceptance was run.
The preceding supplied p34 cutover excludes Ixian Technology from Richese
auctions; ordinary Technology and allied post-purchase replacement remain.
**7 October 2026 — five pending rulings resolved by the user.** The user
answered five recorded questions; each is now recorded in
+24 -8
View File
@@ -1,6 +1,22 @@
# Nullentropy Box: paid search and engine continuation audit
Audit: 2026-09-06, with a Basic runtime amendment on 8 October below. This is a source/continuation contract, not complete Richese certification. Read with [the acquisition audit](RICHESE_ACQUISITION_RULES.md). The full-hand publisher question remains unresolved; the user's Basic-first instruction permits the visibly qualified first version below, not a new timing ruling.
Audit: 2026-09-06, with Basic and Advanced runtime amendments on 8 October below. This is a source/continuation contract, not complete Richese certification. Read with [the acquisition audit](RICHESE_ACQUISITION_RULES.md). The full-hand publisher question remains unresolved; the user's first-version instruction permits the visibly qualified prototype, not a new timing ruling.
## Advanced full-hand exchange follow-up — 8 October 2026
Advanced now shares the Basic atomic final-capacity policy below.
Intermediate acquisition/disposal capacity remains explicitly provisional,
not a supplied-source or publisher ruling. The pure resolver's opt-in
capacity argument is passed consistently for preview and real settlement;
unknown callers retain its conservative spare-slot default.
One before/after Advanced smoke uses four real cards including Box,
pays two once, completes Easy's private selection, retains the other three
cards and leaves four final cards with Box once on top of the shuffled pile.
Actual GameTable SSR before-payment and paid-search panels show the warning
in Chromium, with an enabled paid-search button. Guild-refund and over-limit
safeguards remain; no broad suite, recovery or deployed proof was run.
## Basic full-hand exchange prototype — 8 October 2026
@@ -11,10 +27,10 @@ limit. The Box remains reserved in hand while the owner chooses; it is
still discarded last/on top after the remainder is shuffled. This does
not reverse the printed disposal order or adjudicate intermediate capacity.
The pure resolver accepts the engine's explicit Basic full-hand policy;
its default unknown/Advanced policy still requires a spare slot. Both
the completion preview and real settlement use the same policy. Basic
over-limit hands remain rejected. Payment, private inspection entitlement,
The pure resolver accepts the engine's explicit full-hand policy;
its default unknown-caller policy still requires a spare slot. Both
the completion preview and real settlement use the same policy.
Over-limit hands remain rejected. Payment, private inspection entitlement,
canonical/non-Box identities, search lock, event-bound choice and restored
parent paths are unchanged. Own controls expose `fullHandExchange` with a
provisional notice before payment and during selection.
@@ -24,8 +40,8 @@ Box, pays two once, accepts Easy's private choice, leaves four final
cards and exactly one used Box on top. Chromium observed the actual
SSR panel with the warning and enabled paid-search button. Types pass;
no broad suite, recovery campaign or deployed acceptance was run.
Advanced full-hand and Guild-refund contexts remain guarded; wider
interruption/commitment refinement remains later work.
Advanced now shares the capacity policy above. Guild-refund contexts remain
guarded; wider interruption/commitment refinement remains later work.
## Verified authority and remaining boundaries
@@ -40,7 +56,7 @@ The publisher's physical card face was independently read again from `/tmp/dune-
This is an ordinary card effect: no generic faction/alliance Karama cancellation, no recipient consent, no Emperor purchase income, Harkonnen bonus or Ixian purchase replacement. The bank is explicit, even with Emperor in the game. No bidding exclusion is printed on Box; Distrans's separate unresolved-bid guard is not transferable to this card.
The full-hand intermediate-capacity question remains unresolved. Basic now uses the explicit atomic-exchange prototype above; Advanced retains the spare-slot guard. Empty or only-Box piles still have no legal result and are rejected before payment under the existing unsupported-empty-search policy. There is no deck fallback or permission to waste the fee; every Box is excluded from retrieval.
The full-hand intermediate-capacity question remains unresolved. Basic and Advanced use the explicit atomic-exchange prototype above. Empty or only-Box piles still have no legal result and are rejected before payment under the existing unsupported-empty-search policy. There is no deck fallback or permission to waste the fee; every Box is excluded from retrieval.
A further boundary comes from an existing provisional engine policy, not the Box source. `executeSpecialKaramaIntent` for Guild may refund `g.karamaShipping.card` by taking that exact previously discarded Karama back into its original owner's hand. Box could first recover that same card. Pausing the pile during search does not resolve the later conflicting claim. Do not silently blacklist an otherwise legal non-Box search card as an official rule. Until the provisional refund policy is resolved, guard that particular pending-refund context before payment and label the reason accurately. No broader ban on Box during Shipment is justified.
+21 -4
View File
@@ -2,6 +2,23 @@
Primary-source audit, 2026-09-06. This narrows the broad integration warnings in the earlier No-Field audits. Ordinary turn ownership, consent and typed force selection can be composed without inventing extra faction powers. The genuinely unresolved payment and interruption intersections below remain distinct. The ordinary contract is now implemented in development fixtures as recorded below; this document does not activate a mode or certify all combinations.
## Advanced discounted shipment follow-up — 8 October 2026
The Basic prototype below now also applies in Advanced. Supplied physical
p36 D permits allied off-planet shipment and p37 C supplies the Guild
rounding rule; the specific price/payee precedence remains provisional.
No extra Karama is spent and no additional shipment is granted. The
existing Advanced Guild-stop window still precedes payment/materialization,
including the uniform window on a Guild recipient's own shipment.
Two before/after direct Advanced scenarios cover Guild and an actual native
Karama purchase, private one-spice offers, Easy consent and five arrivals.
Only Richese's one spice is spent, Guild income stays unchanged and only
the recipient's shipment is used. GameTable SSR supplier/recipient panels
show the provisional policy in Chromium, with enabled consent.
No broad suite, recovery campaign or deployed acceptance was run.
## Basic discounted allied shipment prototype — 8 October 2026
The Basic-first pass connects Guild recipients and already-active Karama
@@ -23,9 +40,9 @@ spend a second card implicitly or grant another shipment.
The Guild income adapter routes these Basic payments entirely to bank;
Guild gains no self-shipment/donor fee. The native Heighliner call still
uses the force recipient, not the token supplier. Advanced Guild/active
Karama combinations remain guarded. Ordinary undiscounted allied prices,
on-planet Fremen exclusion, destination restrictions and public-mode gates
uses the force recipient, not the token supplier. Advanced now shares this
policy as described above. Ordinary undiscounted allied prices, on-planet
Fremen exclusion, destination restrictions and public-mode gates
are unchanged.
**Brief smoke:** both old Basic guards reproduced. Guild-recipient and
@@ -89,7 +106,7 @@ Test supplier-versus-recipient turn ownership, both full payers and any supporte
## Implemented ordinary contract before final checks
**Implementation — Partial.** The engine opens `richeseAllyOpportunity` once for the active eligible recipient's unused shipment, holding that turn for Richese to offer or pass. `richeseAllyShipment` requires recipient consent and legal typed composition, or decline. Ordinary full/equal-split funding remains supported. Basic Guild and already-active Karama recipients now use the explicit discounted prototype above; their Advanced counterparts remain guarded. Fremen's ordinary on-planet reserves remain ineligible.
**Implementation — Partial.** The engine opens `richeseAllyOpportunity` once for the active eligible recipient's unused shipment, holding that turn for Richese to offer or pass. `richeseAllyShipment` requires recipient consent and legal typed composition, or decline. Ordinary full/equal-split funding remains supported. Guild and already-active Karama recipients use the explicit discounted prototype in both modes. Fremen's ordinary on-planet reserves remain ineligible.
Prevention precedes commitment. At successful commit the prior owner marker reveals first, the new allied token materializes immediately, exact funding settles once and only the recipient’s shipment is consumed. Decline/cancellation preserves the prior concealed marker and custody. This is the documented transaction composition above, not an explicit publisher FAQ about online action ordering.
+32 -9
View File
@@ -2,6 +2,29 @@
Audit date: 2026-09-06. This document distinguishes the printed token lifecycle from engine integration and unresolved combinations. It does not certify Richese, Homeworlds, or any other gated game mode.
## Advanced first versions — 8 October 2026
Advanced ordinary mixed battles and discounted allied shipments now reuse
the explicitly provisional policies below. Supplied physical p36 B gives
reserve-limited materialization and p36 D permits allied off-planet forces;
p37 C gives the rounded Guild fee. These passages do not specifically
adjudicate the mixed dial cap or price/payee precedence. Combined Ecaz
Occupy and whole-plan inspection remain guarded; mode gates are unchanged.
`Battle.mixedNoFieldPlayers` and the owner-only `battle.mixedNoField` notice
apply in both modes. Native Advanced support is committed separately and
paid at battle resolution; token revelation does not grant free support.
Minimal AI may form mixed groups using its existing private force quote.
Two direct battle smokes cover unsupported and two-spice-supported plans:
physical2 + token3 gives private5, the first seal keeps the marker hidden,
the second materializes3 once, and ordinary losses/aftermath finish.
Two allied smokes cover Guild and actual native Karama rates with Easy
consent, physical5, bank1 and only the recipient's shipment consumed.
Actual GameTable SSR controls were observed in Chromium, including the
Advanced mixed-pool warning and discounted consent. This is isolated
surface evidence, not deployed or full-game acceptance.
## Basic discounted allied price prototype — 8 October 2026
Guild recipients and already-active Karama rates now have a connected
@@ -13,7 +36,7 @@ the materialized unit count or granting another shipment.
[Canonical payment contract](RICHESE_ALLIED_SHIPMENT_AUDIT.md).
Two before/after direct engine cases cover a Guild recipient and an actual
native Karama purchase, private offers, Easy consent, five actual arrivals
and one bank payment. Types pass. Advanced counterparts remain guarded.
and one bank payment. Advanced now shares this provisional policy above.
## Basic mixed battle prototype — 8 October 2026
@@ -22,15 +45,15 @@ physical forces and a concealed No-Field. It reuses the existing private
prospective pool: **physical forces already in the territory plus
`min(token value, current reserves)`**. This is a visibly provisional
mixed-pool interpretation, not an adjudication of the FAQ's reserve-cap
ambiguity below. Advanced mixed battles and combined Ecaz Occupy remain
guarded for their separate pass/composition work.
ambiguity below. Combined Ecaz Occupy remains guarded; Advanced ordinary
mixed battles now use the same policy as described above.
`Battle.basicMixedNoFieldPlayers` retains initial mixed participation.
Only the participating owner's view receives `battle.basicMixedNoField`
`Battle.mixedNoFieldPlayers` retains initial mixed participation.
Only the participating owner's view receives `battle.mixedNoField`
and its private prospective bounds. The actual Battle Wheel explains the
formula and its provisional status; marker-only wording no longer claims
that the mixed pool consists entirely of reserve materialization.
Basic AI may form mixed groups and uses the authoritative own force quote,
Basic and Advanced AI may form mixed groups and use the authoritative own force quote,
without consulting an opponent's hidden denomination.
The existing sealed-plan path materializes the token once after both plans
@@ -101,11 +124,11 @@ This table records the original adapter contract. The implemented subset and cur
## Unresolved or compositional boundaries
1. **Reserve shortage when destroyed.** Voluntary/battle text explicitly caps by reserves; the destruction sentence says to lose the indicated quantity without repeating the shortage clause. The pure model caps materialization to avoid creating physical units, but that is conservation-based composition for storm/worm losses, not an independently answered FAQ. It does not select substitute losses from unrelated board forces.
2. **Mixed forces and battle dials.** The FAQ forbids dialing more than reserves in a No-Field battle. A territory can also contain ordinary forces (the Smuggler answer demonstrates mixed presence), but no retrieved answer expressly defines that limit with existing forces, multiple sectors, typed units or independently committed reserve uses. The Basic prototype above uses an explicitly provisional additive pool; this does not settle the source question. Advanced and combined Occupy remain guarded.
2. **Mixed forces and battle dials.** The FAQ forbids dialing more than reserves in a No-Field battle. A territory can also contain ordinary forces (the Smuggler answer demonstrates mixed presence), but no retrieved answer expressly defines that limit with existing forces, multiple sectors, typed units or independently committed reserve uses. Basic and Advanced prototypes use an explicitly provisional additive pool; this does not settle the source question. Combined Occupy remains guarded.
3. **Full-plan special Karama and structured Truthtrance.** The ordinary Atreides dial prohibition is explicit. Whether a broader entire-plan power or a particular promise question overrides it was not resolved by a retrieved specific answer. Do not leak the value through private legal-plan previews, public maximum dials, error strings or bot reasoning.
4. **Homeworld use.** R3 recommends Richese in a Homeworld combination but supplies no retrieved No-Field-specific rule defining off-planet hidden custody, one-on-planet versus off-planet coexistence, or homeworld threshold disclosure. General module availability is not an answer to those lifecycle questions. The isolated model represents a single Arrakis marker and does not authorize Homeworld placement.
5. **Capturing, transferring or returning a concealed marker as a force.** Movement-as-a-force and Gamont's explicit forced reveal do not establish a general conversion for every card or Guild transport-to-reserves. A generic return helper must not erase a hidden token without a source-backed reveal/custody cause. This module exposes no such automatic escape from last-use history.
6. **Allied discounts and reserve source.** Ordinary consent, typed allocation and funding are integrated. Basic Guild-recipient and already-active Karama price/payee have the explicitly provisional prototype above; their Advanced counterparts remain guarded pending resolution. Ordinary Fremen reserves are on-planet and remain ineligible for this off-planet method. See `RICHESE_ALLIED_SHIPMENT_AUDIT.md`.
6. **Allied discounts and reserve source.** Ordinary consent, typed allocation and funding are integrated. Guild-recipient and already-active Karama price/payee use the explicitly provisional prototype in both modes. Ordinary Fremen reserves are on-planet and remain ineligible for this off-planet method. See `RICHESE_ALLIED_SHIPMENT_AUDIT.md`.
7. **Supply orientation.** Concealed denomination is explicit. Hiding unused IDs/values in public JSON is the minimum privacy consequence, not a claim about an otherwise undocumented physical supply layout. The last revealed used face is public until another deployment; historical log knowledge may legitimately remain.
## Required verification
@@ -126,7 +149,7 @@ Root integration review also corrected the Polar Sink address: its ordinary boar
`game/force-presence.ts` distinguishes presence from actual units, and map/occupancy, battle discovery, collection and control use that distinction. A marker is one collector even at zero. Storm checks the exact exposed marker sector before materialization/casualties; sheltered Imperial Basin and other sectors are preserved in focused checks. Unprotected worm destruction runs the actual reveal/casualty path, including a real Thumper trigger. Protected-worm and additional removal effects remain bounded by the source interpretations above.
Marker-only battle admission computes the owner's prospective pool from denomination and remaining reserves. The view exposes that pool only to its owning combatant; another player sees its own pool or none. Both plans seal before public reveal materializes the marker. The battle's `noFieldPlayers` flag persists, so zero still has its leader/cards/traitor resolution. Ordinary Atreides dial prescience is rejected on the server and avoided by controls/AI. Basic physical-plus-marker admission now has the provisional prototype above; Advanced/combined mixed admission and special whole-plan inspection remain guarded. Broader Truthtrance remains an audit boundary.
Marker-only battle admission computes the owner's prospective pool from denomination and remaining reserves. The view exposes that pool only to its owning combatant; another player sees its own pool or none. Both plans seal before public reveal materializes the marker. The battle's `noFieldPlayers` flag persists, so zero still has its leader/cards/traitor resolution. Ordinary Atreides dial prescience is rejected on the server and avoided by controls/AI. Basic and Advanced physical-plus-marker admission use the provisional prototype above; combined mixed admission and special whole-plan inspection remain guarded. Broader Truthtrance remains an audit boundary.
**Player controls — Partial.** `components/richese-no-field.tsx` provides concealed board markers plus owner-only denomination inventory, last-use status, token selection, ordinary one-force price/ally-share feedback and authoritative unavailable reasons. The parent table adds explicit marker movement selection and private prospective battle bounds. Token identifiers and hidden values are absent from rival board projections. The separate `components/richese-allied-no-field.tsx` supplies owner opportunity/proposal/payment controls and private recipient accept/decline/typed-force controls. Own shipment, marker movement and invitation/reveal have passed browser checks; an allied owner proposal was checked, but recipient browser acceptance and mobile remain pending.
+8 -2
View File
@@ -15,10 +15,10 @@ They supersede earlier software-absence claims only within their named scope.
| 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) |
| 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 and combined Occupy remain separate. | [No-Field](RICHESE_NO_FIELD_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) |
| Already-active Karama / allied No-Field | Honor the already-played rounded one-force Guild rate and bank routing; no implicit additional card or shipment. | [Allied No-Field payment](RICHESE_ALLIED_SHIPMENT_AUDIT.md) |
| Full-hand Nullentropy Box | Basic permits an atomic retrieval/Box-disposal exchange with final hand within its actual limit; Box remains last/on top. Intermediate capacity is not adjudicated; Advanced remains guarded. | [Box runtime](NULLENTROPY_BOX_ENGINE_AUDIT.md) |
| Full-hand Nullentropy Box | Basic and Advanced permit an atomic retrieval/Box-disposal exchange with final hand within its actual limit; Box remains last/on top. Intermediate capacity is not adjudicated. | [Box runtime](NULLENTROPY_BOX_ENGINE_AUDIT.md) |
No publication or faction/mode gate is opened. The exact 7 October user
rulings below remain distinct from these prototype choices.
@@ -35,6 +35,12 @@ Turn-end set-aside is supplied text; one-battle loan release remains the
explicit provisional implementation policy. Existing exceptional custody and
Advanced Harkonnen guards remain. [Current Duke grant contract](ECAZ_DUKE_ACQUISITION.md).
Advanced Richese ordinary mixed battles, Guild/active-Karama allied prices
and full-hand Box now share the visibly qualified Basic prototype policies.
Native Advanced support and shipment prevention remain separate. These are
first-version implementation choices, not exact numerical user rulings;
combined Occupy, whole-plan inspection and Guild-refund boundaries remain.
Supplied **p30 Ecaz G** and **p35 Moritani F** now have connected once-game
special Karama first versions. Ecaz uses an explicitly provisional absolute
disc-value virtual dial addition without extra physical losses; declaration
+1 -5
View File
@@ -3266,15 +3266,13 @@ function policyActions(g: GameView): Action[] {
: null;
if (
reveal &&
((g.advanced && physicalAlongsideMarker) ||
!me.shipped ||
(!me.shipped ||
(me.moved ?? 0) >= (me.movesAllowed ?? 1))
)
return [reveal];
const markerTargets = targets.filter(
(to) =>
to.t !== MOBILE_STRONGHOLD &&
(!g.advanced || countAt(me, to.t) === 0) &&
!territoryEntryBlock(g.players, me.id, to.t),
);
if (noField?.canShip && ownNoField && !marker && !me.shipped) {
@@ -3380,7 +3378,6 @@ function policyActions(g: GameView): Action[] {
(me.faction !== 'fremen' || fremenReserveEntry(to.t)),
)
.slice(0, 24)) {
if (g.advanced && marker?.location.territory === to.t) continue;
const desired = Math.min(
me.reserves,
level === 0 ? (quoteSmugglerShipment(g, me.id, to.t, 2) ? 2 : 1) : Math.max([1, 3, 4, 5][level], to.enemy + 2),
@@ -3512,7 +3509,6 @@ function policyActions(g: GameView): Action[] {
for (const to of targets
.filter(
(to) =>
(!g.advanced || marker?.location.territory !== to.t) &&
movingSources.some((source) =>
botGroundMoveAllowed(g, me, source.from, to.key, source.elite),
),
+13 -17
View File
@@ -730,8 +730,8 @@ export type Battle = {
preLeader?: { event: string; ready: string[]; closed: boolean };
/** Public marker participation persists after a zero-token reveal. */
noFieldPlayers?: string[];
/** Provisional Basic mixed-pool participation, separate from the hidden value. */
basicMixedNoFieldPlayers?: string[];
/** Provisional mixed-pool participation, separate from the hidden value. */
mixedNoFieldPlayers?: string[];
ecazSpecialKarama?: EcazSpecialKaramaDeclaration;
truthPromises?: BattlePromise[];
poisonTooth?: Record<string, boolean>;
@@ -3937,8 +3937,6 @@ function noFieldAllyOfferBlock(
return 'No-Field inventory is not initialized.';
if (ally.faction === 'fremen')
return 'Fremen reserves are on the planet; this ability ships off-planet reserves.';
if (g.advanced && (ally.faction === 'guild' || g.karamaShipping?.player === ally.id))
return 'Allied No-Field pricing with Guild or Karama discounts awaits a ruling.';
if (
g.richeseAllyBlocked?.turn === g.turn &&
g.richeseAllyBlocked.recipient === ally.id
@@ -4095,10 +4093,8 @@ function validateNullentropyBegin(g: Game, owner: Player, cardId: string) {
requireRule(!reserved, reserved ?? 'The Box is already committed.');
const limit = handLimit(owner);
requireRule(
g.advanced ? owner.hand.length < limit : owner.hand.length <= limit,
g.advanced
? 'Full-hand Nullentropy Box use is unresolved; the current guard requires a pre-existing free hand slot.'
: 'The final exchanged hand must not exceed its hand limit.',
owner.hand.length <= limit,
'The final exchanged hand must not exceed its hand limit.',
);
const guild = byFaction(g, 'guild');
requireRule(
@@ -4166,7 +4162,7 @@ function finishNullentropy(
cardId,
remaining.map((c) => c.id),
handLimit(owner),
!g.advanced,
true,
);
} catch (error) {
throw new RuleError(
@@ -4193,7 +4189,7 @@ function finishNullentropy(
cardId,
order,
handLimit(owner),
!g.advanced,
true,
);
owner.hand = result.ownerHand;
g.discard = result.discard;
@@ -4257,7 +4253,7 @@ function nullentropyView(g: Game, owner: Player) {
(c) => richeseCardDefinition(c)?.card.effect === 'nullentropyBox',
);
if (!card) return null;
const fullHandExchange = !g.advanced && owner.hand.length === handLimit(owner);
const fullHandExchange = owner.hand.length === handLimit(owner);
if (pending?.player === owner.id) {
const blocked = nullentropyIntegrity(g);
return {
@@ -31450,15 +31446,15 @@ function applyActionInner(
(player.id === choice.attacker || player.id === choice.defender ||
(g.advanced && connected && ecaz && ally?.ally === ecaz.id && player.id === ally.id &&
(choice.attacker === ecaz.id || choice.defender === ecaz.id)))).map(player => player.id);
let basicMixedNoFieldPlayers: string[] | undefined;
let mixedNoFieldPlayers: string[] | undefined;
for (const playerId of noFieldPlayers) {
const mixed = Object.entries(getPlayer(g, playerId).forces).some(
([key, n]) => n > 0 && splitLocation(key).territory === choice.territory,
);
if (!mixed) continue;
requireRule(!g.advanced && !combined,
'Mixed Advanced or combined Occupy No-Field battle dialing awaits a ruling. Basic ordinary mixed battles use the visible provisional pool.');
(basicMixedNoFieldPlayers ??= []).push(playerId);
requireRule(!combined,
'Combined Occupy No-Field battle dialing awaits a ruling. Ordinary mixed battles use the visible provisional pool.');
(mixedNoFieldPlayers ??= []).push(playerId);
}
if (combined) {
requireRule(ecazOccupyCompositionSupported(g),
@@ -31478,7 +31474,7 @@ function applyActionInner(
? { preLeader: { event: battleEvent, ready: [], closed: false } }
: {}),
...(noFieldPlayers.length ? { noFieldPlayers } : {}),
...(basicMixedNoFieldPlayers ? { basicMixedNoFieldPlayers } : {}),
...(mixedNoFieldPlayers ? { mixedNoFieldPlayers } : {}),
prepared: true,
plans: {},
revealed: false,
@@ -32991,7 +32987,7 @@ export function viewGame(state: Game, id: string) {
) as Record<string, StrongholdId | null>,
tieWinner: battleTieWinner(g),
noFieldPlayers: [b.attacker, b.defender].filter(player => battleNoFieldPlan(g, player)),
...(b.basicMixedNoFieldPlayers?.includes(id) ? { basicMixedNoField: true as const } : {}),
...(b.mixedNoFieldPlayers?.includes(id) ? { mixedNoField: true as const } : {}),
ownForces: [b.attacker, b.defender].includes(id)
? planCombatForces(g, me, getPlayer(g, b.attacker === id ? b.defender : b.attacker))
: null,
+1 -1
View File
@@ -160,7 +160,7 @@ export const FACTION_RULES: Record<
'Before the regular auction sequence, Black Market may offer a concealed card from your hand. The buyer pays you. An unsold card stays in your hand; a completed sale reduces the regular auction pool by one. Atreides can inspect the offered card.',
'Once per game, spend Karama and three spice to acquire an eligible cache card privately for your hand. This is separate from an auction purchase.',
'Richese occupation of Tuek’s Sietch also prevents the Fremen special victory in Advanced play.',
'Black Market self-purchase, Ixian substitution on special lots and wider card interactions remain guarded in development games.',
'Ordinary mixed No-Field battles and Guild/active-Karama allied prices share Basic’s visibly provisional policies, with native Advanced support and shipment-stop timing. Full-hand Box exchange is likewise provisional. Black Market self-purchase and wider card interactions remain guarded; supplied p34 excludes Ixian Technology from Richese auctions.',
],
},
ecaz: {
+8 -8
View File
@@ -949,10 +949,10 @@ export const RULE_TOPICS: RuleTopic[] = [
'During the paid decision, inspect the cards and use Take on one card to finish. Inspection itself does not select anything. There is no free cancellation after viewing the pile and no second confirmation after selection. If exactly one legal card is available, the server selects it automatically without asking for an identical acknowledgement.',
'Payment is recorded once before inspection. Refresh or reconnect restores an unfinished paid search for its owner without charging again. While it is open, other gameplay actions wait so they cannot change the reserved Box or discard pile. The completed search saves the recovered card and shuffled pile before restoring an interrupted response, decision or phase opening. Recovery does not charge, select or shuffle again, and does not replay the earlier action.',
'The selected card enters your hand privately. Other players do not receive the selected identity or the shuffled discard faces. Temporary search access ends on completion; the normal discard pile remains private, even though the played Box is placed face up on top. Past inspection records do not become a permanent live discard browser.',
'An active Truthtrance question and exact card or transaction commitments must resolve as required. Basic full-hand holders now have a visibly provisional atomic exchange: retrieve one non-Box and discard the played Box, leaving the final hand at its current limit. The printed intermediate-capacity question remains unresolved. Advanced still requires a pre-existing spare slot, and Basic over-limit hands are rejected.',
'An active Truthtrance question and exact card or transaction commitments must resolve as required. Basic and Advanced full-hand holders have a visibly provisional atomic exchange: retrieve one non-Box and discard the played Box, leaving the final hand at its current limit. The printed intermediate-capacity question remains unresolved; over-limit hands are rejected.',
'A pending Guild refund claim on a discarded shipping Karama also blocks starting the search while that provisional refund policy is unresolved. The guard protects the competing claim to that card; it is not a general ban on Box during Shipment. Empty or only-Box searches are rejected before payment under the current unsupported-empty-search policy; there is no fallback deck draw.',
'All four AI profiles start only when their own projected availability and spice reserve allow it. They do not inspect unpaid discard contents. Once paid, they choose from their entitled cards, prefer existing functional effects over unfinished Richese faces and complete a legal selection even if only unfinished effects remain. A paid search takes priority over optional actions.',
'The paid search and continuations are integrated in development fixtures, with a connected Basic full-hand prototype. Advanced full-hand activation and the provisional Guild refund interaction remain guarded. The explicit Semuta preview can recover the used Box after a clean completed search without replaying payment or shuffle; other discard compositions remain separate. Full Richese starts and complete browser/mobile/full-game acceptance remain gated.',
'The paid search and continuations are integrated in development fixtures, with a connected full-hand prototype in both modes. The provisional Guild refund interaction remains guarded. The explicit Semuta preview can recover the used Box after a clean completed search without replaying payment or shuffle; other discard compositions remain separate. Full Richese starts and complete browser/mobile/full-game acceptance remain gated.',
],
related: [
'card-richese-nullentropy-box',
@@ -966,7 +966,7 @@ export const RULE_TOPICS: RuleTopic[] = [
area: 'Implementation',
status: 'Partial',
detail:
'Paid inspection, exact private custody, shuffled remainder, Box on top, sole-choice completion and restored parent continuations are integrated. Basic full-hand exchange has a connected provisional final-capacity policy. Advanced full-hand and Guild-refund guards remain; wider discard/commitment refinement is separate.',
'Paid inspection, exact private custody, shuffled remainder, Box on top, sole-choice completion and restored parent continuations are integrated. Basic and Advanced full-hand exchange use a connected provisional final-capacity policy. Guild-refund guards remain; wider discard/commitment refinement is separate.',
},
{
area: 'Player controls',
@@ -1017,15 +1017,15 @@ export const RULE_TOPICS: RuleTopic[] = [
'A normal No-Field shipment pays the one-force price. The concealed token moves like a force. Before Battle, Richese may reveal it voluntarily; a token involved in battle is revealed with the Battle Plan. Revelation brings the indicated forces from reserves, limited by what remains there.',
'The revealed token stays face up until another token is placed. Revealing it does not clear the previous-shipment restriction. An allied No-Field shipment reveals immediately and uses the ally’s reserves; an existing token must be revealed before another shipment.',
'Before an eligible ally uses its shipment, the game holds an offer opportunity for Richese. Richese may pass or privately propose a token, destination and payment. The ally accepts the exact offer and chooses its permitted regular/elite mix, or declines without payment. Success consumes the ally’s shipment, not Richese’s shipment or either player’s movement.',
'Ordinary allied shipment costs one spice into a stronghold or two elsewhere, funded by either ally or one each at cost two. Basic Guild recipients and already-active Karama rates now use a visibly provisional one-spice price, paid entirely to bank even if Richese funds it; their Advanced counterparts remain guarded. Prevention precedes payment and the old-marker/new-token reveals. Fremen reserves are on the planet and remain ineligible.',
'Ordinary allied shipment costs one spice into a stronghold or two elsewhere, funded by either ally or one each at cost two. Guild recipients and already-active Karama rates use a visibly provisional one-spice price in both modes, paid entirely to bank even if Richese funds it. Prevention precedes payment and the old-marker/new-token reveals. Fremen reserves are on the planet and remain ineligible.',
'Storm and worm exposure reveal the token and destroy its forces. A zero token still had one-force presence before revelation. Trip to Gamont forces a reveal, then returns one force if present. Revealing a token already in a territory does not trigger Terror a second time.',
'Development tables support your own concealed shipment, movement of a marker alone or with a physical group, voluntary reveal and one-force board presence. Physical reserves remain unchanged until reveal. Karama can prevent the No-Field shipment, with Guild shipment prevention and payment handled separately. Price and chosen allied funding are shown before shipment.',
'The map shows a concealed marker without its denomination to everyone. Richese privately sees its token values, last-use restriction and reveal control. Movement selection keeps the marker separate from physical forces. No hidden denomination or physical token identity is included in another player’s projected board state.',
'Marker-only battles use the owner’s private reserve-limited force pool. Both plans must be sealed before the token materializes. A zero-token battle still resolves with its leader, cards and traitor decisions. Ordinary Atreides prescience cannot request this opponent’s dial; other eligible plan elements remain available.',
'Basic ordinary mixed battles have a provisional private pool: physical forces already here plus the token value capped by current reserves. The Battle Wheel labels that interpretation explicitly. Both plans seal before materialization, then native casualties and aftermath use actual forces. This first version does not adjudicate the FAQ mixed dial cap.',
'Basic and Advanced ordinary mixed battles have a provisional private pool: physical forces already here plus the token value capped by current reserves. The Battle Wheel labels that interpretation explicitly. Both plans seal before materialization, then native support, casualties and aftermath use actual forces. This first version does not adjudicate the FAQ mixed dial cap.',
'Concealed collection, occupancy and control use one-force presence. Exposed storm sectors and unprotected worm destruction reveal and remove the resulting actual forces. Storm shelter and other sectors remain separate. Trip to Gamont at a location with a marker reveals it, even if ordinary forces also occupy that sector, then returns one actual force if present. It is still used if zero forces remain. Canceling the CHOAM power leaves the marker concealed.',
'All four AI profiles choose from their own private token inventory, pay only the one-force shipment price, move the marker explicitly and reveal positive tokens when useful. They retain zero-token presence and use only public information to assess opponents. They also offer safe positive tokens from their own inventory during the allied opportunity, fund them with their own spice and accept or decline private offers using their own force and payment information. A human Richese player’s offer window holds an AI ally’s shipment. Pending responses, decisions and Truthtrance retain priority.',
'Advanced mixed-force battles, combined Ecaz Occupy, Advanced Guild/Karama allied prices and entire-plan special Karama inspection against a No-Field remain guarded. Homeworld custody, broader Truthtrance and interrupted compositions remain unfinished. Basic mixed-pool and discounted-price prototypes are not publisher-adjudicated formulas. Richese starts remain disabled.',
'Combined Ecaz Occupy and entire-plan special Karama inspection against a No-Field remain guarded. Homeworld custody, broader Truthtrance and interrupted compositions remain unfinished. Mixed-pool and discounted-price prototypes in both modes are not publisher-adjudicated formulas. Richese starts remain disabled.',
],
related: [
'richese-cards',
@@ -1039,7 +1039,7 @@ export const RULE_TOPICS: RuleTopic[] = [
area: 'Implementation',
status: 'Partial',
detail:
'Own shipment, movement, reveal, effective presence, collection, hazards, Gamont and marker-only battles work in development fixtures. Basic mixed battles have a provisional private pool and native aftermath. Allied consent, typed forces, full/split funding, prevention and immediate reveal are integrated; Basic Guild/active-Karama offers have a shared provisional one-spice/bank quote. Advanced/combined mixed battles, Advanced discounted allied prices, whole-plan inspection and wider combinations remain separate.',
'Own shipment, movement, reveal, effective presence, collection, hazards, Gamont and marker-only battles work in development fixtures. Basic and Advanced mixed battles have a provisional private pool and native support/aftermath. Allied consent, typed forces, full/split funding, prevention and immediate reveal are integrated; Guild/active-Karama offers in both modes have a shared provisional one-spice/bank quote. Combined mixed battles, whole-plan inspection and wider combinations remain separate.',
},
{
area: 'Player controls',
@@ -1051,7 +1051,7 @@ export const RULE_TOPICS: RuleTopic[] = [
area: 'AI',
status: 'Partial',
detail:
'All four profiles support own shipment, marker movement/reveal and marker-only battles using entitled projections. Basic mixed groups now use the private authoritative battle pool; one Easy planning/aftermath smoke passes. Allied offer/acceptance preserves human ownership and avoids repeated declined offers and forbidden dial prescience. Complete Richese-game strategy remains unverified.',
'All four profiles support own shipment, marker movement/reveal and marker-only battles using entitled projections. Mixed groups in both modes use the private authoritative battle pool; Basic and Advanced Easy planning/aftermath smokes pass. Allied offer/acceptance preserves human ownership and avoids repeated declined offers and forbidden dial prescience. Complete Richese-game strategy remains unverified.',
},
{
area: 'Documentation',
+5 -6
View File
@@ -27,19 +27,18 @@ export function guildShipmentCost(
const ordinaryAlliedNoFieldPricing = Object.freeze({
stronghold: 1, other: 2, bankOnly: false, policy: null,
});
const basicDiscountedAlliedNoFieldPricing = Object.freeze({
const discountedAlliedNoFieldPricing = Object.freeze({
stronghold: 1, other: 1, bankOnly: true,
policy: 'Provisional Basic pricing: a Guild recipient or already-active Karama rate uses the rounded one-force Guild fee (1 spice), paid entirely to the bank. This price/payee precedence is not an adjudicated publisher ruling.',
policy: 'Provisional pricing: a Guild recipient or already-active Karama rate uses the rounded one-force Guild fee (1 spice), paid entirely to the bank. This price/payee precedence is not an adjudicated publisher ruling.',
});
/** Basic first version; Advanced keeps its separate unresolved-entry guard. */
/** Shared first-version price/payee policy for Basic and Advanced. */
export function alliedNoFieldShipmentPricing(
context: { advanced: boolean; karamaShipping?: { player: string } | null },
recipient: { id: string; faction: FactionId },
) {
return !context.advanced &&
(recipient.faction === 'guild' || context.karamaShipping?.player === recipient.id)
? basicDiscountedAlliedNoFieldPricing : ordinaryAlliedNoFieldPricing;
return recipient.faction === 'guild' || context.karamaShipping?.player === recipient.id
? discountedAlliedNoFieldPricing : ordinaryAlliedNoFieldPricing;
}
/** A pledge is already escrowed. Selecting a share never spends a donor's
+1 -2
View File
@@ -188,8 +188,7 @@ void test('offer choices do not use hidden recipient money and respect projectio
const view = projection(fixture(), difficulty);
view.richeseNoField!.canOfferAlly = false;
assert.ok(!botActions(view).some((a) => a.type === 'offerRicheseNoField'));
for (const faction of ['fremen', 'guild'] as const)
assert.equal(offerAction(fixture(faction), difficulty), undefined);
assert.equal(offerAction(fixture('fremen'), difficulty), undefined);
const inactive = fixture();
inactive.active = 'r';
assert.equal(offerAction(inactive, difficulty), undefined);