import { describe, expect, it } from "vitest"; import referenceData from "./generated/azerothCoreReference.json"; import { enemySpawnEquipmentContract, type EnemyEquipmentSourceReference, } from "./enemyEquipment"; function equipmentSource( selector: number, alternateEntries: readonly number[] = [], templates: Readonly> = {}, alternateTemplates: Readonly>>> = {}, ): EnemyEquipmentSourceReference { return { equipmentAssignmentsBySpawnGuid: { "8765": { entry: 1696, alternateEntries, selector }, }, equipmentTemplatesByEntry: { "1696": templates, ...alternateTemplates }, equipmentItemsById: { "100": { itemClass: 2, inventoryType: 13 }, "101": { itemClass: 4, inventoryType: 14 }, }, }; } const setOne = { sourceItems: [50, 100, 0] as const, items: [50, 100, 0] as const, }; const setTwo = { sourceItems: [51, 101, 0] as const, items: [51, 101, 0] as const, }; describe("pinned AzerothCore spawn equipment resolution", () => { it("requires a source GUID whose pinned spawn entry matches the requested creature", () => { const source = equipmentSource(1, [], { "1": setOne }); expect(enemySpawnEquipmentContract(1696, 8765, undefined, source)).toMatchObject({ entry: 1696, sourceCreatureGuid: 8765, selector: 1, equipmentId: 1, virtualItemIds: [50, 100, 0], }); expect(enemySpawnEquipmentContract(1711, 8765, undefined, source)).toBeUndefined(); expect(enemySpawnEquipmentContract(1696, 1, undefined, source)).toBeUndefined(); expect(enemySpawnEquipmentContract(1696, 0, undefined, source)).toBeUndefined(); }); it("keeps selector zero as an explicit empty equipment assignment", () => { const resolved = enemySpawnEquipmentContract(1696, 8765, undefined, equipmentSource(0)); expect(resolved).toMatchObject({ selector: 0, equipmentId: 0, virtualItemIds: [0, 0, 0], offhandItemId: 0, offhandItemClass: null, }); expect(resolved?.autoOffhand).toBeUndefined(); }); it("uses an exact positive equipment ID and the imported Item.dbc class", () => { const resolved = enemySpawnEquipmentContract( 1696, 8765, undefined, equipmentSource(2, [], { "1": setOne, "2": setTwo }), ); expect(resolved).toMatchObject({ selector: 2, equipmentId: 2, virtualItemIds: [51, 101, 0], offhandItemId: 101, offhandItemClass: 4, }); expect(resolved?.autoOffhand).toBeUndefined(); const weapon = enemySpawnEquipmentContract( 1696, 8765, undefined, equipmentSource(1, [], { "1": setOne }), ); expect(weapon?.autoOffhand).toMatchObject({ entry: 1696, source: "auto-offhand-weapon", dualWieldMode: "auto", }); }); it("resolves -1 with source ordinal-plus-one semantics and rejects sparse follow-up lookups", () => { const denseSource = equipmentSource(-1, [], { "1": setOne, "2": setTwo }); expect(enemySpawnEquipmentContract(1696, 8765, 0.75, denseSource)).toMatchObject({ selector: -1, equipmentId: 2, virtualItemIds: [51, 101, 0], }); const sparseSource = equipmentSource(-1, [], { "2": setTwo }); expect(enemySpawnEquipmentContract(1696, 8765, 0, sparseSource)).toBeUndefined(); expect(enemySpawnEquipmentContract(1696, 8765, undefined, denseSource)).toBeUndefined(); expect(enemySpawnEquipmentContract(1696, 8765, 1, denseSource)).toBeUndefined(); expect(enemySpawnEquipmentContract(1696, 8765, -0.01, denseSource)).toBeUndefined(); }); it("validates positive selectors against alternate creature entries", () => { const alternateMissing = equipmentSource(1, [1711], { "1": setOne }); expect(enemySpawnEquipmentContract(1696, 8765, undefined, alternateMissing)).toBeUndefined(); const alternateAvailable = equipmentSource( 1, [1711], { "1": setOne }, { "1711": { "1": setOne } }, ); expect(enemySpawnEquipmentContract(1696, 8765, undefined, alternateAvailable)) .toMatchObject({ virtualItemIds: [50, 100, 0] }); const randomAlternateMissing = equipmentSource(-1, [1711], { "1": setOne, "2": setTwo }); expect(enemySpawnEquipmentContract(1696, 8765, 0.75, randomAlternateMissing)).toBeUndefined(); const randomAlternateAvailable = equipmentSource( -1, [1711], { "1": setOne, "2": setTwo }, { "1711": { "2": setTwo } }, ); expect(enemySpawnEquipmentContract(1711, 8765, 0.75, randomAlternateAvailable)) .toMatchObject({ equipmentId: 2, virtualItemIds: [51, 101, 0] }); }); it("fails closed for older references without equipment maps", () => { expect(enemySpawnEquipmentContract( 1696, 8765, undefined, {} as EnemyEquipmentSourceReference, )).toBeUndefined(); }); it("resolves a pinned Stockade spawn without inferring its equipment ID from the entry", () => { const assignments = (referenceData as unknown as { creature: EnemyEquipmentSourceReference; }).creature.equipmentAssignmentsBySpawnGuid; const spawn = assignments["84027"]; expect(spawn).toEqual({ entry: 1696, alternateEntries: [], selector: 1 }); expect(enemySpawnEquipmentContract(1696, 84027)).toMatchObject({ selector: 1, equipmentId: 1, virtualItemIds: [5305, 5305, 0], offhandItemId: 5305, offhandItemClass: 2, autoOffhand: { source: "auto-offhand-weapon" }, }); }); });