forked from phenom/healer-man
Release Healer Man 0.1.22
This commit is contained in:
1 parent
f6f2375145
commit
7f6001723a
144 files changed
+54107
-690
No files matched your search
@@ -2,6 +2,11 @@
|
||||
import { open, readFile, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { DUNGEON_DEFINITIONS } from "../../src/game/dungeonRegistry";
|
||||
import {
|
||||
WOW_DUNGEON_BASIC_ONLY_BOSS_EXCEPTIONS,
|
||||
WOW_DUNGEON_NO_TRASH_EXCEPTIONS,
|
||||
} from "../../src/game/wowDungeonContentExceptions";
|
||||
|
||||
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const publicRoot = path.join(projectRoot, "public");
|
||||
@@ -18,24 +23,14 @@ const validTargets = new Set([
|
||||
]);
|
||||
const validSchools = new Set(["physical", "arcane", "fire", "frost", "nature", "shadow", "holy"]);
|
||||
const validEffects = new Set([
|
||||
"damage", "heal", "aura", "control", "transform", "summon", "call-for-help", "encounter-event",
|
||||
]);
|
||||
const basicOnlyBossExceptions = new Map([
|
||||
[
|
||||
"wailing-caverns:entry-3653",
|
||||
"Kresh is melee-only in the pinned AzerothCore snapshot; the historical server has no spell or SmartAI row for entry 3653.",
|
||||
],
|
||||
[
|
||||
"wailing-caverns:deviate-faerie-dragon",
|
||||
"The server-faithful rare entry 5912 has no spell rows and is despawned by the Wailing Caverns initialization event.",
|
||||
],
|
||||
]);
|
||||
const noTrashExceptions = new Map([
|
||||
[
|
||||
"trial-of-the-champion",
|
||||
"Trial of the Champion is an encounter arena; its imported combat population is the five Grand Champion bosses, not a trash route.",
|
||||
],
|
||||
"damage", "heal", "aura", "target-aura", "control", "transform", "summon", "call-for-help", "encounter-event",
|
||||
]);
|
||||
const basicOnlyBossExceptions = new Map(
|
||||
WOW_DUNGEON_BASIC_ONLY_BOSS_EXCEPTIONS.map(({ key, reason }) => [key, reason]),
|
||||
);
|
||||
const noTrashExceptions = new Map(
|
||||
WOW_DUNGEON_NO_TRASH_EXCEPTIONS.map(({ key, reason }) => [key, reason]),
|
||||
);
|
||||
const animationIds = {
|
||||
idle: new Set([0]),
|
||||
move: new Set([4, 5]),
|
||||
@@ -152,13 +147,21 @@ const [campaign, catalog, wailingFixture] = await Promise.all([
|
||||
readJson("dungeon-pipeline/fixtures/wailing-caverns/runtime-fixture.json"),
|
||||
]);
|
||||
const campaignIds = new Set(campaign.dungeons.map((dungeon) => dungeon.slug));
|
||||
const definitions = catalog.definitions.filter((definition) => campaignIds.has(definition.id));
|
||||
const definitions = DUNGEON_DEFINITIONS.filter((definition) => campaignIds.has(definition.id));
|
||||
const coverage = new Map(catalog.coverage.map((entry) => [entry.dungeonId, entry]));
|
||||
const wailingModels = wailingFixtureModels(wailingFixture);
|
||||
const issues = [];
|
||||
if (basicOnlyBossExceptions.size !== WOW_DUNGEON_BASIC_ONLY_BOSS_EXCEPTIONS.length) {
|
||||
issues.push("The shared basic-only boss exception contract contains a duplicate key.");
|
||||
}
|
||||
if (noTrashExceptions.size !== WOW_DUNGEON_NO_TRASH_EXCEPTIONS.length) {
|
||||
issues.push("The shared no-trash exception contract contains a duplicate key.");
|
||||
}
|
||||
const modelUsers = new Map();
|
||||
const animationFallbacks = [];
|
||||
const dungeons = [];
|
||||
const actualBasicOnlyBossKeys = new Set();
|
||||
const actualNoTrashDungeonKeys = new Set();
|
||||
|
||||
if (campaign.dungeons.length !== 54) {
|
||||
issues.push("Expected 54 campaign dungeons; found " + campaign.dungeons.length + ".");
|
||||
@@ -179,15 +182,15 @@ for (const dungeon of definitions) {
|
||||
let specialAttacks = 0;
|
||||
let nativeModels = 0;
|
||||
let proceduralModels = 0;
|
||||
const optionalBossEntityIds = new Set((dungeon.objectiveOrder ?? [])
|
||||
.filter((objective) => objective.optional)
|
||||
.map((objective) => dungeon.staticSpawns?.find((spawn) => spawn.id === objective.id)?.entityId)
|
||||
.filter(Boolean));
|
||||
|
||||
if (!entities.length) dungeonIssues.push("has no combat entities.");
|
||||
if (!bosses.length) dungeonIssues.push("has no bosses.");
|
||||
if (!mobs.length && !noTrashExceptions.has(dungeon.id)) dungeonIssues.push("has no trash mobs.");
|
||||
if (!(dungeon.staticSpawns?.length || dungeon.roamingPacks?.length)) dungeonIssues.push("has no combat spawns.");
|
||||
if (!mobs.length) {
|
||||
actualNoTrashDungeonKeys.add(dungeon.id);
|
||||
if (!noTrashExceptions.has(dungeon.id)) dungeonIssues.push("has no trash mobs.");
|
||||
}
|
||||
if (!(dungeon.staticSpawns?.length || dungeon.roamingPacks?.length || dungeon.encounterSpawnGroups?.some((group) => group.spawns?.length))) {
|
||||
dungeonIssues.push("has no combat spawns.");
|
||||
}
|
||||
|
||||
for (const spawn of dungeon.staticSpawns ?? []) {
|
||||
if (!dungeon.entities?.[spawn.entityId]) {
|
||||
@@ -201,6 +204,13 @@ for (const dungeon of definitions) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const group of dungeon.encounterSpawnGroups ?? []) {
|
||||
for (const spawn of group.spawns ?? []) {
|
||||
if (!dungeon.entities?.[spawn.entityId]) {
|
||||
dungeonIssues.push("encounter group " + group.id + " references missing entity " + spawn.entityId + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [entityId, entity] of entities) {
|
||||
const entityAttacks = entity.combat?.attacks ?? [];
|
||||
@@ -209,8 +219,9 @@ for (const dungeon of definitions) {
|
||||
attacks += entityAttacks.length;
|
||||
const specials = entityAttacks.filter((attack) => attack.id !== "basic-attack");
|
||||
specialAttacks += specials.length;
|
||||
if (entity.kind === "boss" && !specials.length && !optionalBossEntityIds.has(entityId)) {
|
||||
if (entity.kind === "boss" && !specials.length) {
|
||||
const exceptionKey = dungeon.id + ":" + entityId;
|
||||
actualBasicOnlyBossKeys.add(exceptionKey);
|
||||
if (!basicOnlyBossExceptions.has(exceptionKey)) {
|
||||
dungeonIssues.push(entityId + " has no boss mechanic beyond its basic attack.");
|
||||
}
|
||||
@@ -247,6 +258,17 @@ for (const dungeon of definitions) {
|
||||
});
|
||||
}
|
||||
|
||||
for (const key of basicOnlyBossExceptions.keys()) {
|
||||
if (!actualBasicOnlyBossKeys.has(key)) {
|
||||
issues.push("Stale basic-only boss exception does not match a runtime boss: " + key + ".");
|
||||
}
|
||||
}
|
||||
for (const key of noTrashExceptions.keys()) {
|
||||
if (!actualNoTrashDungeonKeys.has(key)) {
|
||||
issues.push("Stale no-trash exception does not match a runtime dungeon: " + key + ".");
|
||||
}
|
||||
}
|
||||
|
||||
for (const [url, users] of modelUsers) {
|
||||
try {
|
||||
const names = await readGlbAnimationNames(url);
|
||||
|
||||
Reference in new issue
Block a user