Files
healer-man/src/game/wotlkStats.test.ts
T
2026-09-06 11:06:03 -04:00

93 lines
3.4 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { EMPTY_ITEM_STATS } from "./itemStats";
import {
baseAttributesFor,
baseResourcesFor,
damageAfterEquipmentMitigation,
deriveCharacterStats,
hastedDuration,
healthFromTotalStamina,
MANA_POOL_MULTIPLIER,
ratingMultiplier,
ratingPerPercent,
} from "./wotlkStats";
describe("WoW 3.3.5a character stats", () => {
it("uses the authored race/class base-stat table", () => {
expect(baseAttributesFor("warrior", 1, "human")).toEqual({
strength: 23,
agility: 20,
stamina: 22,
intellect: 20,
spirit: 20,
});
});
it("uses exact client combat-rating conversions at low level and level 80", () => {
expect(ratingMultiplier("meleeHit", 20)).toBeCloseTo(0.433333, 5);
expect(ratingPerPercent("meleeHit", 80)).toBeCloseTo(32.789989, 5);
expect(ratingPerPercent("spellHit", 80)).toBeCloseTo(26.231993, 5);
expect(ratingPerPercent("meleeCrit", 80)).toBeCloseTo(45.905987, 5);
expect(ratingMultiplier("meleeHaste", 20, "paladin")).toBeGreaterThan(
ratingMultiplier("meleeHaste", 20, "warrior"),
);
});
it("turns primary attributes into class resources and combat power", () => {
const warriorBase = deriveCharacterStats("warrior", 20, EMPTY_ITEM_STATS);
const warriorGeared = deriveCharacterStats("warrior", 20, {
...EMPTY_ITEM_STATS,
strength: 10,
stamina: 10,
});
expect(warriorGeared.attackPower - warriorBase.attackPower).toBe(20);
expect(warriorGeared.health - warriorBase.health).toBe(100);
const mageBase = deriveCharacterStats("mage", 20, EMPTY_ITEM_STATS);
const mageGeared = deriveCharacterStats("mage", 20, {
...EMPTY_ITEM_STATS,
intellect: 10,
spirit: 10,
spellPower: 7,
mp5: 4,
});
expect(mageGeared.mana - mageBase.mana).toBe(150 * MANA_POOL_MULTIPLIER);
expect(mageGeared.spellPower).toBe(7);
expect(mageGeared.spellCritPercent).toBeGreaterThan(mageBase.spellCritPercent);
expect(mageGeared.manaPer5).toBeGreaterThan(mageBase.manaPer5 + 4);
});
it("applies automatic Ascension racial passives to starting attributes and pools", () => {
const humanMage = deriveCharacterStats("mage", 1, EMPTY_ITEM_STATS, "human");
const gnomeMage = deriveCharacterStats("mage", 1, EMPTY_ITEM_STATS, "gnome");
expect(gnomeMage.intellect).toBeGreaterThan(baseAttributesFor("mage", 1, "gnome").intellect);
expect(gnomeMage.mana).toBeGreaterThan(humanMage.mana);
const taurenAttributes = baseAttributesFor("warrior", 1, "tauren");
const taurenWithoutEndurance = baseResourcesFor("warrior", 1).health
+ healthFromTotalStamina(taurenAttributes.stamina);
const taurenWarrior = deriveCharacterStats("warrior", 1, EMPTY_ITEM_STATS, "tauren");
expect(taurenWarrior.health).toBeGreaterThan(taurenWithoutEndurance);
});
it("makes haste, armor, avoidance, block, and resistances affect combat", () => {
expect(hastedDuration(2_000, 25)).toBe(1_600);
const physical = damageAfterEquipmentMitigation(100, {
...EMPTY_ITEM_STATS,
strength: 8,
agility: 8,
armor: 200,
defenseRating: 6,
dodgeRating: 5,
blockRating: 5,
blockValue: 10,
}, 20);
const fire = damageAfterEquipmentMitigation(100, {
...EMPTY_ITEM_STATS,
fireResistance: 100,
}, 20, "fire", 20);
expect(physical).toBeLessThan(100);
expect(fire).toBeLessThan(100);
});
});