forked from phenom/healer-man
176 lines
7.2 KiB
TypeScript
176 lines
7.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import "./abilityCatalog";
|
|
import {
|
|
clipsForAnimationIds,
|
|
parseWoWAnimationName,
|
|
selectCharacterBaseClip,
|
|
selectCharacterEventClip,
|
|
selectCharacterVerticalClip,
|
|
selectWoWAnimationVariation,
|
|
} from "./combatAnimation";
|
|
|
|
const clips = [
|
|
{ name: "Stand (ID 0 variation 0)" },
|
|
{ name: "Walk (ID 4 variation 0)" },
|
|
{ name: "Run (ID 5 variation 0)" },
|
|
{ name: "Attack1H (ID 17 variation 0)" },
|
|
{ name: "Special1H (ID 57 variation 0)" },
|
|
{ name: "ReadySpellDirected (ID 51 variation 0)" },
|
|
{ name: "SpellCastDirected (ID 53 variation 0)" },
|
|
{ name: "CombatWound (ID 9 variation 0)" },
|
|
{ name: "Death (ID 1 variation 0)" },
|
|
{ name: "AttackUnarmed (ID 16 variation 0)" },
|
|
{ name: "AttackUnarmed (ID 16 variation 1)" },
|
|
{ name: "JumpStart (ID 37 variation 0)" },
|
|
{ name: "Fall (ID 40 variation 0)" },
|
|
{ name: "JumpEnd (ID 39 variation 0)" },
|
|
{ name: "JumpLandRun (ID 133 variation 0)" },
|
|
{ name: "Ready1H (ID 26 variation 0)" },
|
|
{ name: "Ready2H (ID 27 variation 0)" },
|
|
{ name: "Ready2HL (ID 28 variation 0)" },
|
|
{ name: "ReadyBow (ID 29 variation 0)" },
|
|
{ name: "HoldBow (ID 109 variation 0)" },
|
|
];
|
|
|
|
describe("WoW character animation selection", () => {
|
|
it("parses AnimationData IDs and preserves labels and variations", () => {
|
|
expect(parseWoWAnimationName("AttackUnarmed (ID 16 variation 1)")).toEqual({
|
|
label: "AttackUnarmed",
|
|
id: 16,
|
|
variation: 1,
|
|
});
|
|
expect(parseWoWAnimationName("custom")).toEqual({ label: "custom", id: null, variation: 0 });
|
|
});
|
|
|
|
it("uses native movement IDs instead of fuzzy attack-name matches", () => {
|
|
expect(selectCharacterBaseClip(clips, "idle")).toBe(clips[0]);
|
|
expect(selectCharacterBaseClip(clips, "walk")).toBe(clips[1]);
|
|
expect(selectCharacterBaseClip(clips, "run")).toBe(clips[2]);
|
|
});
|
|
|
|
it("uses the native ready pose for the equipped weapon stance", () => {
|
|
expect(selectCharacterBaseClip(clips, "idle", "one-handed")).toBe(clips[15]);
|
|
expect(selectCharacterBaseClip(clips, "idle", "two-handed")).toBe(clips[16]);
|
|
expect(selectCharacterBaseClip(clips, "idle", "two-handed-left")).toBe(clips[17]);
|
|
expect(selectCharacterBaseClip(clips, "idle", "bow")).toBe(clips[19]);
|
|
expect(selectCharacterBaseClip(clips, "run", "bow")).toBe(clips[2]);
|
|
expect(selectCharacterBaseClip([
|
|
clips[0],
|
|
clips[15],
|
|
], "idle", "bow")).toBe(clips[15]);
|
|
|
|
const runewakerClips = [
|
|
{ name: "Stand - stand_idle01" },
|
|
{ name: "Idle - 1h_idle" },
|
|
{ name: "Idle - 2h_idle" },
|
|
{ name: "Idle - bow_idle" },
|
|
];
|
|
expect(selectCharacterBaseClip(runewakerClips, "idle", "one-handed"))
|
|
.toBe(runewakerClips[1]);
|
|
expect(selectCharacterBaseClip(runewakerClips, "idle", "two-handed-left"))
|
|
.toBe(runewakerClips[2]);
|
|
expect(selectCharacterBaseClip(runewakerClips, "idle", "bow"))
|
|
.toBe(runewakerClips[3]);
|
|
});
|
|
|
|
it("rotates every variation of the highest-priority available ID", () => {
|
|
expect(selectWoWAnimationVariation(clips, [16], 0)).toBe(clips[9]);
|
|
expect(selectWoWAnimationVariation(clips, [16], 1)).toBe(clips[10]);
|
|
expect(selectWoWAnimationVariation(clips, [16], 2)).toBe(clips[9]);
|
|
expect(clipsForAnimationIds(clips, [57, 17])).toEqual([clips[4], clips[3]]);
|
|
});
|
|
|
|
it("selects native rising, falling, and landing locomotion", () => {
|
|
expect(selectCharacterVerticalClip(clips, "rising", false)).toMatchObject({
|
|
clip: clips[11],
|
|
loop: false,
|
|
});
|
|
expect(selectCharacterVerticalClip(clips, "falling", false)).toMatchObject({
|
|
clip: clips[12],
|
|
loop: true,
|
|
});
|
|
expect(selectCharacterVerticalClip(clips, "landing", false)?.clip).toBe(clips[13]);
|
|
expect(selectCharacterVerticalClip(clips, "landing", true)?.clip).toBe(clips[14]);
|
|
});
|
|
|
|
it("maps hard-cast lifecycle events to ready and release clips", () => {
|
|
expect(selectCharacterEventClip(clips, "priest", {
|
|
revision: 1,
|
|
kind: "ability-start",
|
|
abilityId: "priest-smite",
|
|
})).toMatchObject({ clip: clips[5], loop: true, terminal: false });
|
|
expect(selectCharacterEventClip(clips, "priest", {
|
|
revision: 2,
|
|
kind: "ability-release",
|
|
abilityId: "priest-smite",
|
|
})).toMatchObject({ clip: clips[6], loop: false, terminal: false });
|
|
});
|
|
|
|
it("maps melee, wound, and terminal death events to native clips", () => {
|
|
expect(selectCharacterEventClip(clips, "warrior", { revision: 1, kind: "attack" }))
|
|
.toMatchObject({ clip: clips[4], loop: false });
|
|
expect(selectCharacterEventClip(clips, "warrior", { revision: 2, kind: "wound" }))
|
|
.toMatchObject({ clip: clips[7], loop: false });
|
|
expect(selectCharacterEventClip(clips, "warrior", { revision: 3, kind: "death" }))
|
|
.toMatchObject({ clip: clips[8], terminal: true });
|
|
});
|
|
|
|
it("uses native RuneWaker spell, bow, and melee clips for RoM characters", () => {
|
|
const runewakerClips = [
|
|
{ name: "Action - 1h_charge_up" },
|
|
{ name: "Attack - 1h_attack01" },
|
|
{ name: "Attack - 1h_attack02" },
|
|
{ name: "Action - bow_channel" },
|
|
{ name: "Action - bow_release" },
|
|
{ name: "Cast - casting_delay" },
|
|
{ name: "Cast - cast01" },
|
|
{ name: "Action - buff01" },
|
|
{ name: "Wound - hurt" },
|
|
{ name: "Death - death" },
|
|
{ name: "Action - jump_up" },
|
|
{ name: "Action - jump_down" },
|
|
{ name: "Action - jump_end_run" },
|
|
];
|
|
|
|
expect(selectCharacterEventClip(runewakerClips, "rom-mage", {
|
|
revision: 1,
|
|
kind: "ability-start",
|
|
abilityId: "rom-mage-primary-1",
|
|
})).toMatchObject({ clip: runewakerClips[5], loop: true, native: true });
|
|
expect(selectCharacterEventClip(runewakerClips, "rom-mage", {
|
|
revision: 2,
|
|
kind: "ability-release",
|
|
abilityId: "rom-mage-primary-1",
|
|
})).toMatchObject({ clip: runewakerClips[6], loop: false, native: true });
|
|
expect(selectCharacterEventClip(runewakerClips, "rom-mage", {
|
|
revision: 2,
|
|
kind: "ability-release",
|
|
abilityId: "rom-mage-primary-0",
|
|
})).toMatchObject({ clip: runewakerClips[7], loop: false, native: true });
|
|
expect(selectCharacterEventClip(runewakerClips, "rom-scout", {
|
|
revision: 3,
|
|
kind: "ability-release",
|
|
abilityId: "rom-scout-primary-1",
|
|
})).toMatchObject({ clip: runewakerClips[4], native: true });
|
|
expect(selectCharacterEventClip(runewakerClips, "rom-warrior", {
|
|
revision: 4,
|
|
kind: "ability-release",
|
|
abilityId: "rom-warrior-primary-1",
|
|
})).toMatchObject({ clip: runewakerClips[1], native: true });
|
|
expect(selectCharacterEventClip(runewakerClips, "rom-warrior", {
|
|
revision: 5,
|
|
kind: "wound",
|
|
})).toMatchObject({ clip: runewakerClips[8], native: true });
|
|
expect(selectCharacterEventClip(runewakerClips, "rom-warrior", {
|
|
revision: 6,
|
|
kind: "death",
|
|
})).toMatchObject({ clip: runewakerClips[9], terminal: true, native: true });
|
|
expect(selectCharacterVerticalClip(runewakerClips, "rising", false)?.clip)
|
|
.toBe(runewakerClips[10]);
|
|
expect(selectCharacterVerticalClip(runewakerClips, "falling", false)?.clip)
|
|
.toBe(runewakerClips[11]);
|
|
expect(selectCharacterVerticalClip(runewakerClips, "landing", true)?.clip)
|
|
.toBe(runewakerClips[12]);
|
|
});
|
|
});
|