Update Healer Man server

This commit is contained in:
phenom committed 2026-10-02 10:38:12 -04:00
1 parent 4c768fbec6
commit b16821e92e
330 files changed
+35406 -1760

No files matched your search

+79 -4
View File
@@ -1,12 +1,16 @@
import { describe, expect, it } from "vitest";
import { abilityAtLevel, abilitiesForClass, preloadAbilityCatalogsForClasses } from "./abilityCatalog";
import { useCombatStore } from "./combatStore";
import { clearMobRuntimeRegistry } from "./mobRuntimeRegistry";
import { clearPartyRuntimeRegistry, registerPartyRuntimePosition } from "./partyRuntimeRegistry";
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
import {
clearPartyRuntimeRegistry,
registerPartyRuntimePosition,
updatePartyRuntimeTargetVisibility,
} from "./partyRuntimeRegistry";
import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime";
import { createConfiguredPartyMember, usePartyStore, type PartyMember } from "./partyStore";
import { EMPTY_ITEM_STATS } from "./itemStats";
import { partyAbilityAmount } from "./partyAbilityAi";
import { partyAbilityAmount, partyAbilityCosts } from "./partyAbilityAi";
import { WOW335_SHAMAN_TIDAL_WAVES_AURA_TAG } from "./wow335ShamanTidalWavesRuntime";
function stableUnit(seed: string): number {
@@ -52,6 +56,8 @@ async function setupShamanParty(options: {
readonly tidalRank?: number;
readonly riptideRank?: number;
readonly waterShieldRank?: number;
readonly improvedShieldsRank?: number;
readonly elementalFocusRank?: number;
readonly secondShaman?: boolean;
readonly secondShamanTidalRank?: number;
readonly spellPower?: number;
@@ -69,6 +75,8 @@ async function setupShamanParty(options: {
"talent-2063": options.tidalRank ?? 0,
"talent-2064": options.riptideRank ?? 0,
"talent-583": options.waterShieldRank ?? 0,
"talent-607": options.improvedShieldsRank ?? 0,
"talent-574": options.elementalFocusRank ?? 0,
};
const firstShamanBase = createConfiguredPartyMember({
name: "Party Shaman",
@@ -150,11 +158,77 @@ function findPartyHealTime(
}
describe("party WoW Shaman healing talents", () => {
it("grants and consumes party Elemental Focus Clearcasting after a critical elemental spell", async () => {
const members = await setupShamanParty({ elementalFocusRank: 2, criticalStrikeRating: 1_000_000 });
const shaman = members[0];
const bolt = shamanAbility("Lightning Bolt");
const targetId = "shaman-elemental-focus-party-target";
useCombatStore.getState().registerMob(targetId, {
name: "Elemental Focus target",
level: 80,
maxHealth: 100_000,
xpReward: 0,
});
setMobPosition(targetId, [2, 0, 0]);
useCombatStore.getState().damageMob(targetId, 1, 500);
updatePartyRuntimeTargetVisibility(shaman.id, targetId, true);
const damageShaman: PartyMember = {
...onlyReady(shaman, "Lightning Bolt"),
role: "damage",
health: shaman.maxHealth,
globalCooldownEndsAt: 0,
nextActionAt: 0,
};
const fullManaCost = partyAbilityCosts(damageShaman, bolt, 1_000)
.find((cost) => cost.resource === "mana")?.amount;
usePartyStore.setState((state) => ({
command: "attack",
activeMobId: targetId,
members: state.members.map((member) => member.id === shaman.id
? damageShaman
: { ...member, cooldowns: Object.fromEntries(abilitiesForClass("warrior").map((ability) => [ability.id, 1_000_000])) }),
}));
useCombatStore.getState().commitCompanionActors(usePartyStore.getState().members);
advanceDungeonPartyCombat(1_000);
const firstCast = usePartyStore.getState().members.find((member) => member.id === shaman.id)?.activeCast;
expect(firstCast?.abilityId).toBe(bolt.id);
advanceDungeonPartyCombat(firstCast!.completesAt);
const hit = [...useCombatStore.getState().combatEvents].reverse().find((event) => (
event.kind === "damage" && event.sourceActorId === shaman.id && event.abilityId === bolt.id
));
expect(hit).toMatchObject({ critical: true });
const clearcasting = () => useCombatStore.getState().auras.find((aura) => (
aura.sourceId === shaman.id
&& aura.targetId === shaman.id
&& aura.definition.utilityTags?.includes("wow335-shaman-elemental-focus-clearcasting")
));
expect(clearcasting()).toMatchObject({ stacks: 2, expiresAt: hit!.occurredAt + 15_000 });
expect(fullManaCost).toBeGreaterThan(0);
expect(partyAbilityCosts(shaman, bolt, hit!.occurredAt)
.find((cost) => cost.resource === "mana")?.amount).toBe(Math.round(fullManaCost! * 0.7));
const currentShaman = usePartyStore.getState().members.find((member) => member.id === shaman.id)!;
usePartyStore.setState((state) => ({
members: state.members.map((member) => member.id === shaman.id
? { ...onlyReady(currentShaman, "Lightning Bolt"), globalCooldownEndsAt: 0, nextActionAt: 0 }
: member),
}));
useCombatStore.getState().commitCompanionActors(usePartyStore.getState().members);
advanceDungeonPartyCombat(hit!.occurredAt + 1_000);
expect(usePartyStore.getState().members.find((member) => member.id === shaman.id)?.activeCast?.abilityId)
.toBe(bolt.id);
expect(clearcasting()?.stacks).toBe(1);
});
it("procs rank-owned Improved Water Shield from its own critical Healing Wave and restores only its mana", async () => {
const members = await setupShamanParty({
tidalRank: 3,
riptideRank: 1,
waterShieldRank: 3,
improvedShieldsRank: 3,
spellPower: 1_000,
criticalStrikeRating: 100_000,
secondShaman: true,
@@ -225,7 +299,8 @@ describe("party WoW Shaman healing talents", () => {
expect(healingEvent?.rawAmount).toBe(Math.round((ordinaryHeal + 120) * 1.5));
expect(waterShieldEvent).toMatchObject({
targetActorId: shaman.id,
effectiveAmount: 400,
rawAmount: 460,
effectiveAmount: 460,
overheal: 0,
});
expect(combat.combatEvents).not.toContainEqual(expect.objectContaining({