Files
healer-man/src/game/enemyEquipment.test.ts
T
2026-10-06 22:25:34 -04:00

156 lines
5.6 KiB
TypeScript

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<Record<string, { sourceItems: readonly [number, number, number]; items: readonly [number, number, number] }>> = {},
alternateTemplates: Readonly<Record<string, Readonly<Record<string, { sourceItems: readonly [number, number, number]; items: readonly [number, number, number] }>>>> = {},
): 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" },
});
});
});