import { content } from "@deadhead/content"; import { describe, expect, it } from "vitest"; import { createDispatchRecord, deliveryXp, deliveryXpFor, generateTutorialBoard, pilotLevel, routeDistance, skillPointsAvailable, type Contract, } from "../src/index"; const { config } = content; const loc = (id: string) => content.location(id)!; const now = Date.parse("2100-01-01T00:30:00Z"); const pilot = { id: "avatar", isAvatar: true, assignedShipId: null, inFlight: false, skills: {}, restEndsAt: null, }; const loaner = { id: "loaner", modelId: "company-courier", locationId: "earth", inFlight: false }; /** The XP a contract would pay on a tutorial run. */ function tutorialXp(contract: Contract): number { const record = createDispatchRecord( { id: "t", ship: { ...loaner, locationId: contract.originId }, pilot, contract, tutorial: true, now, worldSeed: 1, }, content, ); return deliveryXpFor(record, contract.tier, content); } describe("tutorial XP (Step 17.2, decision 0.5.107)", () => { it("grants exactly the multiplier times a normal run's XP for the same route and cargo", () => { const [contract] = generateTutorialBoard( { loanerLocationId: "earth", runsCompleted: 0, periodIndex: 0 }, content, ); const normal = deliveryXp(routeDistance(loc("earth"), loc("moon")), contract!.tier, config); expect(tutorialXp(contract!)).toBe(normal * config.tutorialXpMultiplier); expect(config.tutorialXpMultiplier).toBeGreaterThanOrEqual(2); }); it("brings the avatar to level 1 with a skill point after five runs of the lowest-XP jobs", () => { // Every board period gives a different board; take the worst case of many. for (let periodIndex = 0; periodIndex < 50; periodIndex++) { let xp = 0; let at: "earth" | "moon" = "earth"; for (let run = 0; run < config.tutorialRunsBeforeDeal; run++) { const board = generateTutorialBoard( { loanerLocationId: at, runsCompleted: run, periodIndex: periodIndex + run }, content, ); // Run 2 offers the scripted "Unmarked crates" job; the cheapest choice is still taken. xp += Math.min(...board.map(tutorialXp)); at = at === "earth" ? "moon" : "earth"; } const level = pilotLevel(xp, config); expect(level, `period ${periodIndex}: ${xp} XP`).toBeGreaterThanOrEqual(1); expect(skillPointsAvailable(level, 0, config)).toBeGreaterThanOrEqual(1); } }); });