import { describe, expect, it } from "vitest"; import { ENEMY_SLOW_MOVEMENT_MULTIPLIER, enemyControlMovementMultiplier, enemyControlPreventsActions, enemyControlPreventsMovement, normalizeEnemyAttack, type EnemyAttackDefinition, } from "./enemyAttacks"; function attack(overrides: Partial): EnemyAttackDefinition { return { id: "test-special", name: "Test Special", delivery: "area", target: "nearby-party", school: "physical", animation: "attack", range: 12, cooldownMs: 10_000, damageMultiplier: 1, ...overrides, }; } describe("enemy attack telegraphs", () => { it("infers a warned cone for legacy frontal mechanics", () => { const normalized = normalizeEnemyAttack(attack({ name: "Stone Cleave" })); expect(normalized.telegraph).toMatchObject({ shape: "cone", anchor: "source", warningMs: 1_650, }); expect(normalized.castTimeMs).toBe(1_650); }); it("preserves authored geometry and extends too-short cast warnings", () => { const normalized = normalizeEnemyAttack(attack({ name: "Falling Ruin", castTimeMs: 500, telegraph: { shape: "circle", anchor: "target", warningMs: 2_200, radius: 7, }, })); expect(normalized.castTimeMs).toBe(2_200); expect(normalized.telegraph).toEqual({ shape: "circle", anchor: "target", warningMs: 2_200, radius: 7, }); }); it("does not telegraph basic attacks or beneficial mechanics", () => { expect(normalizeEnemyAttack(attack({ id: "basic-attack" })).telegraph).toBeUndefined(); expect(normalizeEnemyAttack(attack({ effect: { kind: "heal", multiplier: 1 }, })).telegraph).toBeUndefined(); expect(normalizeEnemyAttack(attack({ effect: { kind: "composite", effects: [{ kind: "summon", creatureEntry: 1, count: 1 }], }, })).telegraph).toBeUndefined(); expect(normalizeEnemyAttack(attack({ effect: { kind: "composite", effects: [ { kind: "damage", multiplier: 1 }, { kind: "summon", creatureEntry: 1, count: 1 }, ], }, })).telegraph).toMatchObject({ shape: "circle" }); }); }); describe("enemy control movement", () => { it("keeps slowed actors active while reducing movement", () => { expect(enemyControlPreventsActions("slow")).toBe(false); expect(enemyControlPreventsMovement("slow")).toBe(false); expect(enemyControlMovementMultiplier("slow")).toBe(ENEMY_SLOW_MOVEMENT_MULTIPLIER); }); it("keeps roots movement-only while preserving hard-control action locks", () => { expect(enemyControlPreventsActions("root")).toBe(false); expect(enemyControlPreventsMovement("root")).toBe(true); expect(enemyControlMovementMultiplier("root")).toBe(1); expect(enemyControlPreventsActions("stun")).toBe(true); }); });