pike/val Public Public: anyone can read this; nobody can change it.
forked from benjivers/val
workbenchthis machine
Files 7524e23c398cf40fee5ee6886d8b9cb75adfcbbf
| 1 | import { expect, test } from "bun:test"; |
| 2 | import { applyDamage, damage, isLethal, shotSpread, WEAPONS, zoneFromMiss } from "./weapons.ts"; |
| 3 | |
| 4 | test("a Vandal head shot kills through full armour at any range, a Phantom's does not", () => { |
| 5 | for (const distance of [100, 800, 2000]) expect(isLethal(100, 50, damage("vandal", "head", distance))).toBe(true); |
| 6 | // The Phantom only manages it inside fifteen metres; past that the falloff |
| 7 | // leaves the target alive, which is the whole argument between the two guns. |
| 8 | expect(isLethal(100, 50, damage("phantom", "head", 300))).toBe(true); |
| 9 | expect(isLethal(100, 50, damage("phantom", "head", 900))).toBe(false); |
| 10 | expect(isLethal(100, 50, damage("phantom", "head", 2000))).toBe(false); |
| 11 | // Both still one-tap a head with no armour on. |
| 12 | expect(isLethal(100, 0, damage("phantom", "head", 2000))).toBe(true); |
| 13 | }); |
| 14 | |
| 15 | test("the Phantom falls off with range and the Vandal does not", () => { |
| 16 | expect(damage("phantom", "body", 100)).toBe(39); |
| 17 | expect(damage("phantom", "body", 1600)).toBe(31); |
| 18 | expect(damage("vandal", "body", 100)).toBe(damage("vandal", "body", 2300)); |
| 19 | }); |
| 20 | |
| 21 | test("armour is absorbed point for point but empties first", () => { |
| 22 | const hit = applyDamage(100, 50, 40); |
| 23 | expect(hit.armour).toBe(50 - 27); |
| 24 | expect(hit.hp).toBe(87); |
| 25 | // A hundred health behind fifty armour is a hundred and fifty to chew through. |
| 26 | let hp = 100; |
| 27 | let armour = 50; |
| 28 | let shots = 0; |
| 29 | while (hp > 0) { |
| 30 | ({ hp, armour } = applyDamage(hp, armour, 40)); |
| 31 | shots++; |
| 32 | } |
| 33 | expect(shots).toBe(4); |
| 34 | }); |
| 35 | |
| 36 | test("body shots never kill in one, whatever the gun, except the Operator", () => { |
| 37 | expect(isLethal(100, 0, damage("operator", "body", 500))).toBe(true); |
| 38 | for (const id of ["classic", "ghost", "sheriff", "spectre", "phantom", "vandal"] as const) |
| 39 | expect(isLethal(100, 0, damage(id, "body", 500))).toBe(false); |
| 40 | }); |
| 41 | |
| 42 | test("where the ray passes decides the hit location", () => { |
| 43 | expect(zoneFromMiss(0, 16)).toBe("head"); |
| 44 | expect(zoneFromMiss(8, 16)).toBe("body"); |
| 45 | expect(zoneFromMiss(15, 16)).toBe("legs"); |
| 46 | }); |
| 47 | |
| 48 | test("running widens the cone and standing still does not", () => { |
| 49 | expect(shotSpread("vandal", 0)).toBe(WEAPONS.vandal.spread); |
| 50 | expect(shotSpread("vandal", 1)).toBeGreaterThan(shotSpread("vandal", 0)); |
| 51 | // The Operator is the accurate one and the Spectre is not. |
| 52 | expect(shotSpread("operator", 0)).toBeLessThan(shotSpread("spectre", 0)); |
| 53 | }); |