Update Healer Man server
This commit is contained in:
1 parent
35dfdaed61
commit
4fb7a0b9c8
161 files changed
+24618
-529
No files matched your search
@@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { PLAYER_AGGRO_ID } from "./aggro";
|
||||
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
|
||||
import { useCombatStore } from "./combatStore";
|
||||
import { DEFAULT_ENEMY_ATTACK } from "./enemyAttacks";
|
||||
import { subscribeCombatPresentation, type CombatPresentationEvent } from "./combatPresentation";
|
||||
import {
|
||||
normalizeEnemyAttack,
|
||||
@@ -59,6 +60,51 @@ describe("enemy casting and interrupts", () => {
|
||||
expect(normalizeEnemyAttack({ ...withoutCastTime, animation: "attack" }).castTimeMs).toBe(0);
|
||||
});
|
||||
|
||||
it("reduces modeled enemy melee damage by the active Vindication AP share", () => {
|
||||
const swingDamage = (vindicated: boolean): number => {
|
||||
clearMobRuntimeRegistry();
|
||||
useCombatStore.getState().initializeCharacter({ classId: "paladin", level: 80 });
|
||||
useCombatStore.getState().setPlayerPosition([0, 0, 0]);
|
||||
useCombatStore.getState().registerMob("ap-attacker", {
|
||||
name: "AP attacker",
|
||||
serverEntry: 598,
|
||||
level: 80,
|
||||
maxHealth: 10_000,
|
||||
xpReward: 0,
|
||||
attacks: [DEFAULT_ENEMY_ATTACK],
|
||||
});
|
||||
setMobPosition("ap-attacker", [2, 0, 0]);
|
||||
useCombatStore.getState().selectMob("ap-attacker");
|
||||
useCombatStore.getState().damageMob("ap-attacker", 1, 1_000);
|
||||
if (vindicated) {
|
||||
useCombatStore.setState((state) => ({
|
||||
mobs: {
|
||||
...state.mobs,
|
||||
"ap-attacker": {
|
||||
...state.mobs["ap-attacker"],
|
||||
auras: [{
|
||||
id: "wow335:paladin:vindication",
|
||||
sourceAbilityId: "wow335-paladin-exorcism",
|
||||
sourceActorId: "paladin-caster",
|
||||
endsAt: 11_000,
|
||||
magnitude: 357,
|
||||
}],
|
||||
},
|
||||
},
|
||||
}));
|
||||
}
|
||||
const healthBeforeSwing = useCombatStore.getState().health;
|
||||
useCombatStore.getState().advanceMobCombat(1_450);
|
||||
return healthBeforeSwing - useCombatStore.getState().health;
|
||||
};
|
||||
|
||||
const unmodified = swingDamage(false);
|
||||
const reduced = swingDamage(true);
|
||||
expect(unmodified).toBeGreaterThan(0);
|
||||
expect(reduced).toBeGreaterThan(0);
|
||||
expect(reduced).toBeLessThan(unmodified);
|
||||
});
|
||||
|
||||
it("delays an enemy spell effect until its cast completes", () => {
|
||||
registerCaster([spell("shadow-bolt", "shadow")]);
|
||||
const startingHealth = useCombatStore.getState().health;
|
||||
@@ -130,6 +176,61 @@ describe("enemy casting and interrupts", () => {
|
||||
expect(useCombatStore.getState().mobs.caster.schoolLockedUntil).toEqual({});
|
||||
});
|
||||
|
||||
it("grants Improved Kick's capstone only for a successful Kick interrupt", () => {
|
||||
useCombatStore.getState().initializeCharacter({ classId: "rogue", level: 20 });
|
||||
registerCaster([spell("shadow-bolt", "shadow", 2_000)]);
|
||||
useCombatStore.getState().advanceMobCombat(1_000);
|
||||
useCombatStore.setState((state) => ({
|
||||
talentRanks: { ...state.talentRanks, "talent-206": 2 },
|
||||
resource: 70,
|
||||
resourcePools: { ...state.resourcePools, energy: 70 },
|
||||
}));
|
||||
|
||||
expect(useCombatStore.getState().castAbility("rogue-kick", [0, 0, 0], 1_100).ok).toBe(true);
|
||||
expect(useCombatStore.getState().mobs.caster.activeCast).toBeNull();
|
||||
expect(useCombatStore.getState().resourcePools.energy).toBe(85);
|
||||
const bonus = useCombatStore.getState().auras.find((aura) => (
|
||||
aura.definition.utilityTags?.includes("wow335-rogue-improved-kick")
|
||||
));
|
||||
expect(bonus).toMatchObject({ appliedAt: 1_100, expiresAt: 7_100 });
|
||||
expect(bonus?.definition.modifiers).toEqual([
|
||||
{ kind: "stat", stat: "melee-haste", operation: "flat", value: 35 },
|
||||
{ kind: "stat", stat: "ranged-haste", operation: "flat", value: 35 },
|
||||
]);
|
||||
|
||||
useCombatStore.setState((state) => ({
|
||||
autoAttackTargetId: "caster",
|
||||
nextAutoAttackAt: 1_101,
|
||||
}));
|
||||
useCombatStore.getState().tick(0, 1_101);
|
||||
const buffedSwingInterval = useCombatStore.getState().nextAutoAttackAt - 1_101;
|
||||
useCombatStore.setState((state) => ({ nextAutoAttackAt: 7_101 }));
|
||||
useCombatStore.getState().tick(0, 7_101);
|
||||
const unbuffedSwingInterval = useCombatStore.getState().nextAutoAttackAt - 7_101;
|
||||
expect(buffedSwingInterval).toBeLessThan(unbuffedSwingInterval);
|
||||
|
||||
expect(useCombatStore.getState().auras.some((aura) => (
|
||||
aura.definition.utilityTags?.includes("wow335-rogue-improved-kick")
|
||||
))).toBe(false);
|
||||
});
|
||||
|
||||
it("does not grant Improved Kick's interrupt rider when Kick finds no cast", () => {
|
||||
useCombatStore.getState().initializeCharacter({ classId: "rogue", level: 20 });
|
||||
registerCaster([spell("shadow-bolt", "shadow", 2_000)]);
|
||||
useCombatStore.setState((state) => ({
|
||||
talentRanks: { ...state.talentRanks, "talent-206": 2 },
|
||||
resource: 70,
|
||||
resourcePools: { ...state.resourcePools, energy: 70 },
|
||||
}));
|
||||
|
||||
expect(useCombatStore.getState().castAbility("rogue-kick", [0, 0, 0], 1_100).ok).toBe(true);
|
||||
expect(useCombatStore.getState().mobs.caster.activeCast).toBeNull();
|
||||
expect(useCombatStore.getState().resourcePools.energy).toBe(45);
|
||||
expect(useCombatStore.getState().auras.some((aura) => (
|
||||
aura.definition.utilityTags?.includes("wow335-rogue-improved-kick")
|
||||
))).toBe(false);
|
||||
});
|
||||
|
||||
it("cancels casts immediately when crowd control lands", () => {
|
||||
useCombatStore.getState().initializeCharacter({ classId: "rogue", level: 4 });
|
||||
registerCaster([spell("shadow-bolt", "shadow", 2_000)]);
|
||||
|
||||
Reference in new issue
Block a user