Update Healer Man server

This commit is contained in:
phenom committed 2026-09-30 09:57:13 -04:00
1 parent 35dfdaed61
commit 4fb7a0b9c8
161 files changed
+24618 -529

No files matched your search

+111 -15
View File
@@ -27,6 +27,12 @@ import {
} from "./roguePoison";
import { runtimeTalentNodeById } from "./talentRuntimeCatalog";
import { baseResourcesFor } from "./wotlkStats";
import {
WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITIES,
wow335WarlockMetamorphosisAbility,
} from "./wow335WarlockMetamorphosisRuntime";
import { WOW335_WARLOCK_SOUL_LINK_TAG } from "./wow335WarlockSoulLinkRuntime";
import { WOW335_TALENT_NODES } from "./wow335Talents.generated";
export const BASE_CLASS_STARTER_SOURCE_LEVEL = 10;
@@ -542,6 +548,8 @@ function namedAuraForEffect(
id: `${auraId}:holy-shield`,
triggers: "block",
chance: 1,
// Holy Shield ranks 20925/20927/20928 carry procCharges=8 in local Spell.dbc.
charges: 8,
action: { kind: "damage", amount: procAmount, school: "holy", target: "event-other" },
});
}
@@ -646,8 +654,10 @@ function namedAuraForEffect(
...(abilityName === "Divine Favor" ? ["wow335-divine-favor-next-holy-heal"] : []),
...(abilityName === "Aura Mastery" ? ["wow335-aura-mastery-silence-interrupt", "wow335-aura-mastery-aura-effectiveness"] : []),
];
const controlImmunities = classId === "paladin" && abilityName === "Aura Mastery" && effect.miscValue === 3
? ["silence"] as const
const controlImmunities = classId === "paladin" && abilityName === "Aura Mastery"
? effect.miscValue === 3 ? ["silence"] as const
: effect.miscValue === 12 ? ["interrupt"] as const
: undefined
: controlImmunitiesForAura(effect.auraType, effect.miscValue);
return {
id: auraId,
@@ -878,7 +888,10 @@ function classScriptEffects(
maxScalingLevel: rank.maxScalingLevel,
}] : [];
}
case "warrior:Charge": return [{ kind: "status", status: "stun", durationMs: 1_500 }];
case "warrior:Charge": return [
{ kind: "movement", movement: "charge", toward: "target" },
{ kind: "status", status: "stun", durationMs: 1_500 },
];
case "warrior:Intercept": return [{ kind: "status", status: "stun", durationMs: 3_000 }];
case "warrior:Devastate": return [
{
@@ -969,15 +982,14 @@ function classScriptEffects(
aura: {
id: `wow335:${rank.spellId}:kill-command`,
name: abilityName,
description: "Increases your pet's special attack damage by 1% per remaining charge for 30 seconds. Each successful special attack reduces the bonus by 1%.",
description: rank.description,
disposition: "buff",
durationMs: rank.durationMs,
maxStacks: 60,
initialStacks: 60,
stackBehavior: "replace",
utilityTags: ["wow335-hunter-kill-command"],
// The source applies this only to pet special attacks. The current
// summon scheduler emits generic melee swings, so do not boost those.
// The generated row omits the starting damage bonus; leave the pet
// special-attack rider inert until that value and a special-hit event
// are both represented by the runtime.
},
sourceEffectType: 6,
sourceAuraType: 4,
@@ -993,6 +1005,43 @@ function classScriptEffects(
triggerSpellId: 60202,
durationMs: 30_000,
}];
case "hunter:Freezing Trap":
case "hunter:Frost Trap": return [{
kind: "utility",
action: "class-script",
effectType: 104,
auraType: 0,
miscValue: rank.effects.find((effect) => effect.effectType === 104)?.miscValue ?? 0,
triggerSpellId: 0,
durationMs: rank.durationMs,
}];
case "hunter:Immolation Trap": {
const child = HUNTER_IMMOLATION_TRAP_CHILD_BY_RANK[rank.spellId];
return [
{
kind: "utility",
action: "class-script",
effectType: 105,
auraType: 0,
miscValue: rank.effects.find((effect) => effect.effectType === 105)?.miscValue ?? 0,
triggerSpellId: 0,
durationMs: rank.durationMs,
},
...(child ? [{
kind: "dot" as const,
coefficient: 0,
basePoints: child.basePoints,
dieSides: child.dieSides,
rangedAttackPowerCoefficient: 0.02,
sourceLevel: Math.max(1, rank.sourceLevel || rank.level),
...(rank.maxScalingLevel > 0 ? { maxScalingLevel: rank.maxScalingLevel } : {}),
school: "fire" as const,
ticks: 5,
intervalMs: 3_000,
tag: "hunter-immolation-trap",
}] : []),
];
}
case "hunter:Explosive Trap": {
const child = HUNTER_EXPLOSIVE_TRAP_CHILD_BY_RANK[rank.spellId];
return child ? [{
@@ -1433,6 +1482,26 @@ function classScriptEffects(
mode: "percent",
amount: rank.effects.find((effect) => effect.effectType === 3)?.basePoints ?? -50,
}];
// Soul Link's populated talent row provides the gameplay percentage and
// demon restrictions; its active DBC spell row is only a dummy marker.
case "warlock:Soul Link": return [{
kind: "apply-aura",
recipient: "caster",
aura: {
id: "wow335:warlock:soul-link",
name: abilityName,
description: "Shares 6% of incoming damage with your active, controlled demon within 30 yards.",
disposition: "buff",
durationMs: null,
maxStacks: 1,
stackBehavior: "replace",
utilityTags: [WOW335_WARLOCK_SOUL_LINK_TAG],
},
sourceEffectType: 3,
sourceAuraType: 0,
miscValue: 0,
triggerSpellId: 0,
}];
case "warlock:Life Tap": return [{
kind: "resource",
resource: "mana",
@@ -1573,6 +1642,20 @@ const HUNTER_EXPLOSIVE_TRAP_CHILD_BY_RANK: Readonly<Record<number, {
49067: { directBasePoints: 523, directDieSides: 149, periodicBasePoints: 90, periodicDieSides: 1, sourceLevel: 77, maxScalingLevel: 81 },
};
const HUNTER_IMMOLATION_TRAP_CHILD_BY_RANK: Readonly<Record<number, {
basePoints: number;
dieSides: number;
}>> = {
13795: { basePoints: 21, dieSides: 1 },
14302: { basePoints: 43, dieSides: 1 },
14303: { basePoints: 68, dieSides: 1 },
14304: { basePoints: 102, dieSides: 1 },
14305: { basePoints: 138, dieSides: 1 },
27023: { basePoints: 197, dieSides: 1 },
49055: { basePoints: 308, dieSides: 1 },
49056: { basePoints: 377, dieSides: 1 },
};
export function hunterExplosiveTrapDirectScaling(
spellId: number,
sourceLevel = 0,
@@ -2162,7 +2245,11 @@ function abilityDefinition(classId: BaseClassId, chain: Wow335Chain): AbilityDef
return healing ? { ...rank, effects: [...rank.effects, ...healing.effects] } : rank;
})
: playerRanks;
const ranks = castRanks.map((rank, index) => rankDefinition(classId, resource, rank, index, chain.name));
const soulLinkTalentTooltip = classId === "warlock" && chain.name === "Soul Link"
? WOW335_TALENT_NODES.find((node) => node.id === chain.talentNodeId)?.rankDescriptions[0]
: undefined;
const ranks = castRanks.map((rank, index) => rankDefinition(classId, resource, rank, index, chain.name))
.map((rank) => soulLinkTalentTooltip ? { ...rank, description: soulLinkTalentTooltip } : rank);
const first = ranks[0];
const firstRaw = castRanks[0];
if (!first || !firstRaw) return null;
@@ -2254,6 +2341,7 @@ function abilityNameTarget(classId: BaseClassId, abilityName: string): AbilityTa
if (abilityName === "Soulshatter") return "self";
if (abilityName === "Desperate Prayer") return "self";
if (abilityName === "Lightwell") return "self";
if (classId === "warlock" && abilityName === "Soul Link") return "self";
if (abilityName === "Dispel Magic") return "any";
if (abilityName === "Holy Shock") return "any";
if (abilityName === "Volley") return "hostile";
@@ -2272,13 +2360,21 @@ function classicCooldownGroup(classId: BaseClassId, abilityName: string): string
}
export const WOW335_ABILITIES_BY_CLASS: Readonly<Record<BaseClassId, readonly AbilityDefinition[]>> =
Object.freeze(Object.fromEntries(BASE_CLASS_IDS.map((classId) => [
classId,
data.classes[classId]
Object.freeze(Object.fromEntries(BASE_CLASS_IDS.map((classId) => {
const generated = data.classes[classId]
.map((chain) => abilityDefinition(classId, chain))
.filter((ability): ability is AbilityDefinition => Boolean(ability))
.sort((left, right) => left.unlockLevel - right.unlockLevel || left.name.localeCompare(right.name)),
]))) as unknown as Readonly<Record<BaseClassId, readonly AbilityDefinition[]>>;
.filter((ability): ability is AbilityDefinition => Boolean(ability));
const specialized = classId === "warlock"
? [
...generated.filter((ability) => ability.id !== "wow335-warlock-metamorphosis"),
wow335WarlockMetamorphosisAbility(),
...WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITIES,
]
: generated;
return [classId, specialized.sort((left, right) => (
left.unlockLevel - right.unlockLevel || left.name.localeCompare(right.name)
))];
}))) as unknown as Readonly<Record<BaseClassId, readonly AbilityDefinition[]>>;
// These ground channels store their actual damage in same-name triggered
// child spells. Resolve the child once so each channel pulse can use its