import { describe, expect, it } from "vitest"; import { addActorThreat, pruneThreatTable, resolveAggroTarget, seedActorThreat, tauntThreat, threatFromDamage, threatFromHealing, } from "./aggro"; describe("pure aggro rules", () => { it("uses five-times tank damage threat and applies the final talent scalar", () => { expect(threatFromDamage(10, "tank")).toBe(50); expect(threatFromDamage(10, "damage")).toBe(10); expect(threatFromDamage(10, "healer")).toBe(10); expect(threatFromDamage(10, "tank", 0.8)).toBe(40); }); it("uses effective healing at one quarter strength split across engaged mobs", () => { expect(threatFromHealing(80, 1)).toBe(20); expect(threatFromHealing(80, 4)).toBe(5); expect(threatFromHealing(80, 0)).toBe(0); }); it("seeds only a missing actor and adds subsequent threat", () => { const seeded = seedActorThreat({}, "puller"); expect(seeded).toEqual({ puller: 1 }); expect(seedActorThreat(seeded, "puller")).toBe(seeded); expect(addActorThreat(seeded, "puller", 4)).toEqual({ puller: 5 }); }); it("preserves the incumbent on exact ties and otherwise uses actor-id ordering", () => { const table = { bravo: 10, alpha: 10 }; const eligible = new Set(["alpha", "bravo"]); expect(resolveAggroTarget(table, eligible, "bravo", null, 1_000).targetActorId).toBe("bravo"); expect(resolveAggroTarget(table, eligible, null, null, 1_000).targetActorId).toBe("alpha"); }); it("puts a taunter at max plus one for the forced duration", () => { const table = tauntThreat({ healer: 27, tank: 2 }, "tank"); expect(table).toEqual({ healer: 27, tank: 28 }); const forced = { actorId: "tank", endsAt: 4_000 }; const eligible = new Set(["healer", "tank"]); expect(resolveAggroTarget(table, eligible, "healer", forced, 3_999)).toEqual({ targetActorId: "tank", forcedTarget: forced, }); expect(resolveAggroTarget({ ...table, healer: 40 }, eligible, "tank", forced, 4_000)).toEqual({ targetActorId: "healer", forcedTarget: null, }); }); it("drops an unavailable forced target and removes stale threat", () => { const table = { downed: 50, living: 10 }; const eligible = new Set(["living"]); expect(resolveAggroTarget( table, eligible, "downed", { actorId: "downed", endsAt: 9_000 }, 1_000, )).toEqual({ targetActorId: "living", forcedTarget: null, }); expect(pruneThreatTable(table, eligible)).toEqual({ living: 10 }); }); });