140 lines
4.1 KiB
TypeScript
140 lines
4.1 KiB
TypeScript
import { content } from "@deadhead/content";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
createDispatchRecord,
|
|
createRepositionRecord,
|
|
resolveDispatch,
|
|
type Contract,
|
|
type PilotState,
|
|
type ResolveInput,
|
|
type ShipState,
|
|
pilotShare,
|
|
} from "../src/index";
|
|
|
|
/** Fuel enough for any leg in these tests (decision 0.5.94), bought at 10 cr/fu. */
|
|
const PLENTY = { fuelFu: 10_000, avgPrice: 10 };
|
|
|
|
const now = Date.parse("2100-01-01T00:30:00Z");
|
|
const contract: Contract = {
|
|
id: "c1",
|
|
originId: "earth",
|
|
destinationId: "moon",
|
|
cargoTypeId: "standard",
|
|
goodId: "consumer-goods",
|
|
shipper: "Pacific Orbital Logistics",
|
|
priority: false,
|
|
deliveryWindowGameHours: null,
|
|
tier: 0,
|
|
massTonnes: 10,
|
|
payout: 2000,
|
|
requiredSkill: null,
|
|
requiredLongHaulLevel: 0,
|
|
offeredAt: Date.parse("2100-01-01T00:00:00Z"),
|
|
expiresAt: Date.parse("2100-01-01T01:00:00Z"),
|
|
firstContact: false,
|
|
};
|
|
const ship: ShipState = {
|
|
id: "s1",
|
|
modelId: "courier",
|
|
locationId: "earth",
|
|
inFlight: false,
|
|
tank: PLENTY,
|
|
};
|
|
const pilot: PilotState = {
|
|
id: "p1",
|
|
isAvatar: false,
|
|
assignedShipId: "s1",
|
|
inFlight: false,
|
|
skills: {},
|
|
restEndsAt: null,
|
|
};
|
|
const record = createDispatchRecord(
|
|
{ id: "d1", ship, pilot, contract, tutorial: false, now, worldSeed: 7 },
|
|
content,
|
|
);
|
|
const arrived: ResolveInput = {
|
|
record,
|
|
pilotIsAvatar: false,
|
|
discoveredIds: new Set(["earth", "moon"]),
|
|
loanBalance: 0,
|
|
pilotDutyHours: 0,
|
|
pilotSkills: {},
|
|
now: record.arrivalAt,
|
|
};
|
|
|
|
const resolve = (input: ResolveInput) => {
|
|
const result = resolveDispatch(input, content);
|
|
if (result.status !== "resolved") throw new Error("expected a resolution");
|
|
return result.resolution;
|
|
};
|
|
|
|
describe("dispatch resolution", () => {
|
|
it("reports in flight before arrival", () => {
|
|
expect(resolveDispatch({ ...arrived, now: record.arrivalAt - 1 }, content)).toEqual({
|
|
status: "in-flight",
|
|
});
|
|
});
|
|
|
|
it("resolves at and after arrival, moving the ship to the destination", () => {
|
|
expect(resolve(arrived).shipLocationId).toBe("moon");
|
|
expect(resolveDispatch({ ...arrived, now: record.arrivalAt + 60_000 }, content).status).toBe(
|
|
"resolved",
|
|
);
|
|
});
|
|
|
|
it("deducts pilot pay for a hired pilot and grants XP", () => {
|
|
const resolution = resolve(arrived);
|
|
const pay = pilotShare(2000, record.fuelCost, content.config);
|
|
expect(pay).toBeGreaterThan(0);
|
|
expect(resolution).toMatchObject({ pilotPay: pay, credits: 2000 - pay });
|
|
expect(resolution.pilotXp).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("deducts no pilot pay when the avatar flies", () => {
|
|
expect(resolve({ ...arrived, pilotIsAvatar: true }).credits).toBe(2000);
|
|
});
|
|
|
|
it("pays exactly the stored tutorial share on a tutorial run", () => {
|
|
const tutorialRecord = createDispatchRecord(
|
|
{
|
|
id: "t1",
|
|
ship: { ...ship, id: "loaner" },
|
|
pilot: { ...pilot, id: "avatar", isAvatar: true, assignedShipId: null },
|
|
contract: { ...contract, payout: 1000 },
|
|
tutorial: true,
|
|
now,
|
|
worldSeed: 7,
|
|
},
|
|
content,
|
|
);
|
|
const resolution = resolve({ ...arrived, record: tutorialRecord, pilotIsAvatar: true });
|
|
expect(resolution.credits).toBe(1000);
|
|
expect(resolution.shipLocationId).toBe("moon");
|
|
});
|
|
|
|
it("marks an undiscovered destination as discovered", () => {
|
|
expect(resolve(arrived).discoversDestination).toBe(false);
|
|
expect(resolve({ ...arrived, discoveredIds: new Set(["earth"]) }).discoversDestination).toBe(
|
|
true,
|
|
);
|
|
});
|
|
|
|
it("gives no credits or XP for a reposition", () => {
|
|
const reposition = createRepositionRecord(
|
|
{ id: "r1", ship, pilot, destinationId: "moon", now, worldSeed: 7 },
|
|
content,
|
|
);
|
|
expect(resolve({ ...arrived, record: reposition, now: reposition.arrivalAt })).toMatchObject({
|
|
credits: 0,
|
|
loanRepayment: 0,
|
|
pilotXp: 0,
|
|
shipLocationId: "moon",
|
|
discoversDestination: false,
|
|
});
|
|
});
|
|
|
|
it("returns identical results when resolving the same dispatch twice", () => {
|
|
expect(resolveDispatch(arrived, content)).toEqual(resolveDispatch(arrived, content));
|
|
});
|
|
});
|