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,125 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { AbilityDefinition } from "./abilityCatalog";
|
||||
import { ROM_ALL_ABILITIES } from "./romAbilityCatalog";
|
||||
import { romEffectsForCast } from "./romCombatMechanics";
|
||||
import {
|
||||
ROM_WARLOCK_ROGUE_SHADOW_SLICE,
|
||||
romWarlockRogueShadowSliceEffects,
|
||||
} from "./romWarlockRogueShadowSlice";
|
||||
|
||||
function shadowStep(overrides: Partial<AbilityDefinition> = {}): AbilityDefinition {
|
||||
return {
|
||||
id: "rom-rogue-general-7",
|
||||
classId: "rom-rogue",
|
||||
dbcSpellId: ROM_WARLOCK_ROGUE_SHADOW_SLICE.triggerSpellId,
|
||||
name: "Shadow Step",
|
||||
unlockLevel: 28,
|
||||
icon: "",
|
||||
sigil: "",
|
||||
description: "Instantly move behind the target.",
|
||||
target: "hostile",
|
||||
range: { min: 0, max: 10 },
|
||||
castMode: "instant",
|
||||
castTimeMs: 0,
|
||||
cooldownMs: 20_000,
|
||||
gcdMs: 1_000,
|
||||
cost: { resource: "energy", amount: 20 },
|
||||
effects: [],
|
||||
source: "runewaker",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
const emptyCastContext = {
|
||||
sealStacks: 0,
|
||||
bleedCount: 0,
|
||||
charged: false,
|
||||
mainHandDagger: false,
|
||||
casterMaxHealth: 1_000,
|
||||
targetHealthPercent: 1,
|
||||
} as const;
|
||||
|
||||
function catalogShadowStep(): AbilityDefinition {
|
||||
const ability = ROM_ALL_ABILITIES.find((candidate) => candidate.dbcSpellId === 490_344);
|
||||
expect(ability).toBeDefined();
|
||||
return ability!;
|
||||
}
|
||||
|
||||
describe("Warlock/Rogue Shadow Slice source helper", () => {
|
||||
it("adds the exact CoA strike, stun, buffs, and Psi rider only with the matching passive", () => {
|
||||
const effects = romWarlockRogueShadowSliceEffects(
|
||||
shadowStep(),
|
||||
[ROM_WARLOCK_ROGUE_SHADOW_SLICE.passiveSpellId],
|
||||
);
|
||||
|
||||
expect(effects).toEqual([
|
||||
{
|
||||
kind: "damage",
|
||||
coefficient: 0,
|
||||
basePoints: 4_400,
|
||||
school: "shadow",
|
||||
},
|
||||
{ kind: "status", status: "stun", durationMs: 1_000 },
|
||||
expect.objectContaining({
|
||||
kind: "apply-aura",
|
||||
recipient: "caster",
|
||||
aura: expect.objectContaining({
|
||||
id: "rom-warlock-rogue-shadow-slice-498678",
|
||||
durationMs: 30_000,
|
||||
modifiers: expect.arrayContaining([
|
||||
expect.objectContaining({ kind: "damage", school: "shadow", value: 0.3 }),
|
||||
expect.objectContaining({ kind: "stat", stat: "movement-speed", value: 0.1 }),
|
||||
]),
|
||||
}),
|
||||
}),
|
||||
{ kind: "resource", resource: "psi", amount: 3 },
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not map by name, passive ID alone, or another spell/class identity", () => {
|
||||
const passive = [ROM_WARLOCK_ROGUE_SHADOW_SLICE.passiveSpellId];
|
||||
|
||||
expect(romWarlockRogueShadowSliceEffects(shadowStep(), [])).toBeNull();
|
||||
expect(romWarlockRogueShadowSliceEffects(shadowStep({ dbcSpellId: 490345 }), passive)).toBeNull();
|
||||
expect(romWarlockRogueShadowSliceEffects(shadowStep({ classId: "rom-warlock" }), passive)).toBeNull();
|
||||
expect(romWarlockRogueShadowSliceEffects(shadowStep({ secondaryClassId: "rom-priest" }), passive)).toBeNull();
|
||||
expect(romWarlockRogueShadowSliceEffects(shadowStep({ name: "Renamed ability" }), passive)).toBeNull();
|
||||
expect(romWarlockRogueShadowSliceEffects(shadowStep({ source: "coa-tree" }), passive)).toBeNull();
|
||||
});
|
||||
|
||||
it("integrates the Warlock/Rogue passive while preserving ordinary Shadow Step without it", () => {
|
||||
const ability = catalogShadowStep();
|
||||
const passive = ROM_ALL_ABILITIES.find((candidate) => candidate.dbcSpellId === 498_678);
|
||||
expect(passive).toMatchObject({
|
||||
classId: "rom-warlock",
|
||||
secondaryClassId: "rom-rogue",
|
||||
name: "Shadow Slice",
|
||||
});
|
||||
expect(passive?.description).toContain("4,400 Dark damage");
|
||||
expect(ability.description).toContain("In the Warlock/Rogue build with Shadow Slice (498678)");
|
||||
expect(ability.description).toContain("cannot model the behind-target positioning");
|
||||
expect(ability.costs).toEqual([{ resource: "energy", amount: 20 }]);
|
||||
expect(ability.cooldownMs).toBe(20_000);
|
||||
|
||||
const ordinaryEffects = romEffectsForCast(ability, emptyCastContext);
|
||||
expect(ordinaryEffects).toEqual(ability.effects);
|
||||
expect(ordinaryEffects).toContainEqual(expect.objectContaining({ kind: "movement", movement: "teleport" }));
|
||||
|
||||
const shadowSliceEffects = romEffectsForCast(ability, {
|
||||
...emptyCastContext,
|
||||
learnedPassiveSpellIds: [ROM_WARLOCK_ROGUE_SHADOW_SLICE.passiveSpellId],
|
||||
});
|
||||
expect(shadowSliceEffects).toEqual(romWarlockRogueShadowSliceEffects(
|
||||
ability,
|
||||
[ROM_WARLOCK_ROGUE_SHADOW_SLICE.passiveSpellId],
|
||||
));
|
||||
expect(shadowSliceEffects?.some((effect) => effect.kind === "movement")).toBe(false);
|
||||
});
|
||||
|
||||
it("records that Shadow Slice replaces the local teleport instead of adding another movement effect", () => {
|
||||
expect(ROM_WARLOCK_ROGUE_SHADOW_SLICE.replacesShadowStepTeleport).toBe(true);
|
||||
expect(romWarlockRogueShadowSliceEffects(shadowStep(), [498678])?.some((effect) => (
|
||||
effect.kind === "movement"
|
||||
))).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user