Compose native Richese skills and Advanced contribution receipts
This commit is contained in:
1 parent
10d74f8db8
commit
032b41aa87
23 files changed
+1132
-111
No files matched your search
@@ -89,6 +89,16 @@ const ids = (v: unknown): v is string[] =>
|
||||
const object = (v: unknown): v is Record<string, unknown> =>
|
||||
!!v && typeof v === 'object' && !Array.isArray(v);
|
||||
|
||||
/** The original Emperor/bank-routed invoice, not the buyer-to-Richese leg. */
|
||||
export function auctionEmperorIncomeAmount(
|
||||
sale: NonNullable<Game['currentAuctionSale']>,
|
||||
): number {
|
||||
if (sale.free || sale.recipient === 'bank') return 0;
|
||||
return sale.origin === 'normal' || sale.seller === sale.winner
|
||||
? sale.amount
|
||||
: sale.richeseContribution ?? 0;
|
||||
}
|
||||
|
||||
/** Deterministic paid-sale continuation only. A returned response, Richese
|
||||
* transition or normal phase-end is a boundary, not a simulated future action.
|
||||
* Never publish this internal quote: returned lot cards remain private. */
|
||||
@@ -270,6 +280,16 @@ function calculate(
|
||||
count(sale.amount) && typeof sale.free === 'boolean',
|
||||
'The paid auction amount or free flag is invalid.',
|
||||
);
|
||||
requireAuction(
|
||||
sale.richeseContribution === undefined ||
|
||||
(input.advanced &&
|
||||
sale.origin !== 'normal' &&
|
||||
sale.seller !== sale.winner &&
|
||||
count(sale.richeseContribution) &&
|
||||
sale.richeseContribution > 0 &&
|
||||
sale.richeseContribution <= sale.amount),
|
||||
'A Richese contribution requires a positive bounded Advanced other-buyer sale.',
|
||||
);
|
||||
if (operation.kind === 'sale')
|
||||
requireAuction(
|
||||
typeof operation.free === 'boolean' && operation.free === sale.free,
|
||||
@@ -310,9 +330,8 @@ function calculate(
|
||||
} else if (r.kind === 'emperorIncome') {
|
||||
requireAuction(
|
||||
seated(r.owner)?.faction === 'emperor' &&
|
||||
r.owner !== winner.id &&
|
||||
!sale.free &&
|
||||
(sale.origin === 'normal' || sale.seller === winner.id),
|
||||
auctionEmperorIncomeAmount(sale) > 0 &&
|
||||
(r.owner !== winner.id || sale.richeseContribution !== undefined),
|
||||
'The canceled Emperor income is not payable by this sale.',
|
||||
);
|
||||
stage = 'bonus';
|
||||
@@ -347,25 +366,29 @@ function calculate(
|
||||
if (sale.origin !== 'normal' && sale.seller !== winner.id) {
|
||||
if (sale.recipient !== 'bank') {
|
||||
const seller = seated(sale.seller!)!;
|
||||
const amount = sale.amount - (sale.richeseContribution ?? 0);
|
||||
requireAuction(
|
||||
count(seller.spice) && count(seller.spice + sale.amount),
|
||||
count(seller.spice) && count(seller.spice + amount),
|
||||
'The seller credit would overflow its current balance.',
|
||||
);
|
||||
steps.push({
|
||||
kind: 'sellerCredit',
|
||||
player: seller.id,
|
||||
amount: sale.amount,
|
||||
balance: seller.spice + sale.amount,
|
||||
amount,
|
||||
balance: seller.spice + amount,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const emperor = input.players.find((p) => p.faction === 'emperor');
|
||||
if (!sale.free && emperor && emperor.id !== winner.id)
|
||||
return result({
|
||||
kind: 'response',
|
||||
response: { kind: 'emperorIncome', owner: emperor.id, passed: [] },
|
||||
});
|
||||
}
|
||||
const emperor = input.players.find((p) => p.faction === 'emperor');
|
||||
if (
|
||||
emperor &&
|
||||
auctionEmperorIncomeAmount(sale) > 0 &&
|
||||
(emperor.id !== winner.id || sale.richeseContribution !== undefined)
|
||||
)
|
||||
return result({
|
||||
kind: 'response',
|
||||
response: { kind: 'emperorIncome', owner: emperor.id, passed: [] },
|
||||
});
|
||||
stage = 'bonus';
|
||||
}
|
||||
if (
|
||||
|
||||
Reference in new issue
Block a user