Files
healer-man/src/game/wow335WarlockMetamorphosisRuntime.ts
T
2026-09-30 09:57:13 -04:00

221 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { AbilityDefinition } from "./abilityCatalog";
import type { AuraDefinition, DamageSchool } from "./combatAuras";
export const WOW335_WARLOCK_METAMORPHOSIS_AURA_TAG = "wow335-warlock-metamorphosis";
export const WOW335_WARLOCK_METAMORPHOSIS_FORM_ID = 22;
export const WOW335_WARLOCK_METAMORPHOSIS_IMMOLATION_TAG = "wow335-warlock-immolation-aura";
export const WOW335_WARLOCK_METAMORPHOSIS_IMMOLATION_AP_AURA_TAG = "wow335-warlock-immolation-ap";
export const WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITY_IDS = Object.freeze([
"wow335-warlock-shadow-cleave",
"wow335-warlock-challenging-howl",
"wow335-warlock-demon-charge",
"wow335-warlock-immolation-aura",
] as const);
export interface WarlockMetamorphosisEffects {
readonly rank: 1;
readonly durationMs: 30_000;
readonly cooldownMs: 180_000;
readonly armorContributionPercent: 130;
readonly damagePercent: 15;
readonly meleeCritChanceTakenReductionPercent: 6;
readonly stunSnareDurationReductionPercent: 25;
readonly allowedSchools: readonly ["fire", "shadow"];
/** PvP-only modifier is sourced but has no player-target model here. */
readonly pvpDamageBonusPercent: null;
}
/**
* Values come from the generated local Metamorphosis talent-1886 row and its
* source spells 47241, 54817, and 54879 in the local 3.3.5a talent DBC.
* The PvP-only +10% damage tooltip rider is omitted because this runtime has
* no PvP player-target model.
*/
export function wow335WarlockMetamorphosisEffectsForRank(rank: number): WarlockMetamorphosisEffects | null {
if (!Number.isFinite(rank) || Math.trunc(rank) < 1) return null;
return {
rank: 1,
durationMs: 30_000,
cooldownMs: 180_000,
armorContributionPercent: 130,
damagePercent: 15,
meleeCritChanceTakenReductionPercent: 6,
stunSnareDurationReductionPercent: 25,
allowedSchools: ["fire", "shadow"],
pvpDamageBonusPercent: null,
};
}
export interface WarlockMetamorphosisAbilityContext {
readonly school?: DamageSchool;
readonly schools?: readonly DamageSchool[];
/** Explicit local metadata for spells that are allowed during shapeshift. */
readonly usableWhileShapeshifted?: boolean;
}
/** The local Metamorphosis description permits Fire/Shadow or shapeshift-safe spells. */
export function warlockMetamorphosisAbilityEligible(
isMetamorphosisActive: boolean,
ability: WarlockMetamorphosisAbilityContext,
): boolean {
const schools = [ability.school, ...(ability.schools ?? [])];
return !isMetamorphosisActive
|| ability.usableWhileShapeshifted === true
|| schools.some((school) => school === "fire" || school === "shadow");
}
/** Gate based only on explicit spell schools or explicit shapeshift-safe text. */
export function warlockMetamorphosisCanCastAbilityWhileActive(
ability: Pick<AbilityDefinition, "id" | "description" | "effects" | "castRules">,
): boolean {
if ((WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITY_IDS as readonly string[]).includes(ability.id)) return true;
const schools: DamageSchool[] = ability.effects.flatMap((effect) => (
(effect.kind === "damage" || effect.kind === "dot") && effect.school ? [effect.school] : []
));
if (ability.castRules?.school) schools.push(ability.castRules.school);
if (!schools.length && ability.effects.some((effect) => effect.kind === "damage" || effect.kind === "dot")) {
const text = ability.description.toLowerCase();
if (/\bshadow\s+(?:damage|spell|magic)\b/.test(text)) schools.push("shadow");
else if (/\bfire\s+(?:damage|spell|magic)\b/.test(text)) schools.push("fire");
}
return warlockMetamorphosisAbilityEligible(true, {
schools,
usableWhileShapeshifted: /\busable while shapeshifted\b/i.test(ability.description),
});
}
export function warlockMetamorphosisFormActionReady(abilityId: string, isFormActive: boolean): boolean {
return !(WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITY_IDS as readonly string[]).includes(abilityId)
|| isFormActive;
}
export function wow335WarlockMetamorphosisControlDuration(
durationMs: number,
mechanic: string,
isFormActive: boolean,
): number {
const safeDuration = Math.max(0, Number.isFinite(durationMs) ? durationMs : 0);
return isFormActive && ["stun", "root", "slow"].includes(mechanic)
? Math.round(safeDuration * 0.75)
: safeDuration;
}
/** Spell.dbc Immolated child: tooltip formula is 4.5 × player level − 3. */
export function wow335WarlockImmolationAttackPowerReduction(level: number): number {
const safeLevel = Math.max(1, Math.trunc(Number.isFinite(level) ? level : 1));
return Math.max(0, Math.round(4.5 * safeLevel - 3));
}
export function wow335WarlockImmolationAttackPowerAura(level: number): AuraDefinition {
const reduction = wow335WarlockImmolationAttackPowerReduction(level);
return {
id: `wow335:warlock:immolation-ap:${reduction}`,
name: "Immolated",
description: `Reduces attack power by ${reduction} for 30 seconds.`,
disposition: "debuff",
durationMs: 30_000,
maxStacks: 1,
stackBehavior: "replace",
uniqueBySource: true,
utilityTags: [WOW335_WARLOCK_METAMORPHOSIS_IMMOLATION_AP_AURA_TAG],
modifiers: [{ kind: "stat", stat: "attack-power", operation: "flat", value: -reduction }],
};
}
/** Numeric modifiers currently expressible by the shared aura resolver. */
export function wow335WarlockMetamorphosisAuraForRank(rank: number): AuraDefinition | null {
const effects = wow335WarlockMetamorphosisEffectsForRank(rank);
if (!effects) return null;
return {
id: "wow335:warlock:metamorphosis",
name: "Metamorphosis",
description: "Increases armor contribution from cloth and leather by 130% and damage dealt by 15%; reduces melee critical hits against you by 6% and stun and snare durations by 25% while transformed. The PvP-only +10% damage rider is not applied because PvP player targets are unsupported.",
disposition: "buff",
durationMs: effects.durationMs,
maxStacks: 1,
stackBehavior: "replace",
uniqueBySource: true,
exclusiveGroup: "warlock:form",
utilityTags: ["shapeshift", WOW335_WARLOCK_METAMORPHOSIS_AURA_TAG],
modifiers: [
{ kind: "stat", stat: "armor", operation: "percent", value: effects.armorContributionPercent / 100 },
{ kind: "stat", stat: "incoming-melee-critical-strike", operation: "flat", value: -effects.meleeCritChanceTakenReductionPercent },
{ kind: "damage", direction: "dealt", operation: "percent", value: effects.damagePercent / 100 },
],
};
}
const formOnly = { sourceRankText: "Demon", formOnly: true } as const;
/** These rankless buttons are reconstructed from their local Spell.dbc rows and children. */
export const WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITIES: readonly AbilityDefinition[] = [
{
id: WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITY_IDS[0], classId: "warlock", dbcSpellId: 50581,
name: "Shadow Cleave", unlockLevel: 1, sourceUnlockLevel: 1,
icon: "/assets/ui/spells/spell_shadow_shadowfury.png", sigil: "SC",
description: "Inflicts 110 Shadow damage to an enemy target and nearby allies, affecting up to 3 targets. Costs 4% base mana.",
target: "hostile", range: { min: 0, max: 5 }, castMode: "instant", castTimeMs: 0,
cooldownMs: 6_000, gcdMs: 0,
cost: { resource: "mana", amount: 4, percentage: true, percentageBasis: "base-mana" },
effects: [{ kind: "damage", coefficient: 0, school: "shadow", basePoints: 110, dieSides: 1, bonusPowerCoefficient: 1 }],
targeting: { shape: "chain", maximumTargets: 3 },
source: "wow335-progression", ...formOnly,
} as AbilityDefinition,
{
id: WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITY_IDS[1], classId: "warlock", dbcSpellId: 59671,
name: "Challenging Howl", unlockLevel: 1, sourceUnlockLevel: 1,
icon: "/assets/ui/spells/ability_warlock_demonicempowerment.png", sigil: "CH",
description: "Forces all nearby enemies within 10 yards to focus attacks on you for 6 seconds.",
target: "self", range: { min: 0, max: 0 }, radius: 10, castMode: "instant", castTimeMs: 0,
cooldownMs: 180_000, gcdMs: 1_500, cost: { resource: "rage", amount: 0 },
effects: [{ kind: "taunt", durationMs: 6_000 }],
targeting: { shape: "circle", radius: 10 }, source: "wow335-progression", ...formOnly,
} as AbilityDefinition,
{
id: WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITY_IDS[2], classId: "warlock", dbcSpellId: 54785,
name: "Demon Charge", unlockLevel: 1, sourceUnlockLevel: 1,
icon: "/assets/ui/spells/ability_warlock_demonicempowerment.png", sigil: "DC",
description: "Charge an enemy, stunning it for 3 seconds. Range 8–25 yards; 45 second cooldown.",
target: "hostile", range: { min: 8, max: 25 }, castMode: "instant", castTimeMs: 0,
cooldownMs: 45_000, gcdMs: 1_500, cost: { resource: "mana", amount: 0 },
effects: [
{ kind: "movement", movement: "charge", toward: "target" },
{ kind: "status", status: "stun", durationMs: 3_000 },
], source: "wow335-progression", ...formOnly,
} as AbilityDefinition,
{
id: WOW335_WARLOCK_METAMORPHOSIS_FORM_ABILITY_IDS[3], classId: "warlock", dbcSpellId: 50589,
name: "Immolation Aura", unlockLevel: 1, sourceUnlockLevel: 1,
icon: "/assets/ui/spells/spell_fire_selfdestruct.png", sigil: "IA",
description: "For 10 seconds, burns nearby enemies for 251 Fire damage plus 11.5 per level and 14.3% spell power every second within 8 yards, reducing their attack power by 4.5 × level − 3 for 30 seconds. Costs 64% base mana.",
target: "self", range: { min: 0, max: 0 }, radius: 8, castMode: "instant", castTimeMs: 0,
cooldownMs: 30_000, gcdMs: 1_500,
cost: { resource: "mana", amount: 64, percentage: true, percentageBasis: "base-mana" },
effects: [
{ kind: "dot", coefficient: 0, school: "fire", basePoints: 251, dieSides: 1, pointsPerLevel: 11.5,
bonusPowerCoefficient: 0.143, sourceLevel: 1, ticks: 10, intervalMs: 1_000, tag: WOW335_WARLOCK_METAMORPHOSIS_IMMOLATION_TAG },
{ kind: "apply-aura", recipient: "caster", aura: {
id: "wow335:warlock:immolation-aura", name: "Immolation Aura",
description: "Emits Fire pulses for 10 seconds. Loss of control suppresses pulses.",
disposition: "buff", durationMs: 10_000, maxStacks: 1, stackBehavior: "replace",
utilityTags: [WOW335_WARLOCK_METAMORPHOSIS_IMMOLATION_TAG],
}, sourceEffectType: 6, sourceAuraType: 23, miscValue: 0, triggerSpellId: 50590 },
],
targeting: { shape: "circle", radius: 8 }, source: "wow335-progression", ...formOnly,
} as AbilityDefinition,
];
export function wow335WarlockMetamorphosisAbility(): AbilityDefinition {
return {
id: "wow335-warlock-metamorphosis", classId: "warlock", dbcSpellId: 59672,
name: "Metamorphosis", unlockLevel: 1, sourceUnlockLevel: 1,
icon: "/assets/ui/spells/spell_shadow_demonform.png", sigil: "ME",
description: "Transform into a Demon for 30 seconds. Increases armor contribution from cloth and leather items by 130% and damage dealt by 15%; reduces melee critical chance taken by 6% and stun/snare duration by 25%. Grants four Demon-only abilities. Only Fire/Shadow spells and abilities or spells explicitly usable while shapeshifted may be cast. PvP-only +10% damage is unsupported.",
target: "self", range: { min: 0, max: 0 }, castMode: "instant", castTimeMs: 0,
cooldownMs: 180_000, gcdMs: 0, cost: { resource: "mana", amount: 0 },
effects: [{ kind: "apply-aura", recipient: "caster", aura: wow335WarlockMetamorphosisAuraForRank(1)!,
sourceEffectType: 6, sourceAuraType: 36, miscValue: WOW335_WARLOCK_METAMORPHOSIS_FORM_ID, triggerSpellId: 0 }],
talentNodeId: "talent-1886", source: "wow335-progression",
};
}