89 lines
3.0 KiB
TypeScript
89 lines
3.0 KiB
TypeScript
import type { FactionId } from './catalog';
|
||
|
||
/** Ordinary reserve shipment; other transport powers have separate prices. */
|
||
export function reserveShipmentCost(
|
||
player: { faction: FactionId; halfRate: boolean },
|
||
territoryType: string,
|
||
amount: number,
|
||
) {
|
||
if (player.faction === 'fremen') return 0;
|
||
const standard = amount * (territoryType === 'stronghold' ? 1 : 2);
|
||
return player.halfRate ? Math.ceil(standard / 2) : standard;
|
||
}
|
||
|
||
/** Guild cross-planet transport and returns; Fremen southern reserves pay this
|
||
* tariff too. Pass 'reserves' for a return, not a board territory type.
|
||
*/
|
||
export function guildShipmentCost(
|
||
destinationType: string,
|
||
amount: number,
|
||
halfRate = true,
|
||
) {
|
||
const normal = amount *
|
||
(destinationType === 'reserves' || destinationType === 'stronghold' ? 1 : 2);
|
||
return halfRate ? Math.ceil(normal / 2) : normal;
|
||
}
|
||
|
||
const ordinaryAlliedNoFieldPricing = Object.freeze({
|
||
stronghold: 1, other: 2, bankOnly: false, policy: null,
|
||
});
|
||
const discountedAlliedNoFieldPricing = Object.freeze({
|
||
stronghold: 1, other: 1, bankOnly: true,
|
||
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.',
|
||
});
|
||
|
||
const canceledGuildAlliedNoFieldPricing = Object.freeze({
|
||
stronghold: 1, other: 2, bankOnly: true,
|
||
policy: 'Provisional pricing: canceling a Guild recipient’s native rate charges the full one-force fee, still paid entirely to the bank. This price/payee precedence is not an adjudicated publisher ruling.',
|
||
});
|
||
|
||
/** Shared first-version price/payee policy for Basic and Advanced. */
|
||
export function alliedNoFieldShipmentPricing(
|
||
context: {
|
||
purchasedGuildRate: boolean;
|
||
nativeGuildRateCanceled: boolean;
|
||
},
|
||
recipient: { faction: FactionId },
|
||
) {
|
||
if (context.purchasedGuildRate)
|
||
return discountedAlliedNoFieldPricing;
|
||
if (recipient.faction !== 'guild') return ordinaryAlliedNoFieldPricing;
|
||
return context.nativeGuildRateCanceled
|
||
? canceledGuildAlliedNoFieldPricing : discountedAlliedNoFieldPricing;
|
||
}
|
||
|
||
/** A pledge is already escrowed. Selecting a share never spends a donor's
|
||
* unpledged balance or enlarges the contribution they authorized.
|
||
*/
|
||
export function shipmentPaymentBounds(
|
||
cost: number,
|
||
ownSpice: number,
|
||
pledgedSpice: number,
|
||
) {
|
||
return {
|
||
minimum: Math.max(0, cost - ownSpice),
|
||
maximum: Math.min(cost, pledgedSpice),
|
||
};
|
||
}
|
||
|
||
/** November 2020 FAQ, Alliances: each contributor pays the Guild directly;
|
||
* money contributed by the Guild itself goes to the bank. An independent
|
||
* Karama shipment routes the entire payment to the bank.
|
||
*/
|
||
export function guildShipmentIncome(payment: {
|
||
guild: string | undefined;
|
||
shipper: string;
|
||
ally: string | null;
|
||
cost: number;
|
||
allyPayment: number;
|
||
bankOnly: boolean;
|
||
}) {
|
||
if (!payment.guild || payment.bankOnly) return 0;
|
||
return (
|
||
(payment.shipper === payment.guild
|
||
? 0
|
||
: payment.cost - payment.allyPayment) +
|
||
(payment.ally === payment.guild ? 0 : payment.allyPayment)
|
||
);
|
||
}
|