import type { Location, ShipModel } from "@deadhead/content"; import { buildContract, standardCargo, type SimContent } from "./board"; import type { Contract } from "./contract"; import { createRng, deriveSeed, type Seed } from "./rng"; /** The tutorial loaner is the company's Courier. */ export function loanerModel(content: SimContent): ShipModel { const courier = content.shipModels.find((s) => s.archetype === "courier"); if (!courier) throw new Error("Content has no Courier ship model"); return courier; } export type TutorialLocationId = "earth" | "moon"; export interface TutorialBoardInput { /** Where the loaner currently is; contracts start here (decision 0.5.3). */ loanerLocationId: TutorialLocationId; periodIndex: number; worldSeed: Seed; } function location(id: string, content: SimContent): Location { const found = content.locations.find((l) => l.id === id); if (!found) throw new Error(`Unknown location ${id}`); return found; } /** * The tutorial "company board": Earth↔Moon only, Standard cargo sized to fit * the loaner, starting at the loaner's location. Each payout is the tutorial * share of the equivalent normal payout, rounded to whole credits. */ export function generateTutorialBoard(input: TutorialBoardInput, content: SimContent): Contract[] { const { loanerLocationId, periodIndex, worldSeed } = input; const { config } = content; const origin = location(loanerLocationId, content); const destination = location(loanerLocationId === "earth" ? "moon" : "earth", content); const cargoType = standardCargo(content); const maxMass = Math.min(config.contractMassTonnes.max, loanerModel(content).cargoCapacityTonnes); const rng = createRng(deriveSeed(worldSeed, `tutorial:${loanerLocationId}:${periodIndex}`)); return Array.from({ length: config.tutorialBoardSize }, (_, i) => { const contract = buildContract( { id: `tutorial:${loanerLocationId}:${periodIndex}:${i}`, origin, destination, cargoType, tier: 0, massTonnes: rng.int(config.contractMassTonnes.min, maxMass), firstContact: false, periodIndex, }, content, ); return { ...contract, payout: Math.round(contract.payout * config.tutorialPayoutShare) }; }); }