forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
4c768fbec6
commit
b16821e92e
330 files changed
+35406
-1760
No files matched your search
@@ -0,0 +1,171 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { EMPTY_ITEM_STATS } from "./itemStats";
|
||||
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
|
||||
import { clearPartyRuntimeRegistry } from "./partyRuntimeRegistry";
|
||||
import { usePartyStore, createConfiguredPartyMember } from "./partyStore";
|
||||
import { PLAYER_AURA_ENTITY_ID, useCombatStore } from "./combatStore";
|
||||
import {
|
||||
WOW335_SHAMAN_FLURRY_AURA_TAG,
|
||||
WOW335_SHAMAN_FLURRY_DURATION_MS,
|
||||
} from "./wow335ShamanFlurryRuntime";
|
||||
|
||||
const TARGET_ID = "wow335-shaman-flurry-target";
|
||||
const FLURRY_RANK_ID = "talent-602";
|
||||
|
||||
function registerTarget(): void {
|
||||
useCombatStore.getState().registerMob(TARGET_ID, {
|
||||
name: "Flurry target",
|
||||
level: 80,
|
||||
maxHealth: 1_000_000,
|
||||
xpReward: 0,
|
||||
});
|
||||
setMobPosition(TARGET_ID, [3, 0, 0]);
|
||||
useCombatStore.setState((state) => ({
|
||||
mobs: {
|
||||
...state.mobs,
|
||||
[TARGET_ID]: {
|
||||
...state.mobs[TARGET_ID]!,
|
||||
characterDefender: { level: 80, dodgePercent: 0, parryPercent: 0, blockPercent: 0 },
|
||||
},
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
function setupPlayerShaman(rank: number): void {
|
||||
clearMobRuntimeRegistry();
|
||||
clearPartyRuntimeRegistry();
|
||||
useCombatStore.getState().initializeCharacter({ classId: "shaman", level: 80, xp: 0 });
|
||||
useCombatStore.getState().resetSettings();
|
||||
useCombatStore.getState().setPlayerPosition([0, 0, 0]);
|
||||
usePartyStore.getState().initializeParty("wow-shaman-flurry-player", 80, useCombatStore.getState().health);
|
||||
registerTarget();
|
||||
useCombatStore.setState((state) => ({
|
||||
gearStats: {
|
||||
...state.gearStats,
|
||||
hitRating: 100_000,
|
||||
criticalStrikeRating: 100_000,
|
||||
expertiseRating: 100_000,
|
||||
},
|
||||
talentRanks: { ...state.talentRanks, [FLURRY_RANK_ID]: rank },
|
||||
autoAttackTargetId: TARGET_ID,
|
||||
nextAutoAttackAt: 1_000,
|
||||
}));
|
||||
}
|
||||
|
||||
function flurryAura(actorId: string) {
|
||||
return useCombatStore.getState().auras.find((aura) => (
|
||||
aura.sourceId === actorId
|
||||
&& aura.targetId === actorId
|
||||
&& aura.definition.utilityTags?.includes(WOW335_SHAMAN_FLURRY_AURA_TAG)
|
||||
));
|
||||
}
|
||||
|
||||
describe("WoW Shaman Flurry combat integration", () => {
|
||||
beforeEach(() => setupPlayerShaman(0));
|
||||
|
||||
it("procs from the player's landed melee crit and hastens the next main-hand interval", () => {
|
||||
const intervalForRank = (rank: number) => {
|
||||
setupPlayerShaman(rank);
|
||||
useCombatStore.getState().tick(0.1, 1_000);
|
||||
const state = useCombatStore.getState();
|
||||
expect(state.lastCombatResult?.critical).toBe(true);
|
||||
expect(state.lastCombatResult?.landed).toBe(true);
|
||||
return state.nextAutoAttackAt - 1_000;
|
||||
};
|
||||
|
||||
const baselineInterval = intervalForRank(0);
|
||||
const flurryInterval = intervalForRank(1);
|
||||
const aura = flurryAura(PLAYER_AURA_ENTITY_ID);
|
||||
expect(flurryInterval).toBeLessThan(baselineInterval);
|
||||
expect(aura).toMatchObject({
|
||||
stacks: 3,
|
||||
appliedAt: 1_000,
|
||||
expiresAt: 1_000 + WOW335_SHAMAN_FLURRY_DURATION_MS,
|
||||
definition: {
|
||||
modifiers: [{ kind: "stat", stat: "melee-haste", operation: "flat", value: 4, perStack: false }],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("uses a generated companion Shaman's exact rank and consumes the next three autoattack attempts", () => {
|
||||
clearMobRuntimeRegistry();
|
||||
clearPartyRuntimeRegistry();
|
||||
useCombatStore.getState().initializeCharacter({ classId: "mage", level: 80, xp: 0 });
|
||||
usePartyStore.getState().initializeParty("wow-shaman-flurry-companion", 80, useCombatStore.getState().health);
|
||||
const baseMember = createConfiguredPartyMember({
|
||||
name: "Flurry Shaman",
|
||||
classId: "shaman",
|
||||
specialization: "Enhancement",
|
||||
specializationId: "shaman:enhancement",
|
||||
talentTreeId: "shaman-enhancement",
|
||||
talentRanks: { [FLURRY_RANK_ID]: 2 },
|
||||
role: "damage",
|
||||
}, 80, 0, "wow-shaman-flurry-companion:member");
|
||||
const member = {
|
||||
...baseMember,
|
||||
gearStats: { ...EMPTY_ITEM_STATS, hitRating: 100_000, criticalStrikeRating: 100_000, expertiseRating: 100_000 },
|
||||
health: baseMember.maxHealth,
|
||||
};
|
||||
usePartyStore.setState({ members: [member] });
|
||||
useCombatStore.getState().commitCompanionActors([member]);
|
||||
registerTarget();
|
||||
|
||||
const trigger = useCombatStore.getState().damageMob(
|
||||
TARGET_ID,
|
||||
100,
|
||||
2_000,
|
||||
{ actorId: member.id, role: member.role, abilityId: "party-auto-attack" },
|
||||
"physical",
|
||||
{
|
||||
attackKind: "melee",
|
||||
seed: "flurry-companion-trigger",
|
||||
abilityId: "party-auto-attack",
|
||||
rules: {
|
||||
isAutoAttack: true,
|
||||
canMiss: false,
|
||||
canDodge: false,
|
||||
canParry: false,
|
||||
canBlock: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(trigger.combatResult?.landed).toBe(true);
|
||||
expect(trigger.combatResult?.critical).toBe(true);
|
||||
expect(flurryAura(member.id)).toMatchObject({
|
||||
stacks: 3,
|
||||
definition: {
|
||||
modifiers: [{ kind: "stat", stat: "melee-haste", operation: "flat", value: 6, perStack: false }],
|
||||
},
|
||||
});
|
||||
// A fake rank on the Mage player must not supply the companion's Flurry value.
|
||||
useCombatStore.setState((state) => ({
|
||||
talentRanks: { ...state.talentRanks, [FLURRY_RANK_ID]: 3 },
|
||||
}));
|
||||
|
||||
for (let swing = 1; swing <= 3; swing += 1) {
|
||||
useCombatStore.getState().damageMob(
|
||||
TARGET_ID,
|
||||
100,
|
||||
2_000 + swing * 100,
|
||||
{ actorId: member.id, role: member.role, abilityId: "party-auto-attack" },
|
||||
"physical",
|
||||
{
|
||||
attackKind: "melee",
|
||||
seed: `flurry-companion-swing-${swing}`,
|
||||
abilityId: "party-auto-attack",
|
||||
rules: {
|
||||
isAutoAttack: true,
|
||||
canCrit: false,
|
||||
canMiss: false,
|
||||
canDodge: false,
|
||||
canParry: false,
|
||||
canBlock: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
const aura = flurryAura(member.id);
|
||||
expect(aura?.stacks ?? 0).toBe(3 - swing);
|
||||
}
|
||||
expect(flurryAura(PLAYER_AURA_ENTITY_ID)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user