94 lines
3.2 KiB
TypeScript
94 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 * 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);
|
|
});
|
|
});
|