forked from phenom/healer-man
154 lines
7.2 KiB
TypeScript
154 lines
7.2 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
import { abilityById } from "./abilityCatalog";
|
|
import { PLAYER_AGGRO_ID } from "./aggro";
|
|
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
|
|
import { useCombatStore, equipmentAdjustedCombatAmount } from "./combatStore";
|
|
import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime";
|
|
import { clearPartyRuntimeRegistry, registerPartyRuntimePosition, updatePartyRuntimeTargetVisibility } from "./partyRuntimeRegistry";
|
|
import { createConfiguredPartyMember, usePartyStore } from "./partyStore";
|
|
import { ROM_PRIEST_HOLY_BLESSING_TAG, romPriestHolyBlessingStats } from "./romPriestHolyBlessingRuntime";
|
|
import { resolveDamageValue } from "./combatAuras";
|
|
import { deriveCharacterStats } from "./wotlkStats";
|
|
|
|
const spell = abilityById("rom-priest-general-1");
|
|
const spellEffect = spell?.effects.find((effect) => effect.kind === "damage");
|
|
|
|
function damageWithSchool(targetId: string, sourceActorId: string, school: "holy" | "nature", now: number) {
|
|
return useCombatStore.getState().damageMob(
|
|
targetId,
|
|
1_000,
|
|
now,
|
|
{ actorId: sourceActorId, role: "damage" },
|
|
school,
|
|
{
|
|
attackKind: "spell",
|
|
seed: `holy-blessing:${sourceActorId}:${school}:${now}`,
|
|
rules: {
|
|
canMiss: false,
|
|
canCrit: false,
|
|
canDodge: false,
|
|
canParry: false,
|
|
canBlock: false,
|
|
},
|
|
},
|
|
).amount;
|
|
}
|
|
|
|
describe("RoM Priest Holy Blessing combat integration", () => {
|
|
beforeEach(() => {
|
|
clearMobRuntimeRegistry();
|
|
clearPartyRuntimeRegistry();
|
|
resetPartyRuntimeClock();
|
|
useCombatStore.getState().initializeCharacter({
|
|
classId: "rom-priest",
|
|
raceId: "rom-human",
|
|
level: 80,
|
|
role: "healer",
|
|
});
|
|
usePartyStore.getState().initializeParty(
|
|
"rom-priest-holy-blessing-integration", 80, useCombatStore.getState().health, "healer", 2, "rom",
|
|
);
|
|
for (const id of ["holy-blessing-holy-target", "holy-blessing-nature-target"]) {
|
|
useCombatStore.getState().registerMob(id, { name: id, maxHealth: 100_000, level: 80 });
|
|
setMobPosition(id, [3, 0, 0]);
|
|
}
|
|
});
|
|
|
|
it("adds the Wisdom-derived spell power to a real player spell amount and buffs only Holy damage", () => {
|
|
if (!spell || spellEffect?.kind !== "damage") throw new Error("Missing generated Priest spell damage row");
|
|
const state = useCombatStore.getState();
|
|
const passiveAura = state.auras.find((aura) => aura.targetId === PLAYER_AGGRO_ID
|
|
&& aura.definition.utilityTags?.includes(ROM_PRIEST_HOLY_BLESSING_TAG));
|
|
expect(passiveAura).toBeDefined();
|
|
const base = deriveCharacterStats("rom-priest", 80, state.gearStats, state.raceId, {}, state.secondaryClassId);
|
|
const bonus = romPriestHolyBlessingStats(base, state.auras).spellPowerBonus;
|
|
const expectedAmount = equipmentAdjustedCombatAmount(spellEffect, 80, state.gearStats, "rom-priest", spell, bonus);
|
|
const unblessedAmount = equipmentAdjustedCombatAmount(spellEffect, 80, state.gearStats, "rom-priest", spell);
|
|
const playerSourceAuras = state.auras.filter((aura) => aura.targetId === PLAYER_AGGRO_ID);
|
|
const expectedCombatAmount = resolveDamageValue(expectedAmount, playerSourceAuras, {
|
|
direction: "dealt", school: "frost", attackKind: "spell",
|
|
});
|
|
const unblessedCombatAmount = resolveDamageValue(
|
|
unblessedAmount,
|
|
playerSourceAuras.filter((aura) => !aura.definition.utilityTags?.includes(ROM_PRIEST_HOLY_BLESSING_TAG)),
|
|
{ direction: "dealt", school: "frost", attackKind: "spell" },
|
|
);
|
|
expect(bonus).toBeGreaterThan(0);
|
|
expect(expectedCombatAmount).toBeGreaterThan(unblessedCombatAmount);
|
|
|
|
useCombatStore.getState().selectMob("holy-blessing-nature-target");
|
|
expect(useCombatStore.getState().castAbility(spell.id, undefined, 1_000)).toMatchObject({ ok: true });
|
|
useCombatStore.getState().tick(3, 5_000);
|
|
const damage = useCombatStore.getState().combatEvents.find((event) => event.kind === "damage"
|
|
&& event.sourceActorId === PLAYER_AGGRO_ID && event.abilityId === spell.id);
|
|
expect(damage).toBeDefined();
|
|
expect(damage?.rawAmount).toBe(Math.round(expectedCombatAmount * (damage?.critical ? 1.5 : 1)));
|
|
|
|
const holy = damageWithSchool("holy-blessing-holy-target", PLAYER_AGGRO_ID, "holy", 21_000);
|
|
const nature = damageWithSchool("holy-blessing-nature-target", PLAYER_AGGRO_ID, "nature", 22_000);
|
|
expect(holy).toBe(2_009);
|
|
expect(nature).toBe(1_000);
|
|
});
|
|
|
|
it("adds the Wisdom-derived spell power to a generated-companion spell and buffs only Holy damage", () => {
|
|
if (!spell || spellEffect?.kind !== "damage") throw new Error("Missing generated Priest spell damage row");
|
|
const seed = "rom-priest-holy-blessing-companion";
|
|
const priest = createConfiguredPartyMember({
|
|
name: "Holy Blessing Priest",
|
|
classId: "rom-priest",
|
|
specialization: "Primary",
|
|
role: "healer",
|
|
}, 80, 0, seed);
|
|
usePartyStore.setState({ members: [{
|
|
...priest,
|
|
status: "attacking",
|
|
resource: 10_000,
|
|
maxResource: 10_000,
|
|
resourcePools: { ...priest.resourcePools, mana: 10_000 },
|
|
activeCast: {
|
|
abilityId: spell.id,
|
|
school: "frost",
|
|
mode: "cast",
|
|
startedAt: 500,
|
|
completesAt: 1_000,
|
|
originalDurationMs: 500,
|
|
pushbackHits: 0,
|
|
origin: [0, 0, 0],
|
|
targetId: "holy-blessing-nature-target",
|
|
},
|
|
activeCastTargetId: "holy-blessing-nature-target",
|
|
}] });
|
|
registerPartyRuntimePosition(priest.id, [0, 0, 0]);
|
|
updatePartyRuntimeTargetVisibility(priest.id, "holy-blessing-nature-target", true);
|
|
usePartyStore.getState().setCommand("attack");
|
|
useCombatStore.getState().synchronizeActors();
|
|
|
|
const beforeCastAuras = useCombatStore.getState().auras.filter((aura) => aura.targetId === priest.id);
|
|
expect(beforeCastAuras.some((aura) => aura.definition.utilityTags?.includes(ROM_PRIEST_HOLY_BLESSING_TAG)))
|
|
.toBe(false);
|
|
advanceDungeonPartyCombat(1_000);
|
|
|
|
const state = useCombatStore.getState();
|
|
const companionAura = state.auras.filter((aura) => aura.targetId === priest.id);
|
|
expect(companionAura.some((aura) => aura.definition.utilityTags?.includes(ROM_PRIEST_HOLY_BLESSING_TAG)))
|
|
.toBe(true);
|
|
const base = deriveCharacterStats(
|
|
priest.classId, priest.level, priest.gearStats, priest.raceId, {}, priest.secondaryClassId,
|
|
);
|
|
const bonus = romPriestHolyBlessingStats(base, companionAura).spellPowerBonus;
|
|
const expectedAmount = equipmentAdjustedCombatAmount(spellEffect, 80, priest.gearStats, "rom-priest", spell, bonus);
|
|
const unblessedAmount = equipmentAdjustedCombatAmount(spellEffect, 80, priest.gearStats, "rom-priest", spell);
|
|
expect(bonus).toBeGreaterThan(0);
|
|
expect(expectedAmount).toBeGreaterThan(unblessedAmount);
|
|
const damage = state.combatEvents.find((event) => event.kind === "damage"
|
|
&& event.sourceActorId === priest.id && event.abilityId === spell.id);
|
|
expect(damage).toBeDefined();
|
|
expect(damage?.rawAmount).toBe(expectedAmount);
|
|
|
|
const holy = damageWithSchool("holy-blessing-holy-target", priest.id, "holy", 5_000);
|
|
const nature = damageWithSchool("holy-blessing-nature-target", priest.id, "nature", 6_000);
|
|
expect(holy).toBe(2_009);
|
|
expect(nature).toBe(1_000);
|
|
});
|
|
});
|