deadhead-space-freight-tycoon/packages/sim/test/hull.test.ts

96 lines
3.2 KiB
TypeScript

import { content } from "@deadhead/content";
import { describe, expect, it } from "vitest";
import {
damageAfterRating,
damageChance,
hullAfterDamage,
repairCost,
repairShopMs,
validateDispatch,
type Contract,
} from "../src/index";
const { config } = content;
const T0 = Date.parse("2100-01-01T00:00:00Z");
describe("hull condition and repairs (Step 26.4, decisions 0.5.147, 0.5.148)", () => {
it("cuts a hit by 10% per hull rating point: rating 3 turns 20% into 14%", () => {
expect(damageAfterRating(20, 3, config)).toBe(14);
expect(damageAfterRating(20, 0, config)).toBe(20);
// At most half, however good the hull.
expect(damageAfterRating(20, 9, config)).toBe(10);
});
it("makes hits rarer on a rated hull and twice as likely below 25%", () => {
expect(damageChance(0.4, 0, 100, config)).toBeCloseTo(0.4);
expect(damageChance(0.4, 2, 100, config)).toBeCloseTo(0.32);
expect(damageChance(0.4, 2, 24, config)).toBeCloseTo(0.64);
expect(damageChance(0.8, 0, 10, config)).toBe(1);
});
it("never lets a hull go below 5%: no ship is ever lost", () => {
expect(hullAfterDamage(60, 20, config)).toBe(40);
expect(hullAfterDamage(12, 20, config)).toBe(5);
expect(hullAfterDamage(5, 50, config)).toBe(5);
});
it("refuses Dangerous cargo on a hull below 50%, until repaired", () => {
const job = (cargoTypeId: string): Contract => ({
id: "c",
originId: "earth",
destinationId: "moon",
cargoTypeId,
goodId: cargoTypeId === "dangerous" ? "helium-3" : "consumer-goods",
shipper: "Pacific Orbital Logistics",
priority: false,
deliveryWindowGameHours: null,
tier: cargoTypeId === "dangerous" ? 1 : 0,
massTonnes: 5,
payout: 1_000,
requiredSkill: cargoTypeId === "dangerous" ? { skillId: "dangerous-cargo", level: 1 } : null,
requiredLongHaulLevel: 0,
offeredAt: T0,
expiresAt: T0 + 600_000,
firstContact: false,
});
const check = (hullConditionPct: number, cargoTypeId: string) =>
validateDispatch(
{
ship: {
id: "s1",
modelId: "courier",
locationId: "earth",
inFlight: false,
tank: { fuelFu: 40, avgPrice: 5 },
hullConditionPct,
},
pilot: {
id: "p1",
isAvatar: true,
assignedShipId: "s1",
inFlight: false,
skills: { "dangerous-cargo": 1 },
restEndsAt: null,
},
contract: job(cargoTypeId),
tutorial: false,
now: T0,
},
content,
);
expect(check(40, "dangerous")).toEqual({ ok: false, reason: "hull-too-damaged" });
expect(check(50, "dangerous")).toEqual({ ok: true });
expect(check(40, "standard")).toEqual({ ok: true });
});
it("prices a repair on the missing points and times it at a minute per 2%, at least 5 minutes", () => {
const courier = content.shipModel("courier")!;
expect(repairCost(courier, 60, config)).toBe(
Math.round(40 * courier.price * config.hull.repairCostPerPoint),
);
expect(repairCost(courier, 100, config)).toBe(0);
expect(repairShopMs(60, config)).toBe(20 * 60_000);
expect(repairShopMs(98, config)).toBe(5 * 60_000);
});
});