diff --git a/apps/server/test/contract-dispatch.test.ts b/apps/server/test/contract-dispatch.test.ts
index 69ebc8f..1fc9c39 100644
--- a/apps/server/test/contract-dispatch.test.ts
+++ b/apps/server/test/contract-dispatch.test.ts
@@ -157,6 +157,10 @@ describe("contract dispatch", () => {
const o = await owner();
const contract = testContract({
cargoTypeId: "heavy",
+ goodId: "machine-parts",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 2,
requiredSkill: { skillId: "heavy-cargo", level: 2 },
});
diff --git a/apps/server/test/game.ts b/apps/server/test/game.ts
index 456242d..805c73c 100644
--- a/apps/server/test/game.ts
+++ b/apps/server/test/game.ts
@@ -100,6 +100,10 @@ export function testContract(overrides: Partial = {}): Contract {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 2000,
diff --git a/apps/web/src/screens/MapScreen.tsx b/apps/web/src/screens/MapScreen.tsx
index aee560c..4a4decc 100644
--- a/apps/web/src/screens/MapScreen.tsx
+++ b/apps/web/src/screens/MapScreen.tsx
@@ -117,8 +117,8 @@ function LocationPanel({ locationId, onClose }: { locationId: string; onClose: (
: `${formatMillionKm(distanceAt("earth", location.id, now))} from Earth`}
- Produces {location.cargoClassMix.produces.map(cargoName).join(", ") || "nothing"} · demands{" "}
- {location.cargoClassMix.demands.map(cargoName).join(", ") || "nothing"}
+ Produces {location.cargoClassMix.produces.map(cargoName).join(", ") || "nothing"} ·
+ demands {location.cargoClassMix.demands.map(cargoName).join(", ") || "nothing"}
{hasBay ? "Your HQ is here." : "No HQ here."}
diff --git a/apps/web/test/board-refresh.test.tsx b/apps/web/test/board-refresh.test.tsx
index aee828f..4007759 100644
--- a/apps/web/test/board-refresh.test.tsx
+++ b/apps/web/test/board-refresh.test.tsx
@@ -45,6 +45,10 @@ const heavyJob: Contract = {
originId: "earth",
destinationId: "moon",
cargoTypeId: "heavy",
+ goodId: "machine-parts",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 300,
payout: 9000,
diff --git a/apps/web/test/dispatch-duty.test.tsx b/apps/web/test/dispatch-duty.test.tsx
index a35323d..95af04d 100644
--- a/apps/web/test/dispatch-duty.test.tsx
+++ b/apps/web/test/dispatch-duty.test.tsx
@@ -44,6 +44,10 @@ const moonJob: Contract = {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 900,
diff --git a/apps/web/test/dispatch-problems.test.tsx b/apps/web/test/dispatch-problems.test.tsx
index 52a4c04..2bff797 100644
--- a/apps/web/test/dispatch-problems.test.tsx
+++ b/apps/web/test/dispatch-problems.test.tsx
@@ -17,6 +17,10 @@ const job = (
originId: "earth",
destinationId: "moon",
cargoTypeId: skill ? "high-value" : "standard",
+ goodId: skill ? "medical-supplies" : "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: skill?.level ?? 0,
massTonnes,
payout: 1000,
diff --git a/apps/web/test/dispatch-sheet.test.tsx b/apps/web/test/dispatch-sheet.test.tsx
index d2c3e65..6f644b6 100644
--- a/apps/web/test/dispatch-sheet.test.tsx
+++ b/apps/web/test/dispatch-sheet.test.tsx
@@ -52,6 +52,10 @@ const marsJob: Contract = {
originId: "earth",
destinationId: "mars",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 15,
payout: 500_000,
diff --git a/apps/web/test/location-boards.test.tsx b/apps/web/test/location-boards.test.tsx
index 7d08820..8a618a1 100644
--- a/apps/web/test/location-boards.test.tsx
+++ b/apps/web/test/location-boards.test.tsx
@@ -12,6 +12,10 @@ const contract = (overrides: Partial): Contract => ({
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 50,
payout: 2000,
@@ -30,6 +34,10 @@ const boards: Record = {
id: "e2",
destinationId: "mars",
cargoTypeId: "heavy",
+ goodId: "machine-parts",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 2,
requiredSkill: { skillId: "heavy-cargo", level: 2 },
requiredLongHaulLevel: 1,
diff --git a/apps/web/test/render.tsx b/apps/web/test/render.tsx
index 22500de..c7f9095 100644
--- a/apps/web/test/render.tsx
+++ b/apps/web/test/render.tsx
@@ -102,6 +102,10 @@ export function sampleTutorialBoard(
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes,
payout,
diff --git a/apps/web/test/weight-warning.test.tsx b/apps/web/test/weight-warning.test.tsx
index dc3fa91..3b22310 100644
--- a/apps/web/test/weight-warning.test.tsx
+++ b/apps/web/test/weight-warning.test.tsx
@@ -11,6 +11,10 @@ const contract = (id: string, massTonnes: number): Contract => ({
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes,
payout: 1000 + massTonnes,
diff --git a/memory-bank/progress.md b/memory-bank/progress.md
index bbdbb04..814bbba 100644
--- a/memory-bank/progress.md
+++ b/memory-bank/progress.md
@@ -203,3 +203,4 @@ Spec: `memory-bank/change-requests/CR-006-boards-that-fit.md`. New decisions rec
Spec: `memory-bank/change-requests/CR-007-cargo-goods.md` (supplied as "CR-005 / Phase 10E"; renumbered, see its implementation notes). New decisions recorded as plan §0.5.54–0.5.59. Baseline class mix before the change (1,000 Earth boards, all discovered): Standard 76.79 %, High-Value 23.21 %.
- [x] **Step 10G.1 — Content: goods catalog.** `goodSchema` (id, name, `cargoClassId`, `massTonnes {min,max}`, `payMultiplier`, optional `tier` 1–5, `priorityEligible`, optional `priorityName`, `producedAt`, `demandedAt`; min ≤ max refinement) and `data/goods.ts` with all 29 goods from CR-007 §3, plus `goodsProducedAt`/`goodsDemandedAt`. Locations: `produces`/`demands` now derive from the catalog (good ids); the old class lists are kept as `cargoClassMix` (decision 0.5.57) and the sim's class selection and the UI's produces/demands now read them, so nothing visible changes yet; `shippers` added (≥ 1 each). Config: `priorityChance` 0.15, `priorityPayoutMultiplier` 1.5, `priorityReferenceShipModelId` "freighter", `priorityWindowFactor` 1. Bundle: `goods`, `good(id)`. Tests: `goods.test.ts` (schema, references, tiers by class, Standard good everywhere, ≥ 2 Standard goods each way Earth↔Moon, location lists in sync, Priority config), schema tests for Good and the new fields.
+- [x] **Step 10G.2 — Sim: contracts carry goods.** `Contract` gains `goodId`, `shipper`, `priority`, `deliveryWindowGameHours` (null unless Priority); the API `contractSchema` mirrors them now (the schema package's type-parity test requires it), so test fixtures across packages gained a good of their class. `contractPayout` = class base × good `payMultiplier` × tierMultiplier^tier × mass × distance × first-contact × Priority bonus. `buildContract` takes a good (the class comes from it) plus shipper and Priority fields; `tierFor` (0.5.55: Standard 0, High-Value/Dangerous the good's tier, Heavy the random roll or up to a fit pilot's level); `routeGoods` (0.5.54 fallback chain). Interim choice until 10G.3: the first route good in catalog order, the origin's first shipper, never Priority; fit jobs only use goods whose tier the pilot meets. `SimContent` gains `goods`. Tests: `contract.test.ts` (tiers from goods, Heavy 1–5, ×2 pay multiplier doubles payout, Priority = bonus × normal).
diff --git a/packages/schema/src/entities.ts b/packages/schema/src/entities.ts
index fe20412..08a6c1d 100644
--- a/packages/schema/src/entities.ts
+++ b/packages/schema/src/entities.ts
@@ -85,6 +85,13 @@ export const contractSchema = z.object({
originId: idSchema,
destinationId: idSchema,
cargoTypeId: idSchema,
+ /** The named good (CR-007). */
+ goodId: idSchema,
+ /** Flavor: the shipping company (decision 0.5.58). */
+ shipper: z.string().min(1),
+ priority: z.boolean(),
+ /** Priority only: the longest allowed trip in game hours (decision 0.5.56). */
+ deliveryWindowGameHours: z.number().positive().nullable(),
tier: z.number().int().min(0),
massTonnes: z.number().positive(),
payout: credits,
diff --git a/packages/schema/test/schemas.test.ts b/packages/schema/test/schemas.test.ts
index 18350e2..052ee61 100644
--- a/packages/schema/test/schemas.test.ts
+++ b/packages/schema/test/schemas.test.ts
@@ -80,6 +80,10 @@ const contract = {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 12,
payout: 480,
diff --git a/packages/sim/src/board.ts b/packages/sim/src/board.ts
index dfb8a64..adef65b 100644
--- a/packages/sim/src/board.ts
+++ b/packages/sim/src/board.ts
@@ -1,6 +1,7 @@
import type {
CargoType,
GameConfig,
+ Good,
Location,
ScriptedTutorialContract,
ShipModel,
@@ -17,6 +18,7 @@ import { createRng, deriveSeed, type Rng, type Seed } from "./rng";
export interface SimContent {
locations: readonly Location[];
cargoTypes: readonly CargoType[];
+ goods: readonly Good[];
skills: readonly Skill[];
shipModels: readonly ShipModel[];
scriptedTutorialContracts: readonly ScriptedTutorialContract[];
@@ -138,54 +140,85 @@ function fitJob(
(c.requiredSkillId === null || skillLevel(skills, c.requiredSkillId) >= 1),
);
const cargoType = skilled.length > 0 ? rng.pick(skilled) : standardCargo(content);
- const tier =
- cargoType.requiredSkillId === null
- ? 0
- : rng.int(1, skillLevel(skills, cargoType.requiredSkillId));
+ // Only goods this pilot may carry: a good's own tier must not exceed their skill.
+ const good = routeGoods(cargoType, origin, destination, content, (g) => {
+ const skillId = cargoClassOf(g, content).requiredSkillId;
+ return skillId === null || skillLevel(skills, skillId) >= (g.tier ?? 1);
+ })[0]!;
+ const skillId = cargoClassOf(good, content).requiredSkillId;
+ const tier = tierFor(rng, good, content, skillId ? skillLevel(skills, skillId) : undefined);
const massTonnes = rng.int(band.min, Math.min(band.max, model.cargoCapacityTonnes));
- return { destination, cargoType, tier, massTonnes };
+ return { destination, good, tier, massTonnes };
}
return null;
}
-/** Builds one contract from a chosen route, cargo, tier and mass. */
+export function cargoClassOf(good: Good, content: SimContent): CargoType {
+ const cargoType = content.cargoTypes.find((c) => c.id === good.cargoClassId);
+ if (!cargoType) throw new Error(`Unknown cargo class ${good.cargoClassId}`);
+ return cargoType;
+}
+
+/**
+ * A contract's tier (decision 0.5.55): Standard is 0, High-Value and Dangerous
+ * take the good's tier, and Heavy rolls 1 to `maxTier` (the skill's maximum,
+ * or a pilot's level for a fit job).
+ */
+export function tierFor(rng: Rng, good: Good, content: SimContent, maxTier?: number): number {
+ const cargoType = cargoClassOf(good, content);
+ if (cargoType.requiredSkillId === null) return 0;
+ if (good.tier !== undefined) return good.tier;
+ return maxTier === undefined ? pickTier(rng, cargoType, content) : rng.int(1, maxTier);
+}
+
+/** Builds one contract from a chosen route, good, tier and mass. */
export function buildContract(
args: {
id: string;
origin: Location;
destination: Location;
- cargoType: CargoType;
+ good: Good;
tier: number;
massTonnes: number;
firstContact: boolean;
periodIndex: number;
+ shipper: string;
+ priority: boolean;
+ deliveryWindowGameHours: number | null;
},
content: SimContent,
): Contract {
const { config } = content;
+ const cargoType = cargoClassOf(args.good, content);
const offeredAt = args.periodIndex * boardPeriodMs(config);
const distance = routeDistance(args.origin, args.destination, realToGame(offeredAt, config));
return {
id: args.id,
originId: args.origin.id,
destinationId: args.destination.id,
- cargoTypeId: args.cargoType.id,
+ cargoTypeId: cargoType.id,
+ goodId: args.good.id,
+ shipper: args.shipper,
+ priority: args.priority,
+ deliveryWindowGameHours: args.priority ? args.deliveryWindowGameHours : null,
tier: args.tier,
massTonnes: args.massTonnes,
payout: contractPayout(
{
- cargoType: args.cargoType,
+ cargoType,
+ payMultiplier: args.good.payMultiplier,
tier: args.tier,
massTonnes: args.massTonnes,
distanceMillionKm: distance,
firstContact: args.firstContact,
+ priority: args.priority,
},
config,
),
requiredSkill:
- args.cargoType.requiredSkillId === null
+ cargoType.requiredSkillId === null
? null
- : { skillId: args.cargoType.requiredSkillId, level: args.tier },
+ : { skillId: cargoType.requiredSkillId, level: args.tier },
requiredLongHaulLevel: requiredLongHaulLevel(distance, config),
offeredAt,
expiresAt: offeredAt + boardPeriodMs(config),
@@ -193,6 +226,33 @@ export function buildContract(
};
}
+/**
+ * The goods a contract of this class can carry on this route (decision 0.5.54):
+ * that class's goods made at the origin and wanted at the destination; else
+ * Standard goods on the route; else any Standard good made at the origin.
+ * `allow` filters out goods a crew can't take (fit jobs).
+ */
+export function routeGoods(
+ cargoType: CargoType,
+ origin: Location,
+ destination: Location,
+ content: SimContent,
+ allow: (good: Good) => boolean = () => true,
+): Good[] {
+ const made = content.goods.filter((g) => g.producedAt.includes(origin.id) && allow(g));
+ const onRoute = made.filter((g) => g.demandedAt.includes(destination.id));
+ const ofClass = onRoute.filter((g) => g.cargoClassId === cargoType.id);
+ if (ofClass.length > 0) return ofClass;
+ const standardId = standardCargo(content).id;
+ const standardOnRoute = onRoute.filter((g) => g.cargoClassId === standardId);
+ if (standardOnRoute.length > 0) return standardOnRoute;
+ const anyStandard = content.goods.filter(
+ (g) => g.producedAt.includes(origin.id) && g.cargoClassId === standardId,
+ );
+ if (anyStandard.length === 0) throw new Error(`${origin.id} makes no Standard good`);
+ return anyStandard;
+}
+
function pickCargo(rng: Rng, origin: Location, destination: Location, content: SimContent) {
const matching = content.cargoTypes.filter(
(c) =>
@@ -239,7 +299,19 @@ export function generateContractBoard(input: BoardInput, content: SimContent): C
const fit =
kind === "fit" ? fitJob(rng, band, crews, origin, discovered, offeredAt, content) : null;
if (fit) {
- return buildContract({ id, origin, ...fit, firstContact: false, periodIndex }, content);
+ return buildContract(
+ {
+ id,
+ origin,
+ ...fit,
+ firstContact: false,
+ periodIndex,
+ shipper: origin.shippers[0]!,
+ priority: false,
+ deliveryWindowGameHours: null,
+ },
+ content,
+ );
}
const guaranteed = kind !== "open";
const plain = guaranteed && discovered.length > 0;
@@ -249,16 +321,20 @@ export function generateContractBoard(input: BoardInput, content: SimContent): C
(discovered.length === 0 || rng.next() < config.firstContactChance);
const destination = rng.pick(firstContact ? undiscovered : discovered);
const cargoType = plain ? standardCargo(content) : pickCargo(rng, origin, destination, content);
+ const good = routeGoods(cargoType, origin, destination, content)[0]!;
return buildContract(
{
id,
origin,
destination,
- cargoType,
- tier: pickTier(rng, cargoType, content),
+ good,
+ tier: tierFor(rng, good, content),
massTonnes: rng.int(band.min, band.max),
firstContact,
periodIndex,
+ shipper: origin.shippers[0]!,
+ priority: false,
+ deliveryWindowGameHours: null,
},
content,
);
diff --git a/packages/sim/src/contract.ts b/packages/sim/src/contract.ts
index f8c316e..03e946c 100644
--- a/packages/sim/src/contract.ts
+++ b/packages/sim/src/contract.ts
@@ -5,8 +5,20 @@ export interface Contract {
id: string;
originId: string;
destinationId: string;
+ /** The cargo class (decision 0.5.6). */
cargoTypeId: string;
- /** 0 for Standard; 1–5 otherwise, and equal to the required cargo-skill level (decision 0.5.6). */
+ /** The named good (CR-007, decision 0.5.54); its class is `cargoTypeId`. */
+ goodId: string;
+ /** Flavor: the company shipping it, from the origin's list (decision 0.5.58). */
+ shipper: string;
+ /** A Priority contract must arrive within its delivery window (decision 0.5.56). */
+ priority: boolean;
+ /** Priority only: the longest trip allowed, in game hours; null otherwise. */
+ deliveryWindowGameHours: number | null;
+ /**
+ * 0 for Standard; 1–5 otherwise, and equal to the required cargo-skill level
+ * (decision 0.5.6). High-Value and Dangerous take it from the good (0.5.55).
+ */
tier: number;
massTonnes: number;
/** Credits, fixed at offer time (decision 0.5.11). */
@@ -24,24 +36,30 @@ export interface Contract {
export interface PayoutInput {
cargoType: CargoType;
+ /** The good's pay multiplier (CR-007). */
+ payMultiplier: number;
tier: number;
massTonnes: number;
/** Route distance at offer time. */
distanceMillionKm: number;
firstContact: boolean;
+ priority: boolean;
}
/**
- * Payout in whole credits: base pay per tonne per million km × tierMultiplier^tier
- * × mass × distance, × the first-contact multiplier when flagged.
+ * Payout in whole credits: class base pay per tonne per million km × the good's
+ * pay multiplier × tierMultiplier^tier × mass × distance, × the first-contact
+ * multiplier and the Priority bonus when flagged (CR-007).
*/
export function contractPayout(input: PayoutInput, config: GameConfig): number {
- const { cargoType, tier, massTonnes, distanceMillionKm, firstContact } = input;
+ const { cargoType, payMultiplier, tier, massTonnes, distanceMillionKm, firstContact } = input;
const pay =
cargoType.basePayPerTonnePerMillionKm *
+ payMultiplier *
cargoType.tierPayMultiplier ** tier *
massTonnes *
distanceMillionKm *
- (firstContact ? config.firstContactPayoutMultiplier : 1);
+ (firstContact ? config.firstContactPayoutMultiplier : 1) *
+ (input.priority ? config.priorityPayoutMultiplier : 1);
return Math.round(pay);
}
diff --git a/packages/sim/src/tutorial.ts b/packages/sim/src/tutorial.ts
index 0292813..dac6835 100644
--- a/packages/sim/src/tutorial.ts
+++ b/packages/sim/src/tutorial.ts
@@ -1,5 +1,5 @@
import type { Location, ShipModel } from "@deadhead/content";
-import { buildContract, standardCargo, type SimContent } from "./board";
+import { buildContract, routeGoods, standardCargo, type SimContent } from "./board";
import type { Contract } from "./contract";
/** The tutorial loaner: the content's company ship (decision 0.5.29). */
@@ -48,16 +48,20 @@ export function generateTutorialBoard(input: TutorialBoardInput, content: SimCon
? content.cargoTypes.find((c) => c.id === special.cargoTypeId)
: standardCargo(content);
if (!cargoType) throw new Error(`Unknown cargo ${special?.cargoTypeId}`);
+ const good = routeGoods(cargoType, origin, destination, content)[0]!;
const contract = buildContract(
{
id: `tutorial:${loanerLocationId}:${run}:${periodIndex}:${i}`,
origin,
destination,
- cargoType,
+ good,
tier: 0,
massTonnes,
firstContact: false,
periodIndex,
+ shipper: origin.shippers[0]!,
+ priority: false,
+ deliveryWindowGameHours: null,
},
content,
);
diff --git a/packages/sim/test/contract.test.ts b/packages/sim/test/contract.test.ts
index 93f61fa..97d4250 100644
--- a/packages/sim/test/contract.test.ts
+++ b/packages/sim/test/contract.test.ts
@@ -1,6 +1,7 @@
import { content } from "@deadhead/content";
import { describe, expect, it } from "vitest";
-import { contractPayout, type PayoutInput } from "../src/index";
+import { tierFor } from "../src/board";
+import { contractPayout, createRng, type PayoutInput } from "../src/index";
const config = content.config;
const standard = content.cargoType("standard")!;
@@ -8,10 +9,12 @@ const dangerous = content.cargoType("dangerous")!;
const base: PayoutInput = {
cargoType: standard,
+ payMultiplier: 1,
tier: 0,
massTonnes: 10,
distanceMillionKm: 100,
firstContact: false,
+ priority: false,
};
describe("contract payout", () => {
@@ -50,3 +53,35 @@ describe("contract payout", () => {
);
});
});
+
+describe("contracts carry goods (CR-007)", () => {
+ const rng = createRng(42);
+
+ it("takes the tier of a High-Value or Dangerous contract from its good", () => {
+ for (const good of content.goods.filter(
+ (g) => g.cargoClassId === "high-value" || g.cargoClassId === "dangerous",
+ )) {
+ expect(tierFor(rng, good, content)).toBe(good.tier);
+ }
+ });
+
+ it("keeps the random 1–5 tier for Heavy goods and tier 0 for Standard", () => {
+ const parts = content.good("machine-parts")!;
+ const seen = new Set();
+ for (let i = 0; i < 200; i++) seen.add(tierFor(rng, parts, content));
+ expect([...seen].sort()).toEqual([1, 2, 3, 4, 5]);
+ expect(tierFor(rng, content.good("mail")!, content)).toBe(0);
+ });
+
+ it("doubles the payout when the good's pay multiplier doubles", () => {
+ expect(contractPayout({ ...base, payMultiplier: 2 }, config)).toBe(
+ 2 * contractPayout(base, config),
+ );
+ });
+
+ it("pays a Priority contract exactly the bonus times an identical normal one", () => {
+ expect(contractPayout({ ...base, priority: true }, config)).toBe(
+ contractPayout(base, config) * config.priorityPayoutMultiplier,
+ );
+ });
+});
diff --git a/packages/sim/test/dispatch.test.ts b/packages/sim/test/dispatch.test.ts
index b2ee54f..47c2250 100644
--- a/packages/sim/test/dispatch.test.ts
+++ b/packages/sim/test/dispatch.test.ts
@@ -27,6 +27,10 @@ const contract: Contract = {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 2000,
@@ -99,6 +103,10 @@ describe("dispatch validation", () => {
const heavy = {
...contract,
cargoTypeId: "heavy",
+ goodId: "machine-parts",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 1,
requiredSkill: { skillId: "heavy-cargo", level: 1 },
};
diff --git a/packages/sim/test/duty-dispatch.test.ts b/packages/sim/test/duty-dispatch.test.ts
index 0058c2a..a0e2b46 100644
--- a/packages/sim/test/duty-dispatch.test.ts
+++ b/packages/sim/test/duty-dispatch.test.ts
@@ -24,6 +24,10 @@ const contract: Contract = {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 2000,
diff --git a/packages/sim/test/loan.test.ts b/packages/sim/test/loan.test.ts
index d5c1625..1a26b78 100644
--- a/packages/sim/test/loan.test.ts
+++ b/packages/sim/test/loan.test.ts
@@ -44,6 +44,10 @@ describe("resolution with a loan", () => {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 2000,
diff --git a/packages/sim/test/pilot.test.ts b/packages/sim/test/pilot.test.ts
index a8d440f..799af89 100644
--- a/packages/sim/test/pilot.test.ts
+++ b/packages/sim/test/pilot.test.ts
@@ -6,6 +6,10 @@ const shortStandard: Contract = {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 1000,
@@ -18,6 +22,10 @@ const shortStandard: Contract = {
const heavyTier2: Contract = {
...shortStandard,
cargoTypeId: "heavy",
+ goodId: "machine-parts",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 2,
requiredSkill: { skillId: "heavy-cargo", level: 2 },
};
diff --git a/packages/sim/test/record.test.ts b/packages/sim/test/record.test.ts
index d5092ba..bebca8b 100644
--- a/packages/sim/test/record.test.ts
+++ b/packages/sim/test/record.test.ts
@@ -14,6 +14,10 @@ const contract: Contract = {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 2000,
diff --git a/packages/sim/test/resolution.test.ts b/packages/sim/test/resolution.test.ts
index 78ade26..5fe8583 100644
--- a/packages/sim/test/resolution.test.ts
+++ b/packages/sim/test/resolution.test.ts
@@ -16,6 +16,10 @@ const contract: Contract = {
originId: "earth",
destinationId: "moon",
cargoTypeId: "standard",
+ goodId: "consumer-goods",
+ shipper: "Pacific Orbital Logistics",
+ priority: false,
+ deliveryWindowGameHours: null,
tier: 0,
massTonnes: 10,
payout: 2000,
diff --git a/packages/sim/test/tutorial.test.ts b/packages/sim/test/tutorial.test.ts
index b710684..ca95d29 100644
--- a/packages/sim/test/tutorial.test.ts
+++ b/packages/sim/test/tutorial.test.ts
@@ -29,15 +29,17 @@ function distanceOf(contract: Contract): number {
);
}
-/** The normal (non-tutorial) payout for the same Standard cargo and route. */
+/** The normal (non-tutorial) payout for the same Standard good and route. */
function normalPayout(contract: Contract): number {
return contractPayout(
{
cargoType: content.cargoType("standard")!,
+ payMultiplier: content.good(contract.goodId)!.payMultiplier,
tier: 0,
massTonnes: contract.massTonnes,
distanceMillionKm: distanceOf(contract),
firstContact: false,
+ priority: false,
},
config,
);