deadhead-space-freight-tycoon/packages/sim/src/tutorial.ts

74 lines
2.8 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.

import type { Location, ShipModel } from "@deadhead/content";
import { buildContract, standardCargo, type SimContent } from "./board";
import type { Contract } from "./contract";
/** The tutorial loaner: the content's company ship (decision 0.5.29). */
export function loanerModel(content: SimContent): ShipModel {
const id = content.config.tutorialLoanerShipModelId;
const loaner = content.shipModels.find((s) => s.id === id);
if (!loaner) throw new Error(`Content has no loaner ship model "${id}"`);
return loaner;
}
export type TutorialLocationId = "earth" | "moon";
export interface TutorialBoardInput {
/** Where the loaner currently is; contracts start here (decision 0.5.3). */
loanerLocationId: TutorialLocationId;
/** Tutorial runs already flown; the board is for run `runsCompleted + 1`. */
runsCompleted: number;
periodIndex: number;
}
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" (CR-001, Step 10A.3): three Standard contracts
* from the loaner's location to the other end of the Earth–Moon route, at the
* light, medium and full mass tiers, each paying the tutorial share. A scripted
* contract for the upcoming run (decision 0.5.33) replaces the medium slot.
* The board is fully determined by its inputs.
*/
export function generateTutorialBoard(input: TutorialBoardInput, content: SimContent): Contract[] {
const { loanerLocationId, runsCompleted, periodIndex } = input;
const { config } = content;
const origin = location(loanerLocationId, content);
const destination = location(loanerLocationId === "earth" ? "moon" : "earth", content);
const tiers = config.tutorialMassTonnes;
const run = runsCompleted + 1;
const scripted = content.scriptedTutorialContracts.find((s) => s.run === run);
const slot = (i: number, massTonnes: number): Contract => {
const special = i === 1 ? scripted : undefined;
const cargoType = special
? content.cargoTypes.find((c) => c.id === special.cargoTypeId)
: standardCargo(content);
if (!cargoType) throw new Error(`Unknown cargo ${special?.cargoTypeId}`);
const contract = buildContract(
{
id: `tutorial:${loanerLocationId}:${run}:${periodIndex}:${i}`,
origin,
destination,
cargoType,
tier: 0,
massTonnes,
firstContact: false,
periodIndex,
},
content,
);
const share = contract.payout * config.tutorialPayoutShare * (special?.payMultiplier ?? 1);
return {
...contract,
payout: Math.round(share),
...(special ? { scriptedId: special.id } : {}),
};
};
return [slot(0, tiers.light), slot(1, tiers.medium), slot(2, tiers.full)];
}