98 lines
3.0 KiB
TypeScript
98 lines
3.0 KiB
TypeScript
import referenceData from "./generated/azerothCoreReference.json";
|
|
import {
|
|
DEFAULT_ENEMY_ATTACK,
|
|
type EnemyAttackDefinition,
|
|
type EnemyCombatDefinition,
|
|
} from "./enemyAttacks";
|
|
import type {
|
|
PopulationDefinitionMap,
|
|
PopulationEntityDefinition,
|
|
} from "./mobPopulation";
|
|
import { creatureTemplateReference } from "./azerothCoreReference";
|
|
|
|
const ENTITY_SERVER_ENTRIES: Readonly<Record<string, number>> = Object.freeze({
|
|
"deviate-ravager": 3636,
|
|
"deviate-guardian": 3637,
|
|
"druid-of-the-fang": 3840,
|
|
"evolving-ectoplasm": 3640,
|
|
"deviate-crocolisk": 5053,
|
|
"deviate-lasher": 5055,
|
|
"deviate-shambler": 5761,
|
|
"deviate-faerie-dragon": 5912,
|
|
"lady-anacondra": 3671,
|
|
kresh: 3653,
|
|
"lord-cobrahn": 3669,
|
|
"lord-pythas": 3670,
|
|
skum: 3674,
|
|
"lord-serpentis": 3673,
|
|
"verdan-the-everliving": 5775,
|
|
"mutanus-the-devourer": 3654,
|
|
"disciple-of-naralex": 3678,
|
|
"nightmare-ectoplasm": 5763,
|
|
"deviate-viper": 5755,
|
|
"deviate-adder": 5048,
|
|
});
|
|
|
|
interface WailingReferenceShape {
|
|
readonly wailingCaverns: {
|
|
readonly abilitiesByEntry: Readonly<Record<string, readonly EnemyAttackDefinition[]>>;
|
|
readonly unsupportedRequiredBossActions: readonly unknown[];
|
|
};
|
|
}
|
|
|
|
const WAILING = (referenceData as unknown as WailingReferenceShape).wailingCaverns;
|
|
|
|
function serverCombat(
|
|
definition: PopulationEntityDefinition,
|
|
serverEntry: number,
|
|
): EnemyCombatDefinition {
|
|
const template = creatureTemplateReference(serverEntry);
|
|
const basicAttack: EnemyAttackDefinition = {
|
|
...DEFAULT_ENEMY_ATTACK,
|
|
cooldownMs: template?.baseAttackTimeMs ?? DEFAULT_ENEMY_ATTACK.cooldownMs,
|
|
repeatCooldownMs: [
|
|
template?.baseAttackTimeMs ?? DEFAULT_ENEMY_ATTACK.cooldownMs,
|
|
template?.baseAttackTimeMs ?? DEFAULT_ENEMY_ATTACK.cooldownMs,
|
|
],
|
|
initialCooldownMs: [450, 450],
|
|
range: definition.kind === "boss" ? 5.2 : 4.3,
|
|
};
|
|
const scripted = WAILING.abilitiesByEntry[String(serverEntry)] ?? [];
|
|
return Object.freeze({
|
|
serverEntry,
|
|
healthMultiplier: definition.kind === "boss" ? 0.86 : 1,
|
|
damageMultiplier: 1,
|
|
moveSpeed: definition.combat?.moveSpeed,
|
|
leashRange: definition.combat?.leashRange ?? (definition.kind === "boss" ? 55 : 42),
|
|
attacks: Object.freeze([basicAttack, ...scripted]),
|
|
});
|
|
}
|
|
|
|
/** Adds pinned server combat facts without replacing authored models or placement. */
|
|
export function withWailingServerCombat(
|
|
definitions: PopulationDefinitionMap,
|
|
): PopulationDefinitionMap {
|
|
return Object.freeze(Object.fromEntries(
|
|
Object.entries(definitions).map(([id, definition]) => {
|
|
const serverEntry = ENTITY_SERVER_ENTRIES[id];
|
|
if (!serverEntry) return [id, definition];
|
|
return [
|
|
id,
|
|
Object.freeze({
|
|
...definition,
|
|
combat: serverCombat(definition, serverEntry),
|
|
}),
|
|
];
|
|
}),
|
|
));
|
|
}
|
|
|
|
export function wailingServerEntry(entityId: string): number | null {
|
|
return ENTITY_SERVER_ENTRIES[entityId] ?? null;
|
|
}
|
|
|
|
export function unsupportedWailingRequiredBossActions(): readonly unknown[] {
|
|
return WAILING.unsupportedRequiredBossActions;
|
|
}
|
|
|