forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
6114a2295f
commit
69809f7228
593 files changed
+903643
-40774
No files matched your search
@@ -0,0 +1,168 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { abilitiesForClass, type AbilityDefinition } from "./abilityCatalog";
|
||||
import { applyAura, type ActiveAura } from "./combatAuras";
|
||||
import {
|
||||
coaWitchDoctorActiveIngredients,
|
||||
coaWitchDoctorBrewingAbilityForCast,
|
||||
coaWitchDoctorCanBrewIngredient,
|
||||
coaWitchDoctorIngredientCapacity,
|
||||
coaWitchDoctorIngredientIdForAbility,
|
||||
COA_WITCH_DOCTOR_FROG_BONES_POTION_SHIELD,
|
||||
COA_WITCH_DOCTOR_FROG_BONES_SPLASH_SHIELD,
|
||||
} from "./coaWitchDoctorBrewingRuntime";
|
||||
|
||||
const casterId = "witch-doctor-caster";
|
||||
|
||||
function abilityByTalentEntry(talentEntryId: number): AbilityDefinition {
|
||||
const ability = abilitiesForClass("witch-doctor").find((candidate) => candidate.talentEntryId === talentEntryId);
|
||||
if (!ability) throw new Error(`Missing Witch Doctor talent action ${talentEntryId}`);
|
||||
return ability;
|
||||
}
|
||||
|
||||
function markerFromIngredient(ability: AbilityDefinition): Extract<AbilityDefinition["effects"][number], { kind: "apply-aura" }> {
|
||||
const projected = coaWitchDoctorBrewingAbilityForCast(ability, [], casterId, 1_000);
|
||||
const marker = projected.effects.find((effect) => effect.kind === "apply-aura"
|
||||
&& effect.aura.id.startsWith("coa-witch-doctor:active-ingredient:"));
|
||||
if (!marker || marker.kind !== "apply-aura") throw new Error(`Missing marker effect for ${ability.name}`);
|
||||
return marker;
|
||||
}
|
||||
|
||||
function activate(
|
||||
ability: AbilityDefinition,
|
||||
sourceId = casterId,
|
||||
targetId = sourceId,
|
||||
appliedAt = 1_000,
|
||||
): ActiveAura {
|
||||
const marker = markerFromIngredient(ability);
|
||||
return applyAura([], { definition: marker.aura, sourceId, targetId, now: appliedAt }).aura;
|
||||
}
|
||||
|
||||
describe("CoA Witch Doctor Brewing state and Potion Toss", () => {
|
||||
it("uses actor-owned, non-stacking ingredient markers and preserves Frog Bones cauldron pulses", () => {
|
||||
const frogBones = abilityByTalentEntry(29741);
|
||||
const projected = coaWitchDoctorBrewingAbilityForCast(frogBones, [], casterId, 1_000);
|
||||
const cauldronPulse = projected.effects.find((effect) => effect.kind === "apply-aura"
|
||||
&& effect.sourceAuraType === 23);
|
||||
|
||||
expect(projected.effects.some((effect) => effect.kind === "shield")).toBe(false);
|
||||
expect(projected.effects.some((effect) => effect.kind === "apply-aura" && effect.sourceAuraType === 4)).toBe(false);
|
||||
expect(cauldronPulse).toMatchObject({
|
||||
kind: "apply-aura",
|
||||
aura: { maxStacks: 1, stackBehavior: "refresh" },
|
||||
recipient: "caster",
|
||||
});
|
||||
expect(projected.effects.filter((effect) => effect.kind === "apply-aura"
|
||||
&& effect.aura.id === "coa-witch-doctor:active-ingredient:frog-bones")).toHaveLength(1);
|
||||
|
||||
const marker = markerFromIngredient(frogBones);
|
||||
expect(marker.aura).toMatchObject({
|
||||
durationMs: null,
|
||||
maxStacks: 1,
|
||||
stackBehavior: "refresh",
|
||||
hideFromAuraStrip: true,
|
||||
utilityTags: ["coa-witch-doctor-active-ingredient:frog-bones"],
|
||||
});
|
||||
expect(marker.aura.modifiers ?? []).toEqual([]);
|
||||
expect(marker.aura.procs ?? []).toEqual([]);
|
||||
});
|
||||
|
||||
it("gates new ingredients at the sourced one-or-two capacity without replacing a full brew", () => {
|
||||
const jungleShrooms = abilityByTalentEntry(12645);
|
||||
const frogBones = abilityByTalentEntry(29741);
|
||||
const bloodthistle = abilityByTalentEntry(6021);
|
||||
const jungle = activate(jungleShrooms);
|
||||
const ranks = { "coa-entry-6645": 1 };
|
||||
|
||||
expect(coaWitchDoctorIngredientCapacity({})).toBe(1);
|
||||
expect(coaWitchDoctorIngredientCapacity(ranks)).toBe(2);
|
||||
expect(coaWitchDoctorActiveIngredients([jungle], casterId, 2_000)).toEqual(new Set(["jungle-shrooms"]));
|
||||
expect(coaWitchDoctorCanBrewIngredient(jungleShrooms, [jungle], casterId, {}, 2_000)).toBe(true);
|
||||
expect(coaWitchDoctorCanBrewIngredient(frogBones, [jungle], casterId, {}, 2_000)).toBe(false);
|
||||
expect(coaWitchDoctorCanBrewIngredient(frogBones, [jungle], casterId, ranks, 2_000)).toBe(true);
|
||||
expect(coaWitchDoctorCanBrewIngredient(bloodthistle, [jungle, activate(frogBones)], casterId, ranks, 2_000))
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
it("identifies only the four exact Ingredient cast actions", () => {
|
||||
expect(coaWitchDoctorIngredientIdForAbility(abilityByTalentEntry(12645))).toBe("jungle-shrooms");
|
||||
expect(coaWitchDoctorIngredientIdForAbility(abilityByTalentEntry(29741))).toBe("frog-bones");
|
||||
expect(coaWitchDoctorIngredientIdForAbility(abilityByTalentEntry(6021))).toBe("bloodthistle");
|
||||
const knownAbility = abilityByTalentEntry(29741);
|
||||
const fishOil = { ...knownAbility, dbcSpellId: 801662, talentEntryId: undefined };
|
||||
expect(coaWitchDoctorIngredientIdForAbility(fishOil)).toBe("fish-oil");
|
||||
expect(coaWitchDoctorIngredientIdForAbility({ ...fishOil, talentEntryId: 6645 })).toBeNull();
|
||||
expect(coaWitchDoctorIngredientIdForAbility({ ...fishOil, classId: "mage" })).toBeNull();
|
||||
expect(coaWitchDoctorIngredientIdForAbility({ ...knownAbility, talentEntryId: 29_740 })).toBeNull();
|
||||
});
|
||||
|
||||
it("counts only this caster's live ingredient markers", () => {
|
||||
const frogBones = abilityByTalentEntry(29741);
|
||||
const marker = activate(frogBones);
|
||||
const wrongSource = activate(frogBones, "another-witch-doctor", casterId);
|
||||
const wrongTarget = activate(frogBones, casterId, "another-witch-doctor");
|
||||
const expired = { ...activate(frogBones), expiresAt: 2_000 };
|
||||
|
||||
expect(coaWitchDoctorActiveIngredients(
|
||||
[marker, wrongSource, wrongTarget, expired], casterId, 2_000,
|
||||
)).toEqual(new Set(["frog-bones"]));
|
||||
expect(coaWitchDoctorActiveIngredients([wrongSource, wrongTarget], casterId, 1_500).size).toBe(0);
|
||||
});
|
||||
|
||||
it("adds only the sourced eight-second Frog Bones shield to Potion Toss's selected unit heal", () => {
|
||||
const toss = abilityByTalentEntry(12646);
|
||||
const frogBones = abilityByTalentEntry(29741);
|
||||
const baseHeal = toss.effects.find((effect) => effect.kind === "heal");
|
||||
const activeMarker = activate(frogBones);
|
||||
const projected = coaWitchDoctorBrewingAbilityForCast(toss, [activeMarker], casterId, 2_000);
|
||||
const shields = projected.effects.filter((effect) => effect.kind === "shield");
|
||||
|
||||
expect(projected.target).toBe("friendly");
|
||||
expect(projected.effects.find((effect) => effect.kind === "heal")).toBe(baseHeal);
|
||||
expect(shields).toEqual([COA_WITCH_DOCTOR_FROG_BONES_POTION_SHIELD]);
|
||||
expect(shields[0]).toMatchObject({
|
||||
basePoints: 100,
|
||||
dieSides: 1,
|
||||
coefficient: 0,
|
||||
pointsPerLevel: 5,
|
||||
sourceLevel: 10,
|
||||
spiritCoefficient: 0.35,
|
||||
bonusPowerCoefficient: 0.8,
|
||||
durationMs: 8_000,
|
||||
});
|
||||
expect("maxScalingLevel" in shields[0] ? shields[0].maxScalingLevel : undefined).toBeUndefined();
|
||||
|
||||
const foreignMarker = activate(frogBones, "another-witch-doctor");
|
||||
const inactiveProjection = coaWitchDoctorBrewingAbilityForCast(toss, [foreignMarker], casterId, 2_000);
|
||||
expect(inactiveProjection.effects.some((effect) => effect.kind === "shield")).toBe(false);
|
||||
const otherIngredientMarker = activate(abilityByTalentEntry(6021));
|
||||
const nonFrogProjection = coaWitchDoctorBrewingAbilityForCast(toss, [otherIngredientMarker], casterId, 2_000);
|
||||
expect(nonFrogProjection.effects.some((effect) => effect.kind === "shield")).toBe(false);
|
||||
});
|
||||
|
||||
it("projects only the verified Frog Bones rider on Splash Potion's area heal", () => {
|
||||
const splash = abilityByTalentEntry(7128);
|
||||
const frogBones = abilityByTalentEntry(29741);
|
||||
const baseHeal = splash.effects.find((effect) => effect.kind === "heal");
|
||||
const activeMarker = activate(frogBones);
|
||||
const projected = coaWitchDoctorBrewingAbilityForCast(splash, [activeMarker], casterId, 2_000);
|
||||
|
||||
expect(baseHeal).toMatchObject({
|
||||
kind: "heal",
|
||||
basePoints: 54,
|
||||
dieSides: 3,
|
||||
pointsPerLevel: 1.3710700273513794,
|
||||
sourceLevel: 17,
|
||||
bonusPowerCoefficient: 0.224494,
|
||||
spiritCoefficient: 0.08,
|
||||
scope: "party",
|
||||
radius: 10,
|
||||
maximumTargets: 8,
|
||||
});
|
||||
expect(projected.effects).toEqual([baseHeal, COA_WITCH_DOCTOR_FROG_BONES_SPLASH_SHIELD]);
|
||||
expect(projected.effects.some((effect) => effect.kind === "shield"
|
||||
&& effect.basePoints === 25 && effect.durationMs === 8_000)).toBe(true);
|
||||
|
||||
const unmarked = coaWitchDoctorBrewingAbilityForCast(splash, [], casterId, 2_000);
|
||||
expect(unmarked.effects).toEqual([baseHeal]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user