Support paid No-Field companions in Basic allied transit
Verify and publish checkpoint container / container (push) Successful in 10m34s

This commit is contained in:
Quintine committed 2026-10-28 22:49:42 +11:00
1 parent 8083598cef
commit 40d567a053
7 files changed
+270 -9

No files matched your search

+25 -2
View File
@@ -3548,6 +3548,8 @@ function policyActions(g: GameView): Action[] {
const physicalAlongsideMarker = marker
? countAt(me, marker.location.territory) > 0
: !!(deployedWorld && g.homeworlds?.worlds?.find(world => world.id === deployedWorld)?.forces[me.id]);
const visitingMarker = !!marker && !!g.basicAlliedShipment?.noField &&
territory(marker.location.territory).name === g.basicAlliedShipment.territory;
const reveal =
noField?.canReveal &&
deployed &&
@@ -3555,7 +3557,7 @@ function policyActions(g: GameView): Action[] {
? { type: 'revealNoField', token: deployed.tokenId, event: noField.event }
: null;
if (
reveal &&
reveal && !visitingMarker &&
(physicalAlongsideMarker ||
!me.shipped ||
(me.moved ?? 0) >= (me.movesAllowed ?? 1))
@@ -3602,7 +3604,7 @@ function policyActions(g: GameView): Action[] {
const smuggler = !!quoteSmugglerNoField(g, me.id, to.t);
const companions = noField.homeworldForcesEnabled && me.reserves > (smuggler ? 1 : 0) ? [1, 0] : [0];
for (const amount of companions) {
if ((amount > 0 || smuggler) && isAlliedShipmentVisit(g, me, to.t)) continue;
if (smuggler && isAlliedShipmentVisit(g, me, to.t)) continue;
const group = quoteRicheseHomeworldForces({ enabled: !!noField.homeworldForcesEnabled,
reserves: me.reserves, amount, smuggler });
if (Math.min(selected.value, me.reserves) + group.physical === 0 && to.enemy > 0) continue;
@@ -3629,6 +3631,20 @@ function policyActions(g: GameView): Action[] {
const ordinary = botGroundMoveAllowed(g, me, from, to.key, 0);
if (!ordinary && !(markerPlanetologist &&
botGroundMoveAllowed(g, me, from, to.key, 0, 'range'))) continue;
if (visitingMarker && g.basicAlliedShipment && g.basicAlliedShipment.normal > 0) {
let remaining = g.basicAlliedShipment.normal;
const forces: Record<string, number> = {};
for (const [key, total] of Object.entries(me.forces)) {
if (splitLocation(key).territory !== marker.location.territory ||
!botGroundMoveAllowed(g, me, key, to.key, 0, ordinary ? undefined : 'range')) continue;
const normal = total - (me.elites?.forces[key] ?? 0);
const count = Math.min(remaining, normal);
if (count > 0) { forces[key] = count; remaining -= count; }
}
if (!remaining) actions.push({ type: 'move', ...(!ordinary ? {planetologist: 'range'} : {}),
forces, noField: marker.tokenId,
event: noField.event, territory: to.t, sector: to.s });
}
actions.push({
type: 'move',
...(!ordinary ? { planetologist: 'range' } : {}),
@@ -4517,6 +4533,13 @@ export function botActions(g: GameView): Action[] {
(territory(splitLocation(action.from).territory).name === g.basicAlliedShipment?.territory ||
advancedDepartures?.includes(territory(splitLocation(action.from).territory).name)) ||
!!action.noField && !!g.basicAlliedShipment?.noField && markerTerritory === g.basicAlliedShipment.territory));
if (g.basicAlliedShipment?.noField && g.basicAlliedShipment.normal > 0) {
const together = departures.filter(action => action.noField && action.forces &&
typeof action.forces === 'object' && !Array.isArray(action.forces) &&
Object.values(action.forces).reduce<number>((sum, value) => sum + (typeof value === 'number' ? value : 0), 0) >=
g.basicAlliedShipment!.normal);
if (together.length) return together;
}
if (departures.length) return departures;
}
const ghola = standaloneGholaAction(g, actions);
+4 -3
View File
@@ -37660,7 +37660,8 @@ function validateLeaderSkillNoFieldShipment(g: Game, shipment: PendingShipment)
'The saved No-Field shipment lost its current unused opportunity or concealed marker.');
integer(shipment.sector, 0, 18, 'No-Field shipment sector');
requireRule(shipment.territory !== MOBILE_STRONGHOLD, 'Richese cannot ship into the mobile stronghold.');
allowedEntry(g, p, shipment.territory, shipment.sector, false, false);
allowedEntry(g, p, shipment.territory, shipment.sector, false, false,
!g.advanced && !shipment.smugglerCompanion && isAlliedShipmentVisit(g, p, shipment.territory));
noFieldRule(() => deployRicheseNoField(p.noField!, {
tokenId: shipment.noField!.tokenId,
controller: p.id,
@@ -37934,7 +37935,7 @@ function openGuildRate(g: Game, shipment: PendingShipment): boolean {
owner: byFaction(g, 'guild')!.id,
passed: [],
guildRateEvent: event,
intent: `${getPlayer(g, shipment.player).name} declared ${shipment.alliedNoField ? 'one allied No-Field shipment' : shipment.noField ? 'one concealed No-Field' : shipment.nexusEvent ? `${shipment.amount} physical reserve forces priced as one by Richese Secret Ally` : `${shipment.amount} reserve forces`}${shipment.smugglerCompanion ? ' with one free Smuggler companion' : shipment.smuggler ? ' including one free Smuggler companion' : ''} to ${territory(shipment.territory).name} at the Guild rate of ${shipment.cost} spice. Karama can remove this discount before any payment or arrival.${shipment.smuggler || shipment.smugglerCompanion ? ' The independent free companion remains free.' : ''} The same paid units would cost ${fullCost} at full price; if the original authorized split cannot pay that amount, the declaration returns unused and a replacement this turn uses the full rate.${shipment.nexusEvent ? ' Richese still prices only one counter, not the actual force count. Its Nexus is already spent: an unaffordable declaration ends without delivery or a card refund, while the ordinary shipment remains available.' : ''}`,
intent: `${getPlayer(g, shipment.player).name} declared ${shipment.alliedNoField ? 'one allied No-Field shipment' : shipment.noField ? `one concealed No-Field${shipment.noFieldReserves ? ` and ${shipment.noFieldReserves} paid reserve forces` : ''}` : shipment.nexusEvent ? `${shipment.amount} physical reserve forces priced as one by Richese Secret Ally` : `${shipment.amount} reserve forces`}${shipment.smugglerCompanion ? ' with one free Smuggler companion' : shipment.smuggler ? ' including one free Smuggler companion' : ''} to ${territory(shipment.territory).name} at the Guild rate of ${shipment.cost} spice. Karama can remove this discount before any payment or arrival.${shipment.smuggler || shipment.smugglerCompanion ? ' The independent free companion remains free.' : ''} The same paid units would cost ${fullCost} at full price; if the original authorized split cannot pay that amount, the declaration returns unused and a replacement this turn uses the full rate.${shipment.nexusEvent ? ' Richese still prices only one counter, not the actual force count. Its Nexus is already spent: an unaffordable declaration ends without delivery or a card refund, while the ordinary shipment remains available.' : ''}`,
};
log(g, `${getPlayer(g, shipment.player).name} declared a Guild-rate reserve shipment; payment and arrival wait for the rate response.`);
return true;
@@ -44773,7 +44774,7 @@ function applyActionInner(
);
allowedEntry(g, p, to, s, !guildSecretEvent && g.advanced && p.faction === 'fremen', advisors,
(action.noField === undefined || !g.advanced && !richesePair &&
action.noFieldReserves === undefined && action.smuggler !== true) &&
action.smuggler !== true) &&
isAlliedShipmentVisit(g, p, to));
let noField: PendingShipment['noField'];
if (action.noField !== undefined) {
+1 -1
View File
@@ -1122,7 +1122,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'Concealed zero, three and five tokens represent one force until they are revealed.',
steps: [
'Richese has three No-Fields, numbered zero, three and five. A concealed token counts as one force. Only one may be deployed on Arrakis, and consecutive own or allied shipments cannot use the same token.',
'In Basic play, your own single concealed No-Field may provisionally ship into an ally’s territory if it can legally enter; move it out before your turn ends. If it remains, reveal it and send its newly materialized forces to Tanks under the provisional no-departure policy. A zero marker reveals but contributes no casualties. Existing physical forces and the ally are not part of that new-visitor loss. Paired markers and paid companion forces keep their separate guards.',
'In Basic play, your own single concealed No-Field may provisionally ship into an ally’s territory if it can legally enter; move it and any paid accompanying forces out before your turn ends. Paid companions require the High Richese Homeworld power. If the marker remains, reveal it and send its newly materialized forces to Tanks under the provisional no-departure policy. A zero marker reveals but contributes no casualties. Existing physical forces and the ally are not part of that new-visitor loss. Paired markers keep their separate guards.',
'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.',
'Provisional Guild transport treats your owned concealed marker as one billable force alongside any same-origin physical counters. Native Guild allies may cross-ship it through the normal permission and rate responses. The actual absent-Guild Secret Ally may cross-ship or return it face down, spending its Nexus once and paying the Bank. Cross keeps concealment; return creates no denomination-sized reserve deposit and retains the same-token next-shipment ban. Ordinary Guild allies cannot return. Select the marker separately from physical counters; ordinary movement remains available.',
'In supported native Homeworld games, you may provisionally ship one concealed No-Field from your reserves to a foreign non-allied Homeworld, alone or with physical forces from those reserves. On a later turn, you may ship that same concealed marker between distinct eligible foreign Homeworlds, alone or with selected physical Richese counters from the marker’s current World. Price the whole group as one plus those counters; a purchased Guild rate halves the total, rounding up once. The marker retains its identity and last-shipment history, and its value does not materialize until reveal, when available reserves are placed there. Only one marker may be deployed globally. Own-Homeworld placement or return and optional-module combinations remain unavailable. The supplied revised rulebook permits World-to-World shipment (physical p. 22) and counts a concealed marker as one force for effects (physical p. 36), but does not explicitly resolve this combination; this is a provisional interpretation.',