Files
healer-man/src/game/enemyBlocking.test.ts
2026-10-07 13:05:04 -04:00

302 lines
12 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { enemySourceAuraContract } from "./enemySourceAuras";
import {
canEnemyNpcBlock,
canEnemyNpcBlockSpell,
classifyEnemyNpcSpellBlockPhase,
CREATURE_FLAG_EXTRA_NO_BLOCK,
enemyNpcSourceSpellBlockMetadata,
enemyNpcBlockChanceAfterSkill,
enemyNpcSpellBlockChanceAfterSkill,
resolveEnemyNpcBlockStats,
SPELL_ATTR0_CU_DIRECT_DAMAGE,
SPELL_ATTR0_CU_BLOCKING_KNOWN_MASK,
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET,
SPELL_ATTR0_NO_ACTIVE_DEFENSE,
SPELL_ATTR3_ALWAYS_HIT,
SPELL_ATTR3_COMPLETELY_BLOCKED,
SPELL_DAMAGE_CLASS_MAGIC,
SPELL_DAMAGE_CLASS_MELEE,
SPELL_DAMAGE_CLASS_RANGED,
SPELL_SCHOOL_MASK_NORMAL,
} from "./enemyBlocking";
const baseWeaponInput = {
attack: "melee-auto" as const,
blockPercent: 5,
flagsExtra: 0,
isTotem: false,
attackerLevel: 80,
defenderLevel: 80,
attackerIsBehind: false,
ignoresHitDirection: false,
isCastingNonMeleeSpell: false,
isControlled: false,
isEvadingAttacks: false,
};
const physicalDirectSpell = {
damageClass: SPELL_DAMAGE_CLASS_MELEE,
schoolMask: SPELL_SCHOOL_MASK_NORMAL,
attributes0: 0,
attributes3: 0,
directDamageFromEffects: true,
sourceProfile: "wow335" as const,
};
const baseSpellInput = {
spell: physicalDirectSpell,
blockPercent: 5,
flagsExtra: 0,
isTotem: false,
attackerWeaponSkill: 400,
defenderLevel: 80,
attackerIsBehind: false,
ignoresHitDirection: false,
isCastingNonMeleeSpell: false,
isControlled: false,
};
describe("source-backed enemy NPC blocking", () => {
it("uses the ordinary-creature base chance and inherent level-only block value", () => {
expect(resolveEnemyNpcBlockStats({
level: 79,
blockChanceAuraPercent: 0,
isTotem: false,
})).toEqual({ blockPercent: 5, blockValue: 39 });
});
it("adds Improved Blocking's sourced 75 percentage points in both profiles", () => {
for (const profile of ["ascension", "epoch"] as const) {
const contract = enemySourceAuraContract(3419, profile);
expect(contract?.durationMs).toBe(6_000);
expect(contract?.signature.effects).toContainEqual(expect.objectContaining({
auraType: 51,
basePoints: 75,
}));
expect(resolveEnemyNpcBlockStats({
level: 60,
blockChanceAuraPercent: contract!.signature.effects[0]!.basePoints,
isTotem: false,
})).toEqual({ blockPercent: 80, blockValue: 30 });
}
});
it("keeps totems at zero block chance and clamps negative aura totals", () => {
expect(resolveEnemyNpcBlockStats({
level: 60,
blockChanceAuraPercent: 75,
isTotem: true,
})).toEqual({ blockPercent: 0, blockValue: 30 });
expect(resolveEnemyNpcBlockStats({
level: 60,
blockChanceAuraPercent: -10,
isTotem: false,
})?.blockPercent).toBe(0);
});
it("fails closed outside the simulator level cap or for unsourced numeric inputs", () => {
expect(resolveEnemyNpcBlockStats({
level: 81,
blockChanceAuraPercent: 75,
isTotem: false,
})).toBeNull();
expect(resolveEnemyNpcBlockStats({
level: 60,
blockChanceAuraPercent: Number.NaN,
isTotem: false,
})).toBeNull();
expect(enemyNpcBlockChanceAfterSkill({ blockPercent: 5, attackerLevel: 81, defenderLevel: 80 })).toBeNull();
});
it("gates creature no-block, rear, casting, controlled, evading, and nonpositive skill-adjusted chances", () => {
expect(canEnemyNpcBlock({ ...baseWeaponInput, flagsExtra: CREATURE_FLAG_EXTRA_NO_BLOCK })).toBe(false);
expect(canEnemyNpcBlock({ ...baseWeaponInput, attackerIsBehind: true })).toBe(false);
expect(canEnemyNpcBlock({ ...baseWeaponInput, isCastingNonMeleeSpell: true })).toBe(false);
expect(canEnemyNpcBlock({ ...baseWeaponInput, isControlled: true })).toBe(false);
expect(canEnemyNpcBlock({ ...baseWeaponInput, isEvadingAttacks: true })).toBe(false);
expect(canEnemyNpcBlock({ ...baseWeaponInput, attackerLevel: 81 })).toBe(false);
expect(canEnemyNpcBlock({ ...baseWeaponInput, isTotem: true })).toBe(false);
});
it("allows ranged weapon blocks and applies the sourced four-hundredths skill adjustment", () => {
expect(canEnemyNpcBlock({
...baseWeaponInput,
attack: "ranged-auto",
})).toBe(true);
expect(enemyNpcBlockChanceAfterSkill({ blockPercent: 80, attackerLevel: 70, defenderLevel: 80 })).toBe(82);
expect(enemyNpcBlockChanceAfterSkill({ blockPercent: 80, attackerLevel: 80, defenderLevel: 70 })).toBe(78);
expect(enemyNpcBlockChanceAfterSkill({ blockPercent: 5, attackerLevel: 80, defenderLevel: 55 })).toBe(0);
expect(enemyNpcBlockChanceAfterSkill({ blockPercent: 0, attackerLevel: 1, defenderLevel: 80 })).toBe(0);
});
it("fails closed for spell and other packets until spell attributes are imported", () => {
expect(canEnemyNpcBlock({ ...baseWeaponInput, attack: "spell" })).toBe(false);
expect(canEnemyNpcBlock({ ...baseWeaponInput, attack: "other" })).toBe(false);
});
it("classifies source-backed physical direct-damage melee and ranged spells for post-hit blocking", () => {
expect(classifyEnemyNpcSpellBlockPhase(physicalDirectSpell)).toBe("direct-damage");
expect(classifyEnemyNpcSpellBlockPhase({
...physicalDirectSpell,
damageClass: SPELL_DAMAGE_CLASS_RANGED,
sourceProfile: "ascension",
})).toBe("direct-damage");
expect(classifyEnemyNpcSpellBlockPhase({
...physicalDirectSpell,
damageClass: SPELL_DAMAGE_CLASS_MAGIC,
})).toBe("none");
expect(classifyEnemyNpcSpellBlockPhase({
...physicalDirectSpell,
schoolMask: 0x10,
})).toBe("none");
expect(classifyEnemyNpcSpellBlockPhase({
...physicalDirectSpell,
attributes0: SPELL_ATTR0_NO_ACTIVE_DEFENSE,
})).toBe("none");
expect(classifyEnemyNpcSpellBlockPhase({
...physicalDirectSpell,
attributes3: SPELL_ATTR3_ALWAYS_HIT,
})).toBe("none");
});
it("requires explicit AzerothCore custom attributes before enabling a hit-table full block", () => {
const nonDirect = {
...physicalDirectSpell,
directDamageFromEffects: false,
attributes3: SPELL_ATTR3_COMPLETELY_BLOCKED,
};
expect(classifyEnemyNpcSpellBlockPhase(nonDirect)).toBe("none");
expect(classifyEnemyNpcSpellBlockPhase({ ...nonDirect, customAttributes: 0 })).toBe("hit-table");
expect(classifyEnemyNpcSpellBlockPhase({
...nonDirect,
damageClass: SPELL_DAMAGE_CLASS_MAGIC,
customAttributes: 0,
})).toBe("none");
expect(classifyEnemyNpcSpellBlockPhase({
...nonDirect,
attributes0: SPELL_ATTR0_NO_ACTIVE_DEFENSE,
customAttributes: 0,
})).toBe("none");
expect(classifyEnemyNpcSpellBlockPhase({
...nonDirect,
attributes3: SPELL_ATTR3_COMPLETELY_BLOCKED | SPELL_ATTR3_ALWAYS_HIT,
customAttributes: 0,
})).toBe("none");
expect(classifyEnemyNpcSpellBlockPhase({
...nonDirect,
customAttributes: SPELL_ATTR0_CU_DIRECT_DAMAGE,
})).toBe("direct-damage");
expect(classifyEnemyNpcSpellBlockPhase({ ...nonDirect, customAttributes: -1 })).toBeNull();
expect(classifyEnemyNpcSpellBlockPhase({ ...physicalDirectSpell, sourceProfile: "epoch" as never })).toBeNull();
});
it("uses only the two source-proven custom bits for the three exact utility ranks", () => {
const shieldBash = enemyNpcSourceSpellBlockMetadata(72, "wow335");
expect(shieldBash).toMatchObject({
damageClass: SPELL_DAMAGE_CLASS_MELEE,
schoolMask: SPELL_SCHOOL_MASK_NORMAL,
attributes0: 327696,
attributes3: SPELL_ATTR3_COMPLETELY_BLOCKED,
directDamageFromEffects: false,
sourceProfile: "wow335",
customAttributeEvidence: { knownMask: SPELL_ATTR0_CU_BLOCKING_KNOWN_MASK, value: 0 },
});
expect(classifyEnemyNpcSpellBlockPhase(shieldBash!)).toBe("hit-table");
expect(canEnemyNpcBlockSpell({
...baseSpellInput,
spell: shieldBash!,
attackerIsBehind: true,
ignoresHitDirection: true,
})).toBe(true);
expect(enemyNpcSourceSpellBlockMetadata(72, "ascension")).toBeUndefined();
expect(enemyNpcSourceSpellBlockMetadata(1766, "wow335")).toEqual(shieldBash);
expect(enemyNpcSourceSpellBlockMetadata(6552, "wow335")).toEqual(shieldBash);
expect(enemyNpcSourceSpellBlockMetadata(5246, "wow335")).toBeUndefined();
const unknownBehindBit = {
...shieldBash!,
customAttributeEvidence: { knownMask: SPELL_ATTR0_CU_DIRECT_DAMAGE, value: 0 },
};
expect(classifyEnemyNpcSpellBlockPhase(unknownBehindBit)).toBe("hit-table");
expect(canEnemyNpcBlockSpell({
...baseSpellInput,
spell: unknownBehindBit,
attackerIsBehind: true,
ignoresHitDirection: true,
})).toBe(false);
expect(classifyEnemyNpcSpellBlockPhase({
...shieldBash!,
customAttributes: 0,
customAttributeEvidence: { knownMask: SPELL_ATTR0_CU_BLOCKING_KNOWN_MASK, value: 0 },
})).toBe("hit-table");
expect(classifyEnemyNpcSpellBlockPhase({
...shieldBash!,
customAttributes: SPELL_ATTR0_CU_DIRECT_DAMAGE,
customAttributeEvidence: { knownMask: SPELL_ATTR0_CU_BLOCKING_KNOWN_MASK, value: 0 },
})).toBeNull();
});
it("uses the different source skill signs for hit-table and post-hit spell blocks", () => {
expect(enemyNpcSpellBlockChanceAfterSkill({
phase: "direct-damage", blockPercent: 5, attackerWeaponSkill: 450, defenderLevel: 80,
})).toBe(7);
expect(enemyNpcSpellBlockChanceAfterSkill({
phase: "hit-table", blockPercent: 5, attackerWeaponSkill: 450, defenderLevel: 80,
})).toBe(3);
expect(enemyNpcSpellBlockChanceAfterSkill({
phase: "direct-damage", blockPercent: 5, attackerWeaponSkill: 200, defenderLevel: 80,
})).toBe(0);
expect(enemyNpcSpellBlockChanceAfterSkill({
phase: "hit-table", blockPercent: 5, attackerWeaponSkill: 600, defenderLevel: 80,
})).toBe(0);
expect(enemyNpcSpellBlockChanceAfterSkill({
phase: "direct-damage", blockPercent: 0, attackerWeaponSkill: 450, defenderLevel: 80,
})).toBe(2);
expect(enemyNpcSpellBlockChanceAfterSkill({
phase: "hit-table", blockPercent: 0, attackerWeaponSkill: 350, defenderLevel: 80,
})).toBe(2);
});
it("applies direct-spell no-block, direction, cast, control, and skill gates", () => {
expect(canEnemyNpcBlockSpell(baseSpellInput)).toBe(true);
expect(canEnemyNpcBlockSpell({ ...baseSpellInput, flagsExtra: CREATURE_FLAG_EXTRA_NO_BLOCK })).toBe(false);
expect(canEnemyNpcBlockSpell({ ...baseSpellInput, isTotem: true })).toBe(false);
expect(canEnemyNpcBlockSpell({ ...baseSpellInput, attackerIsBehind: true })).toBe(false);
expect(canEnemyNpcBlockSpell({ ...baseSpellInput, attackerIsBehind: true, ignoresHitDirection: true })).toBe(true);
expect(canEnemyNpcBlockSpell({ ...baseSpellInput, isCastingNonMeleeSpell: true })).toBe(false);
expect(canEnemyNpcBlockSpell({ ...baseSpellInput, isControlled: true })).toBe(false);
expect(canEnemyNpcBlockSpell({ ...baseSpellInput, attackerWeaponSkill: 200 })).toBe(false);
expect(canEnemyNpcBlockSpell({
...baseSpellInput,
blockPercent: 0,
attackerWeaponSkill: 450,
})).toBe(true);
});
it("keeps hit-table spell direction exceptions and requires-behind attribute semantics", () => {
const hitTableSpell = {
damageClass: SPELL_DAMAGE_CLASS_MELEE,
schoolMask: SPELL_SCHOOL_MASK_NORMAL,
attributes0: 0,
attributes3: SPELL_ATTR3_COMPLETELY_BLOCKED,
directDamageFromEffects: false,
sourceProfile: "wow335" as const,
customAttributes: 0,
};
expect(canEnemyNpcBlockSpell({ ...baseSpellInput, spell: hitTableSpell })).toBe(true);
expect(canEnemyNpcBlockSpell({
...baseSpellInput,
spell: hitTableSpell,
attackerIsBehind: true,
ignoresHitDirection: true,
})).toBe(true);
expect(canEnemyNpcBlockSpell({
...baseSpellInput,
spell: { ...hitTableSpell, customAttributes: SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET },
attackerIsBehind: true,
ignoresHitDirection: true,
})).toBe(false);
});
});