Files
Dune/components/private-battle-plan.tsx
T
Quintine 66c41b2af5 Add Kwisatz Haderach component inspection
Connect an original companion face and enlarged rules to the private Atreides panel and battle composer, authorized full-plan inspection, public revealed plans and an internal reference topic. Private loss progress and availability come only from the existing owner projection; plan components receive only inclusion. Rules calculations, save shape, AI strategy and mode gates remain unchanged.

Add focused projection, sealed/revealed rendering, JSON restoration, private-status and asset regressions. All 4950 offline tests, types, lint and production build pass. Independent privacy/rules review found no material findings. Browser checks verify reference opening, loaded artwork, Escape/Close focus return, mobile bounds and keyboard scrolling to the final rule. The focusable scroll region has a documented narrow lint exception. Earlier image-convention and focusability lint failures are retained in private evidence. HTTP tests are unnecessary for this presentation-only change.

All 1373 rooms, 2883 seats and original auxiliary rows remain unchanged; SQLite integrity and foreign keys pass. Existing server reused without restart. Screenshot capture, complete live Advanced browser acceptance and final manufactured-component/art verification remain open. No rules gate is opened by this checkpoint.

Private evidence: 20260921-kwisatz-inspection.
Verified source tree: 1181471eed47b86390882999a2ffce0db6a44b1379c7e8f7fc406bef39a94179
2026-09-21 09:00:51 +10:00

88 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import type { GameView } from '@/game/engine';
import { HelpTip } from './help-tip';
import { faction } from '@/game/catalog';
import { leaderStrengthLabel } from '@/game/cards';
import { BattleComponentInspection } from './battle-component-inspection';
export function PrivateBattlePlan({ game }: { game: GameView }) {
const insight = game.battle?.fullPlanInsight;
if (
!insight ||
game.battle?.revealed ||
game.battle?.fullPlan?.owner !== game.me
)
return null;
const leader = game.allLeaders.find((l) => l.id === insight.plan.leader);
const name = (id: string | null) =>
id
? (insight.cards.find((c) => c.id === id)?.name ??
game.allLeaders.find((l) => l.id === id)?.name ??
id)
: 'None';
return (
<section
className="private-battle-plan"
aria-label="Private battle plan inspection"
>
<span className="eyebrow">Atreides · private inspection</span>
<h3>
{game.players.find((p) => p.id === insight.target)?.name}’s committed
plan <HelpTip topic="fullPlan" />
</h3>
<p className="muted">
Only you receive this inspection, including when you are helping an
ally. It stays available until both plans are publicly revealed. The
other combatant can prepare and seal their plan without an inspection
confirmation.
</p>
<dl>
<div>
<dt>Dial</dt>
<dd>{insight.plan.dial}</dd>
</div>
<div>
<dt>Spice support</dt>
<dd>{insight.plan.support}</dd>
</div>
<div>
<dt>Spice Banker commitment</dt>
<dd>{insight.plan.bankerSpice ?? 0}</dd>
</div>
<div>
<dt>Leader</dt>
<dd>{name(insight.plan.leader)}</dd>
</div>
<div>
<dt>Weapon</dt>
<dd>{name(insight.plan.weapon)}</dd>
</div>
<div>
<dt>Defense</dt>
<dd>{name(insight.plan.defense)}</dd>
</div>
<div>
<dt>Kwisatz Haderach</dt>
<dd>{insight.plan.kwisatz ? 'Included' : 'Not included'}</dd>
</div>
</dl>
<BattleComponentInspection
playerName={
game.players.find((p) => p.id === insight.target)?.name ?? 'Player'
}
cards={insight.cards}
kwisatz={insight.plan.kwisatz}
leader={
leader
? {
name: leader.name,
factionName: faction(leader.faction).name,
strength: leaderStrengthLabel(leader),
}
: undefined
}
/>
</section>
);
}