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

168 lines
7.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { applyAura, expireAuras, resolveDamageValue, resolveStatValue } from "./combatAuras";
import {
ENEMY_STANCE_SOURCE_PINS,
enemyStanceContract,
removeEnemyStanceAura,
supportedEnemyStanceAuraDefinition,
} from "./enemyStances";
describe("pinned enemy warrior stance contracts", () => {
it("pins both client profiles and preserves the direct form, duration, and no-restriction rows", () => {
expect(ENEMY_STANCE_SOURCE_PINS.ascension.spellDbcSha256)
.toBe("2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce");
expect(ENEMY_STANCE_SOURCE_PINS.epoch.spellDbcSha256)
.toBe("d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3");
expect(ENEMY_STANCE_SOURCE_PINS.epoch.durationDbcSha256)
.toBe("eeae44ef0185924f3d6ec57ab2701c66566db86e51ab0bae017a9449126eb3a0");
for (const profile of ["ascension", "epoch"] as const) {
expect(enemyStanceContract(7164, profile)).toMatchObject({
name: "Defensive Stance",
form: 18,
durationMs: 180_000,
target: "self",
signature: {
attributes0: 327_696,
dispel: 0,
durationIndex: 25,
durationMs: 180_000,
rangeIndex: 1,
schoolMask: 1,
damageClass: 0,
stackAmount: 0,
stanceMask: [0, 0],
stanceExcludeMask: [0, 0],
equippedItemClass: -1,
equippedItemSubclassMask: 0,
equippedItemInventoryMask: 0,
effects: [{ effectType: 6, auraType: 36, basePoints: 0, implicitTargetA: 1, implicitTargetB: 0, radiusIndex: 0, radius: 0, miscValue: 18, triggerSpellId: 0 }],
},
});
expect(enemyStanceContract(7165, profile)).toMatchObject({
name: "Battle Stance",
form: 17,
durationMs: null,
target: "self",
signature: {
attributes0: 327_696,
durationIndex: 21,
durationMs: -1,
damageClass: 2,
stanceMask: [0, 0],
stanceExcludeMask: [0, 0],
effects: [{ effectType: 6, auraType: 36, basePoints: 0, miscValue: 17, triggerSpellId: 0 }],
},
});
}
expect(enemyStanceContract(99999, "epoch")).toBeUndefined();
});
it("uses the server-linked child passives and applies only supported numeric effects", () => {
const ascDefensive = enemyStanceContract(7164, "ascension")!;
const epochDefensive = enemyStanceContract(7164, "epoch")!;
const ascBattle = enemyStanceContract(7165, "ascension")!;
const epochBattle = enemyStanceContract(7165, "epoch")!;
expect(ascDefensive).toMatchObject({
childPassiveSpellId: 7376,
childPassiveScalars: {
attributes0: 327_888,
dispel: 0,
durationIndex: 0,
durationMs: 0,
rangeIndex: 1,
schoolMask: 1,
damageClass: 0,
stackAmount: 0,
stanceMask: [0, 0],
stanceExcludeMask: [0, 0],
equippedItemClass: -1,
equippedItemSubclassMask: 0,
equippedItemInventoryMask: 0,
},
childPassiveEffects: [
{ effectType: 6, auraType: 87, basePoints: -10, miscValue: 127, triggerSpellId: 0 },
{ effectType: 6, auraType: 79, basePoints: -5, miscValue: 127, triggerSpellId: 0 },
{ effectType: 6, auraType: 4, basePoints: 42, miscValue: 127, triggerSpellId: 0 },
],
modifiers: [
{ kind: "damage", direction: "taken", value: -0.10, multiplicative: true },
{ kind: "damage", direction: "dealt", value: -0.05, multiplicative: true },
],
unsupportedEffects: [{ auraType: 4, basePoints: 42 }],
});
expect(epochDefensive.childPassiveEffects[2]).toMatchObject({ auraType: 10, basePoints: 45 });
expect(epochDefensive.modifiers).toContainEqual({
kind: "stat", stat: "threat", operation: "percent", value: 0.45, multiplicative: true,
});
expect(ascBattle).toMatchObject({
childPassiveSpellId: 21156,
childPassiveScalars: { attributes0: 327_888, durationIndex: 0, rangeIndex: 1, schoolMask: 1, damageClass: 0, stackAmount: 0 },
childPassiveEffects: [{ auraType: 10, basePoints: 0 }, { auraType: 280, basePoints: 0 }],
modifiers: [],
unsupportedEffects: [],
});
expect(epochBattle).toMatchObject({
childPassiveSpellId: 21156,
childPassiveScalars: { attributes0: 327_888, durationIndex: 0, rangeIndex: 1, schoolMask: 1, damageClass: 0, stackAmount: 0 },
childPassiveEffects: [{ auraType: 10, basePoints: -20, miscValue: 127 }],
modifiers: [{ kind: "stat", stat: "threat", operation: "percent", value: -0.20, multiplicative: true }],
unsupportedEffects: [],
});
const definition = supportedEnemyStanceAuraDefinition(ascDefensive);
const active = applyAura([], { definition, sourceId: "mob", targetId: "mob", now: 0 }).auras;
expect(resolveDamageValue(100, active, { direction: "taken", school: "fire", attackKind: "spell" })).toBe(90);
expect(resolveDamageValue(100, active, { direction: "dealt", school: "physical", attackKind: "melee" })).toBe(95);
const combinedMitigation = applyAura(active, {
definition: {
id: "another-source-damage-mitigation",
name: "Another sourced mitigation",
disposition: "buff",
durationMs: null,
modifiers: [{ kind: "damage", direction: "taken", operation: "percent", value: 0.20, multiplicative: true }],
},
sourceId: "second-source",
targetId: "mob",
now: 1,
}).auras;
expect(resolveDamageValue(100, combinedMitigation, { direction: "taken", school: "physical", attackKind: "melee" }))
.toBeCloseTo(108);
expect(resolveStatValue(1, applyAura([], {
definition: supportedEnemyStanceAuraDefinition(epochDefensive), sourceId: "epoch-mob", targetId: "epoch-mob", now: 0,
}).auras, "threat")).toBeCloseTo(1.45);
expect(resolveStatValue(1, applyAura([], {
definition: supportedEnemyStanceAuraDefinition(epochBattle), sourceId: "epoch-mob", targetId: "epoch-mob", now: 0,
}).auras, "threat")).toBeCloseTo(0.80);
});
it("expires Defensive Stance, switches exclusively into metadata-only Battle Stance, then removes it on reset", () => {
const defensive = supportedEnemyStanceAuraDefinition(enemyStanceContract(7164, "ascension")!);
const battle = supportedEnemyStanceAuraDefinition(enemyStanceContract(7165, "ascension")!);
const first = applyAura([], { definition: defensive, sourceId: "mob", targetId: "mob", now: 10 }).auras;
expect(expireAuras(first, 180_009).active).toHaveLength(1);
expect(expireAuras(first, 180_010)).toMatchObject({ active: [], expired: first });
const switchedResult = applyAura(first, { definition: battle, sourceId: "mob", targetId: "mob", now: 20 });
const switched = switchedResult.auras;
expect(defensive.exclusiveGroup).toBe("enemy-warrior-stance");
expect(battle.exclusiveGroup).toBe("enemy-warrior-stance");
expect(switched).toHaveLength(1);
expect(switched[0]).toMatchObject({
definition: {
id: "enemy-source-spell-7165",
modifiers: [],
utilityTags: ["enemy-warrior-stance", "enemy-warrior-form:17", "enemy-passive-spell:21156"],
},
appliedAt: 20,
expiresAt: null,
});
expect(switchedResult.replaced?.definition.id).toBe("enemy-source-spell-7164");
expect(resolveDamageValue(100, switched, { direction: "taken", school: "physical", attackKind: "melee" })).toBe(100);
expect(removeEnemyStanceAura(switched, "another-mob")).toEqual(switched);
expect(removeEnemyStanceAura(switched, "mob")).toEqual([]);
});
});