Connect Tleilaxu revival payments to Bureaucrat
This commit is contained in:
1 parent
3b118dd845
commit
e6bb9809f7
10 files changed
+252
-18
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { basicExpansionLeaderSkillsProfile, noOtherLeaderSkillModules, type LeaderSkillProfile } from './leader-skill-profile';
|
||||
export type BureaucratPaymentKind = 'auction' | 'shipment' | 'bribe';
|
||||
export type BureaucratPaymentKind = 'auction' | 'shipment' | 'bribe' | 'revival';
|
||||
export type BureaucratPaymentSource = {
|
||||
event: string;
|
||||
turn: number;
|
||||
|
||||
+18
-8
@@ -6254,7 +6254,8 @@ function bureaucratPaymentFrame(g: Game): string {
|
||||
}
|
||||
function validateBureaucratSource(g: Game,source:BureaucratPaymentSource) {
|
||||
requireRule(source && typeof source === 'object' && typeof source.event === 'string' && source.event.length > 0 &&
|
||||
source.turn === g.turn && source.phase === g.phase && ['auction','shipment','bribe'].includes(source.kind) &&
|
||||
source.turn === g.turn && source.phase === g.phase && ['auction','shipment','bribe','revival'].includes(source.kind) &&
|
||||
(source.kind !== 'revival' || g.phase === 4) &&
|
||||
g.players.some(p => p.id === source.payer) && g.players.some(p => p.id === source.payee) && source.payer !== source.payee &&
|
||||
Number.isSafeInteger(source.amount) && source.amount >= 5 && source.signature === bureaucratPaymentSignature(source),
|
||||
'The saved Bureaucrat payment changed its actual payer, payee, amount or event.');
|
||||
@@ -6292,7 +6293,10 @@ function bureaucratPaymentIntegrity(g: Game) {
|
||||
'The Bureaucrat source no longer matches its paid auction sale.');
|
||||
else requireRule(source.payee === carrier.owner &&
|
||||
(carrier.kind === 'guildIncome' && source.kind === 'shipment' && source.amount === carrier.amount ||
|
||||
carrier.kind === 'emperorIncome' && source.kind === 'auction' && g.currentAuctionSale?.bureaucratPaymentEvent === source.event),
|
||||
carrier.kind === 'emperorIncome' && source.kind === 'auction' && g.currentAuctionSale?.bureaucratPaymentEvent === source.event ||
|
||||
carrier.kind === 'revivalIncome' && source.kind === 'revival' && byFaction(g,'tleilaxu')?.id === source.payee &&
|
||||
source.amount <= (carrier.amount ?? -1) && (carrier.amount ?? 0) <= source.amount + 1 &&
|
||||
source.payer === carrier.recipient),
|
||||
'The Bureaucrat source no longer matches its original native income.');
|
||||
}
|
||||
const decisions = homeworldSavedDecisions(g).filter(d => d.kind === 'bureaucratPayment');
|
||||
@@ -6328,9 +6332,11 @@ function offerBureaucratPayment(g: Game,source:BureaucratPaymentSource|undefined
|
||||
g.decision = {kind:'bureaucratPayment',player:assignment.owner,event:source.event};
|
||||
return true;
|
||||
}
|
||||
function projectedBureaucrat(g: Game): BureaucratPaymentView {
|
||||
function projectedBureaucrat(g: Game,viewer: string): BureaucratPaymentView {
|
||||
const pending = g.bureaucratPayments?.pending;
|
||||
return {pending:pending ? {event:pending.source.event,owner:pending.owner,payer:pending.source.payer,payee:pending.source.payee,
|
||||
const privateRevival = pending?.source.kind === 'revival' &&
|
||||
![pending.owner,pending.source.payer,pending.source.payee,pending.resume.response?.recipient].includes(viewer);
|
||||
return {pending:pending && !privateRevival ? {event:pending.source.event,owner:pending.owner,payer:pending.source.payer,payee:pending.source.payee,
|
||||
amount:pending.source.amount,kind:pending.source.kind,redirect:2} : null,
|
||||
usedThisPhase:bureaucratUsed(g.bureaucratPayments?.used ?? [],g.turn,g.phase)};
|
||||
}
|
||||
@@ -6343,7 +6349,7 @@ function actBureaucratPayment(g: Game,action:Action) {
|
||||
const use:BureaucratPaymentUse = {event:pending.source.event,owner:pending.owner,turn:g.turn,phase:g.phase,signature:''};
|
||||
use.signature = bureaucratPaymentSignature(use);
|
||||
g.bureaucratPayments!.used.push(use);(g.bureaucratUseEvents ??= []).push(use.event);
|
||||
log(g,`${getPlayer(g,pending.owner).name} used Bureaucrat to redirect 2 spice of the ${pending.source.amount}-spice payment to the Bank.`);
|
||||
log(g,`${getPlayer(g,pending.owner).name} used Bureaucrat to redirect 2 spice of ${pending.source.kind === 'revival' ? 'a qualifying revival payment' : `the ${pending.source.amount}-spice payment`} to the Bank.`);
|
||||
}
|
||||
delete g.bureaucratPayments!.pending;delete g.bureaucratPaymentEvent;
|
||||
g.response = pending.resume.response;g.decision = pending.resume.decision;
|
||||
@@ -18557,7 +18563,11 @@ function finishRevival(
|
||||
g.revivalFreeIncome ??= {};
|
||||
g.revivalFreeIncome[quote.freeIncome.player] = quote.freeIncome.turn;
|
||||
}
|
||||
if (quote.nextResponse) g.response = quote.nextResponse;
|
||||
if (quote.nextResponse) {
|
||||
g.response = quote.nextResponse;
|
||||
if (quote.nextResponse.kind === 'revivalIncome')
|
||||
Object.assign(g.response, stampBureaucratPayment(g,'revival',payer.id,quote.nextResponse.owner,revival.cost));
|
||||
}
|
||||
}
|
||||
function beginRevival(g: Game, revival: PendingRevival) {
|
||||
if (revival.kind === 'leader') requireLeaderSkillRevival(g,revival.player);
|
||||
@@ -19384,7 +19394,7 @@ function finishResponse(g: Game, canceled: boolean,bureaucratDiversion?:number)
|
||||
g.revivalRules ??= newRevivalRules();
|
||||
if (g.pendingRevival) finishRevival(g);
|
||||
} else if (response.kind === 'revivalIncome') {
|
||||
if (!canceled) getPlayer(g, response.owner).spice += response.amount!;
|
||||
if (!canceled) getPlayer(g, response.owner).spice += response.amount! - (bureaucratDiversion ?? 0);
|
||||
if (g.pendingChoamMarketGhola && g.pendingChoamMarketGhola.event === response.intent)
|
||||
g.pendingChoamMarketGhola.stage = 'complete';
|
||||
} else if (response.kind === 'faceDancerReplacement') {
|
||||
@@ -26304,7 +26314,7 @@ export function viewGame(state: Game, id: string) {
|
||||
setupStage: g.status === 'setup' ? (g.setupStage ?? null) : null,
|
||||
setupPending: setupPending(g),
|
||||
leaderSkills: projectedLeaderSkills(g, id),
|
||||
bureaucrat: projectedBureaucrat(g),
|
||||
bureaucrat: projectedBureaucrat(g, id),
|
||||
bribeOptions: projectedBribes(g, me),
|
||||
mentat: projectedMentat(g, id),
|
||||
rihani: projectedRihani(g, id),
|
||||
|
||||
+1
-1
@@ -4178,7 +4178,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
'Spice Banker can commit one through three own spice with its Battle Plan, separate from force support. Only the surviving selected skilled disc gains that strength. The amount stays private until authorized plan inspection or public reveal. It is paid on win or loss, including leader death, except a sole traitor-call winner spends nothing. Normal deferred income remains unfinished.',
|
||||
'Diplomat may use one committed Worthless card as the opponent’s base Shield or Snooper if you played no defense. After both plans reveal, choose the card or decline before traitor decisions. A native Diplomat may protect its own selected trained leader this way; a captive grants no upper effect. The chosen Worthless must be discarded afterward, even if you win. A surviving trained leader that loses a supported battle may retreat selected undialed physical counters up to its printed/copied disc strength into one empty adjacent non-stronghold territory before ordinary loser losses; modified defenses remain unfinished.',
|
||||
'Mentat has a private developer preview for naming a specific weapon before posture and faction powers. The target privately shows the named held card or chooses another held card. It stays in hand and need not enter a Battle Plan. Every answer uses the same private response step; ordinary activation awaits the user’s timing-design decision. Empty hands skip without an answer. Private history records an observation, not a later hand guarantee.',
|
||||
'Bureaucrat may redirect two spice from a payment of at least five between two other players, once per phase. The payer still pays in full; the recipient receives two less. Declining keeps the use available for a later payment. Paid bribes qualify when transferred, with the remaining share still unavailable until Mentat Pause. Ordinary auctions, Guild income and Richese sales have connected payment paths; split funding, other payment families and combined modules remain unfinished.',
|
||||
'Bureaucrat may redirect two spice from a payment of at least five between two other players, once per phase. The payer still pays in full; the recipient receives two less. Declining keeps the use available for a later payment. Paid bribes qualify when transferred, with the remaining share still unavailable until Mentat Pause. Ordinary auctions, Guild income, Richese sales and actual paid Tleilaxu revival income in the Basic Tleilaxu skill profile have connected payment paths. A separate free-revival award is not part of the paid price and stays with Tleilaxu. Split funding, gifts, other payment families and combined modules remain unfinished.',
|
||||
'Smuggler records the existing battle-territory spice when plans reveal, capped by the selected leader’s unmodified strength. If that leader survives, it collects automatically even when losing or no forces remain. A captive pays its controller. Pending spice cannot fund the plan. Collection precedes Sandmaster’s addition; a drained pile receives none. Modified strength, multiple positive piles and combined modules remain guarded. Older saved battles keep their original behavior.',
|
||||
'Other special Sandmaster relocation and Spice Banker normal income remain missing. Diplomat retreat uses a documented conservative outcome-order interpretation in standalone Leader Skills play. Foreign gholas, Face Dancers and combined modules remain unfinished. This development prototype does not enable public module starts.',
|
||||
...LEADER_SKILL_CARDS.map(card => `${card.name}. Normal: ${card.normal.join(' ')} Skilled battle: ${card.battle.join(' ')}`),
|
||||
|
||||
Reference in new issue
Block a user