import { content, type ShipModel } from "@deadhead/content"; import { useState } from "react"; import { formatCredits, formatMillionKm, locationName } from "../format"; import { errorMessage, useGameAction, useLoadedPlayer } from "../state/actions"; import { Art, Button, Icon, Panel, Screen, ScreenHeader, Sheet, type IconName } from "../ui"; const LANDING_LABELS = { vacuum: "Vacuum", atmospheric: "Atmospheric", hardened: "Hardened" }; const MODELS = content.purchasableShipModels; const best = { speed: Math.max(...MODELS.map((m) => m.cruiseSpeedKmPerGameHour)), capacity: Math.max(...MODELS.map((m) => m.cargoCapacityTonnes)), range: Math.max(...MODELS.map((m) => m.fuelRangeMillionKm)), }; /** Range spans 5 to 1,000M km, so its bar uses a log scale to stay readable. */ const rangeShare = (range: number) => Math.log10(1 + range) / Math.log10(1 + best.range); /** Ship models for sale, delivered to the HQ (bay) the player picks (Steps 9.8, 10B.9). */ export function Market() { const state = useLoadedPlayer(); const buy = useGameAction("buyShip"); const [buying, setBuying] = useState(null); return ( {buy.isError && (

{errorMessage(buy.error)}

)} {buy.isSuccess && (

{buy.data.ship.name} is waiting at {locationName(buy.data.ship.locationId ?? "")}.

)}
    {MODELS.map((model) => { const affordable = state.company.credits >= model.price; return (
    {model.name} {formatCredits(model.price)}
    ); })}
{buying && ( buy.mutate({ modelId: buying.id, bayId }, { onSettled: () => setBuying(null) }) } onClose={() => setBuying(null)} /> )}
); } /** One spec line: label and value (dt directly before dd), with a bar relative to the best model. */ function Spec(props: { icon: IconName; label: string; value: string; share?: number }) { return (
{props.label}
{props.value}
{props.share !== undefined && ( ); } /** "Deliver to which HQ?": choose the bay the new ship appears at (decision 0.5.35). */ function DeliveryPicker(props: { model: ShipModel; pending: boolean; onBuy: (bayId: string) => void; onClose: () => void; }) { const state = useLoadedPlayer(); const [bayId, setBayId] = useState(state.bays.length === 1 ? state.bays[0]!.id : null); return (
HQ {state.bays.map((bay) => { const sprite = content.location(bay.locationId)?.sprite; return ( ); })}
); }