forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
39458d5de6
commit
6cc1b9217f
203 files changed
+133929
-31271
No files matched your search
@@ -4,6 +4,7 @@ import { applyAura } from "./combatAuras";
|
||||
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
|
||||
import {
|
||||
clearPartyRuntimeRegistry,
|
||||
getPartyRuntimePosition,
|
||||
registerPartyRuntimePosition,
|
||||
updatePartyRuntimeAttackCorridor,
|
||||
updatePartyRuntimeTargetVisibility,
|
||||
@@ -1285,6 +1286,102 @@ describe("party combat runtime", () => {
|
||||
expect(autoAttackTimes).toEqual([2_200, 3_400]);
|
||||
});
|
||||
|
||||
it("runs party Rogue Killing Spree on its own timed window and frozen cast-time targets", () => {
|
||||
useCombatStore.getState().initializeCharacter({ classId: "mage", role: "damage", level: 80 });
|
||||
const seed = "killing-spree-party-runtime";
|
||||
const spree = abilitiesForClass("rogue").find((candidate) => candidate.name === "Killing Spree");
|
||||
if (!spree) throw new Error("Missing generated Rogue Killing Spree");
|
||||
const spreeTalentNodeId = abilityTalentNodeId(spree);
|
||||
if (!spreeTalentNodeId) throw new Error("Rogue Killing Spree has no generated talent node");
|
||||
const rogue = createConfiguredPartyMember({
|
||||
name: "Combat Rogue",
|
||||
classId: "rogue",
|
||||
specialization: "Combat",
|
||||
specializationId: "rogue:combat",
|
||||
talentTreeId: "rogue-combat",
|
||||
talentRanks: { [spreeTalentNodeId]: 1 },
|
||||
role: "damage",
|
||||
}, 80, 0, seed);
|
||||
usePartyStore.getState().initializeParty(seed, 80, useCombatStore.getState().health, "damage", 2);
|
||||
usePartyStore.setState({
|
||||
members: [{ ...rogue, nextActionAt: 0 }],
|
||||
command: "attack",
|
||||
activeMobId: "party-spree:a",
|
||||
});
|
||||
registerPartyRuntimePosition(rogue.id, [0, 0, 0]);
|
||||
useCombatStore.getState().synchronizeActors();
|
||||
registerEngagedMob("party-spree:a", 1_000_000);
|
||||
registerEngagedMob("party-spree:b", 1_000_000);
|
||||
useCombatStore.getState().selectMob("party-spree:a");
|
||||
usePartyStore.setState({ activeMobId: "party-spree:a", command: "attack" });
|
||||
setMobPosition("party-spree:b", [3, 0, 0]);
|
||||
updatePartyRuntimeTargetVisibility(rogue.id, "party-spree:b", true);
|
||||
updatePartyRuntimeTargetVisibility(rogue.id, "party-spree:a", true);
|
||||
advanceDungeonPartyCombat(1_000);
|
||||
|
||||
const window = useCombatStore.getState().killingSpreeWindows.find((candidate) => candidate.ownerActorId === rogue.id);
|
||||
expect(window).toMatchObject({
|
||||
ownerActorId: rogue.id,
|
||||
abilityId: spree.id,
|
||||
role: "damage",
|
||||
targetIds: ["party-spree:a", "party-spree:b"],
|
||||
startedAt: 1_000,
|
||||
nextAssaultAt: 1_000,
|
||||
completedAssaults: 0,
|
||||
});
|
||||
expect(useCombatStore.getState().auras).toContainEqual(expect.objectContaining({
|
||||
sourceId: rogue.id,
|
||||
targetId: rogue.id,
|
||||
expiresAt: 3_001,
|
||||
definition: expect.objectContaining({
|
||||
utilityTags: ["wow335-rogue-killing-spree"],
|
||||
modifiers: [{ kind: "damage", direction: "dealt", operation: "percent", value: 0.2 }],
|
||||
}),
|
||||
}));
|
||||
expect(usePartyStore.getState().members[0]?.cooldowns[spree.id]).toBeGreaterThan(1_000);
|
||||
|
||||
registerEngagedMob("party-spree:c", 1_000_000);
|
||||
setMobPosition("party-spree:c", [2, 0, 2]);
|
||||
updatePartyRuntimeTargetVisibility(rogue.id, "party-spree:c", true);
|
||||
useCombatStore.getState().advanceMobCombat(1_000);
|
||||
const firstPulse = useCombatStore.getState().combatEvents.filter((event) => (
|
||||
event.kind === "damage" && event.sourceActorId === rogue.id && event.abilityId === spree.id
|
||||
));
|
||||
expect(firstPulse.length).toBeGreaterThan(0);
|
||||
expect(firstPulse.every((event) => event.targetActorId !== "party-spree:c")).toBe(true);
|
||||
expect(getPartyRuntimePosition(rogue.id)).not.toEqual([0, 0, 0]);
|
||||
|
||||
for (const now of [1_499, 1_500, 2_000, 2_500, 3_000]) {
|
||||
useCombatStore.getState().advanceMobCombat(now);
|
||||
}
|
||||
const strikes = useCombatStore.getState().combatEvents.filter((event) => (
|
||||
event.kind === "damage" && event.sourceActorId === rogue.id && event.abilityId === spree.id
|
||||
));
|
||||
expect([...new Set(strikes.map((event) => event.occurredAt))]).toEqual([1_000, 1_500, 2_000, 2_500, 3_000]);
|
||||
expect(strikes.every((event) => event.targetActorId !== "party-spree:c")).toBe(true);
|
||||
expect(strikes.filter((event) => event.occurredAt === 3_000).map((event) => event.rawAmount))
|
||||
.toEqual(window!.hits.map((hit) => Math.round(hit.damage * 1.2)));
|
||||
expect(useCombatStore.getState().killingSpreeWindows).toHaveLength(0);
|
||||
expect(useCombatStore.getState().auras.some((aura) => aura.sourceId === rogue.id
|
||||
&& aura.targetId === rogue.id
|
||||
&& aura.definition.utilityTags?.includes("wow335-rogue-killing-spree"))).toBe(false);
|
||||
|
||||
expect(useCombatStore.getState().beginKillingSpree(
|
||||
rogue.id,
|
||||
spree,
|
||||
["party-spree:a"],
|
||||
[],
|
||||
"damage",
|
||||
3_001,
|
||||
)).toBe(true);
|
||||
expect(useCombatStore.getState().killingSpreeWindows).toHaveLength(1);
|
||||
usePartyStore.setState({ members: [] });
|
||||
useCombatStore.getState().advanceMobCombat(3_001);
|
||||
expect(useCombatStore.getState().killingSpreeWindows).toHaveLength(0);
|
||||
expect(useCombatStore.getState().auras.some((aura) => aura.sourceId === rogue.id
|
||||
&& aura.definition.utilityTags?.includes("wow335-rogue-killing-spree"))).toBe(false);
|
||||
});
|
||||
|
||||
it("precasts Earth Shield on the tank while the Restoration Shaman is at full health", () => {
|
||||
useCombatStore.getState().initializeCharacter({ classId: "mage", role: "damage", level: 80 });
|
||||
const tank = createConfiguredPartyMember({
|
||||
|
||||
Reference in new issue
Block a user