forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
4c768fbec6
commit
b16821e92e
330 files changed
+35406
-1760
No files matched your search
@@ -0,0 +1,115 @@
|
||||
import { WOW335_TALENT_NODES } from "./wow335Talents.generated";
|
||||
import type { EnemyDamageSchool } from "./enemyAttacks";
|
||||
|
||||
export const WOW335_DEATH_KNIGHT_SPELL_DEFLECTION_TALENT_ID = "talent-2018";
|
||||
|
||||
const WOW335_DAMAGE_SCHOOL_MASKS: Readonly<Record<EnemyDamageSchool, number>> = {
|
||||
physical: 1,
|
||||
holy: 2,
|
||||
fire: 4,
|
||||
nature: 8,
|
||||
frost: 16,
|
||||
shadow: 32,
|
||||
arcane: 64,
|
||||
};
|
||||
|
||||
/** Translate the incoming combat-school label into its 3.3.5 DBC school bit. */
|
||||
export function wow335DeathKnightSpellDeflectionSchoolMask(school: EnemyDamageSchool): number {
|
||||
return WOW335_DAMAGE_SCHOOL_MASKS[school];
|
||||
}
|
||||
|
||||
const SPELL_DEFLECTION_NODE = WOW335_TALENT_NODES.find(
|
||||
(node) => node.id === WOW335_DEATH_KNIGHT_SPELL_DEFLECTION_TALENT_ID,
|
||||
);
|
||||
|
||||
export interface Wow335DeathKnightSpellDeflectionProfile {
|
||||
readonly rank: number;
|
||||
readonly absorbFraction: number;
|
||||
readonly procChanceSource: "live-parry";
|
||||
readonly auraType: 69;
|
||||
readonly schoolMask: number;
|
||||
}
|
||||
|
||||
/** Read rank reduction and spell-school mask from generated local talent rows. */
|
||||
export function wow335DeathKnightSpellDeflectionProfile(
|
||||
rank: number,
|
||||
): Wow335DeathKnightSpellDeflectionProfile | null {
|
||||
const normalizedRank = Math.trunc(rank);
|
||||
const rankEffect = SPELL_DEFLECTION_NODE?.rankEffects[normalizedRank - 1];
|
||||
const description = SPELL_DEFLECTION_NODE?.rankDescriptions[normalizedRank - 1];
|
||||
if (normalizedRank < 1 || !rankEffect || !description
|
||||
|| rankEffect.procCharges !== 0
|
||||
|| rankEffect.recoveryTimeMs !== 0
|
||||
|| rankEffect.categoryRecoveryTimeMs !== 0) return null;
|
||||
|
||||
const values = description.match(
|
||||
/^You have a chance equal to your Parry chance of taking (\d+(?:\.\d+)?)% less damage from a direct damage spell\.$/,
|
||||
);
|
||||
const effect = rankEffect.effects.find((candidate) => candidate.effectType === 6 && candidate.auraType === 69);
|
||||
const reductionPercent = Number(values?.[1]);
|
||||
if (!values || !effect || effect.miscValue !== 126
|
||||
|| !Number.isFinite(reductionPercent) || reductionPercent <= 0 || reductionPercent >= 100) return null;
|
||||
|
||||
return {
|
||||
rank: normalizedRank,
|
||||
absorbFraction: reductionPercent / 100,
|
||||
procChanceSource: "live-parry",
|
||||
auraType: effect.auraType,
|
||||
schoolMask: effect.miscValue,
|
||||
};
|
||||
}
|
||||
|
||||
export interface Wow335DeathKnightSpellDeflectionEvent {
|
||||
/** True only for one direct spell-damage hit; periodic ticks and weapon hits are excluded. */
|
||||
readonly directDamageSpell: boolean;
|
||||
/** DBC school mask for the incoming spell hit; Spell Deflection has mask 126. */
|
||||
readonly schoolMask: number;
|
||||
/** Defender's current, fully derived Parry chance in percentage points, such as 7.5. */
|
||||
readonly parryChancePercent: number;
|
||||
/** Deterministic unit roll in [0, 1). */
|
||||
readonly roll: number;
|
||||
/** Resolved spell damage before this talent's absorb; misses and zero-damage hits cannot proc. */
|
||||
readonly damage: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proc chance equals the defender's current Parry chance. The generated aura is
|
||||
* School Absorb (69), limited by school mask 126, and applies to direct hits.
|
||||
*/
|
||||
export function wow335DeathKnightSpellDeflectionShouldProc(
|
||||
rank: number,
|
||||
event: Wow335DeathKnightSpellDeflectionEvent,
|
||||
): boolean {
|
||||
const profile = wow335DeathKnightSpellDeflectionProfile(rank);
|
||||
if (!profile
|
||||
|| !event.directDamageSpell
|
||||
|| !Number.isSafeInteger(event.schoolMask) || event.schoolMask <= 0
|
||||
|| (event.schoolMask & profile.schoolMask) === 0
|
||||
|| !Number.isFinite(event.damage) || event.damage <= 0
|
||||
|| !Number.isFinite(event.parryChancePercent)
|
||||
|| !Number.isFinite(event.roll) || event.roll < 0 || event.roll >= 1) return false;
|
||||
const chance = Math.min(100, Math.max(0, event.parryChancePercent)) / 100;
|
||||
return chance > 0 && event.roll < chance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the amount absorbed from this hit. Generated rows specify the percent,
|
||||
* not fractional-damage rounding; this simulator floors to whole damage points.
|
||||
*/
|
||||
export function wow335DeathKnightSpellDeflectionAbsorbedAmount(
|
||||
damage: number,
|
||||
rank: number,
|
||||
): number {
|
||||
const profile = wow335DeathKnightSpellDeflectionProfile(rank);
|
||||
if (!profile || !Number.isFinite(damage) || damage <= 0) return 0;
|
||||
return Math.min(Math.floor(damage), Math.floor(Math.floor(damage) * profile.absorbFraction));
|
||||
}
|
||||
|
||||
/** Apply the generated partial absorb after the proc roll has succeeded. */
|
||||
export function wow335DeathKnightSpellDeflectionDamage(
|
||||
damage: number,
|
||||
rank: number,
|
||||
): number {
|
||||
if (!Number.isFinite(damage) || damage <= 0) return Math.max(0, Number.isFinite(damage) ? Math.floor(damage) : 0);
|
||||
return Math.max(0, Math.floor(damage) - wow335DeathKnightSpellDeflectionAbsorbedAmount(damage, rank));
|
||||
}
|
||||
Reference in new issue
Block a user