Update Healer Man server

This commit is contained in:
phenom committed 2026-10-04 22:51:21 -04:00
1 parent 6cc1b9217f
commit 6114a2295f
67 files changed
+6241 -347

No files matched your search

+180 -1
View File
@@ -2,6 +2,9 @@ import { describe, expect, it } from "vitest";
import campaign from "../../dungeon-pipeline/dungeon-campaign.json";
import epochInstances from "../../dungeon-pipeline/epoch-five-player-instances.json";
import gameObjectAssetManifest from "../../dungeon-pipeline/WOW_GAMEOBJECT_ASSET_MANIFEST.json";
import stockadeRecipe from "../../dungeon-pipeline/recipes/stormwind-stockade.json";
import theNexusRecipe from "../../dungeon-pipeline/recipes/the-nexus.json";
import worldAi from "./generated/azerothCoreWorldAi.json";
import generated from "./generated/dungeonCampaignCatalog.json";
import manastormPackages from "./generated/manastormAssetPackages.json";
import { DUNGEON_DEFINITIONS, requireDungeonDefinition } from "./dungeonRegistry";
@@ -72,7 +75,7 @@ const WDT_PLACEMENT_DUNGEON_IDS = [
describe("generated dungeon campaign catalog", () => {
it("covers only reviewed five-player instances with loadable assets and combat content", () => {
expect(generated.definitions).toHaveLength(54);
expect(DUNGEON_DEFINITIONS).toHaveLength(92);
expect(DUNGEON_DEFINITIONS).toHaveLength(98);
expect(generated.definitions.map((dungeon) => dungeon.id))
.toEqual(campaign.dungeons.map((dungeon) => dungeon.slug));
for (const dungeon of generated.definitions) {
@@ -86,6 +89,25 @@ describe("generated dungeon campaign catalog", () => {
}
});
it("keeps the six newer source-backed RuneWaker dungeons in the registry", () => {
const newerSourceDungeons = [
["kawaks-tomb", "scripts/runewaker-pipeline/snapshots/kawaks-tomb-zone-134.json"],
["grafu-castle", "scripts/runewaker-pipeline/snapshots/grafu-castle-zone-137.json"],
["sardo-castle", "scripts/runewaker-pipeline/snapshots/sardo-castle-zone-139.json"],
["tomb-seven-heroes", "scripts/runewaker-pipeline/snapshots/tomb-seven-heroes-zone-142.json"],
["aeternal-circle", "scripts/runewaker-pipeline/snapshots/aeternal-circle-zone-144.json"],
["kulech-bones-nest", "scripts/runewaker-pipeline/snapshots/kulech-bones-nest-zone-147.json"],
] as const;
for (const [id, sourceSnapshot] of newerSourceDungeons) {
const definition = DUNGEON_DEFINITIONS.find((candidate) => candidate.id === id);
expect(definition, id).toMatchObject({
expansion: "runewaker",
provenance: { sourceSnapshot },
});
}
});
it("never exposes raw database gameobject rows to the live world-object renderer", () => {
for (const dungeon of DUNGEON_DEFINITIONS) {
for (const object of dungeon.serverGameObjects) {
@@ -857,6 +879,163 @@ describe("generated dungeon campaign catalog", () => {
expect(targorr?.position).toEqual([-159.582, -25.6062, 1.2531]);
});
it("omits only the source-confirmed utility-only Stockade casts and preserves real damage", () => {
const stockades = requireDungeonDefinition("stormwind-stockade");
const blackrockDepths = requireDungeonDefinition("blackrock-depths");
const attacksFor = (dungeon: typeof stockades, entry: number) => (
dungeon.entities[`entry-${entry}`]?.combat?.attacks ?? []
);
const hasSpell = (dungeon: typeof stockades, entry: number, spellId: number) => (
attacksFor(dungeon, entry).some((attack) => attack.spellId === spellId)
);
const sourceSmartAction = (
entry: "1663" | "1666" | "1706" | "1708" | "1711" | "1715" | "1716" | "1717" | "1696",
spellId: number,
) => (
worldAi.smartScriptsByEntry[entry]?.find((row) => (
row.action_type === 11 && row.action_param1 === spellId
))
);
expect(sourceSmartAction("1666", 7164)).toMatchObject({ event_type: 0, target_type: 1 });
expect(sourceSmartAction("1708", 7165)).toMatchObject({ event_type: 1, target_type: 1 });
expect(sourceSmartAction("1715", 13730)).toMatchObject({ event_type: 0, target_type: 1 });
expect(worldAi.creatureSpellsByEntry["1711"]?.map((spell) => spell.spellId)).toContain(16244);
expect([1666, 1708, 1711, 1715].flatMap((entry) => (
attacksFor(stockades, entry).filter((attack) => [7164, 7165, 16244, 13730].includes(attack.spellId ?? 0))
))).toEqual([]);
const kamAttacks = attacksFor(stockades, 1666);
const shieldSlam = kamAttacks.find((attack) => attack.spellId === 8242);
expect(shieldSlam?.effect).toMatchObject({ kind: "control", damageMultiplier: 1.35 });
expect(kamAttacks.map((attack) => attack.spellId)).not.toContain(3419);
expect(kamAttacks.some((attack) => attack.id.endsWith("-surge"))).toBe(false);
const inmateAttacks = attacksFor(stockades, 1708);
expect(hasSpell(stockades, 1708, 6547)).toBe(true);
expect(hasSpell(stockades, 1708, 6253)).toBe(true);
expect(hasSpell(stockades, 1711, 16509)).toBe(true);
const grebmarAttacks = attacksFor(blackrockDepths, 9319);
expect(hasSpell(blackrockDepths, 9319, 21049)).toBe(true);
expect(hasSpell(blackrockDepths, 9319, 15615)).toBe(true);
expect(grebmarAttacks.some((attack) => attack.id.endsWith("-surge"))).toBe(false);
});
it("preserves pinned Stockade hostile targeting, utility omissions, and supported damage", () => {
const stockades = requireDungeonDefinition("stormwind-stockade");
const theNexus = requireDungeonDefinition("the-nexus");
const attacksFor = (entry: number) => (
stockades.entities[`entry-${entry}`]?.combat?.attacks ?? []
);
const attackFor = (entry: number, spellId: number) => (
attacksFor(entry).find((attack) => attack.spellId === spellId)
);
const sourceSmartAction = (
entry: "1663" | "1666" | "1706" | "1708" | "1711" | "1715" | "1716" | "1717" | "1696",
spellId: number,
) => (
worldAi.smartScriptsByEntry[entry]?.find((row) => (
row.action_type === 11 && row.action_param1 === spellId
))
);
expect(sourceSmartAction("1663", 11976)).toMatchObject({ target_type: 2 });
expect(sourceSmartAction("1663", 19134)).toMatchObject({ target_type: 2 });
expect(sourceSmartAction("1666", 8242)).toMatchObject({ target_type: 2 });
expect(sourceSmartAction("1716", 7964)).toMatchObject({ target_type: 1 });
expect(stockadeRecipe.clientBuild).toBe("3.3.5a-Ascension");
expect(theNexusRecipe.clientBuild).toBe("3.3.5a-Epoch");
for (const [entry, spellId] of [
[1666, 3419], [1708, 7165], [1711, 16244], [1715, 13730],
[1706, 6713], [1707, 17230], [1663, 2457], [1717, 6742],
[1716, 9128], [1716, 29651], [1696, 674], [1696, 3391],
] as const) {
expect(attackFor(entry, spellId), `entry ${entry}, spell ${spellId}`).toBeUndefined();
}
expect(attackFor(1666, 8242)).toMatchObject({
target: "primary",
delivery: "melee",
range: 5,
effect: { kind: "control", mechanic: "stun", damageMultiplier: 1.35 },
});
expect(attackFor(1711, 8242)).toMatchObject({
target: "primary",
delivery: "melee",
range: 5,
effect: { kind: "control", mechanic: "stun", damageMultiplier: 1.12 },
});
expect(attackFor(1711, 6253)).toMatchObject({
target: "primary",
delivery: "melee",
range: 5,
effect: { kind: "control", mechanic: "stun", durationMs: 2_000 },
});
expect(attackFor(1708, 6547)).toBeDefined();
expect(attackFor(1711, 16509)).toBeDefined();
expect(attackFor(1663, 11976)).toMatchObject({
target: "primary",
delivery: "melee",
range: 5,
});
expect(attackFor(1707, 15657)).toMatchObject({
target: "primary",
delivery: "melee",
range: 5,
attackKind: "melee",
});
expect(attackFor(1706, 11978)).toMatchObject({
target: "primary",
delivery: "melee",
range: 5,
effect: { kind: "control", mechanic: "interrupt", durationMs: 4_000 },
});
expect(attackFor(1717, 421)).toMatchObject({
target: "primary",
delivery: "projectile",
range: 30,
attackKind: "spell",
});
expect(attackFor(1717, 421)?.damageMultiplier).toBeGreaterThan(0);
expect(attackFor(1663, 5246)).toMatchObject({
target: "nearby-party",
range: 8,
radius: 8,
effect: { kind: "control", mechanic: "fear" },
});
expect(attackFor(1663, 19134)).toMatchObject({
target: "nearby-party",
range: 10,
radius: 8,
effect: { kind: "control", mechanic: "fear", durationMs: 4_000 },
});
expect(attackFor(1716, 7964)).toMatchObject({
target: "nearby-party",
range: 5,
radius: 5,
effect: { kind: "control", mechanic: "stun", durationMs: 4_000 },
});
const epochFrighteningShout = theNexus.entities["entry-26796"]?.combat?.attacks
.find((attack) => attack.spellId === 19134);
expect(epochFrighteningShout).toMatchObject({
target: "nearby-party",
delivery: "area",
range: 10,
radius: 8,
effect: { kind: "control", mechanic: "fear", durationMs: 6_000 },
});
const targorrAttacks = attacksFor(1696);
expect(attackFor(1696, 8599)?.effect).toMatchObject({ kind: "aura" });
expect(targorrAttacks.some((attack) => attack.id.endsWith("-surge"))).toBe(false);
});
it("starts Ragefire Chasm in the dungeon instead of the Orgrimmar portal annex", () => {
const ragefire = requireDungeonDefinition("ragefire-chasm");
const firstSpawn = ragefire.staticSpawns.find(