Files
healer-man/src/game/aggro.test.ts
T
2026-08-14 15:56:39 -04:00

71 lines
2.5 KiB
TypeScript

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 });
});
});