import { describe, expect, it } from "vitest"; import type { Pf2eCreature } from "../creature-types.js"; import { creatureId } from "../creature-types.js"; import { acDelta, adjustedLevel, applyPf2eAdjustment, hpDelta, modDelta, } from "../pf2e-adjustments.js"; describe("adjustedLevel", () => { it("elite on level 5 → 6", () => { expect(adjustedLevel(5, "elite")).toBe(6); }); it("elite on level 0 → 2 (double bump)", () => { expect(adjustedLevel(0, "elite")).toBe(2); }); it("elite on level −1 → 1 (double bump)", () => { expect(adjustedLevel(-1, "elite")).toBe(1); }); it("weak on level 5 → 4", () => { expect(adjustedLevel(5, "weak")).toBe(4); }); it("weak on level 1 → −1 (double drop)", () => { expect(adjustedLevel(1, "weak")).toBe(-1); }); it("weak on level 0 → −1", () => { expect(adjustedLevel(0, "weak")).toBe(-1); }); }); describe("hpDelta", () => { it("level 1 elite → +10", () => { expect(hpDelta(1, "elite")).toBe(10); }); it("level 1 weak → −10", () => { expect(hpDelta(1, "weak")).toBe(-10); }); it("level 3 elite → +15", () => { expect(hpDelta(3, "elite")).toBe(15); }); it("level 3 weak → −15", () => { expect(hpDelta(3, "weak")).toBe(-15); }); it("level 10 elite → +20", () => { expect(hpDelta(10, "elite")).toBe(20); }); it("level 10 weak → −20", () => { expect(hpDelta(10, "weak")).toBe(-20); }); it("level 25 elite → +30", () => { expect(hpDelta(25, "elite")).toBe(30); }); it("level 25 weak → −30", () => { expect(hpDelta(25, "weak")).toBe(-30); }); }); describe("acDelta", () => { it("elite → +2", () => { expect(acDelta("elite")).toBe(2); }); it("weak → −2", () => { expect(acDelta("weak")).toBe(-2); }); }); describe("modDelta", () => { it("elite → +2", () => { expect(modDelta("elite")).toBe(2); }); it("weak → −2", () => { expect(modDelta("weak")).toBe(-2); }); }); function baseCreature(overrides?: Partial): Pf2eCreature { return { system: "pf2e", id: creatureId("test-creature"), name: "Test Creature", source: "test-source", sourceDisplayName: "Test Source", level: 5, traits: ["humanoid"], perception: 12, skills: "Athletics +14", abilityMods: { str: 4, dex: 2, con: 3, int: 0, wis: 1, cha: -1, }, ac: 22, saveFort: 14, saveRef: 11, saveWill: 9, hp: 75, speed: "25 feet", ...overrides, }; } describe("applyPf2eAdjustment", () => { it("adjusts all numeric stats for elite", () => { const creature = baseCreature(); const result = applyPf2eAdjustment(creature, "elite"); expect(result.level).toBe(6); expect(result.ac).toBe(24); expect(result.hp).toBe(95); // 75 + 20 (level 5 bracket) expect(result.perception).toBe(14); expect(result.saveFort).toBe(16); expect(result.saveRef).toBe(13); expect(result.saveWill).toBe(11); }); it("adjusts all numeric stats for weak", () => { const creature = baseCreature(); const result = applyPf2eAdjustment(creature, "weak"); expect(result.level).toBe(4); expect(result.ac).toBe(20); expect(result.hp).toBe(55); // 75 - 20 (level 5 bracket) expect(result.perception).toBe(10); expect(result.saveFort).toBe(12); expect(result.saveRef).toBe(9); expect(result.saveWill).toBe(7); }); it("adjusts attack bonuses and damage", () => { const creature = baseCreature({ attacks: [ { name: "Melee", activity: { number: 1, unit: "action" }, segments: [ { type: "text", value: "+15 [+10/+5] (agile), 2d12+7 piercing plus Grab", }, ], }, ], }); const result = applyPf2eAdjustment(creature, "elite"); const text = result.attacks?.[0].segments[0]; expect(text).toEqual({ type: "text", value: "+17 [+12/+7] (agile), 2d12+9 piercing plus Grab", }); }); it("adjusts attack damage for weak", () => { const creature = baseCreature({ attacks: [ { name: "Melee", activity: { number: 1, unit: "action" }, segments: [ { type: "text", value: "+15 (agile), 2d12+7 piercing plus Grab", }, ], }, ], }); const result = applyPf2eAdjustment(creature, "weak"); const text = result.attacks?.[0].segments[0]; expect(text).toEqual({ type: "text", value: "+13 (agile), 2d12+5 piercing plus Grab", }); }); it("handles damage bonus becoming zero", () => { const creature = baseCreature({ attacks: [ { name: "Melee", activity: { number: 1, unit: "action" }, segments: [{ type: "text", value: "+10, 1d4+2 slashing" }], }, ], }); const result = applyPf2eAdjustment(creature, "weak"); const text = result.attacks?.[0].segments[0]; expect(text).toEqual({ type: "text", value: "+8, 1d4 slashing", }); }); it("handles damage bonus becoming negative", () => { const creature = baseCreature({ attacks: [ { name: "Melee", activity: { number: 1, unit: "action" }, segments: [{ type: "text", value: "+10, 1d4+1 slashing" }], }, ], }); const result = applyPf2eAdjustment(creature, "weak"); const text = result.attacks?.[0].segments[0]; expect(text).toEqual({ type: "text", value: "+8, 1d4-1 slashing", }); }); it("does not modify non-attack abilities", () => { const creature = baseCreature({ abilitiesTop: [ { name: "Darkvision", segments: [{ type: "text", value: "Can see in darkness." }], }, ], }); const result = applyPf2eAdjustment(creature, "elite"); expect(result.abilitiesTop).toEqual(creature.abilitiesTop); }); it("preserves non-text segments in attacks", () => { const creature = baseCreature({ attacks: [ { name: "Melee", activity: { number: 1, unit: "action" }, segments: [ { type: "list", items: [{ text: "some list item" }], }, ], }, ], }); const result = applyPf2eAdjustment(creature, "elite"); expect(result.attacks?.[0].segments[0]).toEqual({ type: "list", items: [{ text: "some list item" }], }); }); });