Connect Basic shared Ecaz Orgiz Collection settlement
This commit is contained in:
1 parent
bcd1b1041a
commit
1f38f12beb
11 files changed
+196
-73
No files matched your search
@@ -286,35 +286,47 @@ export function quoteDiscoveryCollection(
|
||||
|
||||
const SHARED_COLLECTION_RELEASES: readonly AdvisorRelease[] = [];
|
||||
|
||||
/** Advanced's one-territory event waits for the original bilateral allocation.
|
||||
* Charge the first actual positive foreign recipient (Ecaz, then ally), never
|
||||
* a guessed share, the owner itself, a city award or unavailable spice. */
|
||||
export function quoteAdvancedSharedOrgiz(
|
||||
/** Shared collection waits for its original bilateral allocation. Advanced
|
||||
* charges once per territory; Basic retains one event per positive deposit.
|
||||
* Only actual positive foreign recipients qualify; current purses cannot owe. */
|
||||
export function quoteSharedOrgiz(
|
||||
context: DiscoveryCollectionContext,
|
||||
allocation: SpiceAllocationReceipt,
|
||||
balances: Readonly<Record<string,number>>,
|
||||
originalSpice: Readonly<Record<string,number>>,
|
||||
): OrgizCollectionReceipt[] {
|
||||
requireCollection(context.advanced && allocation.ecaz !== allocation.ally &&
|
||||
requireCollection(typeof context.advanced === 'boolean' && allocation.ecaz !== allocation.ally &&
|
||||
context.order.includes(allocation.ecaz) && context.order.includes(allocation.ally) &&
|
||||
whole(allocation.ecazAmount) && whole(allocation.allyAmount) &&
|
||||
record(balances) && context.order.every(id => whole(balances[id])),
|
||||
'Shared Orgiz needs the actual Advanced territory allocation and available balances.');
|
||||
record(balances) && context.order.every(id => whole(balances[id])) &&
|
||||
record(originalSpice) && Object.entries(originalSpice).every(([key,amount]) =>
|
||||
whole(amount) && whole(context.spice[key]) && context.spice[key] <= amount),
|
||||
'Shared Orgiz needs its actual allocation, original board deposits and available balances.');
|
||||
const owners = discoveryCollectionOccupants(context,ORGIZ_PROCESSING_STATION,SHARED_COLLECTION_RELEASES);
|
||||
if (!owners.length) return [];
|
||||
const locations = context.advanced ? [allocation.territory] : Object.keys(originalSpice)
|
||||
.filter(key => splitLocation(key).territory === allocation.territory &&
|
||||
originalSpice[key] > context.spice[key]).sort();
|
||||
requireCollection(locations.length > 0,
|
||||
'Shared Orgiz must retain the original positive Collection source.');
|
||||
const effects: OrgizCollectionReceipt[] = [];
|
||||
let ecazDebited=0, allyDebited=0;
|
||||
for (const owner of owners) {
|
||||
let payer: string;
|
||||
if (owner.id !== allocation.ecaz && allocation.ecazAmount > 0 &&
|
||||
balances[allocation.ecaz] > ecazDebited) {
|
||||
payer=allocation.ecaz; ecazDebited++;
|
||||
} else if (owner.id !== allocation.ally && allocation.allyAmount > 0 &&
|
||||
balances[allocation.ally] > allyDebited) {
|
||||
payer=allocation.ally; allyDebited++;
|
||||
} else continue;
|
||||
requireCollection(Number.isSafeInteger(balances[owner.id]+1),
|
||||
'Shared Orgiz income would overflow the spice balance.');
|
||||
effects.push({kind:'orgiz',player:owner.id,from:payer,location:allocation.territory,
|
||||
amount:1,source:'player'});
|
||||
}
|
||||
const available = {...balances};
|
||||
for (const location of locations)
|
||||
for (const owner of owners) {
|
||||
let payer: string;
|
||||
if (owner.id !== allocation.ecaz && allocation.ecazAmount > 0 &&
|
||||
available[allocation.ecaz] > 0)
|
||||
payer = allocation.ecaz;
|
||||
else if (owner.id !== allocation.ally && allocation.allyAmount > 0 &&
|
||||
available[allocation.ally] > 0)
|
||||
payer = allocation.ally;
|
||||
else continue;
|
||||
requireCollection(Number.isSafeInteger(available[owner.id]+1),
|
||||
'Shared Orgiz income would overflow the spice balance.');
|
||||
available[payer]--;
|
||||
available[owner.id]++;
|
||||
effects.push({kind:'orgiz',player:owner.id,from:payer,location,
|
||||
amount:1,source:'player'});
|
||||
}
|
||||
return effects;
|
||||
}
|
||||
+9
-10
@@ -305,7 +305,7 @@ import {
|
||||
} from './board-resolution-quote';
|
||||
import {
|
||||
quoteDiscoveryCollection,
|
||||
quoteAdvancedSharedOrgiz,
|
||||
quoteSharedOrgiz,
|
||||
DiscoveryCollectionError,
|
||||
type DiscoveryCollectionQuote,
|
||||
} from './discovery-collection';
|
||||
@@ -19690,15 +19690,14 @@ function decideSharedSpice(g: Game, id: string, action: Action) {
|
||||
`${territory(receipt.territory).name} shared collection: Ecaz received ${receipt.ecazAmount} spice and ${faction(getPlayer(g, receipt.ally).faction).name} received ${receipt.allyAmount}, ${receipt.method === 'agreement' ? 'by agreement' : 'using the equal split with any odd spice going to the ally'}.`,
|
||||
{ faction: 'ecaz', name: 'Shared collection' },
|
||||
);
|
||||
if (g.advanced) {
|
||||
const balances = Object.fromEntries(g.players.map(player => [player.id,player.spice]));
|
||||
const transfers = nexusRule(() => quoteAdvancedSharedOrgiz(g,receipt,balances));
|
||||
for (const transfer of transfers) {
|
||||
getPlayer(g,transfer.from).spice -= transfer.amount;
|
||||
getPlayer(g,transfer.player).spice += transfer.amount;
|
||||
log(g, `${faction(getPlayer(g,transfer.player).faction).name} took ${transfer.amount} spice from ${faction(getPlayer(g,transfer.from).faction).name} through Orgiz Processing Station after the original shared territory allocation.`,
|
||||
{faction:getPlayer(g,transfer.player).faction,name:'Orgiz Processing Station'});
|
||||
}
|
||||
const balances = Object.fromEntries(g.players.map(player => [player.id,player.spice]));
|
||||
const transfers = nexusRule(() => quoteSharedOrgiz(g,receipt,balances,pending.sourceSpice));
|
||||
for (const transfer of transfers) {
|
||||
getPlayer(g,transfer.from).spice -= transfer.amount;
|
||||
getPlayer(g,transfer.player).spice += transfer.amount;
|
||||
recordFremenCollection(g,transfer.player,`orgiz:shared:${transfer.location}:${transfer.player}`,transfer.amount);
|
||||
log(g, `${faction(getPlayer(g,transfer.player).faction).name} took ${transfer.amount} spice from ${faction(getPlayer(g,transfer.from).faction).name} through Orgiz Processing Station after the original shared territory allocation.`,
|
||||
{faction:getPlayer(g,transfer.player).faction,name:'Orgiz Processing Station'});
|
||||
}
|
||||
} else
|
||||
log(
|
||||
|
||||
+4
-4
@@ -4226,7 +4226,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
'The five revealed location tokens become separate, initially empty territories inside their surroundings. A private peek does not open the location. Normal ground movement enters through the surrounding territory, shipment uses stronghold prices, at most two factions may occupy it, and forces inside are protected from storms and sandworms. Only Jacurutu Sietch counts toward stronghold victory.',
|
||||
'Native typed forces enter as their actual ordinary and elite groups, never as passengers from the mobile stronghold or the concealed value of a No-Field. Richese may ship or move a concealed marker into an actually revealed nested location at sector zero; it remains one effective presence until its original reveal materializes available reserves. CHOAM Card Stash uses its five-card limit, drawing first and choosing any held discard afterward.',
|
||||
'At the start of the next turn, before the storm and mobile stronghold movement, each eligible faction may move any positive subset of its non-advisor groups from the surrounding territory into the newly revealed location. The signed choice preserves ordinary and elite forces across sectors, normal source storm and occupancy restrictions, and costs no spice, shipment or normal movement. The printed text gives no sequence and does not restate the source-storm restriction; processing tokens in reveal order and factions in storm order while excluding storm sources are source inferences.',
|
||||
'During Collection, after advisor releases, every Cistern fighter occupant receives two bank spice. Orgiz occupants resolve in original storm order using canonical positive ordinary deposit receipts, not force presence or old wallets. Advanced charges once per territory; Basic provisionally charges once per positive deposit. The first actual foreign collector in storm order with available spice pays; self and zero actual collection do not qualify. Advanced shared Ecaz desert lots wait for their real split, then consider positive foreign recipients Ecaz first, ally second. Basic shared settlement remains pending. Payer/occupant ordering is provisional; empty purses never create debt.',
|
||||
'After advisor releases, every Cistern fighter occupant receives two bank spice. Orgiz occupants resolve in original storm order using actual ordinary deposit receipts, not mere force presence or old wallets. Advanced charges once per territory; Basic provisionally charges once per positive deposit. The first actual foreign ordinary collector in storm order with available spice pays. Shared Ecaz lots in both modes wait for the actual split, then consider positive foreign recipients Ecaz first, ally second; Advanced counts the territory once and Basic counts actually reduced source deposits. Self, zero shares and empty purses do not qualify. Balances track each transfer without debt; ordering and Basic mapping remain provisional.',
|
||||
'Jacurutu pays one bank spice for each opposing undialed physical force actually sent to the Tanks. Where an Advanced dial admits different physical counts, the defeated player chooses an exact ordinary/elite/paid reading before support, casualties or rewards settle; unique readings remain automatic. This choice timing is a visibly provisional implementation interpretation. Original Harass returns bind their physical dial and actual withdrawal/retreat counters do not earn spice.',
|
||||
'Each non-advisor Testing Station occupant may decrease ordinary storm movement by one, keep it or increase it by one. The provisional order is the original storm order, once per owner, with cumulative adjustments on current distance. Choose after the ordinary card window; traversal/protection starts only after all choices. Weather Control is unaffected. Original natural source/base and existing sole-frame history remain authoritative; legacy movement without a source is not invented.',
|
||||
'A current non-advisor Shrine occupant may play a physical Truthtrance card as Karama, or a physical Karama as Truthtrance, within the implemented timing and effect paths. The printed identity and actual card custody remain unchanged; a committed Truthtrance conversion survives departure. This does not create missing Karama powers or settle their pending rules.',
|
||||
@@ -4236,7 +4236,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
checklist: [
|
||||
{
|
||||
area: 'Implementation', status: 'Partial',
|
||||
detail: 'Original classic and supported native Skills/Nexus/Discovery entries retain their selected modules and rule controls. Mixed Jacurutu uses an exact defeated-player physical reading before native settlement. Testing Station queues signed cumulative storm-order choices before one traversal. Cistern pays each fighter occupant; Orgiz consumes actual positive ordinary deposit receipts in original storm order, grouping by territory in Advanced and deposit in Basic without guessing co-present payers or creating debt. Advanced shared lots wait for bilateral allocation; Basic shared settlement and broader mode acceptance remain open.',
|
||||
detail: 'Original classic and supported native Skills/Nexus/Discovery entries retain their selected modules and controls. Jacurutu uses an exact defeated-player reading before native settlement; Testing Station queues cumulative choices before one traversal. Cistern pays every fighter occupant. Orgiz uses actual ordinary receipts and bilateral shared allocations in both modes, grouping by territory in Advanced and positive source deposit in Basic without guessed payers or debt. Available balances track all transfers and cumulative overflow. Broader mode/module acceptance remains open.',
|
||||
evidence: ['game/discovery-module-profile.ts', 'game/richese-no-field.ts', 'game/discoveries.ts', 'game/discovery-actions.ts', 'game/discovery-entry.ts', 'game/discovery-collection.ts', 'game/board-resolution-quote.ts', 'game/discovery-flight.ts', 'game/discovery-battle.ts', 'game/discovery-storm.ts', 'game/shrine.ts', 'game/great-maker.ts', 'game/board.ts', 'game/engine.ts'],
|
||||
},
|
||||
{
|
||||
@@ -4251,12 +4251,12 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
},
|
||||
{
|
||||
area: 'Documentation', status: 'Partial',
|
||||
detail: 'Sourced identities and native/classic-skill boundaries are recorded. Advanced Orgiz follows territory Collection and actual ordinary receipts; Basic retains its provisional positive-deposit mapping. Recommended Discovery occupant/payer ordering, Jacurutu allocation and cumulative Testing Station choices are visible interpretations, not publisher rulings. Great Maker, entry/source-storm inferences and Basic shared Orgiz settlement remain open.',
|
||||
detail: 'Sourced identities and native/classic-skill boundaries are recorded. Advanced Orgiz uses territory Collection; Basic retains its provisional deposit mapping, including actual source reductions after bilateral shared settlement. Recommended occupant/payer ordering, Jacurutu allocation and cumulative Testing Station choices are visible interpretations, not publisher rulings. Great Maker and entry/source-storm inferences remain explicit; full acceptance stays open.',
|
||||
evidence: ['docs/DISCOVERY_COMPONENTS.md', 'docs/DISCOVERY_PROTOTYPE.md'],
|
||||
},
|
||||
{
|
||||
area: 'Verification', status: 'Partial',
|
||||
detail: 'Current canonical Collection batch passes72/72 in6 related files, types/lint and build. Genuine Basic/Advanced co-present Sihaya Ridge collectors take2 each or exhaust the6-spice pile in actual storm order; zero actual collection cannot qualify through old wallets. Actual390px Finish shipment & movement produces phase7, Ecaz8/Guild14 from7/10 and one Orgiz transfer with Ready restored, no overflow or errors. Earlier shared-allocation proof passes27/27 and Jacurutu/Testing Station proof104/104, each source-bound. Basic shared settlement, combinations, assurance, strategy and deployed acceptance remain open.',
|
||||
detail: 'Current Collection batch passes80/80 in6 related files, types/lint and build. Genuine Basic/Advanced cases cover shared equal/full/zero splits, acceptance timing, wrong actors and stale events; helper boundaries cover multiple deposits, exhausted recipients, self/zero-share exclusion and cumulative overflow. Actual390px Basic Red Chasm lot4 changes Ecaz7/Guild8 to8/11 with one transfer and Ready restored, no overflow or errors. Four legal policies complete that Basic allocation via actual actions. Earlier canonical-source and Jacurutu/Station evidence remains source-bound; combinations, assurance, strategy and deployed acceptance remain open.',
|
||||
evidence: ['tests/mixed-nexus-modules-runtime.test.ts', 'tests/paired-e3-nexus-modules-runtime.test.ts', 'tests/sample-custody.test.ts', 'tests/ambassador-terror-overlap-engine.test.ts', 'tests/e3-nexus-ecaz-runtime.test.ts', 'tests/e3-nexus-moritani-runtime.test.ts', 'tests/single-nexus-e1-runtime.test.ts', 'tests/single-nexus-e2-runtime.test.ts', 'tests/homeworld-paired-nexus-runtime.test.ts', 'tests/homeworld-standalone-nexus-runtime.test.ts',
|
||||
'tests/fixture-jacurutu-mixed-dial.ts', 'tests/jacurutu-mixed-dial-runtime.test.ts', 'tests/fixture-testing-station-contest.ts', 'tests/testing-station-contest-runtime.test.ts',
|
||||
'tests/fixture-discovery-occupied-collection.ts', 'tests/discovery-occupied-collection-runtime.test.ts', 'tests/fixture-discovery-shared-orgiz.ts', 'tests/discovery-shared-orgiz-runtime.test.ts',
|
||||
|
||||
Reference in new issue
Block a user