import { expect, test } from "bun:test"; import { applyDamage, damage, isLethal, shotSpread, WEAPONS, zoneFromMiss } from "./weapons.ts"; test("a Vandal head shot kills through full armour at any range, a Phantom's does not", () => { for (const distance of [100, 800, 2000]) expect(isLethal(100, 50, damage("vandal", "head", distance))).toBe(true); // The Phantom only manages it inside fifteen metres; past that the falloff // leaves the target alive, which is the whole argument between the two guns. expect(isLethal(100, 50, damage("phantom", "head", 300))).toBe(true); expect(isLethal(100, 50, damage("phantom", "head", 900))).toBe(false); expect(isLethal(100, 50, damage("phantom", "head", 2000))).toBe(false); // Both still one-tap a head with no armour on. expect(isLethal(100, 0, damage("phantom", "head", 2000))).toBe(true); }); test("the Phantom falls off with range and the Vandal does not", () => { expect(damage("phantom", "body", 100)).toBe(39); expect(damage("phantom", "body", 1600)).toBe(31); expect(damage("vandal", "body", 100)).toBe(damage("vandal", "body", 2300)); }); test("armour is absorbed point for point but empties first", () => { const hit = applyDamage(100, 50, 40); expect(hit.armour).toBe(50 - 27); expect(hit.hp).toBe(87); // A hundred health behind fifty armour is a hundred and fifty to chew through. let hp = 100; let armour = 50; let shots = 0; while (hp > 0) { ({ hp, armour } = applyDamage(hp, armour, 40)); shots++; } expect(shots).toBe(4); }); test("body shots never kill in one, whatever the gun, except the Operator", () => { expect(isLethal(100, 0, damage("operator", "body", 500))).toBe(true); for (const id of ["classic", "ghost", "sheriff", "spectre", "phantom", "vandal"] as const) expect(isLethal(100, 0, damage(id, "body", 500))).toBe(false); }); test("where the ray passes decides the hit location", () => { expect(zoneFromMiss(0, 16)).toBe("head"); expect(zoneFromMiss(8, 16)).toBe("body"); expect(zoneFromMiss(15, 16)).toBe("legs"); }); test("running widens the cone and standing still does not", () => { expect(shotSpread("vandal", 0)).toBe(WEAPONS.vandal.spread); expect(shotSpread("vandal", 1)).toBeGreaterThan(shotSpread("vandal", 0)); // The Operator is the accurate one and the Spectre is not. expect(shotSpread("operator", 0)).toBeLessThan(shotSpread("spectre", 0)); });