Update Healer Man server
This commit is contained in:
1 parent
f90ba7d989
commit
189b94d6b7
51 files changed
+3448
-154
No files matched your search
@@ -0,0 +1,108 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { abilityById, type AbilityEffect } from "./abilityCatalog";
|
||||
import { romEffectsForCast, romTargetBleedCount, type RomCastMechanics } from "./romCombatMechanics";
|
||||
|
||||
const empty: RomCastMechanics = {
|
||||
sealStacks: 0, bleedCount: 0, charged: false, mainHandDagger: false, casterMaxHealth: 2_000,
|
||||
};
|
||||
|
||||
function cast(id: string, overrides: Partial<RomCastMechanics> = {}): readonly AbilityEffect[] {
|
||||
const ability = abilityById(id);
|
||||
expect(ability).toBeDefined();
|
||||
return romEffectsForCast(ability!, { ...empty, ...overrides });
|
||||
}
|
||||
|
||||
function kinds(effects: readonly AbilityEffect[]): readonly string[] {
|
||||
return effects.map((effect) => effect.kind);
|
||||
}
|
||||
|
||||
describe("RoM primary class conditional combat effects", () => {
|
||||
it("counts only active Rogue bleeds applied by the caster to that target", () => {
|
||||
const timed = [
|
||||
{ kind: "dot", sourceAbilityId: "rom-rogue-primary-1", sourceActorId: "rogue", targetId: "mob", remainingTicks: 3 },
|
||||
{ kind: "dot", sourceAbilityId: "rom-rogue-general-0", sourceActorId: "rogue", targetId: "mob", remainingTicks: 2 },
|
||||
{ kind: "dot", sourceAbilityId: "rom-rogue-general-0", sourceActorId: "rogue", targetId: "mob", remainingTicks: 1 },
|
||||
{ kind: "dot", sourceAbilityId: "rom-rogue-primary-9", sourceActorId: "other", targetId: "mob", remainingTicks: 2 },
|
||||
{ kind: "dot", sourceAbilityId: "rom-rogue-primary-4", sourceActorId: "rogue", targetId: "other-mob", remainingTicks: 2 },
|
||||
];
|
||||
expect(romTargetBleedCount(timed, "rogue", "mob")).toBe(2);
|
||||
});
|
||||
|
||||
it("gives Wound Attack one hit plus one hit per active bleed, without inventing a DoT", () => {
|
||||
expect(kinds(cast("rom-rogue-primary-2"))).toEqual(["damage"]);
|
||||
expect(kinds(cast("rom-rogue-primary-2", { bleedCount: 1 }))).toEqual(["damage", "damage"]);
|
||||
expect(kinds(cast("rom-rogue-primary-2", { bleedCount: 2 }))).toEqual(["damage", "damage", "damage"]);
|
||||
expect(kinds(cast("rom-rogue-primary-1"))).toEqual(["damage"]);
|
||||
expect(kinds(cast("rom-rogue-primary-1", { bleedCount: 1 }))).toEqual(["damage", "dot"]);
|
||||
});
|
||||
|
||||
it("selects exactly one Electric Explosion hit for normal and Charged casts", () => {
|
||||
const normal = cast("rom-mage-primary-54");
|
||||
const charged = cast("rom-mage-primary-54", { charged: true });
|
||||
expect(kinds(normal)).toEqual(["damage"]);
|
||||
expect(kinds(charged)).toEqual(["damage"]);
|
||||
expect((charged[0] as Extract<AbilityEffect, { kind: "damage" }>).basePoints)
|
||||
.toBeGreaterThan((normal[0] as Extract<AbilityEffect, { kind: "damage" }>).basePoints ?? 0);
|
||||
});
|
||||
|
||||
it("requires Holy Seals for Punishment and scales its payoff by stack count", () => {
|
||||
expect(cast("rom-knight-general-0")).toEqual([]);
|
||||
const one = cast("rom-knight-general-0", { sealStacks: 1 });
|
||||
const four = cast("rom-knight-general-0", { sealStacks: 4 });
|
||||
expect(kinds(one)).toEqual(["damage", "dot", "combo"]);
|
||||
expect((four[0] as Extract<AbilityEffect, { kind: "damage" }>).basePoints)
|
||||
.toBe(4 * ((one[0] as Extract<AbilityEffect, { kind: "damage" }>).basePoints ?? 0));
|
||||
});
|
||||
|
||||
it("gates Knight seal riders and grants Shield Bash's absorb to the caster", () => {
|
||||
expect(kinds(cast("rom-knight-primary-7"))).toEqual(["damage", "apply-aura"]);
|
||||
expect(kinds(cast("rom-knight-primary-7", { sealStacks: 4 })).filter((kind) => kind === "damage")).toHaveLength(2);
|
||||
expect(kinds(cast("rom-knight-primary-12"))).toEqual(["damage", "apply-aura"]);
|
||||
expect(kinds(cast("rom-knight-primary-12", { sealStacks: 4 })).filter((kind) => kind === "damage")).toHaveLength(2);
|
||||
const bash = cast("rom-knight-primary-11", { sealStacks: 3 });
|
||||
const shield = bash.find((effect) => effect.kind === "apply-aura");
|
||||
expect(shield?.kind === "apply-aura" && shield.recipient).toBe("caster");
|
||||
expect(shield?.kind === "apply-aura" && shield.aura.absorbs?.[0]?.amount).toBe(300);
|
||||
expect(kinds(bash)).toEqual(["damage", "apply-aura", "combo"]);
|
||||
});
|
||||
|
||||
it("requires a dagger for Shadowstab and Sneak Attack bleeds", () => {
|
||||
expect(kinds(cast("rom-rogue-general-0"))).toEqual(["damage"]);
|
||||
expect(kinds(cast("rom-rogue-general-0", { mainHandDagger: true }))).toEqual(["damage", "dot"]);
|
||||
expect(kinds(cast("rom-rogue-primary-9"))).toEqual(["damage", "apply-aura"]);
|
||||
expect(kinds(cast("rom-rogue-primary-9", { mainHandDagger: true }))).toEqual(["damage", "apply-aura", "dot"]);
|
||||
});
|
||||
|
||||
it("keeps auxiliary source rows from adding extra hits, heals, or false control", () => {
|
||||
expect(kinds(cast("rom-priest-general-2"))).toEqual(["hot"]);
|
||||
expect(kinds(cast("rom-mage-primary-1"))).toEqual(["damage"]);
|
||||
expect(kinds(cast("rom-mage-general-0"))).toEqual(["damage"]);
|
||||
expect(kinds(cast("rom-rogue-primary-0"))).toEqual(["apply-aura", "apply-aura"]);
|
||||
expect(kinds(cast("rom-scout-general-3"))).toEqual(["damage", "apply-aura"]);
|
||||
});
|
||||
|
||||
it("executes the source count for multi-hit Mage storms", () => {
|
||||
expect(kinds(cast("rom-mage-primary-5"))).toEqual(Array(5).fill("damage"));
|
||||
expect(kinds(cast("rom-mage-primary-12"))).toEqual([
|
||||
"damage", "damage", "damage", "apply-aura", "apply-aura",
|
||||
]);
|
||||
});
|
||||
|
||||
it("holds Shield of Discipline for 30 seconds and reflects only on being hit", () => {
|
||||
const effects = cast("rom-knight-general-7");
|
||||
expect(kinds(effects)).toEqual(["apply-aura", "apply-aura", "apply-aura"]);
|
||||
const proc = effects.find((effect) => effect.kind === "apply-aura" && effect.aura.procs?.length);
|
||||
expect(proc?.kind === "apply-aura" && proc.aura.durationMs).toBe(30_000);
|
||||
expect(proc?.kind === "apply-aura" && proc.aura.procs?.[0]?.action).toMatchObject({
|
||||
kind: "custom", id: "rom-shield-discipline-reflect",
|
||||
});
|
||||
});
|
||||
|
||||
it("uses one breakable control effect for each single-target restraint", () => {
|
||||
for (const id of ["rom-scout-primary-4", "rom-rogue-primary-5", "rom-mage-primary-56"]) {
|
||||
const effects = cast(id);
|
||||
expect(effects).toHaveLength(1);
|
||||
expect(effects[0]).toMatchObject({ kind: "status", maxTargets: 1, breakOnDamage: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user