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 * 0.005)); expect(repairCost(courier, 100, config)).toBe(0); expect(repairShopMs(60, config)).toBe(20 * 60_000); expect(repairShopMs(98, config)).toBe(5 * 60_000); }); });