Update Healer Man server
This commit is contained in:
1 parent
35dfdaed61
commit
4fb7a0b9c8
161 files changed
+24618
-529
No files matched your search
@@ -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
|
||||
|
||||
Reference in new issue
Block a user