117 lines
4.6 KiB
TypeScript
117 lines
4.6 KiB
TypeScript
import { WOW335_TALENT_NODES } from "./wow335Talents.generated";
|
|
|
|
export const WOW335_DEATH_KNIGHT_BLOOD_GORGED_TALENT_ID = "talent-2034";
|
|
|
|
const BLOOD_GORGED_DAMAGE_CHILD_IDS = [50096, 50108, 50109, 50110, 50111] as const;
|
|
const BLOOD_GORGED_ARMOR_CHILD_IDS = [61274, 61275, 61276, 61277, 61278] as const;
|
|
|
|
/** Local Spell.dbc uses Death Knight family 15 and this three-word aura mask. */
|
|
export const WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_NAME = 15;
|
|
export const WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_MASK = [0x01400001, 0, 0] as const;
|
|
|
|
const BLOOD_GORGED_NODE = WOW335_TALENT_NODES.find(
|
|
(node) => node.id === WOW335_DEATH_KNIGHT_BLOOD_GORGED_TALENT_ID,
|
|
);
|
|
|
|
export interface Wow335DeathKnightBloodGorgedProfile {
|
|
readonly rank: number;
|
|
readonly damageBonusPercent: number;
|
|
readonly armorPenetrationPercent: number;
|
|
readonly damageChildSpellId: number;
|
|
readonly armorChildSpellId: number;
|
|
readonly damageAuraType: 79;
|
|
readonly damageSchoolMask: 127;
|
|
readonly armorAuraType: 280;
|
|
readonly spellFamilyName: 15;
|
|
readonly spellFamilyMask: readonly [number, number, number];
|
|
}
|
|
|
|
/**
|
|
* Read the rank values and child-spell links from the generated local talent
|
|
* rows. Aura types and the family mask are verified against the local 3.3.5
|
|
* Spell.dbc and recorded in docs/WOW_DEATH_KNIGHT_BLOOD_GORGED.md.
|
|
*/
|
|
export function wow335DeathKnightBloodGorgedProfile(
|
|
rank: number,
|
|
): Wow335DeathKnightBloodGorgedProfile | null {
|
|
const normalizedRank = Math.trunc(rank);
|
|
const rankEffect = BLOOD_GORGED_NODE?.rankEffects[normalizedRank - 1];
|
|
const rankDescription = BLOOD_GORGED_NODE?.rankDescriptions[normalizedRank - 1];
|
|
if (normalizedRank < 1 || !rankEffect || !rankDescription) return null;
|
|
|
|
const descriptionValues = rankDescription.match(
|
|
/^When you are above 75% health, you deal (\d+)% more damage\. In addition, your attacks ignore up to (\d+)% of your opponent's armor at all times\.$/,
|
|
);
|
|
const damageBonusPercent = Number(descriptionValues?.[1]);
|
|
const armorPenetrationPercent = Number(descriptionValues?.[2]);
|
|
const damageChild = rankEffect.effects.find(
|
|
(effect) => effect.triggerSpellId === BLOOD_GORGED_DAMAGE_CHILD_IDS[normalizedRank - 1],
|
|
);
|
|
const armorChild = rankEffect.effects.find(
|
|
(effect) => effect.triggerSpellId === BLOOD_GORGED_ARMOR_CHILD_IDS[normalizedRank - 1],
|
|
);
|
|
|
|
if (!descriptionValues
|
|
|| !damageChild
|
|
|| !armorChild
|
|
|| damageChild.basePoints !== damageBonusPercent
|
|
|| armorChild.basePoints !== armorPenetrationPercent
|
|
|| damageBonusPercent <= 0
|
|
|| armorPenetrationPercent <= 0) return null;
|
|
|
|
return {
|
|
rank: normalizedRank,
|
|
damageBonusPercent,
|
|
armorPenetrationPercent,
|
|
damageChildSpellId: damageChild.triggerSpellId,
|
|
armorChildSpellId: armorChild.triggerSpellId,
|
|
damageAuraType: 79,
|
|
damageSchoolMask: 127,
|
|
armorAuraType: 280,
|
|
spellFamilyName: WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_NAME,
|
|
spellFamilyMask: WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_MASK,
|
|
};
|
|
}
|
|
|
|
/** The local DBC aura applies only to matching Death Knight family-15 spells. */
|
|
export function wow335DeathKnightBloodGorgedAffectsSpell(
|
|
spellFamilyName: number,
|
|
spellFamilyFlags: readonly [number, number, number],
|
|
): boolean {
|
|
if (spellFamilyName !== WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_NAME) return false;
|
|
if (spellFamilyFlags.some((flags) => !Number.isSafeInteger(flags) || flags < 0 || flags > 0xFFFFFFFF)) return false;
|
|
return WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_MASK.some((mask, index) => (
|
|
(spellFamilyFlags[index] & mask) !== 0
|
|
));
|
|
}
|
|
|
|
/** Above 75% is strict; exactly 75% does not receive the damage bonus. */
|
|
export function wow335DeathKnightBloodGorgedDamageBonusPercent(
|
|
rank: number,
|
|
currentHealth: number,
|
|
maximumHealth: number,
|
|
spellFamilyName: number,
|
|
spellFamilyFlags: readonly [number, number, number],
|
|
): number {
|
|
const profile = wow335DeathKnightBloodGorgedProfile(rank);
|
|
if (!profile
|
|
|| !wow335DeathKnightBloodGorgedAffectsSpell(spellFamilyName, spellFamilyFlags)
|
|
|| !Number.isFinite(currentHealth)
|
|
|| currentHealth < 0
|
|
|| !Number.isFinite(maximumHealth)
|
|
|| maximumHealth <= 0
|
|
|| currentHealth <= maximumHealth * 0.75) return 0;
|
|
return profile.damageBonusPercent;
|
|
}
|
|
|
|
/** Armor penetration is unconditional on health, but remains family-mask gated. */
|
|
export function wow335DeathKnightBloodGorgedArmorPenetrationPercent(
|
|
rank: number,
|
|
spellFamilyName: number,
|
|
spellFamilyFlags: readonly [number, number, number],
|
|
): number {
|
|
const profile = wow335DeathKnightBloodGorgedProfile(rank);
|
|
if (!profile || !wow335DeathKnightBloodGorgedAffectsSpell(spellFamilyName, spellFamilyFlags)) return 0;
|
|
return profile.armorPenetrationPercent;
|
|
}
|