115 lines
4.6 KiB
TypeScript
115 lines
4.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { creatureTemplateReference } from "./azerothCoreReference";
|
|
import referenceData from "./generated/azerothCoreReference.json";
|
|
import {
|
|
CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK,
|
|
ENEMY_AUTOMATIC_OFFHAND_ITEM_SOURCE,
|
|
ENEMY_AUTOMATIC_OFFHAND_WORLD_SOURCE,
|
|
ENEMY_OFFHAND_ITEM_CLASS_WEAPON,
|
|
enemyAutoEquippedOffhandContract,
|
|
enemyFlagDrivenOffhandContract,
|
|
} from "./enemyAutomaticOffhand";
|
|
|
|
describe("automatic AzerothCore creature offhand contracts", () => {
|
|
it("pins the world table and the exact USE_OFFHAND_ATTACK flag bit", () => {
|
|
expect(ENEMY_AUTOMATIC_OFFHAND_WORLD_SOURCE).toEqual({
|
|
repository: "https://github.com/azerothcore/azerothcore-wotlk",
|
|
commit: "4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3",
|
|
table: "creature_template",
|
|
path: "data/sql/base/db_world/creature_template.sql",
|
|
sha256: "0066e4fd35b809986dd325487515087f5a95f4ffe50ea03846c8d8bf5196870a",
|
|
});
|
|
expect(ENEMY_AUTOMATIC_OFFHAND_ITEM_SOURCE).toEqual({
|
|
path: "../wow335a/Data/patch-A.MPQ/DBFilesClient/Item.dbc",
|
|
sha256: "22061a811523790ddd2ee95b36ade2ac6e0c79a8b3121324d32a639acf50567f",
|
|
classField: 1,
|
|
});
|
|
expect(CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK).toBe(0x800);
|
|
expect(ENEMY_OFFHAND_ITEM_CLASS_WEAPON).toBe(2);
|
|
});
|
|
|
|
it("enables source creatures whose pinned template carries the offhand flag", () => {
|
|
const cases = [
|
|
[4540, "Scarlet Monk", 0x800],
|
|
[10478, "Splintered Skeleton", 0x800],
|
|
[10488, "Risen Construct", 0x800],
|
|
[16593, "Shattered Hand Brawler", 0x0800_0000 | 0x800],
|
|
[16808, "Warchief Kargath Bladefist", 0x800],
|
|
] as const;
|
|
const templates = (referenceData as unknown as {
|
|
creature: { templates: Record<string, { entry: number; name: string; flagsExtra?: number }> };
|
|
}).creature.templates;
|
|
const allFlagged = Object.values(templates)
|
|
.filter((template) => (template.flagsExtra ?? 0) & CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK)
|
|
.sort((left, right) => left.entry - right.entry)
|
|
.map(({ entry, name, flagsExtra }) => [entry, name, flagsExtra]);
|
|
|
|
expect(Object.keys(templates)).toHaveLength(1_671);
|
|
expect(allFlagged).toEqual(cases.map(([entry, name, flagsExtra]) => [entry, name, flagsExtra]));
|
|
|
|
for (const [entry, name, flagsExtra] of cases) {
|
|
expect(creatureTemplateReference(entry)).toMatchObject({ entry, name, flagsExtra });
|
|
expect(enemyFlagDrivenOffhandContract(entry)).toMatchObject({
|
|
entry,
|
|
name,
|
|
source: "creature-template-flag",
|
|
dualWieldMode: "enabled",
|
|
requiresEquippedWeapon: false,
|
|
attackType: "offhand",
|
|
damageMultiplier: 0.5,
|
|
whiteSwingMissPenaltyPercent: 19,
|
|
attackTimeFrom: "creature-template-base-attack-time",
|
|
independentSwingTimer: true,
|
|
firstSwingDelayFractionOnEngage: 0.5,
|
|
simultaneousSwingDelayMs: 200,
|
|
});
|
|
}
|
|
});
|
|
|
|
it("fails closed for absent templates, unflagged rows, and invalid entry IDs", () => {
|
|
expect(enemyFlagDrivenOffhandContract(6)).toBeUndefined();
|
|
expect(enemyFlagDrivenOffhandContract(999_999_999)).toBeUndefined();
|
|
expect(enemyFlagDrivenOffhandContract(0)).toBeUndefined();
|
|
expect(enemyFlagDrivenOffhandContract(-4540)).toBeUndefined();
|
|
expect(enemyFlagDrivenOffhandContract(4540.5)).toBeUndefined();
|
|
});
|
|
|
|
it("uses the core AUTO-mode item-class gate without inventing item mappings", () => {
|
|
expect(enemyAutoEquippedOffhandContract({
|
|
entry: 1696,
|
|
offhandItemId: 123,
|
|
offhandItemClass: ENEMY_OFFHAND_ITEM_CLASS_WEAPON,
|
|
})).toMatchObject({
|
|
entry: 1696,
|
|
name: "Targorr the Dread",
|
|
source: "auto-offhand-weapon",
|
|
dualWieldMode: "auto",
|
|
requiresEquippedWeapon: true,
|
|
attackType: "offhand",
|
|
baseDamageFrom: "same-creature-template-offhand-range-and-ap-formula",
|
|
damageMultiplier: 0.5,
|
|
whiteSwingMissPenaltyPercent: 19,
|
|
});
|
|
|
|
for (const offhandItemClass of [null, undefined, 0, 1, 3, 4, -1]) {
|
|
expect(enemyAutoEquippedOffhandContract({
|
|
entry: 1696,
|
|
offhandItemId: 123,
|
|
offhandItemClass,
|
|
})).toBeUndefined();
|
|
}
|
|
for (const offhandItemId of [0, -1, 1.5, Number.NaN]) {
|
|
expect(enemyAutoEquippedOffhandContract({
|
|
entry: 1696,
|
|
offhandItemId,
|
|
offhandItemClass: ENEMY_OFFHAND_ITEM_CLASS_WEAPON,
|
|
})).toBeUndefined();
|
|
}
|
|
expect(enemyAutoEquippedOffhandContract({
|
|
entry: 999_999_999,
|
|
offhandItemId: 123,
|
|
offhandItemClass: ENEMY_OFFHAND_ITEM_CLASS_WEAPON,
|
|
})).toBeUndefined();
|
|
});
|
|
});
|