Files
Dune/game/tupile-intelligence-options.ts
T

48 lines
1.8 KiB
TypeScript

import type { Action, GameView } from './engine';
import type { TupileIntelligenceCategory } from './tupile-intelligence';
/** Eligibility is projected by the server. Never inspect hands or reconstruct
* occupation history, card categories or balances in a client or bot. */
export function tupileIntelligenceCanAct(g: GameView): boolean {
return !!(
g.status === 'playing' &&
g.tupileIntelligence?.owner === g.me &&
!g.tupileIntelligence.blocked
);
}
export function tupileIntelligenceChoice(
g: GameView,
target: string,
category: TupileIntelligenceCategory,
): { blocked: string | null; action: Action | null } {
const offer = g.tupileIntelligence;
let blocked: string | null = null;
if (!offer || offer.owner !== g.me || g.status !== 'playing')
blocked = 'Tupile intelligence is not available to this seat.';
else if (offer.blocked) blocked = offer.blocked;
else if (category !== 'weapons' && category !== 'defenses')
blocked = 'Choose the weapon count or defense count.';
else {
const targets = offer.targets.filter((candidate) => candidate.player === target);
if (targets.length !== 1 || target === g.me)
blocked = 'Choose a current opposing faction.';
else blocked = targets[0].blocked;
}
return {
blocked,
action: blocked ? null : { type: 'tupileIntelligence', target, category },
};
}
/** A deterministic legal request shared by every bot profile. Historical
* answers never determine whether another faction is currently eligible. */
export function tupileIntelligenceActions(g: GameView): Action[] {
if (!tupileIntelligenceCanAct(g)) return [];
for (const target of g.tupileIntelligence!.targets) {
const choice = tupileIntelligenceChoice(g, target.player, 'weapons');
if (choice.action) return [choice.action];
}
return [];
}