diff --git a/public/img/Icons/inv_axe_2h_fyrakk_d_01_shadowflame.jpg b/public/img/Icons/inv_axe_2h_fyrakk_d_01_shadowflame.jpg new file mode 100644 index 00000000000..92248e26530 Binary files /dev/null and b/public/img/Icons/inv_axe_2h_fyrakk_d_01_shadowflame.jpg differ diff --git a/src/CHANGELOG.tsx b/src/CHANGELOG.tsx index 8ce2e432c7f..c5c21ff6978 100644 --- a/src/CHANGELOG.tsx +++ b/src/CHANGELOG.tsx @@ -32,6 +32,9 @@ import SpellLink from 'interface/SpellLink'; // prettier-ignore export default [ + change(date(2024, 1, 7), <>Add checklist support for ., ToppleTheNun), + change(date(2024, 1, 4), <>Add statistics for ., Arbixal), + change(date(2024, 1, 2), 'Remove Shadowlands food and augment rune support.', ToppleTheNun), change(date(2023, 12, 31), <>Add resource initialization and granularity support for ResourceTracker module., Vollmer), change(date(2023, 12, 30), 'Fix errors caused by ESLint update.', ToppleTheNun), change(date(2023, 12, 28), 'Improve internal handling of phases', emallson), diff --git a/src/analysis/retail/demonhunter/havoc/CHANGELOG.tsx b/src/analysis/retail/demonhunter/havoc/CHANGELOG.tsx index 150e58b6eca..bec9063bd8b 100644 --- a/src/analysis/retail/demonhunter/havoc/CHANGELOG.tsx +++ b/src/analysis/retail/demonhunter/havoc/CHANGELOG.tsx @@ -7,6 +7,7 @@ import SHARED_CHANGELOG from 'analysis/retail/demonhunter/shared/CHANGELOG'; // prettier-ignore export default [ + change(date(2024, 1, 4), <>Update explanation for to match 10.2 logic., ToppleTheNun), change(date(2023, 7, 13), 'Disable checklist.', ToppleTheNun), change(date(2023, 7, 11), 'Update for 10.1.5.', ToppleTheNun), change(date(2023, 6, 17), <>Fix damage calculations for ., ToppleTheNun), diff --git a/src/analysis/retail/demonhunter/havoc/Guide.tsx b/src/analysis/retail/demonhunter/havoc/Guide.tsx index af71da56dcc..b673eb07388 100644 --- a/src/analysis/retail/demonhunter/havoc/Guide.tsx +++ b/src/analysis/retail/demonhunter/havoc/Guide.tsx @@ -16,6 +16,9 @@ import { } from './modules/resourcetracker/FuryTracker'; import FuryCapWaste from './guide/FuryCapWaste'; import HideGoodCastsToggle from 'interface/guide/components/HideGoodCastsToggle'; +import { PerformanceStrong } from 'analysis/retail/priest/shadow/modules/guide/ExtraComponents'; +import { formatPercentage } from 'common/format'; +import ActiveTimeGraph from 'parser/ui/ActiveTimeGraph'; export default function Guide({ modules, events, info }: GuideProps) { return ( @@ -28,12 +31,12 @@ export default function Guide({ modules, events, info }: GuideProps) { +function ResourceUsageSection({ info, modules }: GuideProps) { const percentAtFuryCap = modules.furyTracker.percentAtCap; const percentAtFuryCapPerformance = modules.furyTracker.percentAtCapPerformance; const furyWasted = modules.furyTracker.wasted; return ( -
+

Havoc's primary resource is . You should avoid @@ -50,6 +53,28 @@ function ResourceUsageSection({ modules }: GuideProps) { /> {modules.furyGraph.plot} + +

+ + Continuously casting throughout an encounter is the single most important thing for + achieving good DPS. + +
+ Some fights have unavoidable downtime due to phase transitions and the like, so in these + cases 0% downtime will not be possible - do the best you can. +

+

+ Active Time:{' '} + + {formatPercentage(modules.alwaysBeCasting.activeTimePercentage, 1)}% + {' '} +

+ +
); } diff --git a/src/analysis/retail/demonhunter/havoc/constants.ts b/src/analysis/retail/demonhunter/havoc/constants.ts index 4f4bde1de96..aba37c46094 100644 --- a/src/analysis/retail/demonhunter/havoc/constants.ts +++ b/src/analysis/retail/demonhunter/havoc/constants.ts @@ -22,6 +22,4 @@ export const GROWING_INFERNO_SCALING = [0, 0.08, 0.15]; export const BURNING_WOUND_SCALING = [0, 0.4]; -export const ACCELERATING_BLADE_SCALING = [0, 0.2]; - export const MOMENTUM_SCALING = [0, 0.08]; diff --git a/src/analysis/retail/demonhunter/havoc/modules/spells/ThrowGlaive/AcceleratingBladeExplanation.tsx b/src/analysis/retail/demonhunter/havoc/modules/spells/ThrowGlaive/AcceleratingBladeExplanation.tsx index c634fae1dea..9097eb069da 100644 --- a/src/analysis/retail/demonhunter/havoc/modules/spells/ThrowGlaive/AcceleratingBladeExplanation.tsx +++ b/src/analysis/retail/demonhunter/havoc/modules/spells/ThrowGlaive/AcceleratingBladeExplanation.tsx @@ -2,27 +2,26 @@ import { useInfo } from 'interface/guide'; import TALENTS from 'common/TALENTS/demonhunter'; import SpellLink from 'interface/SpellLink'; import { formatPercentage } from 'common/format'; -import { ACCELERATING_BLADE_SCALING } from 'analysis/retail/demonhunter/havoc/constants'; import Tooltip from 'interface/Tooltip'; import InformationIcon from 'interface/icons/Information'; +export const SCALING_PER_TARGET_HIT = 0.3; +export const INITIAL_HIT_SCALING = 0.6; + export const AcceleratingBladeExplanation = () => { const info = useInfo(); if (!info || !info.combatant.hasTalent(TALENTS.ACCELERATED_BLADE_TALENT)) { return null; } - const scaling = - ACCELERATING_BLADE_SCALING[info.combatant.getTalentRank(TALENTS.ACCELERATED_BLADE_TALENT)]; - const perTargetScaling = 1 + scaling; + const primaryTargetScalingValue = 1 + INITIAL_HIT_SCALING; + const secondaryTargetScalingValue = primaryTargetScalingValue * (1 - SCALING_PER_TARGET_HIT); + const tertiaryTargetScalingValue = secondaryTargetScalingValue * (1 - SCALING_PER_TARGET_HIT); // multiplicative scaling - const primaryTargetScaling = formatPercentage(perTargetScaling, 0); - const secondaryTargetScaling = formatPercentage(perTargetScaling * perTargetScaling, 0); - const tertiaryTargetScaling = formatPercentage( - perTargetScaling * perTargetScaling * perTargetScaling, - 0, - ); + const primaryTargetScaling = formatPercentage(primaryTargetScalingValue, 0); + const secondaryTargetScaling = formatPercentage(secondaryTargetScalingValue, 0); + const tertiaryTargetScaling = formatPercentage(tertiaryTargetScalingValue, 0); return (
  • diff --git a/src/analysis/retail/demonhunter/shared/CHANGELOG.tsx b/src/analysis/retail/demonhunter/shared/CHANGELOG.tsx index 9d60043d7dd..e2c4e4a4919 100644 --- a/src/analysis/retail/demonhunter/shared/CHANGELOG.tsx +++ b/src/analysis/retail/demonhunter/shared/CHANGELOG.tsx @@ -8,6 +8,7 @@ import { ResourceLink } from 'interface'; // prettier-ignore export default [ + change(date(2024, 1, 4), 'Add uptime graph.', ToppleTheNun), change(date(2023, 11, 6), 'Mark as updated for 10.2.', ToppleTheNun), change(date(2023, 10, 9), 'Update ability cooldowns and scaling in spellbooks.', ToppleTheNun), change(date(2023, 10, 9), 'Start updating for 10.2.', ToppleTheNun), diff --git a/src/analysis/retail/demonhunter/vengeance/Guide.tsx b/src/analysis/retail/demonhunter/vengeance/Guide.tsx index fa3af576716..ede53729c47 100644 --- a/src/analysis/retail/demonhunter/vengeance/Guide.tsx +++ b/src/analysis/retail/demonhunter/vengeance/Guide.tsx @@ -19,11 +19,14 @@ import { OK_TIME_AT_FURY_CAP, PERFECT_TIME_AT_FURY_CAP, } from './modules/resourcetracker/FuryTracker'; +import { PerformanceStrong } from 'analysis/retail/priest/shadow/modules/guide/ExtraComponents'; +import { formatPercentage } from 'common/format'; +import ActiveTimeGraph from 'parser/ui/ActiveTimeGraph'; export default function Guide({ modules, events, info }: GuideProps) { return ( <> - + @@ -32,13 +35,13 @@ export default function Guide({ modules, events, info }: GuideProps) { +function CoreSection({ modules, info }: GuideProps) { const percentAtFuryCap = modules.furyTracker.percentAtCap; const percentAtFuryCapPerformance = modules.furyTracker.percentAtCapPerformance; const furyWasted = modules.furyTracker.wasted; return ( -
    +

    Vengeance's primary resource is . You should @@ -68,6 +71,28 @@ function ResourceUsageSection({ modules }: GuideProps) {

    {modules.soulFragmentsGraph.plot}
    + +

    + + Continuously casting throughout an encounter is the single most important thing for + achieving good DPS. + +
    + Some fights have unavoidable downtime due to phase transitions and the like, so in these + cases 0% downtime will not be possible - do the best you can. +

    +

    + Active Time:{' '} + + {formatPercentage(modules.alwaysBeCasting.activeTimePercentage, 1)}% + {' '} +

    + +
    ); } diff --git a/src/analysis/retail/druid/restoration/CHANGELOG.tsx b/src/analysis/retail/druid/restoration/CHANGELOG.tsx index 1b6cff02874..b5392e1192e 100644 --- a/src/analysis/retail/druid/restoration/CHANGELOG.tsx +++ b/src/analysis/retail/druid/restoration/CHANGELOG.tsx @@ -5,6 +5,7 @@ import { TALENTS_DRUID } from 'common/TALENTS'; import SPELLS from 'common/SPELLS'; export default [ + change(date(2024, 1, 2), <>Fixed a bug where the 2nd stack of Clearcasting wasn't being properly counted., Sref), change(date(2023, 11, 7), <>Added statistic for the ToL version of , and split healing from Grove Guardians due to this talent into the next statistic (and out of the existing Grove Guardians statistic)., Sref), change(date(2023, 11, 7), <>Updated all talent and spell values for 10.2, and updated guide text to be more appropriate for 10.2 playstyles., Sref), change(date(2023, 10, 17), <>Enable spec with 10.2 changes, Arlie), diff --git a/src/analysis/retail/druid/restoration/modules/spells/RegrowthAndClearcasting.tsx b/src/analysis/retail/druid/restoration/modules/spells/RegrowthAndClearcasting.tsx index 1833ea8bf89..0360d5eb0f4 100644 --- a/src/analysis/retail/druid/restoration/modules/spells/RegrowthAndClearcasting.tsx +++ b/src/analysis/retail/druid/restoration/modules/spells/RegrowthAndClearcasting.tsx @@ -69,6 +69,10 @@ class RegrowthAndClearcasting extends Analyzer { Events.applybuff.by(SELECTED_PLAYER).spell(SPELLS.CLEARCASTING_BUFF), this.onApplyClearcast, ); + this.addEventListener( + Events.applybuffstack.by(SELECTED_PLAYER).spell(SPELLS.CLEARCASTING_BUFF), + this.onApplyClearcast, + ); this.addEventListener( Events.refreshbuff.by(SELECTED_PLAYER).spell(SPELLS.CLEARCASTING_BUFF), this.onRefreshClearcast, diff --git a/src/analysis/retail/mage/fire/CHANGELOG.tsx b/src/analysis/retail/mage/fire/CHANGELOG.tsx index 42c4c37a1f5..4e4aab00c14 100644 --- a/src/analysis/retail/mage/fire/CHANGELOG.tsx +++ b/src/analysis/retail/mage/fire/CHANGELOG.tsx @@ -6,6 +6,10 @@ import { Sharrq, ToppleTheNun } from 'CONTRIBUTORS'; // prettier-ignore export default [ + change(date(2024, 1, 3), <>Updated during to disregard casts where the player had a proc. Reworded the suggestion to include Double Lust and Flame Accelerant., Sharrq), + change(date(2023, 12, 31), <> Active Time had one job, and it now does it properly. And counts in seconds instead of milliseconds., Sharrq), + change(date(2023, 12, 31), <>Adjusted to be acceptable to cast in AOE at 5+ targets., Sharrq), + change(date(2023, 12, 31), <>Fixed the wording on to specify that it has to land during ., Sharrq), change(date(2023, 12, 2), <>Fixed an issue that was causing to not calculate expirations and wasted properly., Sharrq), change(date(2023, 11, 30), 'Rewrote a number of modules to vastly increase performance in M+ dungeons and prevent crashes from especially long dungeon logs.', Sharrq), change(date(2023, 8, 20), <>Added , , and to the Checklist., Sharrq), diff --git a/src/analysis/retail/mage/fire/Checklist/Component.tsx b/src/analysis/retail/mage/fire/Checklist/Component.tsx index 316c414784c..17088796a7e 100644 --- a/src/analysis/retail/mage/fire/Checklist/Component.tsx +++ b/src/analysis/retail/mage/fire/Checklist/Component.tsx @@ -70,7 +70,7 @@ const FireMageChecklist = ({ combatant, castEfficiency, thresholds }: ChecklistP ; export default spells; diff --git a/src/analysis/retail/mage/fire/core/Combustion.tsx b/src/analysis/retail/mage/fire/core/Combustion.tsx index e0f33ec0ca7..2b7fc804a39 100644 --- a/src/analysis/retail/mage/fire/core/Combustion.tsx +++ b/src/analysis/retail/mage/fire/core/Combustion.tsx @@ -1,4 +1,3 @@ -import { Trans } from '@lingui/macro'; import { formatNumber, formatPercentage } from 'common/format'; import SPELLS from 'common/SPELLS'; import TALENTS from 'common/TALENTS/mage'; @@ -26,6 +25,7 @@ class CombustionCasts extends Analyzer { protected abilityTracker!: AbilityTracker; hasFlameOn: boolean = this.selectedCombatant.hasTalent(TALENTS.FLAME_ON_TALENT); + hasFlameAccelerant: boolean = this.selectedCombatant.hasTalent(TALENTS.FLAME_ACCELERANT_TALENT); combustionCasts: { cast: CastEvent; precast: CastEvent | undefined; delay: number }[] = []; combustionCastEvents: CastEvent[] = []; @@ -124,7 +124,12 @@ class CombustionCasts extends Analyzer { return activeBuffs < 2 ? true : false; }) - const tooltip = `This Fireball was cast during Combustion. Since Combustion has a short duration, you are better off using your instant abilities to get as many instant/free Pyroblasts as possible. If you run out of instant abilities, cast Scorch instead since it has a shorter cast time.`; + //If the player had a Flame Accelerant proc, disregard it. + if (this.hasFlameAccelerant) { + fireballCasts = fireballCasts.filter(f => this.selectedCombatant.hasBuff(SPELLS.FLAME_ACCELERANT_BUFF.id)); + } + + const tooltip = `This Fireball was cast during Combustion. Since Combustion has a short duration, you are better off using your instant abilities to get as many instant/free Pyroblasts as possible. If you run out of instant abilities, cast Scorch instead unless you have >100% Haste (Double Lust) or you have a Flame Accelerant proc`; fireballCasts.forEach(e => e.cast && highlightInefficientCast(e.cast, tooltip)); return fireballCasts.length; @@ -238,11 +243,7 @@ class CombustionCasts extends Analyzer { , ) .icon(TALENTS.COMBUSTION_TALENT.icon) - .actual( - - {formatNumber(actual)}s Avg. Pre-Cast Delay - , - ) + .actual(`${formatNumber(actual)}s Avg. Pre-Cast Delay`) .recommended(`${recommended} is recommended`), ); when(this.fireballDuringCombustionThresholds).addSuggestion((suggest, actual, recommended) => @@ -250,19 +251,20 @@ class CombustionCasts extends Analyzer { <> On average, you cast {' '} {this.fireballCastsDuringCombustion()} times ({actual.toFixed(2)} per Combustion), during{' '} - . Combustion has a short duration, so you - are better off using instant abilities like or{' '} - . If you run out of instant cast - abilities, use instead of Fireball since it has a - shorter cast time. + . In order to get the most casts (and{' '} + + s) as possible before Combustion ends, you should use your instant abilities like + or{' '} + . If you are running low on charges of + those spells, or need to conserve charges to make it to the end of the Combustion buff, + you should cast instead of Fireball since it has a + shorter cast time. The only exception to this is if you have 100% Haste (such as during + Double Lust), or if you have a proc of{' '} + . , ) .icon(TALENTS.COMBUSTION_TALENT.icon) - .actual( - - {this.fireballDuringCombustionThresholds.actual.toFixed(2)} Casts Per Combustion - , - ) + .actual(`${actual.toFixed(2)} Casts Per Combustion`) .recommended(`${formatNumber(recommended)} is recommended`), ); } diff --git a/src/analysis/retail/mage/fire/core/CombustionActiveTime.tsx b/src/analysis/retail/mage/fire/core/CombustionActiveTime.tsx index cdf86aae571..59bcee39d3c 100644 --- a/src/analysis/retail/mage/fire/core/CombustionActiveTime.tsx +++ b/src/analysis/retail/mage/fire/core/CombustionActiveTime.tsx @@ -57,10 +57,10 @@ class CombustionActiveTime extends Analyzer { if (!buffApply) { return; } - this.activeTime[buffApply.timestamp] = this.alwaysBeCasting.getActiveTimePercentageInWindow( - buffApply.timestamp, - event.timestamp, - ); + const combustDuration = event.timestamp - buffApply.timestamp; + this.activeTime[buffApply.timestamp] = + combustDuration - + this.alwaysBeCasting.getActiveTimeMillisecondsInWindow(buffApply.timestamp, event.timestamp); } onFightEnd(event: FightEndEvent) { @@ -71,28 +71,24 @@ class CombustionActiveTime extends Analyzer { if (!this.selectedCombatant.hasBuff(TALENTS.COMBUSTION_TALENT.id) || !buffApply) { return; } - this.activeTime[buffApply.timestamp] = this.alwaysBeCasting.getActiveTimePercentageInWindow( - buffApply.timestamp, - event.timestamp, - ); + const combustDuration = event.timestamp - buffApply.timestamp; + this.activeTime[buffApply.timestamp] = + combustDuration - + this.alwaysBeCasting.getActiveTimeMillisecondsInWindow(buffApply.timestamp, event.timestamp); } - combustionActiveTime = () => { + combustionDowntime = () => { let activeTime = 0; this.activeTime.forEach((c) => (activeTime += c)); - return activeTime; + return activeTime / 1000; }; get buffUptime() { - return this.selectedCombatant.getBuffUptime(TALENTS.COMBUSTION_TALENT.id); - } - - get downtimeSeconds() { - return this.buffUptime - this.combustionActiveTime(); + return this.selectedCombatant.getBuffUptime(TALENTS.COMBUSTION_TALENT.id) / 1000; } get percentActiveTime() { - return this.combustionActiveTime() / this.buffApplies; + return 1 - this.combustionDowntime() / this.buffUptime; } get combustionActiveTimeThresholds() { @@ -111,8 +107,8 @@ class CombustionActiveTime extends Analyzer { when(this.combustionActiveTimeThresholds).addSuggestion((suggest, actual, recommended) => suggest( <> - You spent {formatNumber(this.downtimeSeconds)} ( - {formatNumber(this.downtimeSeconds / this.buffApplies)} average per{' '} + You spent {formatNumber(this.combustionDowntime())}s ( + {formatNumber(this.combustionDowntime() / this.buffApplies)}s average per{' '} ), not casting anything while was active. Because a large portion of your damage comes from Combustion, you should ensure that you diff --git a/src/analysis/retail/mage/fire/normalizers/CastLinkNormalizer.ts b/src/analysis/retail/mage/fire/normalizers/CastLinkNormalizer.ts index a8b4a210b9f..9affb8a9ed6 100644 --- a/src/analysis/retail/mage/fire/normalizers/CastLinkNormalizer.ts +++ b/src/analysis/retail/mage/fire/normalizers/CastLinkNormalizer.ts @@ -24,6 +24,7 @@ export const CAST_BEGIN = 'CastBegin'; export const SPELL_CAST = 'SpellCast'; export const PRE_CAST = 'PreCast'; export const SPELL_DAMAGE = 'SpellDamage'; +export const EXPLODE_DEBUFF = 'ExplosionDebuff'; const EVENT_LINKS: EventLink[] = [ { @@ -126,6 +127,17 @@ const EVENT_LINKS: EventLink[] = [ forwardBufferMs: 600_000, //If you manage your charges, you can keep the buff up pretty much the whole fight, so 10min just in case. backwardBufferMs: CAST_BUFFER_MS, }, + { + reverseLinkRelation: SPELL_CAST, + linkingEventId: TALENTS.LIVING_BOMB_TALENT.id, + linkingEventType: EventType.Cast, + linkRelation: EXPLODE_DEBUFF, + referencedEventId: SPELLS.LIVING_BOMB_EXPLODE_DEBUFF.id, + referencedEventType: EventType.ApplyDebuff, + anyTarget: true, + forwardBufferMs: 7000, + backwardBufferMs: CAST_BUFFER_MS, + }, { reverseLinkRelation: CAST_BEGIN, linkingEventId: TALENTS.PYROBLAST_TALENT.id, diff --git a/src/analysis/retail/mage/fire/talents/LivingBomb.tsx b/src/analysis/retail/mage/fire/talents/LivingBomb.tsx index d7b7821ec94..cd8f1c66a3b 100644 --- a/src/analysis/retail/mage/fire/talents/LivingBomb.tsx +++ b/src/analysis/retail/mage/fire/talents/LivingBomb.tsx @@ -1,34 +1,57 @@ -import { Trans } from '@lingui/macro'; import TALENTS from 'common/TALENTS/mage'; +import { formatPercentage } from 'common/format'; import { SpellLink } from 'interface'; -import Analyzer, { Options } from 'parser/core/Analyzer'; +import Analyzer, { Options, SELECTED_PLAYER } from 'parser/core/Analyzer'; +import Events, { CastEvent, GetRelatedEvents } from 'parser/core/Events'; import { When, ThresholdStyle } from 'parser/core/ParseResults'; import AbilityTracker from 'parser/shared/modules/AbilityTracker'; +const AOE_THRESHOLD = 5; + class LivingBomb extends Analyzer { static dependencies = { abilityTracker: AbilityTracker, }; protected abilityTracker!: AbilityTracker; + livingBombs: { timestamp: number; targetsHit: number }[] = []; + constructor(options: Options) { super(options); this.active = this.selectedCombatant.hasTalent(TALENTS.LIVING_BOMB_TALENT); + this.addEventListener( + Events.cast.by(SELECTED_PLAYER).spell(TALENTS.LIVING_BOMB_TALENT), + this.onLivingBomb, + ); + } + + onLivingBomb(event: CastEvent) { + const debuffs = GetRelatedEvents(event, 'ExplosionDebuff'); + this.livingBombs.push({ + timestamp: event.timestamp, + targetsHit: debuffs.length, + }); + } + + get badCasts() { + return this.livingBombs.filter((c) => c.targetsHit < AOE_THRESHOLD).length || 0; + } + + get castUtilization() { + return 1 - this.badCasts / this.totalCasts; } - get livingBombCasts() { + get totalCasts() { return this.abilityTracker.getAbility(TALENTS.LIVING_BOMB_TALENT.id).casts; } get livingBombCastThresholds() { return { - actual: this.livingBombCasts, - isGreaterThan: { - minor: 0, + actual: this.castUtilization, + isLessThan: { average: 1, - major: 2, }, - style: ThresholdStyle.NUMBER, + style: ThresholdStyle.PERCENTAGE, }; } @@ -36,20 +59,19 @@ class LivingBomb extends Analyzer { when(this.livingBombCastThresholds).addSuggestion((suggest, actual, recommended) => suggest( <> - You cast {this.livingBombCasts} times. + You misused {this.badCasts} times. Although it is worth it to take the {' '} - talent, this is only to get to the talent. - On Single Target there is no benefit to casting{' '} - and is overall considered a DPS loss. On - AOE fights, it is not worth taking the {' '} - talent at all. + talent in Single Target, this is only to get to the{' '} + talent. On Single Target there is no benefit + to casting and it is overall considered a + DPS loss. On AOE fights, you can get a very minor DPS increase from casting{' '} + as filler if it will hit at least{' '} + {AOE_THRESHOLD} targets. , ) .icon(TALENTS.LIVING_BOMB_TALENT.icon) - .actual( - {this.livingBombCasts} casts, - ) - .recommended(`${this.livingBombCasts} is recommended`), + .actual(`${formatPercentage(actual)}% utilization`) + .recommended(`${formatPercentage(recommended)}% is recommended`), ); } } diff --git a/src/analysis/retail/mage/fire/talents/MeteorCombustion.tsx b/src/analysis/retail/mage/fire/talents/MeteorCombustion.tsx index 370322253db..9aceb15ff31 100644 --- a/src/analysis/retail/mage/fire/talents/MeteorCombustion.tsx +++ b/src/analysis/retail/mage/fire/talents/MeteorCombustion.tsx @@ -121,8 +121,8 @@ class MeteorCombustion extends Analyzer { You failed to cast during{' '} {this.combustionWithoutMeteor} times. In order to make the most of Combustion and , you should - always cast Meteor during Combustion. If Meteor will not come off cooldown before - Combustion is available, then you should hold Meteor for Combustion. + always ensure Meteor hits the target during Combustion. If Meteor will not come off + cooldown before Combustion is available, then you should hold Meteor for Combustion. , ) .icon(TALENTS.METEOR_TALENT.icon) diff --git a/src/analysis/retail/mage/frost/CHANGELOG.tsx b/src/analysis/retail/mage/frost/CHANGELOG.tsx index d6e0b393ca2..822422d04fb 100644 --- a/src/analysis/retail/mage/frost/CHANGELOG.tsx +++ b/src/analysis/retail/mage/frost/CHANGELOG.tsx @@ -6,6 +6,14 @@ import { Sharrq, ToppleTheNun } from 'CONTRIBUTORS'; // prettier-ignore export default [ + change(date(2024, 1, 6), <>Fixed a crash in ., Sharrq), + change(date(2024, 1, 5), 'Updated spec support to full 10.2 support.', Sharrq), + change(date(2024, 1, 5), <>Fixed the cooldowns for and ., Sharrq), + change(date(2024, 1, 5), <>Added a statistic for the average delay to use . This is just informational., Sharrq), + change(date(2024, 1, 5), <>Added tracking for ., Sharrq), + change(date(2024, 1, 5), <>Adjusted to change the spells that can be used to spend ., Sharrq), + change(date(2024, 1, 5), <>Updated to ignore pre-casts at 4 ., Sharrq), + change(date(2024, 1, 5), 'Rewrote most core frost functionality to use event links instead.', Sharrq), change(date(2023, 7, 10), 'Remove references to 10.1.5 removed talents.', Sharrq), change(date(2023, 7, 3), 'Update SpellLink usage.', ToppleTheNun), change(date(2023, 6, 27), <>Added to list of Bloodlust Buffs., Sharrq), diff --git a/src/analysis/retail/mage/frost/CONFIG.tsx b/src/analysis/retail/mage/frost/CONFIG.tsx index 200b6266521..4574441d39a 100644 --- a/src/analysis/retail/mage/frost/CONFIG.tsx +++ b/src/analysis/retail/mage/frost/CONFIG.tsx @@ -11,7 +11,7 @@ const config: Config = { expansion: Expansion.Dragonflight, // The WoW client patch this spec was last updated. patchCompatibility: '10.2.0', - isPartial: true, + isPartial: false, // Explain the status of this spec's analysis here. Try to mention how complete it is, and perhaps show links to places users can learn more. If this spec's analysis does not show a complete picture please mention this in the `` component. description: ( <> diff --git a/src/analysis/retail/mage/frost/CombatLogParser.ts b/src/analysis/retail/mage/frost/CombatLogParser.ts index 75d267bf7f1..8d21902bba5 100644 --- a/src/analysis/retail/mage/frost/CombatLogParser.ts +++ b/src/analysis/retail/mage/frost/CombatLogParser.ts @@ -23,7 +23,7 @@ import Buffs from './core/Buffs'; import CooldownThroughputTracker from './core/CooldownThroughputTracker'; import IceLance from './core/IceLance'; import IcyVeins from './core/IcyVeins'; -import MunchedProcs from './core/MunchedProcs'; +import FingersOfFrost from './core/FingersOfFrost'; import WintersChill from './core/WintersChill'; //Talents @@ -35,6 +35,7 @@ import ColdFront from './talents/ColdFront'; import IcyPropulsion from './talents/IcyPropulsion'; import BoneChilling from './talents/BoneChilling'; import CometStorm from './talents/CometStorm'; +import RayOfFrost from './talents/RayOfFrost'; import GlacialSpike from './talents/GlacialSpike'; import LonelyWinter from './talents/LonelyWinter'; import SplittingIce from './talents/SplittingIce'; @@ -42,6 +43,7 @@ import ThermalVoid from './talents/ThermalVoid'; //Normalizers import CometStormLinkNormalizer from './normalizers/CometStormLinkNormalizer'; +import CastLinkNormalizer from './normalizers/CastLinkNormalizer'; class CombatLogParser extends CoreCombatLogParser { static specModules = { @@ -50,6 +52,7 @@ class CombatLogParser extends CoreCombatLogParser { //Normalizers cometStormLinkNormalizer: CometStormLinkNormalizer, + castLinkNormalizer: CastLinkNormalizer, //Core abilities: Abilities, @@ -62,7 +65,7 @@ class CombatLogParser extends CoreCombatLogParser { iceLance: IceLance, icyVeins: IcyVeins, arcaneIntellect: ArcaneIntellect, - munchedProcs: MunchedProcs, + fingersOfFrost: FingersOfFrost, // Talents - Frost boneChilling: BoneChilling, @@ -72,6 +75,7 @@ class CombatLogParser extends CoreCombatLogParser { thermalVoid: ThermalVoid, glacialSpike: GlacialSpike, cometStorm: CometStorm, + rayOfFrost: RayOfFrost, icyPropulsion: IcyPropulsion, coldFront: ColdFront, mirrorImage: MirrorImage, diff --git a/src/analysis/retail/mage/frost/checklist/Component.tsx b/src/analysis/retail/mage/frost/checklist/Component.tsx index 95fbf565cef..51978a31aca 100644 --- a/src/analysis/retail/mage/frost/checklist/Component.tsx +++ b/src/analysis/retail/mage/frost/checklist/Component.tsx @@ -109,32 +109,6 @@ const FrostMageChecklist = ({ combatant, castEfficiency, thresholds }: Checklist tooltip="Munching a proc refers to a situation where you have a Fingers of Frost proc at the same time that Winters Chill is on the target. This essentially leads to a wasted Fingers of Frost proc since Fingers of Frost and Winter's Chill both do the same thing, and casting Ice Lance will remove both a Fingers of Frost proc and a stack of Winter's Chill. This is sometimes unavoidable, but if you have both a Fingers of Frost proc and a Brain Freeze proc, you can minimize this by ensuring that you use the Fingers of Frost procs first before you start casting Frostbolt and Flurry to use the Brain Freeze proc." /> - - When talented into you should always - ensure that you are getting the most out of it, because a large part of your damage will - come from making sure that you are handling Glacial Spike properly. As a rule, once you - have Glacial Spike available, you should not cast it unless you can cast{' '} - alongside it ( - {'>'}{' '} - {'>'} - ) or if you also have the{' '} - and the Glacial Spike will hit a - second target. If neither of those are true, then you should continue casting{' '} - until {' '} - is available or you get a proc. - - } - > - {combatant.hasTalent(TALENTS.GLACIAL_SPIKE_TALENT) && ( - - )} - { - let casts = this.eventHistory.getEvents(EventType.Cast, { - spell: TALENTS.FLURRY_TALENT, + brainFreezeRefreshes = 0; + flurry: { timestamp: number; damage: DamageEvent | undefined; overlapped: boolean }[] = []; + brainFreeze: { apply: ApplyBuffEvent; remove: RemoveBuffEvent | undefined; expired: boolean }[] = + []; + + constructor(options: Options) { + super(options); + this.addEventListener( + Events.cast.by(SELECTED_PLAYER).spell(TALENTS.FLURRY_TALENT), + this.onFlurryCast, + ); + this.addEventListener( + Events.applybuff.by(SELECTED_PLAYER).spell(SPELLS.BRAIN_FREEZE_BUFF), + this.onBrainFreeze, + ); + this.addEventListener( + Events.refreshbuff.by(SELECTED_PLAYER).spell(SPELLS.BRAIN_FREEZE_BUFF), + this.onBrainFreezeRefresh, + ); + } + + onFlurryCast(event: CastEvent) { + const damage: DamageEvent | undefined = GetRelatedEvent(event, 'SpellDamage'); + const enemy = damage && this.enemies.getEntity(damage); + this.flurry.push({ + timestamp: event.timestamp, + damage: damage, + overlapped: enemy?.hasBuff(SPELLS.WINTERS_CHILL.id, event.timestamp - 10) || false, }); - casts = casts.filter((c) => { - const enemy = this.enemies.getEntity(c); - return enemy && enemy.hasBuff(SPELLS.WINTERS_CHILL.id); + } + + onBrainFreeze(event: ApplyBuffEvent) { + const remove: RemoveBuffEvent | undefined = GetRelatedEvent(event, 'BuffRemove'); + const spender: CastEvent | undefined = remove && GetRelatedEvent(remove, 'SpellCast'); + this.brainFreeze.push({ + apply: event, + remove: remove || undefined, + expired: !spender, }); - return casts.length || 0; - }; + } - get expiredProcs() { - return ( - this.sharedCode.getExpiredProcs(SPELLS.BRAIN_FREEZE_BUFF, TALENTS.FLURRY_TALENT).length || 0 - ); + onBrainFreezeRefresh(event: RefreshBuffEvent) { + this.brainFreezeRefreshes += 1; } - get totalProcs() { - return ( - this.eventHistory.getEvents(EventType.ApplyBuff, { - spell: SPELLS.BRAIN_FREEZE_BUFF, - }).length || 0 - ); + get overlappedFlurries() { + return this.flurry.filter((f) => f.overlapped).length; } - get overwrittenProcs() { - return ( - this.eventHistory.getEvents(EventType.RefreshBuff, { - spell: SPELLS.BRAIN_FREEZE_BUFF, - }).length || 0 - ); + get expiredProcs() { + return this.brainFreeze.filter((bf) => bf.expired).length; + } + + get totalProcs() { + return this.brainFreeze.length; } get wastedPercent() { - return (this.overwrittenProcs + this.expiredProcs) / this.totalProcs || 0; + return (this.brainFreezeRefreshes + this.expiredProcs) / this.totalProcs || 0; } get utilPercent() { @@ -79,7 +104,7 @@ class BrainFreeze extends Analyzer { // Percentages lowered from .00, .08, .16; with the addition of the forgiveness window it is almost as bad as letting BF expire when you waste a proc get brainFreezeOverwritenThresholds() { return { - actual: this.overwrittenProcs / this.totalProcs || 0, + actual: this.brainFreezeRefreshes / this.totalProcs || 0, isGreaterThan: { minor: 0.0, average: 0.05, @@ -104,7 +129,7 @@ class BrainFreeze extends Analyzer { get overlappedFlurryThresholds() { return { - actual: this.overlappedFlurries(), + actual: this.overlappedFlurries, isGreaterThan: { average: 0, major: 3, @@ -126,11 +151,7 @@ class BrainFreeze extends Analyzer { , ) .icon(TALENTS.BRAIN_FREEZE_TALENT.icon) - .actual( - - {formatPercentage(actual)}% overwritten - , - ) + .actual(`${formatPercentage(actual)}% overwritten`) .recommended(`Overwriting none is recommended`), ); when(this.brainFreezeExpiredThresholds).addSuggestion((suggest, actual, recommended) => @@ -142,11 +163,7 @@ class BrainFreeze extends Analyzer { , ) .icon(TALENTS.BRAIN_FREEZE_TALENT.icon) - .actual( - - {formatPercentage(actual)}% expired - , - ) + .actual(`${formatPercentage(actual)}% expired`) .recommended(`Letting none expire is recommended`), ); when(this.overlappedFlurryThresholds).addSuggestion((suggest, actual, recommended) => @@ -154,17 +171,15 @@ class BrainFreeze extends Analyzer { <> You cast and applied{' '} while the target still had the{' '} - debuff on them {this.overlappedFlurries()}{' '} - times. Casting applies 2 stacks of{' '} + debuff on them {this.overlappedFlurries} times. + Casting applies 2 stacks of{' '} to the target so you should always ensure you are spending both stacks before you cast and apply again. , ) .icon(TALENTS.FLURRY_TALENT.icon) - .actual( - {formatNumber(actual)} casts, - ) + .actual(`${formatNumber(actual)} casts`) .recommended(`Casting none is recommended`), ); } @@ -178,8 +193,8 @@ class BrainFreeze extends Analyzer { <> You got {this.totalProcs} total procs.
      -
    • {this.totalProcs - this.expiredProcs - this.overwrittenProcs} used
    • -
    • {this.overwrittenProcs} overwritten
    • +
    • {this.totalProcs - this.expiredProcs - this.brainFreezeRefreshes} used
    • +
    • {this.brainFreezeRefreshes} overwritten
    • {this.expiredProcs} expired
    diff --git a/src/analysis/retail/mage/frost/core/MunchedProcs.tsx b/src/analysis/retail/mage/frost/core/FingersOfFrost.tsx similarity index 60% rename from src/analysis/retail/mage/frost/core/MunchedProcs.tsx rename to src/analysis/retail/mage/frost/core/FingersOfFrost.tsx index 0dc3e0c6650..5e0cbd019d9 100644 --- a/src/analysis/retail/mage/frost/core/MunchedProcs.tsx +++ b/src/analysis/retail/mage/frost/core/FingersOfFrost.tsx @@ -1,37 +1,40 @@ -import { Trans } from '@lingui/macro'; -import { formatPercentage } from 'common/format'; +import { formatPercentage, formatNumber } from 'common/format'; import SPELLS from 'common/SPELLS'; import TALENTS from 'common/TALENTS/mage'; import { SpellLink } from 'interface'; import Analyzer, { SELECTED_PLAYER, Options } from 'parser/core/Analyzer'; -import Events, { DamageEvent, ApplyBuffEvent, ApplyBuffStackEvent } from 'parser/core/Events'; +import Events, { + DamageEvent, + CastEvent, + ApplyBuffEvent, + RemoveBuffEvent, + ApplyBuffStackEvent, + GetRelatedEvent, +} from 'parser/core/Events'; import { ThresholdStyle, When } from 'parser/core/ParseResults'; -import AbilityTracker from 'parser/shared/modules/AbilityTracker'; import Enemies from 'parser/shared/modules/Enemies'; -import EventHistory from 'parser/shared/modules/EventHistory'; import BoringSpellValueText from 'parser/ui/BoringSpellValueText'; import Statistic from 'parser/ui/Statistic'; import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER'; +import { SHATTER_DEBUFFS } from '../../shared'; -class MunchedProcs extends Analyzer { +class FingersOfFrost extends Analyzer { static dependencies = { - abilityTracker: AbilityTracker, enemies: Enemies, - eventHistory: EventHistory, }; - protected abilityTracker!: AbilityTracker; - protected eventHistory!: EventHistory; protected enemies!: Enemies; - munchedProcs = 0; - totalFingersProcs = 0; + fingers: { + apply: ApplyBuffEvent | ApplyBuffStackEvent; + remove: RemoveBuffEvent | undefined; + spender: CastEvent | undefined; + expired: boolean; + munched: boolean; + spendDelay: number | undefined; + }[] = []; constructor(options: Options) { super(options); - this.addEventListener( - Events.damage.by(SELECTED_PLAYER).spell(SPELLS.ICE_LANCE_DAMAGE), - this.onIceLanceDamage, - ); this.addEventListener( Events.applybuff.by(SELECTED_PLAYER).spell(SPELLS.FINGERS_OF_FROST_BUFF), this.onFingersProc, @@ -42,28 +45,46 @@ class MunchedProcs extends Analyzer { ); } - onIceLanceDamage(event: DamageEvent) { - const enemy = this.enemies.getEntity(event); - if (!enemy || !enemy.hasBuff(SPELLS.WINTERS_CHILL.id)) { - return; - } + onFingersProc(event: ApplyBuffEvent | ApplyBuffStackEvent) { + const remove: RemoveBuffEvent | undefined = GetRelatedEvent(event, 'BuffRemove'); + const spender: CastEvent | undefined = remove && GetRelatedEvent(remove, 'SpellCast'); + const damage: DamageEvent | undefined = spender && GetRelatedEvent(spender, 'SpellDamage'); + const enemy = damage && this.enemies.getEntity(damage); + this.fingers.push({ + apply: event, + remove: remove, + spender: spender, + expired: !spender, + munched: + SHATTER_DEBUFFS.some((effect) => enemy?.hasBuff(effect.id, damage?.timestamp)) || false, + spendDelay: spender && spender.timestamp - event.timestamp, + }); + } - const iceLanceCast = this.eventHistory.last( - 1, - undefined, - Events.cast.by(SELECTED_PLAYER).spell(TALENTS.ICE_LANCE_TALENT), - )[0]; - if (this.selectedCombatant.hasBuff(SPELLS.FINGERS_OF_FROST_BUFF.id, iceLanceCast.timestamp)) { - this.munchedProcs += 1; - } + get expiredProcs() { + return this.fingers.filter((f) => f.expired).length; } - onFingersProc(event: ApplyBuffEvent | ApplyBuffStackEvent) { - this.totalFingersProcs += 1; + get averageSpendDelaySeconds() { + let spendDelay = 0; + this.fingers.forEach((f) => f.spendDelay && (spendDelay += f.spendDelay)); + return spendDelay / this.fingers.filter((f) => f.spendDelay).length / 1000; + } + + get usedFingersProcs() { + return this.totalProcs - this.expiredProcs; + } + + get munchedProcs() { + return this.fingers.filter((f) => f.munched).length; + } + + get totalProcs() { + return this.fingers.length; } get munchedPercent() { - return this.munchedProcs / this.totalFingersProcs; + return this.munchedProcs / this.totalProcs; } get munchedProcsThresholds() { @@ -78,13 +99,25 @@ class MunchedProcs extends Analyzer { }; } + get fingersProcUtilizationThresholds() { + return { + actual: 1 - this.expiredProcs / this.totalProcs || 0, + isLessThan: { + minor: 0.95, + average: 0.85, + major: 0.7, + }, + style: ThresholdStyle.PERCENTAGE, + }; + } + suggestions(when: When) { when(this.munchedProcsThresholds).addSuggestion((suggest, actual, recommended) => suggest( <> You wasted (munched) {this.munchedProcs}{' '} procs ( - {formatPercentage(this.munchedPercent)} of total procs). Because of the way{' '} + {formatPercentage(this.munchedPercent)}% of total procs). Because of the way{' '} works, this is sometimes unavoidable (i.e. you get a proc while you are using a{' '} proc), but if you have both a{' '} @@ -97,11 +130,7 @@ class MunchedProcs extends Analyzer { , ) .icon(TALENTS.FINGERS_OF_FROST_TALENT.icon) - .actual( - - {formatPercentage(actual)}% procs wasted - , - ) + .actual(`${formatPercentage(actual)}% procs wasted`) .recommended(formatPercentage(recommended)), ); } @@ -125,10 +154,12 @@ class MunchedProcs extends Analyzer { > {formatPercentage(this.munchedPercent, 0)}% Munched Fingers of Frost procs +
    + {formatNumber(this.averageSpendDelaySeconds)}s Avg. delay to spend procs
    ); } } -export default MunchedProcs; +export default FingersOfFrost; diff --git a/src/analysis/retail/mage/frost/core/IceLance.tsx b/src/analysis/retail/mage/frost/core/IceLance.tsx index e79807220a0..f01e5b1cc49 100644 --- a/src/analysis/retail/mage/frost/core/IceLance.tsx +++ b/src/analysis/retail/mage/frost/core/IceLance.tsx @@ -1,16 +1,13 @@ -import { Trans } from '@lingui/macro'; -import { MS_BUFFER_100, SHATTER_DEBUFFS } from 'analysis/retail/mage/shared'; +import { SHATTER_DEBUFFS } from 'analysis/retail/mage/shared'; import { formatPercentage } from 'common/format'; import SPELLS from 'common/SPELLS'; import TALENTS from 'common/TALENTS/mage'; import { SpellLink } from 'interface'; +import { highlightInefficientCast } from 'interface/report/Results/Timeline/Casts'; import Analyzer, { SELECTED_PLAYER, Options } from 'parser/core/Analyzer'; -import Events, { CastEvent, DamageEvent, ChangeBuffStackEvent } from 'parser/core/Events'; +import Events, { CastEvent, DamageEvent, GetRelatedEvent } from 'parser/core/Events'; import { When, ThresholdStyle } from 'parser/core/ParseResults'; -import AbilityTracker from 'parser/shared/modules/AbilityTracker'; -import Enemies, { encodeTargetString } from 'parser/shared/modules/Enemies'; -import EventHistory from 'parser/shared/modules/EventHistory'; -import SpellUsable from 'parser/shared/modules/SpellUsable'; +import Enemies from 'parser/shared/modules/Enemies'; import BoringSpellValueText from 'parser/ui/BoringSpellValueText'; import Statistic from 'parser/ui/Statistic'; import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER'; @@ -18,23 +15,10 @@ import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER'; class IceLance extends Analyzer { static dependencies = { enemies: Enemies, - abilityTracker: AbilityTracker, - eventHistory: EventHistory, - spellUsable: SpellUsable, }; protected enemies!: Enemies; - protected abilityTracker!: AbilityTracker; - protected eventHistory!: EventHistory; - protected spellUsable!: SpellUsable; - hadFingersProc = false; - iceLanceTargetId = ''; - nonShatteredCasts = 0; - - iceLanceCastTimestamp = 0; - totalFingersProcs = 0; - overwrittenFingersProcs = 0; - expiredFingersProcs = 0; + icelance: { cast: CastEvent; shattered: boolean; hadFingers: boolean; cleaved: boolean }[] = []; constructor(options: Options) { super(options); @@ -42,90 +26,44 @@ class IceLance extends Analyzer { Events.cast.by(SELECTED_PLAYER).spell(TALENTS.ICE_LANCE_TALENT), this.onCast, ); - this.addEventListener( - Events.damage.by(SELECTED_PLAYER).spell(SPELLS.ICE_LANCE_DAMAGE), - this.onDamage, - ); - this.addEventListener( - Events.changebuffstack.by(SELECTED_PLAYER).spell(SPELLS.FINGERS_OF_FROST_BUFF), - this.onFingersStackChange, - ); } onCast(event: CastEvent) { - this.iceLanceCastTimestamp = event.timestamp; - if (event.targetID) { - this.iceLanceTargetId = encodeTargetString(event.targetID, event.targetInstance); - } - this.hadFingersProc = false; - if (this.selectedCombatant.hasBuff(SPELLS.FINGERS_OF_FROST_BUFF.id)) { - this.hadFingersProc = true; - } + const damage: DamageEvent | undefined = GetRelatedEvent(event, 'SpellDamage'); + const enemy = damage && this.enemies.getEntity(damage); + const cleave: DamageEvent | undefined = GetRelatedEvent(event, 'CleaveDamage'); + this.icelance.push({ + cast: event, + shattered: + SHATTER_DEBUFFS.some((effect) => enemy?.hasBuff(effect.id, damage?.timestamp)) || false, + hadFingers: this.selectedCombatant.hasBuff( + SPELLS.FINGERS_OF_FROST_BUFF.id, + event.timestamp - 10, + ), + cleaved: cleave ? true : false, + }); } - onDamage(event: DamageEvent) { - const damageTarget = encodeTargetString(event.targetID, event.targetInstance); - if (this.iceLanceTargetId !== damageTarget) { - return; - } + nonShatteredCasts = () => { + //Get casts that were not shattered + let badCasts = this.icelance.filter((il) => !il.shattered); - const enemy = this.enemies.getEntity(event); - if ( - enemy && - !SHATTER_DEBUFFS.some((effect) => enemy.hasBuff(effect.id, event.timestamp)) && - !this.hadFingersProc - ) { - this.nonShatteredCasts += 1; - } - } + //If they had Fingers of Frost, disregard it + badCasts = badCasts.filter((il) => !il.hadFingers); - onFingersStackChange(event: ChangeBuffStackEvent) { - // FoF overcaps don't show as a refreshbuff, instead they are a stack lost followed immediately by a gain - const stackChange = event.stacksGained; - if (stackChange > 0) { - this.totalFingersProcs += stackChange; - } else if ( - this.iceLanceCastTimestamp && - this.iceLanceCastTimestamp + MS_BUFFER_100 > event.timestamp - ) { - // just cast ice lance, so this stack removal probably a proc used - } else if (event.newStacks === 0) { - this.expiredFingersProcs += -stackChange; // stacks zero out, must be expiration - } else { - this.overwrittenFingersProcs += -stackChange; // stacks don't zero, this is an overwrite - } - } + const tooltip = `This Ice Lance was not shattered.`; + badCasts.forEach((e) => e.cast && highlightInefficientCast(e.cast, tooltip)); - get wastedFingersProcs() { - return this.expiredFingersProcs + this.overwrittenFingersProcs; - } - - get usedFingersProcs() { - return this.totalFingersProcs - this.wastedFingersProcs; - } + return badCasts.length; + }; get shatteredPercent() { - return ( - 1 - this.nonShatteredCasts / this.abilityTracker.getAbility(TALENTS.ICE_LANCE_TALENT.id).casts - ); - } - - get fingersProcUtilizationThresholds() { - return { - actual: 1 - this.wastedFingersProcs / this.totalFingersProcs || 0, - isLessThan: { - minor: 0.95, - average: 0.85, - major: 0.7, - }, - style: ThresholdStyle.PERCENTAGE, - }; + return 1 - this.nonShatteredCasts() / this.icelance.length; } get nonShatteredIceLanceThresholds() { return { - actual: - this.nonShatteredCasts / this.abilityTracker.getAbility(TALENTS.ICE_LANCE_TALENT.id).casts, + actual: this.nonShatteredCasts() / this.icelance.length, isGreaterThan: { minor: 0.05, average: 0.15, @@ -139,7 +77,7 @@ class IceLance extends Analyzer { when(this.nonShatteredIceLanceThresholds).addSuggestion((suggest, actual, recommended) => suggest( <> - You cast {this.nonShatteredCasts} times ( + You cast {this.nonShatteredCasts()} times ( {formatPercentage(actual)}%) without . Make sure that you are only casting Ice Lance when the target has{' '} (or other Shatter effects), if you have a{' '} @@ -148,11 +86,7 @@ class IceLance extends Analyzer { , ) .icon(TALENTS.ICE_LANCE_TALENT.icon) - .actual( - - {formatPercentage(actual)}% missed - , - ) + .actual(`${formatPercentage(actual)}% missed`) .recommended(`<${formatPercentage(recommended)}% is recommended`), ); } diff --git a/src/analysis/retail/mage/frost/core/IcyVeins.tsx b/src/analysis/retail/mage/frost/core/IcyVeins.tsx index 4161152b4b6..6acc2002981 100644 --- a/src/analysis/retail/mage/frost/core/IcyVeins.tsx +++ b/src/analysis/retail/mage/frost/core/IcyVeins.tsx @@ -1,62 +1,87 @@ -import { Trans } from '@lingui/macro'; import { formatNumber, formatPercentage } from 'common/format'; import TALENTS from 'common/TALENTS/mage'; import { SpellLink } from 'interface'; import Analyzer, { Options } from 'parser/core/Analyzer'; import { SELECTED_PLAYER } from 'parser/core/EventFilter'; -import Events, { RemoveBuffEvent } from 'parser/core/Events'; +import Events, { + EventType, + GetRelatedEvent, + ApplyBuffEvent, + RemoveBuffEvent, + FightEndEvent, +} from 'parser/core/Events'; import { When, ThresholdStyle } from 'parser/core/ParseResults'; -import AbilityTracker from 'parser/shared/modules/AbilityTracker'; import EventHistory from 'parser/shared/modules/EventHistory'; -import FilteredActiveTime from 'parser/shared/modules/FilteredActiveTime'; import BoringSpellValueText from 'parser/ui/BoringSpellValueText'; import Statistic from 'parser/ui/Statistic'; import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER'; +import AlwaysBeCasting from './AlwaysBeCasting'; class IcyVeins extends Analyzer { static dependencies = { eventHistory: EventHistory, - filteredActiveTime: FilteredActiveTime, - abilityTracker: AbilityTracker, + alwaysBeCasting: AlwaysBeCasting, }; protected eventHistory!: EventHistory; - protected filteredActiveTime!: FilteredActiveTime; - protected abilityTracker!: AbilityTracker; + protected alwaysBeCasting!: AlwaysBeCasting; - activeTime = 0; + activeTime: number[] = []; + buffApplies: number = 0; constructor(options: Options) { super(options); + this.addEventListener( + Events.applybuff.by(SELECTED_PLAYER).spell(TALENTS.ICY_VEINS_TALENT), + this.onIcyVeinsStart, + ); this.addEventListener( Events.removebuff.by(SELECTED_PLAYER).spell(TALENTS.ICY_VEINS_TALENT), - this.onIcyVeinsRemoved, + this.onIcyVeinsEnd, ); + this.addEventListener(Events.fightend, this.onFightEnd); } - onIcyVeinsRemoved(event: RemoveBuffEvent) { - const buffApplied = this.eventHistory.last( - 1, - undefined, - Events.applybuff.by(SELECTED_PLAYER).spell(TALENTS.ICY_VEINS_TALENT), - )[0].timestamp; - const uptime = this.filteredActiveTime.getActiveTime(buffApplied, event.timestamp); - this.activeTime += uptime; + onIcyVeinsStart(event: ApplyBuffEvent) { + this.buffApplies += 1; } - get buffUptime() { - return this.selectedCombatant.getBuffUptime(TALENTS.ICY_VEINS_TALENT.id); + onIcyVeinsEnd(event: RemoveBuffEvent) { + const buffApply: ApplyBuffEvent | undefined = GetRelatedEvent(event, 'BuffApply'); + if (!buffApply) { + return; + } + const icyVeinsDuration = event.timestamp - buffApply.timestamp; + this.activeTime[buffApply.timestamp] = + icyVeinsDuration - + this.alwaysBeCasting.getActiveTimeMillisecondsInWindow(buffApply.timestamp, event.timestamp); } - get percentActiveTime() { - return this.activeTime / this.buffUptime || 0; + onFightEnd(event: FightEndEvent) { + const buffApply = this.eventHistory.getEvents(EventType.ApplyBuff, { + spell: TALENTS.ICY_VEINS_TALENT, + count: 1, + })[0]; + if (!this.selectedCombatant.hasBuff(TALENTS.ICY_VEINS_TALENT.id) || !buffApply) { + return; + } + const icyVeinsDuration = event.timestamp - buffApply.timestamp; + this.activeTime[buffApply.timestamp] = + icyVeinsDuration - + this.alwaysBeCasting.getActiveTimeMillisecondsInWindow(buffApply.timestamp, event.timestamp); } - get downtimeSeconds() { - return (this.buffUptime - this.activeTime) / 1000; + icyVeinsDowntime = () => { + let activeTime = 0; + this.activeTime.forEach((c) => (activeTime += c)); + return activeTime / 1000; + }; + + get buffUptime() { + return this.selectedCombatant.getBuffUptime(TALENTS.ICY_VEINS_TALENT.id) / 1000; } - get averageDowntime() { - return this.downtimeSeconds / this.abilityTracker.getAbility(TALENTS.ICY_VEINS_TALENT.id).casts; + get percentActiveTime() { + return 1 - this.icyVeinsDowntime() / this.buffUptime; } get icyVeinsActiveTimeThresholds() { @@ -75,22 +100,18 @@ class IcyVeins extends Analyzer { when(this.icyVeinsActiveTimeThresholds).addSuggestion((suggest, actual, recommended) => suggest( <> - You spent {formatNumber(this.downtimeSeconds)} seconds ( - {formatNumber(this.averageDowntime)}s per cast) not casting anything while{' '} - was active. Because a large portion of your - damage comes from Icy Veins, you should ensure that you are getting the most out of it - every time it is cast. While sometimes this is out of your control (you got targeted by a - mechanic at the worst possible time), you should try to minimize that risk by casting{' '} + You spent {formatNumber(this.icyVeinsDowntime())} seconds ( + {formatNumber(this.icyVeinsDowntime() / this.buffApplies)}s per cast) not casting anything + while was active. Because a large portion + of your damage comes from Icy Veins, you should ensure that you are getting the most out + of it every time it is cast. While sometimes this is out of your control (you got targeted + by a mechanic at the worst possible time), you should try to minimize that risk by casting{' '} when you are at a low risk of being interrupted or when the target is vulnerable. , ) .icon(TALENTS.ICY_VEINS_TALENT.icon) - .actual( - - {formatPercentage(this.percentActiveTime)}% Active Time during Icy Veins - , - ) + .actual(`${formatPercentage(this.percentActiveTime)}% Active Time during Icy Veins`) .recommended(`${formatPercentage(recommended)}% is recommended`), ); } diff --git a/src/analysis/retail/mage/frost/core/WintersChill.tsx b/src/analysis/retail/mage/frost/core/WintersChill.tsx index 6cfcc1df547..202d52203f1 100644 --- a/src/analysis/retail/mage/frost/core/WintersChill.tsx +++ b/src/analysis/retail/mage/frost/core/WintersChill.tsx @@ -1,174 +1,136 @@ -import { Trans } from '@lingui/macro'; -import { formatPercentage, formatDuration } from 'common/format'; +import { formatPercentage } from 'common/format'; import SPELLS from 'common/SPELLS'; import TALENTS from 'common/TALENTS/mage'; import { SpellIcon } from 'interface'; import { SpellLink } from 'interface'; -import Analyzer from 'parser/core/Analyzer'; -import { EventType } from 'parser/core/Events'; +import Analyzer, { Options, SELECTED_PLAYER } from 'parser/core/Analyzer'; +import Events, { + ApplyDebuffEvent, + RemoveDebuffEvent, + CastEvent, + DamageEvent, + GetRelatedEvent, +} from 'parser/core/Events'; import { When, ThresholdStyle } from 'parser/core/ParseResults'; import Enemies from 'parser/shared/modules/Enemies'; -import EventHistory from 'parser/shared/modules/EventHistory'; import BoringSpellValueText from 'parser/ui/BoringSpellValueText'; import Statistic from 'parser/ui/Statistic'; import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER'; -const WINTERS_CHILL_SPENDERS = [ - SPELLS.ICE_LANCE_DAMAGE, - SPELLS.GLACIAL_SPIKE_DAMAGE, - TALENTS.ICE_NOVA_TALENT, - TALENTS.RAY_OF_FROST_TALENT, -]; - -const WINTERS_CHILL_PRECAST_CASTS = [SPELLS.FROSTBOLT, TALENTS.GLACIAL_SPIKE_TALENT]; - -const WINTERS_CHILL_PRECAST_DAMAGE = [SPELLS.FROSTBOLT_DAMAGE, SPELLS.GLACIAL_SPIKE_DAMAGE]; - -const debug = false; +const WINTERS_CHILL_SPENDERS = [SPELLS.ICE_LANCE_DAMAGE.id, SPELLS.GLACIAL_SPIKE_DAMAGE.id]; class WintersChill extends Analyzer { static dependencies = { enemies: Enemies, - eventHistory: EventHistory, }; protected enemies!: Enemies; - protected eventHistory!: EventHistory; hasGlacialSpike: boolean = this.selectedCombatant.hasTalent(TALENTS.GLACIAL_SPIKE_TALENT); + wintersChill: { + apply: ApplyDebuffEvent; + remove: RemoveDebuffEvent | undefined; + precast: CastEvent | undefined; + precastIcicles: number; + damageEvents: DamageEvent[]; + }[] = []; + + constructor(options: Options) { + super(options); + this.addEventListener( + Events.applydebuff.by(SELECTED_PLAYER).spell(SPELLS.WINTERS_CHILL), + this.onWintersChill, + ); + this.addEventListener( + Events.damage + .by(SELECTED_PLAYER) + .spell([ + SPELLS.FROSTBOLT_DAMAGE, + SPELLS.GLACIAL_SPIKE_DAMAGE, + SPELLS.ICE_LANCE_DAMAGE, + TALENTS.RAY_OF_FROST_TALENT, + ]), + this.onDamage, + ); + } - wintersChillHardCasts = () => { - let debuffApplies = this.eventHistory.getEvents(EventType.ApplyDebuff, { - spell: SPELLS.WINTERS_CHILL, + onWintersChill(event: ApplyDebuffEvent) { + const remove: RemoveDebuffEvent | undefined = GetRelatedEvent(event, 'DebuffRemove'); + const flurry: CastEvent | undefined = GetRelatedEvent(event, 'SpellCast'); + const precast: CastEvent | undefined = GetRelatedEvent(event, 'PreCast'); + this.wintersChill.push({ + apply: event, + remove: remove, + precast: precast, + precastIcicles: + (flurry && + this.selectedCombatant.getBuff(SPELLS.ICICLES_BUFF.id, flurry.timestamp)?.stacks) || + 0, + damageEvents: [], }); + } - //Filter out buffs where there was not a valid precast before Winter's Chill was applied or the precast didnt land in Winter's Chill - debuffApplies = debuffApplies.filter((e) => { - const debuffRemoved = this.eventHistory.getEvents(EventType.RemoveDebuff, { - searchBackwards: false, - spell: SPELLS.WINTERS_CHILL, - count: 1, - startTimestamp: e.timestamp, - })[0]; - const preCast = this.eventHistory.getEvents(EventType.Cast, { - spell: WINTERS_CHILL_PRECAST_CASTS, - count: 1, - startTimestamp: e.timestamp, - duration: 1000, - })[0]; - if (!preCast) { - debug && - this.log( - 'PRECAST NOT FOUND @' + formatDuration(e.timestamp - this.owner.fight.start_time), - ); - return false; - } + onDamage(event: DamageEvent) { + const enemy = this.enemies.getEntity(event); + if (!enemy || !enemy.hasBuff(SPELLS.WINTERS_CHILL.id)) { + return; + } + const wintersChillDebuff: number | undefined = this.wintersChill.findIndex( + (d) => + d.apply.timestamp <= event.timestamp && d.remove && d.remove.timestamp >= event.timestamp, + ); + if (wintersChillDebuff === -1) { + return; + } + this.wintersChill[wintersChillDebuff].damageEvents?.push(event); + } - //Check to see if the precast landed in Winter's Chill - const duration = debuffRemoved - ? debuffRemoved.timestamp - e.timestamp - : this.owner.fight.end_time - e.timestamp; - const damageEvents = this.eventHistory.getEvents(EventType.Damage, { - searchBackwards: false, - spell: WINTERS_CHILL_PRECAST_DAMAGE, - startTimestamp: preCast.timestamp, - duration: duration, - }); - if (!damageEvents || damageEvents.length === 0) { - debug && - this.log( - 'PRECAST DAMAGE NOT FOUND @' + - formatDuration(e.timestamp - this.owner.fight.start_time), - ); - return false; - } + missedPreCasts = () => { + //If there is no Pre Cast, or if there is a Precast but it didnt land in Winter's Chlll + let missingPreCast = this.wintersChill.filter( + (w) => + !w.precast || + w.damageEvents.filter((d) => w.precast?.ability.guid === d.ability.guid).length > 0, + ); - //Check if the target had Winter's Chill - let preCastHits = 0; - damageEvents.forEach((d) => { - const enemy = this.enemies.getEntity(d); - if (enemy && enemy.hasBuff(SPELLS.WINTERS_CHILL.id, d.timestamp)) { - preCastHits += 1; - } - }); - if (preCastHits < 1) { - debug && - this.log( - 'PRECAST DAMAGE NOT SHATTERED @ ' + - formatDuration(e.timestamp - this.owner.fight.start_time), - ); - return false; - } - return true; - }); - return debuffApplies.length; + //If the player had exactly 4 Icicles, disregard it + missingPreCast = missingPreCast.filter((w) => w.precastIcicles !== 4); + + return missingPreCast.length; }; - wintersChillShatters = () => { - let debuffApplies = this.eventHistory.getEvents(EventType.ApplyDebuff, { - spell: SPELLS.WINTERS_CHILL, + missedShatters = () => { + //Winter's Chill Debuffs where there are at least 2 damage hits of Glacial Spike and/or Ice Lance + let badDebuffs = this.wintersChill.filter((w) => { + const shatteredSpenders = w.damageEvents.filter((d) => + WINTERS_CHILL_SPENDERS.includes(d.ability.guid), + ); + return shatteredSpenders.length < 2; }); - //Filter out buffs where both stacks of Winter's Chill were used before Winter's Chill expired - debuffApplies = debuffApplies.filter((e) => { - const debuffRemoved = this.eventHistory.getEvents(EventType.RemoveDebuff, { - searchBackwards: false, - spell: SPELLS.WINTERS_CHILL, - count: 1, - startTimestamp: e.timestamp, - })[0]; - const duration = debuffRemoved - ? debuffRemoved.timestamp - e.timestamp - : this.owner.fight.end_time - e.timestamp; - const damageEvents = this.eventHistory.getEvents(EventType.Damage, { - searchBackwards: false, - spell: WINTERS_CHILL_SPENDERS, - startTimestamp: e.timestamp, - duration: duration, - }); - if (!damageEvents) { - return false; - } - - //Check if the target had Winter's Chill - let shatteredCasts = 0; - damageEvents.forEach((d) => { - const enemy = this.enemies.getEntity(d); - if (enemy && enemy.hasBuff(SPELLS.WINTERS_CHILL.id, d.timestamp)) { - shatteredCasts += 1; - } - }); - debug && - this.log( - 'Shattered Casts: ' + - shatteredCasts + - ' @ ' + - formatDuration(e.timestamp - this.owner.fight.start_time), - ); - return shatteredCasts >= 2; + //If they shattered one spell but also they used Ray Of Frost, then disregard it. + badDebuffs = badDebuffs.filter((w) => { + const shatteredSpenders = w.damageEvents.filter((d) => + WINTERS_CHILL_SPENDERS.includes(d.ability.guid), + ); + const rayHits = w.damageEvents.filter( + (d) => d.ability.guid === TALENTS.RAY_OF_FROST_TALENT.id, + ); + return shatteredSpenders.length !== 1 || rayHits.length < 2; }); - return debuffApplies.length; + + return badDebuffs.length; }; get totalProcs() { - return this.eventHistory.getEvents(EventType.ApplyDebuff, { - spell: SPELLS.WINTERS_CHILL, - }).length; - } - - get missedShatters() { - return this.totalProcs - this.wintersChillShatters(); + return this.wintersChill.length; } get shatterPercent() { - return this.wintersChillShatters() / this.totalProcs || 0; - } - - get missedPreCasts() { - return this.totalProcs - this.wintersChillHardCasts(); + return 1 - this.missedShatters() / this.totalProcs; } get preCastPercent() { - return this.wintersChillHardCasts() / this.totalProcs || 0; + return 1 - this.missedPreCasts() / this.totalProcs; } // less strict than the ice lance suggestion both because it's less important, @@ -202,8 +164,8 @@ class WintersChill extends Analyzer { suggest( <> You failed to properly take advantage of on - your target {this.missedShatters} times ({formatPercentage(1 - actual)}%). After debuffing - the target via and{' '} + your target {this.missedShatters()} times ({formatPercentage(1 - actual)}%). After + debuffing the target via and{' '} , you should ensure that you hit the target with{' '} {this.hasGlacialSpike ? ( @@ -220,32 +182,28 @@ class WintersChill extends Analyzer { , ) .icon(TALENTS.ICE_LANCE_TALENT.icon) - .actual( - - {formatPercentage(1 - actual)}% Winter's Chill not shattered with Ice Lance - , - ) + .actual(`${formatPercentage(1 - actual)}% Winter's Chill not shattered with Ice Lance`) .recommended(`${formatPercentage(1 - recommended)}% is recommended`), ); when(this.wintersChillPreCastThresholds).addSuggestion((suggest, actual, recommended) => suggest( <> You failed to use a pre-cast ability before {' '} - {this.missedPreCasts} times ({formatPercentage(1 - actual)}%). Because of the travel time - of , you should cast a damaging ability such as{' '} - immediately before using{' '} + {this.missedPreCasts()} times ({formatPercentage(1 - actual)}%). Because of the travel + time of , you should cast a damaging ability + such as immediately before using{' '} . Doing this will allow your pre-cast ability to hit the target after (unless you are standing too close to the target) allowing it to benefit from{' '} - . + . If you have 4 Icicles, it can be acceptable + to use without a pre-cast. , ) .icon(SPELLS.FROSTBOLT.icon) .actual( - - {formatPercentage(1 - actual)}% Winter's Chill not shattered with Frostbolt, Glacial - Spike, or Ebonbolt - , + `${formatPercentage( + 1 - actual, + )}% Winter's Chill not shattered with Frostbolt or Glacial Spike`, ) .recommended(`${formatPercentage(1 - recommended)}% is recommended`), ); diff --git a/src/analysis/retail/mage/frost/core/apl.tsx b/src/analysis/retail/mage/frost/core/apl.tsx deleted file mode 100644 index be6cfe84d88..00000000000 --- a/src/analysis/retail/mage/frost/core/apl.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import SPELLS from 'common/SPELLS'; -import TALENTS from 'common/TALENTS/mage'; -import { SpellLink } from 'interface'; -import { suggestion as buildSuggestion } from 'parser/core/Analyzer'; -import { EventType } from 'parser/core/Events'; -import aplCheck, { build, Condition } from 'parser/shared/metrics/apl'; -import annotateTimeline from 'parser/shared/metrics/apl/annotate'; -import * as cnd from 'parser/shared/metrics/apl/conditions'; - -const precastFrostbolt: Condition<{ brainFreeze?: number; frostbolt?: number }> = { - key: 'precast-frostbolt', - init: () => ({}), - update: (state, event) => { - if ( - event.type === EventType.ApplyBuff && - event.ability.guid === TALENTS.BRAIN_FREEZE_TALENT.id - ) { - state.brainFreeze = event.timestamp; - } - - if ( - event.type === EventType.RemoveBuff && - event.ability.guid === TALENTS.BRAIN_FREEZE_TALENT.id - ) { - state.brainFreeze = undefined; - } - - if (event.type === EventType.Cast && event.ability.guid === SPELLS.FROSTBOLT.id) { - state.frostbolt = event.timestamp; - } - - return state; - }, - validate: (state, _event) => { - if (!state.brainFreeze) { - return false; - } - - // if brain freeze is up, did the previous cast overlap sufficiently? - if ((state.frostbolt || 0) > state.brainFreeze + 500) { - return false; - } - - // otherwise, brain freeze is up and the previous frostbolt doesn't count - return true; - }, - describe: () => ( - <> - was just applied - - ), -}; - -export const apl = build([ - { - spell: TALENTS.ICE_LANCE_TALENT, - condition: cnd.debuffPresent(SPELLS.WINTERS_CHILL), - }, - { - spell: SPELLS.FROSTBOLT, - condition: cnd.and(precastFrostbolt), - }, - { - spell: TALENTS.FLURRY_TALENT, - condition: cnd.buffPresent(TALENTS.BRAIN_FREEZE_TALENT), - }, - { spell: TALENTS.ICE_LANCE_TALENT, condition: cnd.buffPresent(TALENTS.FINGERS_OF_FROST_TALENT) }, - TALENTS.FROZEN_ORB_TALENT, - SPELLS.FROSTBOLT, -]); - -export const check = aplCheck(apl); - -export default buildSuggestion((events, info) => { - const { violations } = check(events, info); - annotateTimeline(violations); - - return undefined; -}); diff --git a/src/analysis/retail/mage/frost/normalizers/CastLinkNormalizer.ts b/src/analysis/retail/mage/frost/normalizers/CastLinkNormalizer.ts new file mode 100644 index 00000000000..eb4e6141058 --- /dev/null +++ b/src/analysis/retail/mage/frost/normalizers/CastLinkNormalizer.ts @@ -0,0 +1,303 @@ +import SPELLS from 'common/SPELLS'; +import TALENTS from 'common/TALENTS/mage'; +import EventLinkNormalizer, { EventLink } from 'parser/core/EventLinkNormalizer'; +import { + AbilityEvent, + BeginCastEvent, + RemoveBuffEvent, + CastEvent, + DamageEvent, + EventType, + GetRelatedEvents, + HasRelatedEvent, + HasTarget, +} from 'parser/core/Events'; +import { Options } from 'parser/core/Module'; +import { encodeTargetString } from 'parser/shared/modules/Enemies'; + +const CAST_BUFFER_MS = 75; + +export const BUFF_APPLY = 'BuffApply'; +export const BUFF_REMOVE = 'BuffRemove'; +export const BUFF_REFRESH = 'BuffRefresh'; +export const DEBUFF_APPLY = 'DebuffApply'; +export const DEBUFF_REMOVE = 'DebuffRemove'; +export const CAST_BEGIN = 'CastBegin'; +export const SPELL_CAST = 'SpellCast'; +export const PRE_CAST = 'PreCast'; +export const SPELL_DAMAGE = 'SpellDamage'; +export const CLEAVE_DAMAGE = 'CleaveDamage'; + +const EVENT_LINKS: EventLink[] = [ + { + reverseLinkRelation: SPELL_CAST, + linkingEventId: TALENTS.GLACIAL_SPIKE_TALENT.id, + linkingEventType: EventType.Cast, + linkRelation: SPELL_DAMAGE, + referencedEventId: SPELLS.GLACIAL_SPIKE_DAMAGE.id, + referencedEventType: EventType.Damage, + anyTarget: true, + additionalCondition(linkingEvent, referencedEvent): boolean { + return isCleaveDamage(linkingEvent as CastEvent, referencedEvent as DamageEvent) === false; + }, + maximumLinks: 1, + forwardBufferMs: 3000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: SPELL_CAST, + linkingEventId: TALENTS.GLACIAL_SPIKE_TALENT.id, + linkingEventType: EventType.Cast, + linkRelation: CLEAVE_DAMAGE, + referencedEventId: SPELLS.GLACIAL_SPIKE_DAMAGE.id, + referencedEventType: EventType.Damage, + anyTarget: true, + additionalCondition(linkingEvent, referencedEvent): boolean { + return isCleaveDamage(linkingEvent as CastEvent, referencedEvent as DamageEvent) === true; + }, + maximumLinks: 1, + forwardBufferMs: 3000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: SPELL_CAST, + linkingEventId: TALENTS.FLURRY_TALENT.id, + linkingEventType: EventType.Cast, + linkRelation: SPELL_DAMAGE, + referencedEventId: SPELLS.FLURRY_DAMAGE.id, + referencedEventType: EventType.Damage, + anyTarget: true, + forwardBufferMs: 1500, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: SPELL_CAST, + linkingEventId: TALENTS.ICE_LANCE_TALENT.id, + linkingEventType: EventType.Cast, + linkRelation: SPELL_DAMAGE, + referencedEventId: SPELLS.ICE_LANCE_DAMAGE.id, + referencedEventType: EventType.Damage, + anyTarget: true, + additionalCondition(linkingEvent, referencedEvent): boolean { + return isCleaveDamage(linkingEvent as CastEvent, referencedEvent as DamageEvent) === false; + }, + maximumLinks: 1, + forwardBufferMs: 1000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: SPELL_CAST, + linkingEventId: TALENTS.ICE_LANCE_TALENT.id, + linkingEventType: EventType.Cast, + linkRelation: CLEAVE_DAMAGE, + referencedEventId: SPELLS.ICE_LANCE_DAMAGE.id, + referencedEventType: EventType.Damage, + anyTarget: true, + additionalCondition(linkingEvent, referencedEvent): boolean { + return isCleaveDamage(linkingEvent as CastEvent, referencedEvent as DamageEvent) === true; + }, + maximumLinks: 1, + forwardBufferMs: 1000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: BUFF_APPLY, + linkingEventId: SPELLS.BRAIN_FREEZE_BUFF.id, + linkingEventType: EventType.ApplyBuff, + linkRelation: BUFF_REMOVE, + referencedEventId: SPELLS.BRAIN_FREEZE_BUFF.id, + referencedEventType: EventType.RemoveBuff, + maximumLinks: 1, + forwardBufferMs: 17_000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: BUFF_REMOVE, + linkingEventId: SPELLS.BRAIN_FREEZE_BUFF.id, + linkingEventType: EventType.RemoveBuff, + linkRelation: SPELL_CAST, + referencedEventId: TALENTS.FLURRY_TALENT.id, + referencedEventType: EventType.Cast, + maximumLinks: 1, + anyTarget: true, + forwardBufferMs: CAST_BUFFER_MS, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: DEBUFF_APPLY, + linkingEventId: SPELLS.WINTERS_CHILL.id, + linkingEventType: EventType.ApplyDebuff, + linkRelation: DEBUFF_REMOVE, + referencedEventId: SPELLS.WINTERS_CHILL.id, + referencedEventType: EventType.RemoveDebuff, + maximumLinks: 1, + forwardBufferMs: 7000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: DEBUFF_APPLY, + linkingEventId: SPELLS.WINTERS_CHILL.id, + linkingEventType: EventType.ApplyDebuff, + linkRelation: SPELL_CAST, + referencedEventId: TALENTS.FLURRY_TALENT.id, + referencedEventType: EventType.Cast, + maximumLinks: 1, + forwardBufferMs: CAST_BUFFER_MS, + backwardBufferMs: 1000, + }, + { + reverseLinkRelation: DEBUFF_APPLY, + linkingEventId: SPELLS.WINTERS_CHILL.id, + linkingEventType: EventType.ApplyDebuff, + linkRelation: PRE_CAST, + referencedEventId: [SPELLS.FROSTBOLT.id, TALENTS.GLACIAL_SPIKE_TALENT.id], + referencedEventType: EventType.Cast, + anyTarget: true, + maximumLinks: 1, + forwardBufferMs: CAST_BUFFER_MS, + backwardBufferMs: 1000, + }, + { + reverseLinkRelation: BUFF_APPLY, + linkingEventId: SPELLS.FINGERS_OF_FROST_BUFF.id, + linkingEventType: [EventType.ApplyBuff, EventType.ApplyBuffStack], + linkRelation: BUFF_REMOVE, + referencedEventId: SPELLS.FINGERS_OF_FROST_BUFF.id, + referencedEventType: [EventType.RemoveBuff, EventType.RemoveBuffStack], + anyTarget: true, + additionalCondition(linkingEvent, referencedEvent): boolean { + return !HasRelatedEvent(referencedEvent, BUFF_APPLY); + }, + maximumLinks: 1, + forwardBufferMs: 18_000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: BUFF_REMOVE, + linkingEventId: SPELLS.FINGERS_OF_FROST_BUFF.id, + linkingEventType: [EventType.RemoveBuff, EventType.RemoveBuffStack], + linkRelation: SPELL_CAST, + referencedEventId: TALENTS.ICE_LANCE_TALENT.id, + referencedEventType: EventType.Cast, + anyTarget: true, + additionalCondition(linkingEvent, referencedEvent): boolean { + return !HasRelatedEvent(referencedEvent, BUFF_REMOVE); + }, + maximumLinks: 1, + forwardBufferMs: CAST_BUFFER_MS, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: BUFF_REMOVE, + linkingEventId: SPELLS.FINGERS_OF_FROST_BUFF.id, + linkingEventType: EventType.RemoveBuff, + linkRelation: SPELL_CAST, + referencedEventId: TALENTS.ICE_LANCE_TALENT.id, + referencedEventType: EventType.Cast, + anyTarget: true, + maximumLinks: 1, + forwardBufferMs: CAST_BUFFER_MS, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: BUFF_APPLY, + linkingEventId: TALENTS.ICY_VEINS_TALENT.id, + linkingEventType: EventType.ApplyBuff, + linkRelation: BUFF_REMOVE, + referencedEventId: TALENTS.ICY_VEINS_TALENT.id, + referencedEventType: EventType.RemoveBuff, + anyTarget: true, + maximumLinks: 1, + forwardBufferMs: 60_000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: BUFF_APPLY, + linkingEventId: TALENTS.COLD_FRONT_TALENT.id, + linkingEventType: EventType.ApplyBuff, + linkRelation: BUFF_REMOVE, + referencedEventId: TALENTS.COLD_FRONT_TALENT.id, + referencedEventType: EventType.RemoveBuff, + anyTarget: true, + maximumLinks: 1, + forwardBufferMs: 500, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: SPELL_CAST, + linkingEventId: TALENTS.COMET_STORM_TALENT.id, + linkingEventType: EventType.Cast, + linkRelation: SPELL_DAMAGE, + referencedEventId: SPELLS.COMET_STORM_DAMAGE.id, + referencedEventType: EventType.Damage, + anyTarget: true, + forwardBufferMs: 3000, + backwardBufferMs: CAST_BUFFER_MS, + }, + { + reverseLinkRelation: SPELL_CAST, + linkingEventId: TALENTS.RAY_OF_FROST_TALENT.id, + linkingEventType: EventType.Cast, + linkRelation: SPELL_DAMAGE, + referencedEventId: TALENTS.RAY_OF_FROST_TALENT.id, + referencedEventType: EventType.Damage, + anyTarget: true, + forwardBufferMs: 7000, + backwardBufferMs: CAST_BUFFER_MS, + }, +]; + +/** + * When a spell is cast on a target, the ordering of the Cast and ApplyBuff/RefreshBuff/(direct)Heal + * can be semi-arbitrary, making analysis difficult. + * + * This normalizer adds a _linkedEvent to the ApplyBuff/RefreshBuff/Heal linking back to the Cast event + * that caused it (if one can be found). + * + * This normalizer adds links for the buffs Rejuvenation, Regrowth, Wild Growth, Lifebloom, + * and for the direct heals of Swiftmend and Regrowth, and the self buff from Flourish. + * A special link key is used when the HoTs were applied by an Overgrowth cast instead of a normal hardcast. + */ +class CastLinkNormalizer extends EventLinkNormalizer { + constructor(options: Options) { + super(options, EVENT_LINKS); + } +} + +/** Returns true iff the given buff application or heal can be matched back to a hardcast */ +export function isFromHardcast(event: AbilityEvent): boolean { + return HasRelatedEvent(event, SPELL_CAST); +} + +export function isInstantCast(event: CastEvent): boolean { + const beginCast = GetRelatedEvents(event, CAST_BEGIN)[0]; + return !beginCast || event.timestamp - beginCast.timestamp <= CAST_BUFFER_MS; +} + +export function hasPreCast(event: AbilityEvent): boolean { + return HasRelatedEvent(event, PRE_CAST); +} + +/** Returns the hardcast event that caused this buff or heal, if there is one */ +export function getHardcast(event: AbilityEvent): CastEvent | undefined { + return GetRelatedEvents( + event, + SPELL_CAST, + (e): e is CastEvent => e.type === EventType.Cast, + ).pop(); +} + +export function isProcExpired(event: RemoveBuffEvent, spenderId: number): boolean { + const cast = GetRelatedEvents(event, SPELL_CAST)[0]; + return !cast || cast.ability.guid !== spenderId; +} + +export function isCleaveDamage(castEvent: CastEvent, damageEvent: DamageEvent): boolean { + const castTarget = + HasTarget(castEvent) && encodeTargetString(castEvent.targetID, castEvent.targetInstance); + const damageTarget = + HasTarget(damageEvent) && encodeTargetString(damageEvent.targetID, damageEvent.targetInstance); + return castTarget !== damageTarget; +} + +export default CastLinkNormalizer; diff --git a/src/analysis/retail/mage/frost/talents/ColdFront.tsx b/src/analysis/retail/mage/frost/talents/ColdFront.tsx index d33bfda0a79..7118b7467cf 100644 --- a/src/analysis/retail/mage/frost/talents/ColdFront.tsx +++ b/src/analysis/retail/mage/frost/talents/ColdFront.tsx @@ -4,18 +4,12 @@ import TALENTS from 'common/TALENTS/mage'; import { SpellIcon } from 'interface'; import Analyzer, { Options } from 'parser/core/Analyzer'; import { SELECTED_PLAYER } from 'parser/core/EventFilter'; -import Events from 'parser/core/Events'; -import EventHistory from 'parser/shared/modules/EventHistory'; +import Events, { GetRelatedEvent, ApplyBuffEvent, RemoveBuffEvent } from 'parser/core/Events'; import BoringSpellValueText from 'parser/ui/BoringSpellValueText'; import Statistic from 'parser/ui/Statistic'; import STATISTIC_CATEGORY from 'parser/ui/STATISTIC_CATEGORY'; class ColdFront extends Analyzer { - static dependencies = { - eventHistory: EventHistory, - }; - protected eventHistory!: EventHistory; - bonusFrozenOrbs = 0; constructor(options: Options) { @@ -27,13 +21,9 @@ class ColdFront extends Analyzer { ); } - onBuffApplied() { - const buffRemovedEvent = this.eventHistory.last( - 1, - 500, - Events.removebuff.to(SELECTED_PLAYER).spell(SPELLS.COLD_FRONT_BUFF), - ); - if (buffRemovedEvent) { + onBuffApplied(event: ApplyBuffEvent) { + const remove: RemoveBuffEvent | undefined = GetRelatedEvent(event, 'BuffRemove'); + if (remove) { this.bonusFrozenOrbs += 1; } } diff --git a/src/analysis/retail/mage/frost/talents/CometStorm.tsx b/src/analysis/retail/mage/frost/talents/CometStorm.tsx index 9faf90e1eea..8a4d585a139 100644 --- a/src/analysis/retail/mage/frost/talents/CometStorm.tsx +++ b/src/analysis/retail/mage/frost/talents/CometStorm.tsx @@ -1,74 +1,76 @@ -import { Trans } from '@lingui/macro'; -import { COMET_STORM_AOE_MIN_TARGETS } from 'analysis/retail/mage/shared'; +import { COMET_STORM_AOE_MIN_TARGETS, SHATTER_DEBUFFS } from 'analysis/retail/mage/shared'; import { formatPercentage } from 'common/format'; import SPELLS from 'common/SPELLS'; import TALENTS from 'common/TALENTS/mage'; import { SpellLink } from 'interface'; +import { highlightInefficientCast } from 'interface/report/Results/Timeline/Casts'; import Analyzer, { Options } from 'parser/core/Analyzer'; import { SELECTED_PLAYER } from 'parser/core/EventFilter'; -import Events, { AnyEvent, CastEvent } from 'parser/core/Events'; +import Events, { CastEvent, DamageEvent, GetRelatedEvents } from 'parser/core/Events'; import { When, ThresholdStyle } from 'parser/core/ParseResults'; -import AbilityTracker from 'parser/shared/modules/AbilityTracker'; import Enemies from 'parser/shared/modules/Enemies'; -import { cometStormHits } from '../normalizers/CometStormLinkNormalizer'; - const MIN_SHATTERED_PROJECTILES_PER_CAST = 4; class CometStorm extends Analyzer { static dependencies = { - abilityTracker: AbilityTracker, enemies: Enemies, }; - protected abilityTracker!: AbilityTracker; protected enemies!: Enemies; - badCometStormCast = 0; + cometStorm: { cast: CastEvent; enemiesHit: number[]; shatteredHits: number }[] = []; constructor(options: Options) { super(options); this.active = this.selectedCombatant.hasTalent(TALENTS.COMET_STORM_TALENT); this.addEventListener( Events.cast.by(SELECTED_PLAYER).spell(TALENTS.COMET_STORM_TALENT), - this.onCometStormCast, + this.onCometCast, ); } - onCometStormCast(event: CastEvent) { - const damageEvents: AnyEvent[] = cometStormHits(event); - const enemiesHit: number[] = []; - let projectilesShattered = 0; - - damageEvents.forEach((hit) => { - const enemy = this.enemies.getEntity(hit); - if (!enemy) { - return; - } - //Tracks each unique enemy that was hit by the cast - if (!enemiesHit.includes(enemy.guid)) { - enemiesHit.push(enemy.guid); + onCometCast(event: CastEvent) { + const damage: DamageEvent[] | undefined = GetRelatedEvents(event, 'SpellDamage'); + let shattered = 0; + const enemies: number[] = []; + damage.forEach((d) => { + const enemy = this.enemies.getEntity(d); + const enemies: number[] = []; + if (enemy && enemies.includes(enemy.guid)) { + enemies.push(enemy.guid); } - //Tracks how many projectiles were shattered - if (enemy.hasBuff(SPELLS.WINTERS_CHILL.id)) { - projectilesShattered += 1; + if (enemy && SHATTER_DEBUFFS.some((effect) => enemy.hasBuff(effect.id, d.timestamp))) { + shattered += 1; } }); - if ( - enemiesHit.length < COMET_STORM_AOE_MIN_TARGETS && - projectilesShattered < MIN_SHATTERED_PROJECTILES_PER_CAST - ) { - this.badCometStormCast += 1; - } + this.cometStorm.push({ + cast: event, + enemiesHit: enemies, + shatteredHits: shattered, + }); } + badCasts = () => { + const badCasts = this.cometStorm.filter( + (cs) => + cs.enemiesHit.length < COMET_STORM_AOE_MIN_TARGETS && + cs.shatteredHits < MIN_SHATTERED_PROJECTILES_PER_CAST, + ); + + const tooltip = `This Comet Storm was not shattered and did not hit multiple enemies.`; + badCasts.forEach((e) => e.cast && highlightInefficientCast(e.cast, tooltip)); + + return badCasts.length; + }; + get totalCasts() { - return this.abilityTracker.getAbility(TALENTS.COMET_STORM_TALENT.id).casts; + return this.cometStorm.length; } get castUtilization() { - return 1 - this.badCometStormCast / this.totalCasts; + return 1 - this.badCasts() / this.totalCasts; } get cometStormUtilizationThresholds() { @@ -88,7 +90,7 @@ class CometStorm extends Analyzer { suggest( <> You failed to get the most out of your {' '} - casts {this.badCometStormCast} times. Because the projectiles from{' '} + casts {this.badCasts} times. Because the projectiles from{' '} no longer remove your stacks of{' '} , you should always cast{' '} immediately after casting{' '} @@ -101,11 +103,7 @@ class CometStorm extends Analyzer { , ) .icon(TALENTS.COMET_STORM_TALENT.icon) - .actual( - - {formatPercentage(actual)}% Utilization - , - ) + .actual(`${formatPercentage(actual)}% Utilization`) .recommended(`${formatPercentage(recommended)}% is recommended`), ); } diff --git a/src/analysis/retail/mage/frost/talents/GlacialSpike.tsx b/src/analysis/retail/mage/frost/talents/GlacialSpike.tsx index 7a9c561f366..13fedc5256f 100644 --- a/src/analysis/retail/mage/frost/talents/GlacialSpike.tsx +++ b/src/analysis/retail/mage/frost/talents/GlacialSpike.tsx @@ -1,15 +1,8 @@ -import { Trans } from '@lingui/macro'; import { SHATTER_DEBUFFS } from 'analysis/retail/mage/shared'; -import { formatPercentage } from 'common/format'; -import SPELLS from 'common/SPELLS'; import TALENTS from 'common/TALENTS/mage'; -import { SpellLink } from 'interface'; -import { TooltipElement } from 'interface'; import Analyzer, { SELECTED_PLAYER, Options } from 'parser/core/Analyzer'; -import Events, { CastEvent, DamageEvent, FightEndEvent, HasTarget } from 'parser/core/Events'; -import { When, ThresholdStyle } from 'parser/core/ParseResults'; -import AbilityTracker from 'parser/shared/modules/AbilityTracker'; -import Enemies, { encodeTargetString } from 'parser/shared/modules/Enemies'; +import Events, { CastEvent, DamageEvent, GetRelatedEvent } from 'parser/core/Events'; +import Enemies from 'parser/shared/modules/Enemies'; import BoringSpellValueText from 'parser/ui/BoringSpellValueText'; import Statistic from 'parser/ui/Statistic'; import STATISTIC_CATEGORY from 'parser/ui/STATISTIC_CATEGORY'; @@ -17,15 +10,15 @@ import STATISTIC_CATEGORY from 'parser/ui/STATISTIC_CATEGORY'; class GlacialSpike extends Analyzer { static dependencies = { enemies: Enemies, - abilityTracker: AbilityTracker, }; protected enemies!: Enemies; - protected abilityTracker!: AbilityTracker; - lastCastEvent?: CastEvent; - lastCastDidDamage = false; - spikeShattered = 0; - spikeNotShattered = 0; + glacialSpike: { + timestamp: number; + shattered: boolean; + damage: DamageEvent | undefined; + cleave: DamageEvent | undefined; + }[] = []; constructor(options: Options) { super(options); @@ -35,122 +28,28 @@ class GlacialSpike extends Analyzer { Events.cast.by(SELECTED_PLAYER).spell(TALENTS.GLACIAL_SPIKE_TALENT), this.onGlacialSpikeCast, ); - this.addEventListener( - Events.damage.by(SELECTED_PLAYER).spell(SPELLS.GLACIAL_SPIKE_DAMAGE), - this.onGlacialSpikeDamage, - ); - this.addEventListener(Events.fightend, this.onFightEnd); } onGlacialSpikeCast(event: CastEvent) { - if (this.lastCastEvent) { - this.flagTimeline(this.lastCastEvent); - } - - this.lastCastEvent = event; - this.lastCastDidDamage = false; - } - - onGlacialSpikeDamage(event: DamageEvent) { - if (!this.lastCastEvent) { - return; - } - if (!HasTarget(this.lastCastEvent)) { - return; - } - - const castTarget = encodeTargetString( - this.lastCastEvent.targetID, - this.lastCastEvent.targetInstance, - ); - const damageTarget = encodeTargetString(event.targetID, event.targetInstance); - - //We dont care about the Glacial Spikes that split to something else via Splitting Ice. - if (castTarget !== damageTarget) { - return; - } - - this.lastCastDidDamage = true; - const enemy: any = this.enemies.getEntity(event); - if (enemy && SHATTER_DEBUFFS.some((effect) => enemy.hasBuff(effect.id, event.timestamp))) { - this.spikeShattered += 1; - } else { - this.spikeNotShattered += 1; - this.flagTimeline(this.lastCastEvent); - } - this.lastCastEvent = undefined; + const damage: DamageEvent | undefined = GetRelatedEvent(event, 'SpellDamage'); + const enemy = damage && this.enemies.getEntity(damage); + const cleave: DamageEvent | undefined = GetRelatedEvent(event, 'CleaveDamage'); + this.glacialSpike.push({ + timestamp: event.timestamp, + shattered: + (enemy && SHATTER_DEBUFFS.some((effect) => enemy.hasBuff(effect.id, event.timestamp))) || + false, + damage: damage, + cleave: cleave, + }); } - onFightEnd(event: FightEndEvent) { - if (this.lastCastEvent) { - this.flagTimeline(this.lastCastEvent); - } - } - - flagTimeline(event: CastEvent) { - if (!this.lastCastEvent) { - return; - } - - event.meta = event.meta || {}; - event.meta.isInefficientCast = true; - if (this.lastCastDidDamage) { - event.meta.inefficientCastReason = `You cast Glacial Spike without shattering it. You should wait until it is frozen or you are able to use a Brain Freeze proc to maximize its damage.`; - } else { - event.meta.inefficientCastReason = - 'The target died before Glacial Spike hit it. You should avoid this by casting faster spells on very low-health targets, it is important to not waste potential Glacial Spike damage.'; - } - } - - get utilPercentage() { - return this.spikeShattered / this.totalCasts || 0; + get shatteredCasts() { + return this.glacialSpike.filter((gs) => gs.shattered).length; } get totalCasts() { - return this.abilityTracker.getAbility(TALENTS.GLACIAL_SPIKE_TALENT.id).casts; - } - - get glacialSpikeUtilizationThresholds() { - return { - actual: this.utilPercentage, - isLessThan: { - minor: 1.0, - average: 0.85, - major: 0.7, - }, - style: ThresholdStyle.PERCENTAGE, - }; - } - - suggestions(when: When) { - when(this.glacialSpikeUtilizationThresholds).addSuggestion((suggest, actual, recommended) => - suggest( - <> - You cast without{' '} - - ing it {this.spikeNotShattered} times. Because it is such a potent ability, it is - important to maximize it's damage by only casting it if the target is - - Winter's Chill, Frost Nova, Ice Nova, Ring of Frost, and your pet's Freeze will all - cause the target to be frozen or act as frozen. - - } - > - Frozen or acting as Frozen - - . - , - ) - .icon(TALENTS.GLACIAL_SPIKE_TALENT.icon) - .actual( - - {formatPercentage(actual, 1)}% utilization - , - ) - .recommended(`${formatPercentage(recommended, 1)}% is recommended`), - ); + return this.glacialSpike.length; } statistic() { @@ -160,13 +59,15 @@ class GlacialSpike extends Analyzer { size="flexible" tooltip={ <> - You cast Glacial Spike {this.totalCasts} times, {this.spikeShattered} casts of which + You cast Glacial Spike {this.totalCasts} times, {this.shatteredCasts} casts of which were Shattered } > - {`${formatPercentage(this.utilPercentage, 0)}%`} Cast utilization + {this.shatteredCasts} Shattered Casts +
    + {this.totalCasts - this.shatteredCasts} Non-Shattered Casts
    ); diff --git a/src/analysis/retail/mage/frost/talents/RayOfFrost.tsx b/src/analysis/retail/mage/frost/talents/RayOfFrost.tsx new file mode 100644 index 00000000000..926082bb564 --- /dev/null +++ b/src/analysis/retail/mage/frost/talents/RayOfFrost.tsx @@ -0,0 +1,92 @@ +import { SHATTER_DEBUFFS } from 'analysis/retail/mage/shared'; +import { formatPercentage } from 'common/format'; +import SPELLS from 'common/SPELLS'; +import TALENTS from 'common/TALENTS/mage'; +import { SpellLink } from 'interface'; +import Analyzer, { Options } from 'parser/core/Analyzer'; +import { SELECTED_PLAYER } from 'parser/core/EventFilter'; +import Events, { CastEvent, DamageEvent, GetRelatedEvents } from 'parser/core/Events'; +import { When, ThresholdStyle } from 'parser/core/ParseResults'; +import Enemies from 'parser/shared/modules/Enemies'; + +class RayOfFrost extends Analyzer { + static dependencies = { + enemies: Enemies, + }; + protected enemies!: Enemies; + + rayOfFrost: { hits: number; shatteredHits: number }[] = []; + + constructor(options: Options) { + super(options); + this.active = this.selectedCombatant.hasTalent(TALENTS.RAY_OF_FROST_TALENT); + this.addEventListener( + Events.cast.by(SELECTED_PLAYER).spell(TALENTS.RAY_OF_FROST_TALENT), + this.onRayCast, + ); + } + + onRayCast(event: CastEvent) { + const damage: DamageEvent[] | undefined = GetRelatedEvents(event, 'SpellDamage'); + let shattered = 0; + damage.forEach((d) => { + const enemy = this.enemies.getEntity(d); + if (SHATTER_DEBUFFS.some((effect) => enemy?.hasBuff(effect.id, d.timestamp))) { + shattered += 1; + } + }); + + this.rayOfFrost.push({ + hits: damage.length, + shatteredHits: shattered, + }); + } + + get badCasts() { + return this.rayOfFrost.filter((r) => r.shatteredHits < 2 || r.hits < 4).length; + } + + get totalCasts() { + return this.rayOfFrost.length; + } + + get castUtilization() { + return 1 - this.badCasts / this.totalCasts; + } + + get rayOfFrostUtilizationThresholds() { + return { + actual: this.castUtilization, + isLessThan: { + minor: 0.9, + average: 0.8, + major: 0.7, + }, + style: ThresholdStyle.PERCENTAGE, + }; + } + + suggestions(when: When) { + when(this.rayOfFrostUtilizationThresholds).addSuggestion((suggest, actual, recommended) => + suggest( + <> + You failed to get the most out of your {' '} + casts {this.badCasts} times. Because the ticks from{' '} + do not remove your stacks of{' '} + , you should always cast{' '} + during{' '} + . However, because{' '} + has such a short duration and therefore will + likely naturally end before finishes, + you should spend your first stack of and then + cast instead of spending the 2nd stack. + , + ) + .icon(TALENTS.RAY_OF_FROST_TALENT.icon) + .actual(`${formatPercentage(actual)}% Utilization`) + .recommended(`${formatPercentage(recommended)}% is recommended`), + ); + } +} + +export default RayOfFrost; diff --git a/src/analysis/retail/mage/frost/talents/WaterElemental.tsx b/src/analysis/retail/mage/frost/talents/WaterElemental.tsx index e63ae9e78b7..2324956ba30 100644 --- a/src/analysis/retail/mage/frost/talents/WaterElemental.tsx +++ b/src/analysis/retail/mage/frost/talents/WaterElemental.tsx @@ -1,4 +1,3 @@ -import { Trans } from '@lingui/macro'; import { formatPercentage, formatNumber, formatThousands, formatDuration } from 'common/format'; import SPELLS from 'common/SPELLS'; import { PLACEHOLDER_TALENT } from 'common/TALENTS/types'; @@ -142,11 +141,7 @@ class WaterElemental extends Analyzer { , ) .icon(PLACEHOLDER_TALENT.icon) - .actual( - - {formatPercentage(actual)}% uptime - , - ) + .actual(`${formatPercentage(actual)}% uptime`) .recommended( `mirroring your own uptime (${formatPercentage( this.abc.activeTimePercentage, @@ -162,13 +157,13 @@ class WaterElemental extends Analyzer { ) .icon(SPELLS.WATERBOLT.icon) .actual( - - {this._timestampFirstCast === 0 + `${ + this._timestampFirstCast === 0 ? 'Never attacked or not summoned' : 'First attack: ' + formatDuration(this._timestampFirstCast - this.owner.fight.start_time) + - ' into the fight'} - , + ' into the fight' + }`, ) .recommended(`summoning pre-fight is recommended`), ); diff --git a/src/analysis/retail/paladin/retribution/CHANGELOG.tsx b/src/analysis/retail/paladin/retribution/CHANGELOG.tsx index b605eed25f8..94f24527d21 100644 --- a/src/analysis/retail/paladin/retribution/CHANGELOG.tsx +++ b/src/analysis/retail/paladin/retribution/CHANGELOG.tsx @@ -1,7 +1,10 @@ import { change, date } from 'common/changelog'; import { emallson, Klamuz, ToppleTheNun, xizbow } from 'CONTRIBUTORS'; +import { ItemLink } from 'interface'; +import ITEMS from 'common/ITEMS'; export default [ + change(date(2024, 1, 7), <>Add to cooldown graph., ToppleTheNun), change(date(2023, 7, 19), 'Make CooldownGraphSubsection generic enough that it can be used by other specs.', ToppleTheNun), change(date(2023, 7, 18), 'Show percentage wasted Holy Power instead of percentage at Holy Power cap.', ToppleTheNun), change(date(2023, 7, 16), 'First pass at a Guide for Ret Paladin.', ToppleTheNun), diff --git a/src/analysis/retail/paladin/retribution/Guide.tsx b/src/analysis/retail/paladin/retribution/Guide.tsx index a19e2c50e21..818fdbaf0db 100644 --- a/src/analysis/retail/paladin/retribution/Guide.tsx +++ b/src/analysis/retail/paladin/retribution/Guide.tsx @@ -8,6 +8,8 @@ import HideExplanationsToggle from 'interface/guide/components/HideExplanationsT import HideGoodCastsToggle from 'interface/guide/components/HideGoodCastsToggle'; import { QualitativePerformance } from 'parser/ui/QualitativePerformance'; import PerformancePercentage from 'analysis/retail/demonhunter/shared/guide/PerformancePercentage'; +import DRAGONFLIGHT_OTHERS_ITEMS from 'common/ITEMS/dragonflight/others'; +import DRAGONFLIGHT_OTHERS_SPELLS from 'common/SPELLS/dragonflight/others'; import TALENTS from 'common/TALENTS/paladin'; import SpellLink from 'interface/SpellLink'; import CooldownGraphSubsection, { @@ -117,6 +119,10 @@ const cooldowns: Cooldown[] = [ spell: TALENTS.DIVINE_TOLL_TALENT, isActive: (c) => c.hasTalent(TALENTS.DIVINE_TOLL_TALENT), }, + { + spell: DRAGONFLIGHT_OTHERS_SPELLS.RAGE_OF_FYRALATH_1, + isActive: (c) => c.hasMainHand(DRAGONFLIGHT_OTHERS_ITEMS.FYRALATH.id), + }, ]; function CooldownSection() { return ( diff --git a/src/analysis/retail/warlock/demonology/CHANGELOG.tsx b/src/analysis/retail/warlock/demonology/CHANGELOG.tsx index ea456b853a0..9ad0841643d 100644 --- a/src/analysis/retail/warlock/demonology/CHANGELOG.tsx +++ b/src/analysis/retail/warlock/demonology/CHANGELOG.tsx @@ -1,10 +1,11 @@ import { change, date } from 'common/changelog'; import SPELLS from 'common/SPELLS'; import { TALENTS_WARLOCK } from 'common/TALENTS'; -import { Sharrq, Zeboot, Meldris, ToppleTheNun, Jonfanz, Mae, dodse, Arlie } from 'CONTRIBUTORS'; +import { Sharrq, Zeboot, Meldris, ToppleTheNun, Jonfanz, Mae, dodse, Arlie, Putro } from 'CONTRIBUTORS'; import { SpellLink } from 'interface'; export default [ + change(date(2024, 1, 6), <>Fix a crash related to ., Putro), change(date(2023, 7, 31), <>Add support for Aberrus 2set CDR on , Arlie), change(date(2023, 7, 31), 'Update CDR on Dark Pact and Unending Resolve', Arlie), change(date(2023, 7, 8), 'Update SpellLink usage.', ToppleTheNun), diff --git a/src/analysis/retail/warlock/demonology/modules/pets/PETS.ts b/src/analysis/retail/warlock/demonology/modules/pets/PETS.ts index 2ad353b0d9d..0063066fa53 100644 --- a/src/analysis/retail/warlock/demonology/modules/pets/PETS.ts +++ b/src/analysis/retail/warlock/demonology/modules/pets/PETS.ts @@ -1,4 +1,6 @@ import SPELLS from 'common/SPELLS'; +import Spell from 'common/SPELLS/Spell'; +import { Talent } from 'common/TALENTS/types'; import TALENTS from 'common/TALENTS/warlock'; const INNER_DEMON_NETHER_PORTAL_DURATION = 15000; @@ -6,7 +8,7 @@ const INNER_DEMON_NETHER_PORTAL_DURATION = 15000; type PetRecord = { guid: number; duration: number; - summonAbility: number; + summonAbility: Spell | Talent; isRandom?: boolean; }; @@ -22,92 +24,92 @@ const PETS = { WILD_IMP_HOG: { guid: 55659, duration: 15000, // maximum duration, realistically is handled differently - summonAbility: SPELLS.WILD_IMP_HOG_SUMMON.id, + summonAbility: SPELLS.WILD_IMP_HOG_SUMMON, }, DREADSTALKER: { guid: 98035, duration: 12000, - summonAbility: SPELLS.DREADSTALKER_SUMMON_1.id, + summonAbility: SPELLS.DREADSTALKER_SUMMON_1, }, VILEFIEND: { guid: 135816, duration: 15000, - summonAbility: TALENTS.SUMMON_VILEFIEND_TALENT.id, + summonAbility: TALENTS.SUMMON_VILEFIEND_TALENT, }, GRIMOIRE_FELGUARD: { guid: 17252, duration: 15000, - summonAbility: TALENTS.GRIMOIRE_FELGUARD_TALENT.id, + summonAbility: TALENTS.GRIMOIRE_FELGUARD_TALENT, }, DEMONIC_TYRANT: { guid: 135002, duration: 15000, - summonAbility: SPELLS.SUMMON_DEMONIC_TYRANT.id, + summonAbility: SPELLS.SUMMON_DEMONIC_TYRANT, }, // Inner Demons and Nether Portal demons WILD_IMP_INNER_DEMONS: { guid: 143622, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.WILD_IMP_ID_SUMMON.id, + summonAbility: SPELLS.WILD_IMP_ID_SUMMON, }, BILESCOURGE: { guid: 136404, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.BILESCOURGE_SUMMON.id, + summonAbility: SPELLS.BILESCOURGE_SUMMON, isRandom: true, }, VICIOUS_HELLHOUND: { guid: 136399, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.VICIOUS_HELLHOUND_SUMMON.id, + summonAbility: SPELLS.VICIOUS_HELLHOUND_SUMMON, isRandom: true, }, SHIVARRA: { guid: 136406, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.SHIVARRA_SUMMON.id, + summonAbility: SPELLS.SHIVARRA_SUMMON, isRandom: true, }, DARKHOUND: { guid: 136408, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.DARKHOUND_SUMMON.id, + summonAbility: SPELLS.DARKHOUND_SUMMON, isRandom: true, }, ILLIDARI_SATYR: { guid: 136398, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.ILLIDARI_SATYR_SUMMON.id, + summonAbility: SPELLS.ILLIDARI_SATYR_SUMMON, isRandom: true, }, VOID_TERROR: { guid: 136403, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.VOID_TERROR_SUMMON.id, + summonAbility: SPELLS.VOID_TERROR_SUMMON, isRandom: true, }, URZUL: { guid: 136402, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.URZUL_SUMMON.id, + summonAbility: SPELLS.URZUL_SUMMON, isRandom: true, }, WRATHGUARD: { guid: 136407, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.WRATHGUARD_SUMMON.id, + summonAbility: SPELLS.WRATHGUARD_SUMMON, isRandom: true, }, EYE_OF_GULDAN: { guid: 136401, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.EYE_OF_GULDAN_SUMMON.id, + summonAbility: SPELLS.EYE_OF_GULDAN_SUMMON, isRandom: true, }, PRINCE_MALCHEZAAR: { guid: 136397, duration: INNER_DEMON_NETHER_PORTAL_DURATION, - summonAbility: SPELLS.PRINCE_MALCHEZAAR_SUMMON.id, + summonAbility: SPELLS.PRINCE_MALCHEZAAR_SUMMON, isRandom: true, }, }; diff --git a/src/analysis/retail/warlock/demonology/modules/pets/normalizers/PrepullPetNormalizer.ts b/src/analysis/retail/warlock/demonology/modules/pets/normalizers/PrepullPetNormalizer.ts index 676ec140e09..0c9dac78f4b 100644 --- a/src/analysis/retail/warlock/demonology/modules/pets/normalizers/PrepullPetNormalizer.ts +++ b/src/analysis/retail/warlock/demonology/modules/pets/normalizers/PrepullPetNormalizer.ts @@ -94,7 +94,7 @@ class PrepullPetNormalizer extends EventsNormalizer { ); continue; } - spell = SPELLS[PETS[petGUID].summonAbility]; + spell = PETS[petGUID].summonAbility; } const fabricatedEvent: SummonEvent = { target: { diff --git a/src/common/ITEMS/dragonflight/others.ts b/src/common/ITEMS/dragonflight/others.ts index 7a8126e19e4..e6d55f41c49 100644 --- a/src/common/ITEMS/dragonflight/others.ts +++ b/src/common/ITEMS/dragonflight/others.ts @@ -71,6 +71,16 @@ const others = { name: 'Voice of the Silent Star', icon: 'inv_cloth_raidpriestdragon_d_01_cape', }, + ECHOING_TYRSTONE: { + id: 207552, + name: 'Echoing Tyrstone', + icon: 'ability_paladin_lightofthemartyr', + }, + FYRALATH: { + id: 206448, + name: "Fyr'alath the Dreamrender", + icon: 'inv_axe_2h_fyrakk_d_01_shadowflame', + }, } satisfies Record; export default others; diff --git a/src/common/SPELLS/dragonflight/others.ts b/src/common/SPELLS/dragonflight/others.ts index 8b18bb3d982..de0abcc62c6 100644 --- a/src/common/SPELLS/dragonflight/others.ts +++ b/src/common/SPELLS/dragonflight/others.ts @@ -22,6 +22,26 @@ const others = { name: 'Disintegrate', icon: 'ability_evoker_disintegrate', }, + RAGE_OF_FYRALATH_1: { + id: 417131, + name: "Rage of Fyr'alath", + icon: 'inv_axe_2h_fyrakk_d_01_shadowflame', + }, + RAGE_OF_FYRALATH_2: { + id: 417132, + name: "Rage of Fyr'alath", + icon: 'inv_axe_2h_fyrakk_d_01_shadowflame', + }, + RAGE_OF_FYRALATH_DAMAGE_1: { + id: 417134, + name: "Rage of Fyr'alath", + icon: 'inv_axe_2h_fyrakk_d_01_shadowflame', + }, + RAGE_OF_FYRALATH_DAMAGE_2: { + id: 424094, + name: "Rage of Fyr'alath", + icon: 'inv_axe_2h_fyrakk_d_01_shadowflame', + }, } satisfies Record; export default others; diff --git a/src/common/SPELLS/dragonflight/trinkets.ts b/src/common/SPELLS/dragonflight/trinkets.ts index 53ddc83f871..0633eaae868 100644 --- a/src/common/SPELLS/dragonflight/trinkets.ts +++ b/src/common/SPELLS/dragonflight/trinkets.ts @@ -71,6 +71,21 @@ const spells = { name: 'Elemental Lariat - Empowered Frost', icon: 'inv_10_elementalcombinedfoozles_frost', }, + ECHOING_TYRSTONE_HEAL: { + id: 417957, + name: 'Echoing Tyrstone', + icon: 'ability_paladin_lightofthemartyr', + }, + ECHOING_TYRSTONE_BUFF: { + id: 417939, + name: 'Echoing Tyrstone', + icon: 'ability_paladin_lightofthemartyr', + }, + ECHOING_TYRSTONE_HASTE_BUFF: { + id: 418080, + name: 'Echoing Tyrstone', + icon: 'achievement_dungeon_ulduarraid_titan_01', + }, } satisfies Record; export default spells; diff --git a/src/common/SPELLS/shadowlands/others.ts b/src/common/SPELLS/shadowlands/others.ts deleted file mode 100644 index 925c82a8763..00000000000 --- a/src/common/SPELLS/shadowlands/others.ts +++ /dev/null @@ -1,141 +0,0 @@ -import Spell from '../Spell'; - -const spells = { - ETERNAL_CAULDRON: { - id: 171281, - name: 'Eternal Cauldron', - icon: 'inv_alchemy_90_cauldron', - }, - ETERNAL_FLASK: { - id: 307166, - name: 'Eternal Flask', - icon: 'inv_potion_132', - }, - SPECTRAL_FLASK_OF_POWER: { - id: 307185, - name: 'Spectral Flask of Power', - icon: 'inv_alchemy_90_flask_green', - }, - SPECTRAL_FLASK_OF_STAMINA: { - id: 307187, - name: 'Spectral Flask of Stamina', - icon: 'inv_alchemy_90_flask_red', - }, - BUTTERSCOTCH_MARINATED_RIBS: { - id: 308430, - name: 'Butterscotch Marinated Ribs', - icon: 'inv_cooking_90_butterscotchmarinatedribs', - }, - CINNAMON_BONEFISH_STEW: { - id: 308474, - name: 'Cinnamon Bonefish Stew', - icon: 'inv_cooking_90_cinnamonbonefishstew', - }, - MEATY_APPLE_DUMPLINGS: { - id: 308504, - name: 'Meaty Apple Dumplings', - icon: 'inv_cooking_90_meatyappledumplings', - }, - SWEET_SILVERGILL_SAUSAGES: { - id: 308509, - name: 'Sweet Silvergill Sausages', - icon: 'inv_cooking_90_silvergillsausage', - }, - PICKLED_MEAT_SMOOTHIE: { - id: 308520, - name: 'Pickled Meat Smoothie', - icon: 'inv_cooking_90_pickledmeatsmoothie', - }, - SPINEFIN_SOUFFLE_AND_FRIES: { - id: 308434, - name: 'Spinefin Souffle and Fries', - icon: 'inv_cooking_90_phantasmalsoufflefries', - }, - TENEBROUS_CROWN_ROAST_ASPIC: { - id: 308488, - name: 'Tenebrous Crown Roast Aspic', - icon: 'inv_cooking_90_tenebrouscrownroastaspic', - }, - IRIDESCENT_RAVIOLI_WITH_APPLE_SAUCE: { - id: 308506, - name: 'Iridescent Ravioli with Apple Sauce', - icon: 'inv_cooking_90_crawlerravioliapplesauce', - }, - STEAK_A_LA_MODE: { - id: 308514, - name: 'Steak a la Mode', - icon: 'inv_cooking_90_steakalamode', - }, - BANANA_BEEF_PUDDING: { - id: 308525, - name: 'Banana Beef Pudding', - icon: 'inv_cooking_90_bananabeefpudding', - }, - FRIED_BONEFISH: { - id: 327860, - name: 'Fried Bonefish', - icon: 'inv_cooking_90_friedbonefish', - }, - QUIETHOUNDS: { - id: 308629, - name: 'Quiethounds', - icon: 'inv_cooking_90_quiethounds', - }, - SMOTHERED_SHANK: { - id: 327877, - name: 'Smothered Shank', - icon: 'inv_cooking_90_smotheredshank', - }, - SURPRISINGLY_PALATABLE_FEAST_INT: { - id: 327704, - name: 'Surprisingly Palatable Feast', - icon: 'inv_tradeskill_cooking_shadowlandsfeast_small01', - }, - SURPRISINGLY_PALATABLE_FEAST_AGI: { - id: 327705, - name: 'Surprisingly Palatable Feast', - icon: 'inv_tradeskill_cooking_shadowlandsfeast_small01', - }, - SURPRISINGLY_PALATABLE_FEAST_STR: { - id: 327701, - name: 'Surprisingly Palatable Feast', - icon: 'inv_tradeskill_cooking_shadowlandsfeast_small01', - }, - FEAST_OF_GLUTTONOUS_HEDONISM_INT: { - id: 327708, - name: 'Feast of Gluttonous Hedonism', - icon: 'inv_tradeskill_cooking_shadowlandsfeast_large01', - }, - FEAST_OF_GLUTTONOUS_HEDONISM_AGI: { - id: 327709, - name: 'Feast of Gluttonous Hedonism', - icon: 'inv_tradeskill_cooking_shadowlandsfeast_large01', - }, - FEAST_OF_GLUTTONOUS_HEDONISM_STR: { - id: 327706, - name: 'Feast of Gluttonous Hedonism', - icon: 'inv_tradeskill_cooking_shadowlandsfeast_large01', - }, - DRUID_BORN_ANEW: { - id: 341449, - name: 'Born Anew', - icon: 'spell_nature_reincarnation', - }, - VEILED_AUGMENT_RUNE: { - id: 347901, - name: 'Veiled Augment Rune', - icon: 'inv_misc_gem_azuredraenite_01', - }, - ADAPTIVE_ARMOR_FRAGMENT_BUFF: { - // buff procced by Adaptive Armor Fragment, a generic tanking conduit - id: 357972, - name: 'Adaptive Armor Fragment', - icon: 'inv_belt_plate_ardenweald_d_01', - }, - ETERNAL_AUGMENT_RUNE: { - id: 367405, - name: 'Eternal Augmentation', - icon: 'inv_jewelcrafting_optionalreagent_02', - }, -} satisfies Record; -export default spells; diff --git a/src/interface/BAD_ICONS.ts b/src/interface/BAD_ICONS.ts index 0f13d023729..78b17446a0a 100644 --- a/src/interface/BAD_ICONS.ts +++ b/src/interface/BAD_ICONS.ts @@ -24,5 +24,6 @@ const BAD_ICONS = [ 'spell_priest_void_flay', 'spell_priest_shadow_mend', 'spell_priest_void_blast', + 'inv_axe_2h_fyrakk_d_01_shadowflame', ]; export default BAD_ICONS; diff --git a/src/parser/core/CASTS_THAT_ARENT_CASTS.ts b/src/parser/core/CASTS_THAT_ARENT_CASTS.ts index 3c6ec6bffb9..a7c2da413d2 100644 --- a/src/parser/core/CASTS_THAT_ARENT_CASTS.ts +++ b/src/parser/core/CASTS_THAT_ARENT_CASTS.ts @@ -27,6 +27,10 @@ const spells: number[] = [ SPELLS.RIONTHUS_DISINTEGRATE.id, // targeted player is shown as 'casting' this spell //endregion + //region Items + SPELLS.RAGE_OF_FYRALATH_2.id, // second cast logged by Fyr'alath + //endregion + //region Consumables //endregion diff --git a/src/parser/core/CombatLogParser.tsx b/src/parser/core/CombatLogParser.tsx index da2b754da84..90300b12343 100644 --- a/src/parser/core/CombatLogParser.tsx +++ b/src/parser/core/CombatLogParser.tsx @@ -106,6 +106,8 @@ import UsurpedFromBeyond from 'parser/retail/modules/items/dragonflight/UsurpedF import VoiceOfTheSilentStar from 'parser/retail/modules/items/dragonflight/VoiceOfTheSilentStar'; import AmalgamsSeventhSpine from 'parser/retail/modules/items/dragonflight/AmalgamsSeventhSpine'; import ElementalLariat from 'parser/retail/modules/items/dragonflight/ElementalLariat'; +import EchoingTyrstone from 'parser/retail/modules/items/dragonflight/EchoingTyrstone'; +import Fyralath from 'parser/retail/modules/items/dragonflight/Fyralath'; // This prints to console anything that the DI has to do const debugDependencyInjection = false; @@ -225,6 +227,8 @@ class CombatLogParser { voiceOfTheSilentStar: VoiceOfTheSilentStar, amalgamsSeventhSpine: AmalgamsSeventhSpine, elementalLariat: ElementalLariat, + echoingTyrstone: EchoingTyrstone, + fyralath: Fyralath, // Enchants burningDevotion: BurningDevotion, diff --git a/src/parser/core/effectMultiplierTables.generated.jsx b/src/parser/core/effectMultiplierTables.generated.jsx new file mode 100644 index 00000000000..c5be7741913 --- /dev/null +++ b/src/parser/core/effectMultiplierTables.generated.jsx @@ -0,0 +1,401 @@ +// copied from https://github.com/simulationcraft/simc/blob/dragonflight/engine/dbc/generated/rand_prop_points.inc, column 3 +export const damageSecondary = [ + 0.0, 0.0, 0.0, 0.08483823, 0.10496229, 0.12607884, 0.14995892, 0.15589654, 0.18081029, 0.18512012, + 0.21277912, 0.21756545, 0.24557212, 0.25080174, 0.25614274, 0.29836267, 0.30143923, 0.30753383, + 0.31054947, 0.35903385, 0.36594343, 0.37298596, 0.42831287, 0.43617707, 0.44418567, 0.51129156, + 0.52026707, 0.5957585, 0.60577685, 0.61210108, 0.6984362, 0.70869154, 0.71909755, 0.81318909, + 0.82466507, 0.93178129, 0.94443876, 0.95726818, 1.07747269, 1.09216416, 1.22517443, 1.24217176, + 1.2594049, 1.35445094, 1.41621864, 1.56253922, 1.63473821, 1.71027327, 1.8925364, 1.98038065, + 2.07230234, 2.28219652, 2.38860655, 2.62712145, 2.75016546, 2.79275107, 2.97655582, 3.02325273, + 3.07068229, 3.25714612, 3.30890775, 3.36149192, 3.56217527, 3.61950874, 3.67776513, 3.89377522, + 3.95723748, 4.02173376, 4.25427055, 4.3244729, 4.39583349, 4.53699589, 4.61278534, 4.68984079, + 4.83940887, 4.9212327, 5.00444031, 5.16300535, 5.25134897, 5.34120369, 5.50940371, 5.60479259, + 5.70183229, 5.8803544, 5.98335838, 6.08816671, 6.27775145, 6.36052132, 6.47322655, 6.67377472, + 6.76277685, 6.88398027, 6.97682762, 7.19194508, 7.32229805, 7.42216444, 7.64998913, 7.75432491, + 7.89644146, 8.1378088, 8.25002861, 8.4029007, 8.52004623, 8.77945709, 8.94391727, 9.06995678, + 9.34510517, 9.47679806, 9.65623951, 9.94818115, 10.08987617, 10.28296661, 10.43098164, + 10.74535847, 10.90002918, 11.05857182, 11.39089584, 11.55657864, 11.78241062, 11.95556355, + 12.31388569, 12.49485016, 12.68035889, 13.05947018, 13.2533617, 13.45013237, 13.65185165, + 14.05909348, 14.26994514, 14.48610973, 14.70554924, 15.14332962, 15.37272453, 15.6079092, + 16.07169724, 16.31757545, 16.56721687, 16.82316971, 17.42473984, 17.69394302, 17.87660217, + 18.15547562, 18.80024338, 19.09352493, 19.39425659, 19.6997242, 20.39480972, 20.71603584, + 21.04543686, 21.78347397, 22.12984848, 22.48172951, 22.84258652, 23.63903618, 24.01846886, + 24.27599907, 24.66930389, 25.52478027, 25.93831635, 26.21901512, 26.6477375, 27.56710434, + 28.01786995, 28.32386398, 28.79125595, 29.77980614, 30.27122498, 30.60484123, 32.18738174, + 32.751091, 33.35290909, 33.80961227, 34.30161285, 35.55413055, 36.28045273, 37.01726151, + 37.76468277, 38.52285385, 39.29190826, 40.07198715, 40.86322784, 41.66577148, 42.47975922, + 43.30533218, 44.14264297, 44.99183273, 45.85305405, 46.72645569, 47.61219025, 48.51041412, + 49.42128372, 50.34495544, 51.28158951, 52.23134613, 53.19438934, 54.17089081, 55.16100693, + 56.16491699, 57.18278885, 58.21479416, 59.2611084, 60.32191086, 61.39738464, 62.48770142, + 63.59305573, 64.71363068, 65.84960938, 67.00118256, 68.16854858, 69.35189819, 70.55142975, + 71.76733398, 72.99983215, 74.24910736, 75.51538086, 76.79885101, 78.09973145, 79.41824341, + 80.7545929, 82.10900116, 83.48169708, 84.87288666, 86.28281403, 87.71170044, 89.15977478, + 90.62728119, 92.11444092, 93.62150574, 95.14871216, 96.69631195, 98.26454163, 99.85366058, + 101.46392059, 103.09558105, 104.74889374, 106.4241333, 108.12153625, 109.84142303, 111.58400726, + 113.34960938, 115.13848114, 116.95091248, 118.7871933, 120.64759064, 122.5324173, 124.4419632, + 126.37651825, 128.33639526, 130.32188416, 132.33329773, 134.37094116, 136.43515015, 138.52622986, + 140.64450073, 142.7902832, 144.96392822, 147.16575623, 149.39608765, 151.6552887, 153.94369507, + 156.26165771, 158.60952759, 160.98765564, 163.39642334, 165.83616638, 168.30726624, 170.81010437, + 173.34506226, 175.91249084, 178.51281738, 181.14639282, 183.81364441, 186.51495361, 189.25073242, + 192.02137756, 194.82733154, 197.66897583, 200.54675293, 203.46107483, 206.41239929, 209.40115356, + 212.42776489, 215.49269104, 218.59638977, 221.73930359, 224.92192078, 228.14468384, 231.4080658, + 234.71255493, 238.05863953, 241.4467926, 244.87753296, 248.35133362, 251.86871338, 255.43019104, + 259.0362854, 262.6875, 266.3843689, 270.12741089, 273.91720581, 277.75430298, 281.63922119, + 285.57250977, 289.55477905, 293.58657837, 297.66848755, 301.80111694, 305.98501587, 310.22076416, + 314.5090332, 318.85040283, 319.14764404, 319.44512939, 319.74291992, 320.04098511, 320.33932495, + 320.63793945, 320.93682861, 321.23599243, 321.53543091, 321.83517456, 322.13519287, 322.43545532, + 322.73602295, 323.03689575, 323.3380127, 323.63943481, 323.94110107, 324.24307251, 324.54534912, + 324.84786987, 325.1506958, 325.45379639, 325.75717163, 326.06082153, 326.36477661, 326.66900635, + 326.97354126, 327.27832031, 327.58340454, 327.88876343, 328.19442749, 329.11309814, 330.03433228, + 330.95812988, 331.884552, 332.8135376, 333.74514771, 334.67935181, 335.6161499, 336.55560303, + 337.49765015, 338.44238281, 339.38970947, 340.33972168, 341.29238892, 342.24771118, 343.20571899, + 344.16641235, 345.12976074, 346.09585571, 347.06460571, 348.03610229, 349.01031494, 349.98724365, + 350.96691895, 351.9493103, 352.93447876, 353.9223938, 354.91308594, 355.90652466, 356.902771, + 357.90179443, 358.90359497, 359.90823364, 360.91567993, 361.92593384, 362.93899536, 363.95492554, + 364.97369385, 365.99530029, 367.01977539, 368.04711914, 369.07733154, 370.11044312, 371.14645386, + 376.92825317, 383.10852051, 389.37149048, 395.71810913, 402.14944458, 408.66653442, 415.27035522, + 421.96203613, 428.74261475, 435.61312866, 442.57473755, 449.628479, 456.7755127, 464.01696777, + 471.35394287, 478.78762817, 486.31918335, 493.94979858, 501.68066406, 509.51296997, 517.44793701, + 525.48681641, 533.63092041, 541.88140869, 550.23956299, 558.70672607, 567.28424072, 575.97338867, + 584.77545166, 593.6918335, 602.72393799, 611.87310791, 621.14074707, 630.52832031, 640.03717041, + 649.66882324, 659.42468262, 669.30627441, 679.31506348, 689.45263672, 699.72045898, 710.12005615, + 720.65313721, 731.32110596, 742.12567139, 753.06842041, 764.15106201, 775.37518311, 786.74243164, + 798.25457764, 809.91333008, 821.72039795, 833.67755127, 845.78656006, 858.04925537, 870.46734619, + 883.04278564, 895.77740479, 908.67303467, 921.73156738, 934.95501709, 948.34521484, 961.9041748, + 975.63391113, 989.53643799, 1003.6137085, 1017.86779785, 1032.30090332, 1046.91491699, + 1061.7121582, 1076.69458008, 1091.86462402, 1107.22424316, 1122.77575684, 1138.5213623, + 1154.46350098, 1170.60424805, 1186.94604492, 1203.49108887, 1220.24206543, 1237.2010498, + 1254.37072754, 1271.75341797, 1289.3515625, 1307.16772461, 1325.20458984, 1343.46447754, + 1361.95019531, 1380.66418457, 1399.60925293, 1418.78796387, 1438.203125, 1457.85754395, + 1477.75378418, 1497.89477539, 1518.28344727, 1538.92248535, 1559.81494141, 1580.96362305, + 1602.37158203, 1624.04187012, 1645.97741699, 1668.18127441, 1690.65673828, 1713.40673828, + 1736.43444824, 1759.74316406, 1783.33618164, 1807.2166748, 1831.38793945, 1855.85339355, + 1880.61645508, 1905.68041992, 1931.0489502, 1956.7253418, 1982.71325684, 2009.01623535, + 2035.63793945, 2062.58203125, 2089.85205078, 2117.45214844, 2145.38574219, 2173.65673828, + 2202.26879883, 2231.22631836, 2260.53295898, 2290.19287109, 2320.2097168, 2350.58813477, + 2381.33178711, 2412.44506836, 2443.93212891, 2475.79760742, 2508.04516602, 2540.6796875, + 2573.70532227, 2607.12670898, 2640.94824219, 2675.17456055, 2709.81005859, 2744.85986328, + 2780.328125, 2816.22021484, 2852.5402832, 2889.29394531, 2926.48535156, 2964.12011719, + 3002.203125, 3040.73925781, 3079.73364258, 3119.19189453, 3159.11865234, 3199.52001953, + 3240.40063477, 3281.76635742, 3323.62255859, 3365.97485352, 3408.82885742, 3452.19018555, + 3496.06445312, 3540.45776367, 3585.37597656, 3630.82470703, 3676.81030273, 3723.33862305, + 3770.41577148, 3818.0480957, 3866.24194336, 3915.00317383, 3964.33886719, 4014.25488281, + 4064.75830078, 4115.85498047, 4167.55273438, 4219.85742188, 4272.77636719, 4326.31591797, + 4380.48339844, 4435.28613281, 4490.73095703, 4546.82519531, 4603.57617188, 4660.99121094, + 4719.07763672, 1436.6784668, 1450.12719727, 1463.70178223, 1477.40356445, 1491.23352051, + 1505.19299316, 1519.28308105, 1533.50512695, 1547.86022949, 1562.34985352, 1576.97497559, + 1591.73706055, 1606.6373291, 1621.67700195, 1636.85754395, 1652.18017578, 1667.64624023, + 1683.25708008, 1699.01403809, 1714.9185791, 1730.97192383, 1747.17553711, 1763.53088379, + 1780.03930664, 1796.70227051, 1813.52124023, 1830.49755859, 1847.63293457, 1864.92858887, + 1882.38623047, 1900.00720215, 1917.79321289, 1935.74572754, 1953.86621094, 1972.15637207, + 1990.61767578, 2009.25195312, 2028.06054688, 2047.04516602, 2066.20751953, 2085.54931641, + 2105.07226562, 2124.77783203, 2144.66796875, 2164.74414062, 2185.00830078, 2205.4621582, + 2226.10742188, 2246.94604492, 2267.97973633, 2289.21044922, 2310.63964844, 2332.26953125, + 2354.10205078, 2376.13867188, 2398.38183594, 2420.83300781, 2443.49438477, 2466.36816406, + 2489.45581055, 2512.75952148, 2536.28149414, 2560.02368164, 2583.98803711, 2608.17675781, + 2632.59204102, 2657.2355957, 2682.11010742, 2707.21728516, 2732.55957031, 2758.13916016, + 2783.95800781, 2810.01855469, 2836.32324219, 2862.87402344, 2889.67358398, 2916.72363281, + 2944.02709961, 2971.58618164, 2999.40332031, 3027.48071289, 3055.82104492, 3084.42651367, + 3113.29980469, 3142.44360352, 3171.85986328, 3201.55175781, 3231.52148438, 3261.77172852, + 3292.30517578, 3323.12451172, 3354.23242188, 3385.63134766, 3417.32421875, 3449.3137207, + 3481.6027832, 3514.1940918, 3547.09057617, 3580.29492188, 3613.81005859, 3647.63891602, + 3681.78442383, 3716.24975586, 3751.03759766, 3786.15112305, 3821.59326172, 3857.3671875, + 3893.47607422, 3929.92285156, 3966.7109375, 4003.84326172, 4041.32324219, 4079.15405273, + 4117.33886719, 4155.88134766, 4194.78466797, 4234.05224609, 4273.68701172, 4313.69335938, + 4354.07373047, 4394.83203125, 4435.97216797, 4477.49755859, 4519.41113281, 4561.71728516, + 4604.41992188, 4647.52197266, 4691.02734375, 4734.93994141, 4779.26367188, 4824.00244141, + 4869.16015625, 4914.74023438, 4960.74707031, 5007.18457031, 5054.05712891, 5101.36816406, + 5149.12207031, 5197.32275391, 5245.97509766, 5295.08251953, 5344.64990234, 5394.68115234, + 5445.18115234, 5496.15332031, 5547.60302734, 5599.53417969, 5651.95117188, 5704.859375, + 5758.26220703, 5812.16552734, 5866.57324219, 5921.49023438, 5976.92138672, 6032.87158203, + 6089.34521484, 6146.34765625, 6203.88330078, 6261.95800781, 6320.57617188, 6379.74316406, + 6439.46386719, 6499.74414062, 6560.58789062, 6622.00195312, 6683.99023438, 6746.55908203, + 6809.71386719, 6873.45947266, 6937.80224609, 7002.74707031, 7068.29980469, 7134.46582031, + 7201.25195312, 7268.66259766, 7336.70458984, 7405.38378906, 7474.70556641, 7544.67626953, + 7615.30224609, 7686.58886719, 7758.54296875, 7831.17089844, 7904.47851562, 7978.47216797, + 8053.15869141, 8128.54443359, 8204.63574219, 8281.43945312, 8358.96191406, 8437.2109375, + 8516.19140625, 8595.91113281, 8676.37792969, 8757.59765625, 8839.57714844, 8922.32421875, + 9005.84667969, 9090.15039062, 9175.24316406, 9261.1328125, 9347.82617188, 9435.33105469, + 9523.65527344, 9612.80664062, 9702.79199219, 9793.62011719, 9885.29785156, 9977.83398438, + 10071.23730469, 10165.51367188, 10260.67285156, 10356.72363281, 10453.67285156, 10551.52929688, + 10650.30273438, 10750.0, 10850.63085938, 10952.20410156, 11054.72753906, 11158.2109375, + 11262.66308594, 11368.09277344, 11474.50976562, 11581.92285156, 11690.34082031, 11799.77441406, + 11910.23242188, 12021.72363281, 12134.25878906, 12247.84765625, 12362.5, 12478.22558594, + 12595.03417969, 12712.93652344, 12831.94238281, 12952.06347656, 13073.30664062, 13195.68554688, + 13319.2109375, 13443.89257812, 13569.74023438, 13696.76660156, 13824.98242188, 13954.3984375, + 14085.02539062, 14216.875, 14349.95996094, 14484.29003906, 14619.87695312, 14756.73339844, + 14894.87207031, 15034.30273438, 15175.0390625, 15317.09277344, 15460.47558594, 15605.20117188, + 15751.28222656, 15898.72851562, 16047.55761719, 16197.77929688, 16349.40625, 16502.453125, + 16656.93359375, 16812.859375, 16970.24414062, 17129.1015625, 17289.44726562, 17451.29492188, + 17614.65625, 17779.546875, 17945.98242188, 18113.97460938, 18283.5390625, 18454.69140625, + 18627.4453125, 18801.81835938, 18977.82226562, 19155.47265625, 19334.78710938, 19515.78125, + 19698.46875, 19882.86523438, 20068.98828125, 20256.85546875, 20446.47851562, 20637.87890625, + 20831.0703125, 21026.0703125, 21222.89453125, 21421.5625, 21622.08984375, 21824.49414062, + 22028.79492188, 22235.00585938, 22443.1484375, 22653.23828125, 22865.29492188, 23079.33789062, + 23295.3828125, 23513.45117188, 23733.56054688, 23955.73046875, 24179.98046875, 24406.33007812, + 24634.796875, 24865.40429688, 25098.16796875, 25333.11328125, 25570.25585938, 25809.61914062, + 26051.22460938, 26295.08984375, 26541.23828125, 26789.69140625, 27040.46875, 27293.59570312, + 27549.08984375, 27806.97851562, 28067.27929688, 28330.01757812, 28595.21484375, 28862.89453125, + 29133.08007812, 29405.79492188, 29681.0625, 29958.90820312, 30239.35351562, 30522.42382812, + 30808.14453125, 31096.5390625, 31387.63476562, 31681.453125, 31978.0234375, 32277.37109375, + 32579.51953125, 32884.49609375, 33192.328125, 33503.04296875, 33816.6640625, 34133.22265625, + 34452.7421875, 34775.25390625, 35100.78515625, 35429.3671875, 35761.01953125, 36095.78125, + 36433.671875, 36774.7265625, 37118.9765625, 37466.44921875, 37817.171875, 38171.17578125, 38528.5, + 38889.1640625, 39253.20703125, 39620.65625, 39991.54296875, 40365.90625, 40743.76953125, + 41125.171875, 41510.14453125, 41898.72265625, 42290.9375, 42686.82421875, 43086.4140625, + 43489.74609375, 43896.85546875, 44307.7734375, 44722.5390625, 45141.1875, 45563.75390625, + 45990.27734375, 46420.7890625, 46855.3359375, 47293.94921875, 47736.66796875, 48183.53125, + 48634.578125, 49089.84765625, 49549.375, 50013.20703125, 50481.3828125, 50953.9375, + 51430.91796875, 51912.36328125, 52398.31640625, 52888.81640625, 53383.91015625, 53883.63671875, + 54388.04296875, 54897.16796875, 55411.0625, 55929.765625, 56453.32421875, 56981.78125, + 57515.19140625, 58053.58984375, 58597.03125, 59145.55859375, 59699.21875, 60258.0625, + 60822.140625, 61391.49609375, 61966.18359375, 62546.24609375, 63131.7421875, 63722.71875, + 64319.23046875, 64921.3203125, 65529.05078125, 66142.46875, 66761.625, 67386.5859375, + 68017.390625, 68654.1015625, 69296.7734375, 69945.4609375, 70600.21875, 71261.109375, 71928.1875, + 72601.5078125, 73281.125, 73967.1171875, 74659.5234375, 75358.40625, 76063.8359375, 76775.875, + 77494.5703125, 78220.0, 78952.21875, 79691.2890625, 80437.28125, 81190.25, 81950.2734375, + 82717.4140625, 83491.734375, 84273.296875, 85062.1796875, 85858.4453125, 86662.171875, + 87473.4140625, 88292.25, 89118.7578125, 89953.0, 90795.046875, 91644.984375, 92502.875, + 93368.7890625, 94242.8203125, 95125.0234375, 96015.4921875, 96914.2890625, 97821.5078125, + 98737.21875, 99661.4921875, 100594.4296875, 101536.09375, 102486.5703125, 103445.953125, + 104414.296875, 105391.7265625, 106378.296875, 107374.109375, 108379.2421875, 109393.78125, + 110417.8125, 111451.4375, 112494.7265625, 113547.796875, 114610.71875, 115683.59375, + 116766.5078125, 117859.546875, 118962.84375, 120076.453125, 121200.4921875, 122335.046875, + 123480.2265625, 124636.1328125, 125802.84375, 126980.4765625, 128169.1484375, 129368.953125, + 130579.96875, 131802.328125, 133036.125, 134281.484375, 135538.484375, 136807.265625, + 138087.921875, 139380.5625, 140685.3125, 142002.265625, 143331.546875, 144673.265625, 146027.5625, + 147394.53125, 148774.28125, 150166.96875, 151572.671875, 152991.546875, 154423.703125, + 155869.265625, 157328.359375, 158801.109375, 160287.640625, 161788.09375, 163302.59375, + 164831.28125, 166374.265625, 167931.6875, 169503.703125, 171090.421875, 172692.0, 174308.578125, + 175940.28125, 177587.265625, 179249.65625, 180927.609375, 182621.28125, 184330.796875, + 186056.3125, 187797.984375, 189555.96875, 191330.40625, 193121.453125, 194929.265625, + 196753.984375, 198595.8125, 200454.859375, 202331.328125, 204225.34375, 206137.109375, 208066.75, + 210014.46875, 211980.40625, 213964.765625, 215967.6875, 217989.359375, 220029.96875, + 222089.671875, 224168.640625, 226267.09375, 228385.171875, 230523.09375, 232681.015625, + 234859.15625, 237057.671875, 239276.765625, 241516.640625, 243777.46875, 246059.484375, + 248362.84375, 250687.765625, 253034.453125, 255403.109375, 257793.9375, 260207.15625, + 262642.96875, 265101.5625, 267583.1875, 270088.03125, 272616.3125, 275168.28125, 277744.125, + 280344.09375, 282968.40625, 285617.28125, 288290.9375, 290989.625, 293713.59375, 296463.03125, + 299238.21875, 302039.40625, 304866.78125, 307720.65625, 310601.21875, 313508.75, 316443.53125, + 319405.75, 322395.71875, 325413.65625, 328459.84375, 331534.5625, 334638.0625, 337770.625, + 340932.5, 344123.96875, 347345.3125, 350596.8125, 353878.75, 357191.40625, 360535.09375, + 363910.0625, 367316.625, 370755.0625, 374225.71875, 377728.84375, 381264.75, 384833.78125, + 388436.21875, 392072.375, 395742.5625, 399447.09375, 403186.34375, 406960.5625, 410770.125, + 414615.34375, 418496.5625, 422414.09375, 426368.3125, 430359.5625, 434388.15625, 438454.46875, + 442558.84375, 446701.65625, 450883.21875, 455103.9375, 459364.15625, 463664.28125, 468004.65625, + 472385.625, 476807.65625, 481271.03125, 485776.21875, 490323.5625, 494913.5, 499546.375, + 504222.65625, 508942.6875, 513706.875, 518515.6875, 523369.53125, 528268.8125, 533213.9375, + 538205.3125, 543243.5, 548328.8125, 553461.6875, 558642.6875, 563872.125, 569150.5, 574478.375, + 579856.0625, 585284.0625, 590762.9375, 596293.0625, 601874.9375, 607509.125, 613196.0, 618936.125, + 624730.0, 630578.125, 636480.9375, 642439.0625, 648452.9375, 654523.125, 660650.125, 666834.4375, + 673076.6875, 679377.375, 685737.0, 692156.1875, 698635.5, 705175.4375, 711776.5625, 718439.5, + 725164.8125, 731953.125, 738804.9375, 745720.875, 752701.5625, 759747.625, 766859.625, + 774038.1875, 781283.9375, 788597.5625, 795979.625, 803430.8125, 810951.75, 818543.0625, + 826205.4375, 833939.5625, 841746.0625, 849625.625, 857579.0, 865606.8125, 873709.75, 881888.5625, + 890143.9375, 898476.5625, 906887.1875, 915376.5625, 923945.4375, 932594.5, 941324.5, 950136.25, + 959030.5, 968008.0, 977069.5, 986215.875, 995447.8125, 1004766.1875, 1014171.8125, 1023665.5, + 1033248.125, 1042920.3125, 1052683.125, 1062537.25, 1072483.625, 1082523.125, 1092656.625, + 1102885.0, 1113209.125, 1123629.875, 1134148.25, 1144765.0, 1155481.125, 1166297.625, 1177215.375, + 1188235.25, 1199358.375, 1210585.5, 1221917.875, 1233356.25, 1244901.625, 1256555.25, 1268317.75, + 1280190.5, +]; + +// copied from https://github.com/simulationcraft/simc/blob/dragonflight/engine/dbc/generated/rand_prop_points.inc, column 2 +export const damageReplaceStat = [ + 0.0, 0.0, 0.0, 0.08483823, 0.10496229, 0.12607884, 0.14995892, 0.15589654, 0.18081029, 0.18512012, + 0.21277912, 0.21756545, 0.24557212, 0.25080174, 0.25614274, 0.29836267, 0.30143923, 0.30753383, + 0.31054947, 0.35903385, 0.36594343, 0.37298596, 0.42831287, 0.43617707, 0.44418567, 0.51129156, + 0.52026707, 0.5957585, 0.60577685, 0.61210108, 0.6984362, 0.70869154, 0.71909755, 0.81318909, + 0.82466507, 0.93178129, 0.94443876, 0.95726818, 1.07747269, 1.09216416, 1.22517443, 1.24217176, + 1.2594049, 1.35445094, 1.41621864, 1.56253922, 1.63473821, 1.71027327, 1.8925364, 1.98038065, + 2.07230234, 2.28219652, 2.38860655, 2.62712145, 2.75016546, 2.79275107, 2.97655582, 3.02325273, + 3.07068229, 3.25714612, 3.30890775, 3.36149192, 3.56217527, 3.61950874, 3.67776513, 3.89377522, + 3.95723748, 4.02173376, 4.25427055, 4.3244729, 4.39583349, 4.53699589, 4.61278534, 4.68984079, + 4.83940887, 4.9212327, 5.00444031, 5.16300535, 5.25134897, 5.34120369, 5.50940371, 5.60479259, + 5.70183229, 5.8803544, 5.98335838, 6.08816671, 6.27775145, 6.36052132, 6.47322655, 6.67377472, + 6.76277685, 6.88398027, 6.97682762, 7.19194508, 7.32229805, 7.42216444, 7.64998913, 7.75432491, + 7.89644146, 8.1378088, 8.25002861, 8.4029007, 8.52004623, 8.77945709, 8.94391727, 9.06995678, + 9.34510517, 9.47679806, 9.65623951, 9.94818115, 10.08987617, 10.28296661, 10.43098164, + 10.74535847, 10.90002918, 11.05857182, 11.39089584, 11.55657864, 11.78241062, 11.95556355, + 12.31388569, 12.49485016, 12.68035889, 13.05947018, 13.2533617, 13.45013237, 13.65185165, + 14.05909348, 14.26994514, 14.48610973, 14.70554924, 15.14332962, 15.37272453, 15.6079092, + 16.07169724, 16.31757545, 16.56721687, 16.82316971, 17.42473984, 17.69394302, 17.87660217, + 18.15547562, 18.80024338, 19.09352493, 19.39425659, 19.6997242, 20.39480972, 20.71603584, + 21.04543686, 21.78347397, 22.12984848, 22.48172951, 22.84258652, 23.63903618, 24.01846886, + 24.27599907, 24.66930389, 25.52478027, 25.93831635, 26.21901512, 26.6477375, 27.56710434, + 28.01786995, 28.32386398, 28.79125595, 29.77980614, 30.27122498, 30.60484123, 32.18738174, + 32.751091, 33.35290909, 33.80961227, 34.30161285, 35.55413055, 35.92337418, 36.29641724, + 36.67329407, 37.05405045, 37.43871689, 37.82733917, 38.21995926, 38.61661148, 39.01734161, + 39.42219162, 39.83120346, 40.24441528, 40.66187668, 41.08362198, 41.50970459, 41.94016266, + 42.37504196, 42.81438828, 43.25824738, 43.70666122, 44.15968323, 44.61735535, 45.07972717, + 45.5468483, 46.01876068, 46.49551773, 46.97716904, 47.46376038, 47.95534897, 48.45198059, + 48.95370865, 49.46058273, 49.97266006, 50.48998642, 51.01262283, 51.54061508, 52.0740242, + 52.61290359, 53.15731049, 53.70729828, 54.26292419, 54.82424545, 55.39132309, 55.96421432, + 56.54297256, 57.12766647, 57.71834946, 58.31508636, 58.91793823, 59.52696609, 60.1422348, + 60.76380539, 61.39174271, 62.0261116, 62.66697693, 63.31440353, 63.9684639, 64.62921906, + 65.29673767, 65.97109222, 66.65235138, 67.3405838, 68.03585815, 68.73825073, 69.4478302, + 70.16467285, 70.88885498, 71.62043762, 72.35951233, 73.10614014, 73.8604126, 74.62239838, + 75.39217377, 76.16983032, 76.95543671, 77.74906921, 78.55082703, 79.36077881, 80.17900848, + 81.00559998, 81.84064484, 82.68422699, 83.53643036, 84.39733887, 85.2670517, 86.14565277, + 87.03322601, 87.92986298, 88.83567047, 89.75072479, 90.67513275, 91.60897827, 92.55236053, + 93.50537872, 94.46812439, 95.44070435, 96.42321777, 97.41575623, 98.41843414, 99.43134308, + 100.45459747, 101.48828888, 102.53253937, 103.58744049, 104.65310669, 105.7296524, 106.81717682, + 107.91578674, 109.02562714, 110.14678192, 111.27937317, 112.42350769, 113.57932281, 114.74691772, + 115.92642212, 117.11795044, 118.32163239, 119.53759003, 120.76593781, 122.00681305, 123.26033783, + 124.52662659, 125.80583954, 127.0980835, 128.40350342, 129.72221375, 131.05436707, 132.40008545, + 133.75952148, 135.1328125, 136.52008057, 137.92149353, 139.33717346, 140.76727295, 142.21192932, + 143.67131042, 145.14555359, 145.89028931, 146.63883972, 147.39123535, 148.14749146, 148.90763855, + 149.67167664, 150.43963623, 151.21153259, 151.98739624, 152.76722717, 153.55107117, 154.33894348, + 155.13084412, 155.92681885, 156.72686768, 157.53103638, 158.33932495, 159.15174866, 159.96835327, + 160.78913879, 161.614151, 162.44337463, 163.27687073, 164.11463928, 164.95671082, 165.80308533, + 166.65382385, 167.50891113, 168.36839294, 169.23228455, 170.10061646, 171.85430908, 173.62594604, + 175.41567993, 177.22370911, 179.05021667, 180.895401, 182.75942993, 184.64250183, 186.54483032, + 188.46658325, 190.40795898, 192.3691864, 194.35043335, 196.35191345, 198.37384033, 200.41642761, + 202.4798584, 204.56436157, 206.67015076, 208.79742432, 210.94642639, 213.11737061, 215.31047058, + 217.5259552, 219.76405334, 222.02497864, 224.30899048, 226.61630249, 228.94714355, 231.30178833, + 233.68043518, 236.08335876, 238.51078796, 240.96296692, 243.44017029, 245.94262695, 248.47061157, + 251.02436829, 253.60415649, 256.21026611, 258.84292603, 261.50244141, 264.18902588, 266.90304565, + 269.64468384, 272.41427612, 275.21209717, 278.03845215, 280.89358521, 283.77780151, 286.69140625, + 289.63467407, 292.60794067, 295.61151123, 298.64562988, 301.71069336, 304.8069458, 307.9347229, + 311.09436035, 314.28619385, 317.51049805, 320.76760864, 324.05789185, 327.38168335, 330.73928833, + 334.131073, 337.55737305, 341.01855469, 344.51495361, 348.04690552, 351.61480713, 355.21902466, + 358.8598938, 362.53778076, 366.25311279, 370.00622559, 373.79751587, 377.62734985, 381.49612427, + 385.40423584, 389.35211182, 393.34011841, 397.36865234, 401.43817139, 405.54904175, 409.70169067, + 413.89654541, 418.13406372, 422.41461182, 426.73867798, 431.10668945, 435.51907349, 439.97628784, + 444.4788208, 449.02703857, 453.62149048, 458.26263428, 462.95089722, 467.68676758, 472.47073364, + 477.30328369, 482.18493652, 487.11611938, 492.09738159, 497.12924194, 502.2121582, 507.34667969, + 512.5333252, 517.77264404, 523.06512451, 528.41131592, 533.81170654, 539.26696777, 544.77758789, + 550.34411621, 555.96710205, 561.64715576, 567.38482666, 573.18066406, 579.03533936, 584.94940186, + 590.92340088, 596.95800781, 603.05383301, 609.21148682, 615.43151855, 621.71466064, 628.06152344, + 634.47271729, 640.94885254, 647.49072266, 654.09881592, 660.77398682, 667.51672363, 674.32781982, + 681.20800781, 688.15783691, 695.17810059, 702.26953125, 709.43273926, 716.6685791, 723.97772217, + 731.36090088, 738.81884766, 746.35235596, 753.9621582, 761.64898682, 769.41369629, 777.25708008, + 785.17980957, 793.18280029, 801.26678467, 809.43267822, 817.68115234, 826.01318359, 834.42956543, + 842.93109131, 851.51867676, 860.1932373, 868.95550537, 877.80645752, 886.74700928, 895.77801514, + 904.90032959, 914.11499023, 923.4229126, 932.82495117, 942.32208252, 951.9152832, 961.60552979, + 971.39379883, 981.28100586, 991.26824951, 1001.35638428, 1011.54669189, 1021.84002686, + 1032.23730469, 1042.73974609, 1053.34838867, 1064.06420898, 1074.88842773, 1085.82202148, + 1096.86608887, 1108.02185059, 1119.2902832, 1130.67260742, 1142.16992188, 1153.78344727, + 1165.51428223, 1177.36376953, 1189.33276367, 1201.42285156, 1213.63500977, 1225.97045898, + 1238.43054199, 1251.01647949, 1263.72961426, 1276.57104492, 1289.54211426, 1302.64428711, + 1315.87866211, 1329.2467041, 1342.74975586, 1356.38903809, 1370.16601562, 1384.08215332, + 1398.13867188, 1412.3371582, 1426.67895508, 1441.16540527, 1455.7980957, 1470.57849121, + 1485.50805664, 1500.58813477, 1515.82043457, 1531.2064209, 1546.74768066, 1562.44567871, + 1578.30212402, 1594.31848145, 1610.49633789, 1626.83740234, 1643.34326172, 1660.01550293, + 1676.8560791, 1693.86633301, 1711.0480957, 1728.40319824, 1736.47412109, 1744.58276367, + 1752.72924805, 1760.91381836, 1769.13659668, 1777.39770508, 1785.69750977, 1794.03601074, + 1802.41345215, 1810.82995605, 1819.28588867, 1827.78112793, 1836.31616211, 1844.89099121, + 1853.50598145, 1862.16101074, 1870.85656738, 1879.59277344, 1888.36975098, 1897.18762207, + 1906.04675293, 1914.94726562, 1923.88928223, 1932.87304688, 1941.89880371, 1950.9666748, + 1960.0769043, 1969.22973633, 1978.4251709, 1987.66369629, 1996.9453125, 2006.27026367, + 2015.63867188, 2025.05090332, 2034.50708008, 2044.00744629, 2053.55224609, 2063.14135742, + 2072.77539062, 2082.45458984, 2092.17871094, 2105.07226562, 2124.77783203, 2144.66796875, + 2164.74414062, 2185.00830078, 2205.4621582, 2226.10742188, 2246.94604492, 2267.97973633, + 2289.21044922, 2310.63964844, 2332.26953125, 2354.10205078, 2376.13867188, 2398.38183594, + 2420.83300781, 2443.49438477, 2466.36816406, 2489.45581055, 2512.75952148, 2536.28149414, + 2560.02368164, 2583.98803711, 2608.17675781, 2632.59204102, 2657.2355957, 2682.11010742, + 2707.21728516, 2732.55957031, 2758.13916016, 2783.95800781, 2810.01855469, 2836.32324219, + 2862.87402344, 2889.67358398, 2916.72363281, 2944.02709961, 2971.58618164, 2999.40332031, + 3027.48071289, 3055.82104492, 3084.42651367, 3113.29980469, 3142.44360352, 3171.85986328, + 3201.55175781, 3231.52148438, 3261.77172852, 3292.30517578, 3323.12451172, 3354.23242188, + 3385.63134766, 3417.32421875, 3449.3137207, 3481.6027832, 3514.1940918, 3547.09057617, + 3580.29492188, 3613.81005859, 3647.63891602, 3681.78442383, 3716.24975586, 3751.03759766, + 3786.15112305, 3821.59326172, 3857.3671875, 3893.47607422, 3929.92285156, 3966.7109375, + 4003.84326172, 4041.32324219, 4079.15405273, 4117.33886719, 4155.88134766, 4194.78466797, + 4234.05224609, 4273.68701172, 4313.69335938, 4354.07373047, 4394.83203125, 4435.97216797, + 4477.49755859, 4519.41113281, 4561.71728516, 4604.41992188, 4647.52197266, 4691.02734375, + 4734.93994141, 4779.26367188, 4824.00244141, 4869.16015625, 4914.74023438, 4960.74707031, + 5007.18457031, 5054.05712891, 5101.36816406, 5149.12207031, 5197.32275391, 5245.97509766, + 5295.08251953, 5344.64990234, 5394.68115234, 5445.18115234, 5496.15332031, 5547.60302734, + 5599.53417969, 5651.95117188, 5704.859375, 5758.26220703, 5812.16552734, 5866.57324219, + 5921.49023438, 5976.92138672, 6032.87158203, 6089.34521484, 6146.34765625, 6203.88330078, + 6261.95800781, 6320.57617188, 6379.74316406, 6439.46386719, 6499.74414062, 6560.58789062, + 6622.00195312, 6683.99023438, 6746.55908203, 6809.71386719, 6873.45947266, 6937.80224609, + 7002.74707031, 7068.29980469, 7134.46582031, 7201.25195312, 7268.66259766, 7336.70458984, + 7405.38378906, 7474.70556641, 7544.67626953, 7615.30224609, 7686.58886719, 7758.54296875, + 7831.17089844, 7904.47851562, 7978.47216797, 8053.15869141, 8128.54443359, 8204.63574219, + 8281.43945312, 8358.96191406, 8437.2109375, 8516.19140625, 8595.91113281, 8676.37792969, + 8757.59765625, 8839.57714844, 8922.32421875, 9005.84667969, 9090.15039062, 9175.24316406, + 9261.1328125, 9347.82617188, 9435.33105469, 9523.65527344, 9612.80664062, 9702.79199219, + 9793.62011719, 9885.29785156, 9977.83398438, 10071.23730469, 10165.51367188, 10260.67285156, + 10356.72363281, 10453.67285156, 10551.52929688, 10650.30273438, 10750.0, 10850.63085938, + 10952.20410156, 11054.72753906, 11158.2109375, 11262.66308594, 11368.09277344, 11474.50976562, + 11581.92285156, 11690.34082031, 11799.77441406, 11910.23242188, 12021.72363281, 12134.25878906, + 12247.84765625, 12362.5, 12478.22558594, 12595.03417969, 12712.93652344, 12831.94238281, + 12952.06347656, 13073.30664062, 13195.68554688, 13319.2109375, 13443.89257812, 13569.74023438, + 13696.76660156, 13824.98242188, 13954.3984375, 14085.02539062, 14216.875, 14349.95996094, + 14484.29003906, 14619.87695312, 14756.73339844, 14894.87207031, 15034.30273438, 15175.0390625, + 15317.09277344, 15460.47558594, 15605.20117188, 15751.28222656, 15898.72851562, 16047.55761719, + 16197.77929688, 16349.40625, 16502.453125, 16656.93359375, 16812.859375, 16970.24414062, + 17129.1015625, 17289.44726562, 17451.29492188, 17614.65625, 17779.546875, 17945.98242188, + 18113.97460938, 18283.5390625, 18454.69140625, 18627.4453125, 18801.81835938, 18977.82226562, + 19155.47265625, 19334.78710938, 19515.78125, 19698.46875, 19882.86523438, 20068.98828125, + 20256.85546875, 20446.47851562, 20637.87890625, 20831.0703125, 21026.0703125, 21222.89453125, + 21421.5625, 21622.08984375, 21824.49414062, 22028.79492188, 22235.00585938, 22443.1484375, + 22653.23828125, 22865.29492188, 23079.33789062, 23295.3828125, 23513.45117188, 23733.56054688, + 23955.73046875, 24179.98046875, 24406.33007812, 24634.796875, 24865.40429688, 25098.16796875, + 25333.11328125, 25570.25585938, 25809.61914062, 26051.22460938, 26295.08984375, 26541.23828125, + 26789.69140625, 27040.46875, 27293.59570312, 27549.08984375, 27806.97851562, 28067.27929688, + 28330.01757812, 28595.21484375, 28862.89453125, 29133.08007812, 29405.79492188, 29681.0625, + 29958.90820312, 30239.35351562, 30522.42382812, 30808.14453125, 31096.5390625, 31387.63476562, + 31681.453125, 31978.0234375, 32277.37109375, 32579.51953125, 32884.49609375, 33192.328125, + 33503.04296875, 33816.6640625, 34133.22265625, 34452.7421875, 34775.25390625, 35100.78515625, + 35429.3671875, 35761.01953125, 36095.78125, 36433.671875, 36774.7265625, 37118.9765625, + 37466.44921875, 37817.171875, 38171.17578125, 38528.5, 38889.1640625, 39253.20703125, 39620.65625, + 39991.54296875, 40365.90625, 40743.76953125, 41125.171875, 41510.14453125, 41898.72265625, + 42290.9375, 42686.82421875, 43086.4140625, 43489.74609375, 43896.85546875, 44307.7734375, + 44722.5390625, 45141.1875, 45563.75390625, 45990.27734375, 46420.7890625, 46855.3359375, + 47293.94921875, 47736.66796875, 48183.53125, 48634.578125, 49089.84765625, 49549.375, + 50013.20703125, 50481.3828125, 50953.9375, 51430.91796875, 51912.36328125, 52398.31640625, + 52888.81640625, 53383.91015625, 53883.63671875, 54388.04296875, 54897.16796875, 55411.0625, + 55929.765625, 56453.32421875, 56981.78125, 57515.19140625, 58053.58984375, 58597.03125, + 59145.55859375, 59699.21875, 60258.0625, 60822.140625, 61391.49609375, 61966.18359375, + 62546.24609375, 63131.7421875, 63722.71875, 64319.23046875, 64921.3203125, 65529.05078125, + 66142.46875, 66761.625, 67386.5859375, 68017.390625, 68654.1015625, 69296.7734375, 69945.4609375, + 70600.21875, 71261.109375, 71928.1875, 72601.5078125, 73281.125, 73967.1171875, 74659.5234375, + 75358.40625, 76063.8359375, 76775.875, 77494.5703125, 78220.0, 78952.21875, 79691.2890625, + 80437.28125, 81190.25, 81950.2734375, 82717.4140625, 83491.734375, 84273.296875, 85062.1796875, + 85858.4453125, 86662.171875, 87473.4140625, 88292.25, 89118.7578125, 89953.0, 90795.046875, + 91644.984375, 92502.875, 93368.7890625, 94242.8203125, 95125.0234375, 96015.4921875, + 96914.2890625, 97821.5078125, 98737.21875, 99661.4921875, 100594.4296875, 101536.09375, + 102486.5703125, 103445.953125, 104414.296875, 105391.7265625, 106378.296875, 107374.109375, + 108379.2421875, 109393.78125, 110417.8125, 111451.4375, 112494.7265625, 113547.796875, + 114610.71875, 115683.59375, 116766.5078125, 117859.546875, 118962.84375, 120076.453125, + 121200.4921875, 122335.046875, 123480.2265625, 124636.1328125, 125802.84375, 126980.4765625, + 128169.1484375, 129368.953125, 130579.96875, 131802.328125, 133036.125, 134281.484375, + 135538.484375, 136807.265625, 138087.921875, 139380.5625, 140685.3125, 142002.265625, + 143331.546875, 144673.265625, 146027.5625, 147394.53125, 148774.28125, 150166.96875, + 151572.671875, 152991.546875, 154423.703125, 155869.265625, 157328.359375, 158801.109375, + 160287.640625, 161788.09375, 163302.59375, 164831.28125, 166374.265625, 167931.6875, + 169503.703125, 171090.421875, 172692.0, 174308.578125, 175940.28125, 177587.265625, 179249.65625, + 180927.609375, 182621.28125, 184330.796875, 186056.3125, 187797.984375, 189555.96875, + 191330.40625, 193121.453125, 194929.265625, 196753.984375, 198595.8125, 200454.859375, + 202331.328125, 204225.34375, 206137.109375, 208066.75, 210014.46875, 211980.40625, 213964.765625, + 215967.6875, 217989.359375, 220029.96875, 222089.671875, 224168.640625, 226267.09375, + 228385.171875, 230523.09375, 232681.015625, 234859.15625, 237057.671875, 239276.765625, + 241516.640625, 243777.46875, 246059.484375, 248362.84375, 250687.765625, 253034.453125, + 255403.109375, 257793.9375, 260207.15625, 262642.96875, 265101.5625, 267583.1875, 270088.03125, + 272616.3125, 275168.28125, 277744.125, 280344.09375, 282968.40625, 285617.28125, 288290.9375, + 290989.625, 293713.59375, 296463.03125, 299238.21875, 302039.40625, 304866.78125, 307720.65625, + 310601.21875, 313508.75, 316443.53125, 319405.75, 322395.71875, 325413.65625, 328459.84375, + 331534.5625, 334638.0625, 337770.625, 340932.5, 344123.96875, 347345.3125, 350596.8125, 353878.75, + 357191.40625, 360535.09375, 363910.0625, 367316.625, 370755.0625, 374225.71875, 377728.84375, + 381264.75, 384833.78125, 388436.21875, 392072.375, 395742.5625, 399447.09375, 403186.34375, + 406960.5625, 410770.125, 414615.34375, 418496.5625, 422414.09375, 426368.3125, 430359.5625, + 434388.15625, 438454.46875, 442558.84375, 446701.65625, 450883.21875, 455103.9375, 459364.15625, + 463664.28125, 468004.65625, 472385.625, 476807.65625, 481271.03125, 485776.21875, 490323.5625, + 494913.5, 499546.375, 504222.65625, 508942.6875, 513706.875, 518515.6875, 523369.53125, + 528268.8125, 533213.9375, 538205.3125, 543243.5, 548328.8125, 553461.6875, 558642.6875, + 563872.125, 569150.5, 574478.375, 579856.0625, 585284.0625, 590762.9375, 596293.0625, 601874.9375, + 607509.125, 613196.0, 618936.125, 624730.0, 630578.125, 636480.9375, 642439.0625, 648452.9375, + 654523.125, 660650.125, 666834.4375, 673076.6875, 679377.375, 685737.0, 692156.1875, 698635.5, + 705175.4375, 711776.5625, 718439.5, 725164.8125, 731953.125, 738804.9375, 745720.875, 752701.5625, + 759747.625, 766859.625, 774038.1875, 781283.9375, 788597.5625, 795979.625, 803430.8125, 810951.75, + 818543.0625, 826205.4375, 833939.5625, 841746.0625, 849625.625, 857579.0, 865606.8125, 873709.75, + 881888.5625, 890143.9375, 898476.5625, 906887.1875, 915376.5625, 923945.4375, 932594.5, 941324.5, + 950136.25, 959030.5, 968008.0, 977069.5, 986215.875, 995447.8125, 1004766.1875, 1014171.8125, + 1023665.5, 1033248.125, 1042920.3125, 1052683.125, 1062537.25, 1072483.625, 1082523.125, + 1092656.625, 1102885.0, 1113209.125, 1123629.875, 1134148.25, 1144765.0, 1155481.125, 1166297.625, + 1177215.375, 1188235.25, 1199358.375, 1210585.5, 1221917.875, 1233356.25, 1244901.625, 1256555.25, + 1268317.75, 1280190.5, +]; diff --git a/src/parser/core/stats.jsx b/src/parser/core/stats.jsx index f388c53ece5..92018151dd2 100644 --- a/src/parser/core/stats.jsx +++ b/src/parser/core/stats.jsx @@ -1,4 +1,5 @@ import multiplierTables from './statsMultiplierTables.generated'; +import * as effectTables from './effectMultiplierTables.generated'; function scaleStat(baseItemLevel, baseStat, itemLevel) { return Math.round(baseStat * 1.15 ** ((itemLevel - baseItemLevel) / 15)); @@ -30,3 +31,15 @@ export function calculateSecondaryStatDefault(baseItemLevel, baseStat, itemLevel export function calculateSecondaryStatJewelry(baseItemLevel, baseStat, itemLevel) { return scaleStatViaMultiplierTable(baseItemLevel, baseStat, itemLevel, multiplierTables.jewelry); } + +/** + * Calculate the value of a secondary damage or healing effect. For example: the healing cap on Echoing Tyrstone. + * + * This is *almost never* needed since we can just read the logged values. This should only be used when the value is not logged (like Tyrstone) and you should take care to double-check the value produced against **in-game** tooltips! + */ +export function calculateEffectScaling(baseItemLevel, baseValue, itemLevel) { + return ( + baseValue * + (effectTables.damageSecondary[itemLevel - 1] / effectTables.damageSecondary[baseItemLevel - 1]) + ); +} diff --git a/src/parser/core/statsMultiplierTables.generated.jsx b/src/parser/core/statsMultiplierTables.generated.jsx index 238530f3214..e7b20114e15 100644 --- a/src/parser/core/statsMultiplierTables.generated.jsx +++ b/src/parser/core/statsMultiplierTables.generated.jsx @@ -363,946 +363,946 @@ export default { 1.449819046, 1.446620228, 1.443356043, // 360 - 1.440027978, - 1.4366375, - 1.433186052, - 1.429675057, - 1.426105916, // 365 - 1.42248001, - 1.418798698, - 1.41506332, + 1.440027979, + 1.436637501, + 1.433186053, + 1.429675058, + 1.426105917, // 365 + 1.422480011, + 1.418798699, + 1.415063321, 1.411275196, - 1.407435624, // 370 - 1.403545886, - 1.399607242, + 1.407435625, // 370 + 1.403545887, + 1.399607243, 1.395620934, 1.391588184, - 1.387510196, // 375 - 1.383388158, - 1.379223236, - 1.375016581, - 1.370769324, - 1.366482581, // 380 - 1.36215745, - 1.357795011, - 1.353396328, - 1.348962448, - 1.344494404, // 385 - 1.339993209, - 1.335459864, - 1.330895351, - 1.326300639, - 1.32167668, // 390 - 1.317024412, - 1.312344758, - 1.307638626, - 1.30290691, - 1.298150488, // 395 - 1.293370227, - 1.288566977, - 1.283741575, - 1.278894847, - 1.274027603, // 400 - 1.269140639, - 1.264234741, - 1.25931068, - 1.254369214, - 1.249411091, // 405 - 1.244437044, - 1.239447794, - 1.234444053, - 1.229426517, - 1.224395872, // 410 - 1.219352795, - 1.214297947, - 1.209231982, - 1.204155539, - 1.199069249, // 415 - 1.193973732, - 1.188869596, - 1.183757438, - 1.178637848, - 1.173511402, // 420 - 1.168378668, - 1.163240203, - 1.158096556, - 1.152948263, - 1.147795855, // 425 - 1.14263985, - 1.137480758, - 1.132319079, - 1.127155306, - 1.121989921, // 430 - 1.116823399, - 1.111656203, - 1.106488793, - 1.101321615, - 1.09615511, // 435 - 1.09098971, - 1.085825839, - 1.080663913, - 1.07550434, - 1.07034752, // 440 - 1.065193845, - 1.060043702, - 1.054897468, - 1.049755513, - 1.0446182, // 445 - 1.039485886, - 1.03435892, - 1.029237645, - 1.024122394, - 1.019013498, // 450 - 1.013911279, - 1.008816051, - 1.003728125, - 0.998647802, - 0.99357538, // 455 - 0.988511149, - 0.983455393, - 0.97840839, - 0.973370414, - 0.968341731, // 460 - 0.963322601, - 0.958313281, - 0.953314019, - 0.94832506, - 0.943346644, // 465 - 0.938379003, - 0.933422365, - 0.928476955, - 0.92354299, - 0.918620684, // 470 - 0.913710243, - 0.908811872, - 0.903925769, - 0.899052128, - 0.894191138, // 475 - 0.889342984, - 0.884507845, - 0.879685897, - 0.874877311, - 0.870082255, // 480 - 0.86530089, - 0.860533376, - 0.855779866, - 0.851040511, - 0.846315457, // 485 - 0.841604847, - 0.836908819, - 0.832227508, - 0.827561044, - 0.822909556, // 490 - 0.818273166, - 0.813651994, - 0.809046158, - 0.80445577, - 0.799880939, // 495 - 0.795321773, - 0.790778373, - 0.78625084, - 0.78173927, - 0.777243757, // 500 - 0.77276439, - 0.768301257, - 0.763854442, - 0.759424026, - 0.755010087, // 505 - 0.750612701, - 0.746231941, - 0.741867877, - 0.737520574, - 0.733190099, // 510 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 515 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 520 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 525 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 530 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 535 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 540 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 545 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 550 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 555 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 560 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 565 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 570 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 575 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 580 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 585 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 590 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 595 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 600 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 605 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 610 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 615 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 620 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 625 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 630 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 635 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 640 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 645 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 650 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 655 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 660 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 665 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 670 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 675 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 680 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 685 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 690 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 695 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 700 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 705 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 710 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 715 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 720 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 725 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 730 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 735 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 740 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 745 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 750 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 755 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 760 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 765 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 770 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 775 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 780 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 785 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 790 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 795 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 800 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 805 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 810 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 815 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 820 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 825 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 830 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 835 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 840 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 845 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 850 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 855 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 860 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 865 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 870 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 875 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 880 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 885 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 890 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 895 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 900 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 905 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 910 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 915 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 920 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 925 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 930 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 935 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 940 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 945 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 950 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 955 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 960 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 965 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 970 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 975 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 980 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 985 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 990 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 995 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1000 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1005 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1010 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1015 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1020 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1025 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1030 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1035 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1040 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1045 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1050 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1055 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1060 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1065 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1070 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1075 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1080 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1085 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1090 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1095 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1100 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1105 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1110 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1115 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1120 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1125 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1130 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1135 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1140 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1145 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1150 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1155 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1160 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1165 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1170 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1175 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1180 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1185 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1190 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1195 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1200 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1205 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1210 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1215 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1220 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1225 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1230 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1235 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1240 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1245 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1250 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1255 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1260 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1265 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1270 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1275 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1280 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1285 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1290 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1295 - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, - 0.733190099, // 1300 + 1.387510197, // 375 + 1.383388159, + 1.379223237, + 1.375016582, + 1.370769325, + 1.366482582, // 380 + 1.362157451, + 1.357795012, + 1.353396329, + 1.348962449, + 1.344494405, // 385 + 1.33999321, + 1.335459865, + 1.330895352, + 1.32630064, + 1.321676681, // 390 + 1.317024413, + 1.312344759, + 1.307638627, + 1.302906911, + 1.298150489, // 395 + 1.293370228, + 1.288566978, + 1.283741577, + 1.278894848, + 1.274027604, // 400 + 1.26914064, + 1.264234742, + 1.259310681, + 1.254369215, + 1.249411092, // 405 + 1.244437045, + 1.239447795, + 1.234444054, + 1.229426518, + 1.224395874, // 410 + 1.219352796, + 1.214297949, + 1.209231983, + 1.20415554, + 1.199069251, // 415 + 1.193973733, + 1.188869597, + 1.18375744, + 1.178637849, + 1.173511403, // 420 + 1.168378669, + 1.163240204, + 1.158096557, + 1.152948265, + 1.147795857, // 425 + 1.142639851, + 1.137480759, + 1.132319081, + 1.127155308, + 1.121989923, // 430 + 1.1168234, + 1.111656205, + 1.106488794, + 1.101321616, + 1.096155111, // 435 + 1.090989712, + 1.085825841, + 1.080663914, + 1.075504341, + 1.070347521, // 440 + 1.065193847, + 1.060043703, + 1.054897469, + 1.049755514, + 1.044618201, // 445 + 1.039485888, + 1.034358922, + 1.029237646, + 1.024122396, + 1.0190135, // 450 + 1.01391128, + 1.008816052, + 1.003728126, + 0.998647803, + 0.993575381, // 455 + 0.98851115, + 0.983455394, + 0.978408392, + 0.973370415, + 0.968341732, // 460 + 0.963322602, + 0.958313282, + 0.95331402, + 0.948325062, + 0.943346645, // 465 + 0.938379004, + 0.933422367, + 0.928476957, + 0.923542992, + 0.918620685, // 470 + 0.913710244, + 0.908811873, + 0.903925771, + 0.89905213, + 0.89419114, // 475 + 0.889342985, + 0.884507846, + 0.879685898, + 0.874877313, + 0.870082256, // 480 + 0.865300891, + 0.860533377, + 0.855779867, + 0.851040512, + 0.846315459, // 485 + 0.841604848, + 0.83690882, + 0.832227509, + 0.827561046, + 0.822909557, // 490 + 0.818273167, + 0.813651996, + 0.809046159, + 0.804455771, + 0.799880941, // 495 + 0.795321774, + 0.790778374, + 0.786250841, + 0.781739271, + 0.777243758, // 500 + 0.772764391, + 0.768301258, + 0.763854443, + 0.759424027, + 0.755010088, // 505 + 0.750612703, + 0.746231943, + 0.741867878, + 0.737520575, + 0.7331901, // 510 + 0.728876513, + 0.724579875, + 0.720300241, + 0.716037665, + 0.7117922, // 515 + 0.707563895, + 0.703352796, + 0.699158948, + 0.694982394, + 0.690823173, // 520 + 0.686681322, + 0.682556879, + 0.678449875, + 0.674360342, + 0.67028831, // 525 + 0.666233805, + 0.662196852, + 0.658177476, + 0.654175696, + 0.650191533, // 530 + 0.646225003, + 0.642276123, + 0.638344906, + 0.634431364, + 0.630535508, // 535 + 0.626657345, + 0.622796884, + 0.618954128, + 0.615129082, + 0.611321748, // 540 + 0.607532127, + 0.603760216, + 0.600006014, + 0.596269517, + 0.592550719, // 545 + 0.588849613, + 0.585166191, + 0.581500443, + 0.577852358, + 0.574221924, // 550 + 0.570609128, + 0.567013953, + 0.563436385, + 0.559876406, + 0.556333997, // 555 + 0.552809139, + 0.549301811, + 0.54581199, + 0.542339654, + 0.538884779, // 560 + 0.535447339, + 0.532027309, + 0.52862466, + 0.525239365, + 0.521871394, // 565 + 0.518520717, + 0.515187304, + 0.511871122, + 0.508572138, + 0.505290318, // 570 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 575 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 580 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 585 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 590 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 595 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 600 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 605 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 610 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 615 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 620 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 625 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 630 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 635 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 640 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 645 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 650 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 655 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 660 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 665 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 670 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 675 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 680 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 685 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 690 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 695 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 700 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 705 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 710 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 715 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 720 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 725 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 730 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 735 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 740 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 745 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 750 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 755 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 760 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 765 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 770 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 775 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 780 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 785 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 790 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 795 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 800 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 805 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 810 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 815 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 820 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 825 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 830 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 835 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 840 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 845 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 850 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 855 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 860 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 865 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 870 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 875 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 880 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 885 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 890 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 895 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 900 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 905 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 910 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 915 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 920 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 925 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 930 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 935 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 940 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 945 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 950 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 955 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 960 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 965 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 970 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 975 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 980 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 985 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 990 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 995 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1000 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1005 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1010 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1015 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1020 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1025 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1030 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1035 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1040 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1045 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1050 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1055 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1060 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1065 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1070 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1075 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1080 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1085 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1090 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1095 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1100 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1105 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1110 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1115 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1120 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1125 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1130 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1135 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1140 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1145 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1150 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1155 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1160 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1165 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1170 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1175 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1180 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1185 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1190 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1195 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1200 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1205 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1210 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1215 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1220 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1225 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1230 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1235 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1240 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1245 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1250 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1255 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1260 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1265 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1270 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1275 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1280 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1285 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1290 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1295 + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, + 0.505290318, // 1300 ], // https://github.com/simulationcraft/simc/blob/dragonflight/engine/dbc/generated/sc_scale_data.inc#L1825-2085 jewelry: [ @@ -1654,957 +1654,957 @@ export default { 1.223039857, 1.230032045, 1.236789344, - 1.24331551, - 1.24961425, // 350 - 1.25568922, - 1.261544029, - 1.267182238, - 1.272607362, - 1.277822867, // 355 - 1.282832175, + 1.243315511, + 1.249614251, // 350 + 1.255689221, + 1.26154403, + 1.267182239, + 1.272607363, + 1.277822868, // 355 + 1.282832176, 1.287638663, - 1.29224566, - 1.296656455, - 1.30087429, // 360 - 1.304902365, - 1.308743836, - 1.312401819, - 1.315879387, - 1.31917957, // 365 - 1.322305361, - 1.325259711, - 1.328045529, - 1.330665689, - 1.333123023, // 370 - 1.335420327, - 1.337560356, - 1.339545831, - 1.341379434, - 1.343063812, // 375 - 1.344601574, - 1.345995296, - 1.347247516, - 1.34836074, - 1.349337438, // 380 - 1.350180046, - 1.350890968, - 1.351472574, - 1.351927201, - 1.352257154, // 385 - 1.352464708, - 1.352552103, - 1.35252155, - 1.352375231, - 1.352115294, // 390 - 1.351743861, - 1.35126302, - 1.350674834, - 1.349981335, - 1.349184527, // 395 - 1.348286386, - 1.347288859, - 1.346193868, - 1.345003307, - 1.343719041, // 400 - 1.342342912, - 1.340876734, - 1.339322295, - 1.337681359, - 1.335955664, // 405 - 1.334146923, - 1.332256825, - 1.330287034, - 1.328239191, - 1.326114914, // 410 - 1.323915796, - 1.321643409, - 1.319299299, - 1.316884994, - 1.314401996, // 415 - 1.311851788, - 1.30923583, - 1.30655556, - 1.303812397, - 1.301007737, // 420 - 1.298142958, - 1.295219415, - 1.292238445, - 1.289201365, - 1.286109471, // 425 - 1.282964042, - 1.279766337, - 1.276517595, - 1.273219039, - 1.269871872, // 430 - 1.266477278, - 1.263036427, - 1.259550467, - 1.256020532, - 1.252447737, // 435 - 1.24883318, - 1.245177943, - 1.241483093, - 1.237749677, - 1.233978729, // 440 - 1.230171267, - 1.226328292, - 1.22245079, - 1.218539732, - 1.214596075, // 445 - 1.210620758, - 1.206614709, - 1.202578839, - 1.198514047, - 1.194421215, // 450 - 1.190301214, - 1.1861549, - 1.181983114, - 1.177786686, - 1.173566432, // 455 - 1.169323155, - 1.165057645, - 1.160770678, - 1.156463021, - 1.152135425, // 460 - 1.147788631, - 1.143423367, - 1.13904035, - 1.134640284, - 1.130223863, // 465 - 1.125791768, - 1.12134467, - 1.116883228, - 1.112408091, - 1.107919897, // 470 - 1.103419273, - 1.098906836, - 1.094383191, - 1.089848935, - 1.085304653, // 475 - 1.080750922, - 1.076188307, - 1.071617365, - 1.067038644, - 1.06245268, // 480 - 1.057860001, - 1.053261127, - 1.048656568, - 1.044046824, - 1.039432387, // 485 - 1.034813742, - 1.030191363, - 1.025565717, - 1.020937262, - 1.016306447, // 490 - 1.011673715, - 1.0070395, - 1.002404227, - 0.997768315, - 0.993132174, // 495 - 0.988496208, - 0.983860811, - 0.979226372, - 0.974593272, - 0.969961885, // 500 - 0.965332577, - 0.960705709, - 0.956081632, - 0.951460694, - 0.946843233, // 505 - 0.942229583, - 0.93762007, - 0.933015015, - 0.92841473, - 0.923819525, // 510 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 515 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 520 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 525 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 530 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 535 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 540 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 545 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 550 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 555 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 560 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 565 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 570 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 575 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 580 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 585 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 590 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 595 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 600 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 605 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 610 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 615 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 620 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 625 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 630 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 635 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 640 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 645 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 650 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 655 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 660 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 665 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 670 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 675 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 680 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 685 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 690 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 695 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 700 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 705 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 710 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 715 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 720 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 725 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 730 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 735 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 740 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 745 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 750 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 755 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 760 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 765 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 770 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 775 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 780 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 785 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 790 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 795 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 800 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 805 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 810 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 815 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 820 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 825 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 830 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 835 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 840 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 845 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 850 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 855 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 860 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 865 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 870 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 875 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 880 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 885 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 890 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 895 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 900 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 905 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 910 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 915 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 920 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 925 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 930 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 935 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 940 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 945 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 950 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 955 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 960 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 965 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 970 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 975 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 980 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 985 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 990 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 995 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1000 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1005 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1010 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1015 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1020 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1025 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1030 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1035 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1040 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1045 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1050 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1055 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1060 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1065 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1070 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1075 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1080 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1085 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1090 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1095 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1100 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1105 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1110 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1115 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1120 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1125 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1130 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1135 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1140 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1145 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1150 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1155 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1160 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1165 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1170 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1175 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1180 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1185 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1190 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1195 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1200 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1205 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1210 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1215 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1220 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1225 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1230 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1235 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1240 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1245 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1250 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1255 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1260 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1265 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1270 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1275 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1280 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1285 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1290 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1295 - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, - 0.923819525, // 1300 + 1.292245661, + 1.296656456, + 1.300874291, // 360 + 1.304902366, + 1.308743837, + 1.31240182, + 1.315879388, + 1.319179571, // 365 + 1.322305362, + 1.325259712, + 1.32804553, + 1.33066569, + 1.333123025, // 370 + 1.335420328, + 1.337560357, + 1.339545832, + 1.341379435, + 1.343063813, // 375 + 1.344601575, + 1.345995297, + 1.347247518, + 1.348360741, + 1.349337439, // 380 + 1.350180048, + 1.35089097, + 1.351472576, + 1.351927203, + 1.352257156, // 385 + 1.352464709, + 1.352552104, + 1.352521552, + 1.352375233, + 1.352115296, // 390 + 1.351743862, + 1.351263022, + 1.350674836, + 1.349981337, + 1.349184529, // 395 + 1.348286387, + 1.347288861, + 1.34619387, + 1.345003308, + 1.343719043, // 400 + 1.342342914, + 1.340876736, + 1.339322297, + 1.337681361, + 1.335955666, // 405 + 1.334146925, + 1.332256826, + 1.330287036, + 1.328239193, + 1.326114916, // 410 + 1.323915798, + 1.32164341, + 1.319299301, + 1.316884996, + 1.314401998, // 415 + 1.31185179, + 1.309235832, + 1.306555562, + 1.303812399, + 1.301007739, // 420 + 1.29814296, + 1.295219417, + 1.292238447, + 1.289201367, + 1.286109473, // 425 + 1.282964044, + 1.279766339, + 1.276517597, + 1.273219041, + 1.269871874, // 430 + 1.266477281, + 1.263036429, + 1.259550469, + 1.256020534, + 1.252447739, // 435 + 1.248833182, + 1.245177945, + 1.241483095, + 1.237749679, + 1.233978732, // 440 + 1.230171269, + 1.226328294, + 1.222450792, + 1.218539734, + 1.214596077, // 445 + 1.21062076, + 1.206614711, + 1.202578841, + 1.198514049, + 1.194421217, // 450 + 1.190301216, + 1.186154902, + 1.181983116, + 1.177786688, + 1.173566434, // 455 + 1.169323157, + 1.165057647, + 1.16077068, + 1.156463023, + 1.152135427, // 460 + 1.147788633, + 1.143423369, + 1.139040352, + 1.134640286, + 1.130223865, // 465 + 1.12579177, + 1.121344672, + 1.11688323, + 1.112408093, + 1.1079199, // 470 + 1.103419275, + 1.098906838, + 1.094383193, + 1.089848937, + 1.085304655, // 475 + 1.080750924, + 1.076188309, + 1.071617367, + 1.067038646, + 1.062452682, // 480 + 1.057860003, + 1.053261129, + 1.04865657, + 1.044046826, + 1.039432389, // 485 + 1.034813744, + 1.030191365, + 1.025565719, + 1.020937264, + 1.016306449, // 490 + 1.011673717, + 1.007039502, + 1.002404229, + 0.997768317, + 0.993132176, // 495 + 0.98849621, + 0.983860813, + 0.979226374, + 0.974593274, + 0.969961887, // 500 + 0.965332579, + 0.96070571, + 0.956081634, + 0.951460695, + 0.946843235, // 505 + 0.942229585, + 0.937620072, + 0.933015017, + 0.928414732, + 0.923819527, // 510 + 0.919229701, + 0.914645551, + 0.910067366, + 0.905495429, + 0.90093002, // 515 + 0.896371409, + 0.891819863, + 0.887275644, + 0.882739006, + 0.878210201, // 520 + 0.873689473, + 0.869177062, + 0.864673202, + 0.860178123, + 0.855692049, // 525 + 0.8512152, + 0.846747791, + 0.842290032, + 0.837842127, + 0.833404278, // 530 + 0.828976681, + 0.824559527, + 0.820153003, + 0.815757292, + 0.811372573, // 535 + 0.806999019, + 0.802636801, + 0.798286085, + 0.793947032, + 0.7896198, // 540 + 0.785304544, + 0.781001413, + 0.776710554, + 0.772432108, + 0.768166216, // 545 + 0.763913012, + 0.759672627, + 0.75544519, + 0.751230825, + 0.747029653, // 550 + 0.742841793, + 0.738667358, + 0.73450646, + 0.730359207, + 0.726225703, // 555 + 0.72210605, + 0.718000347, + 0.713908689, + 0.70983117, + 0.705767878, // 560 + 0.7017189, + 0.697684321, + 0.693664222, + 0.689658681, + 0.685667773, // 565 + 0.681691573, + 0.677730149, + 0.673783572, + 0.669851904, + 0.665935211, // 570 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 575 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 580 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 585 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 590 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 595 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 600 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 605 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 610 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 615 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 620 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 625 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 630 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 635 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 640 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 645 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 650 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 655 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 660 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 665 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 670 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 675 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 680 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 685 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 690 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 695 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 700 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 705 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 710 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 715 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 720 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 725 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 730 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 735 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 740 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 745 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 750 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 755 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 760 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 765 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 770 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 775 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 780 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 785 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 790 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 795 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 800 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 805 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 810 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 815 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 820 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 825 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 830 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 835 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 840 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 845 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 850 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 855 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 860 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 865 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 870 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 875 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 880 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 885 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 890 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 895 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 900 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 905 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 910 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 915 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 920 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 925 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 930 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 935 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 940 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 945 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 950 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 955 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 960 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 965 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 970 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 975 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 980 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 985 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 990 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 995 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1000 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1005 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1010 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1015 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1020 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1025 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1030 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1035 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1040 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1045 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1050 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1055 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1060 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1065 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1070 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1075 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1080 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1085 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1090 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1095 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1100 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1105 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1110 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1115 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1120 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1125 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1130 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1135 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1140 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1145 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1150 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1155 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1160 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1165 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1170 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1175 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1180 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1185 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1190 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1195 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1200 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1205 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1210 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1215 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1220 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1225 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1230 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1235 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1240 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1245 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1250 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1255 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1260 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1265 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1270 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1275 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1280 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1285 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1290 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1295 + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, + 0.665935211, // 1300 ], }; diff --git a/src/parser/retail/modules/items/FoodChecker.ts b/src/parser/retail/modules/items/FoodChecker.ts index e9a37692c6d..dd86004a113 100644 --- a/src/parser/retail/modules/items/FoodChecker.ts +++ b/src/parser/retail/modules/items/FoodChecker.ts @@ -1,25 +1,7 @@ -import SHADOWLANDS_SPELLS from 'common/SPELLS/shadowlands/others'; import SPELLS from 'common/SPELLS/dragonflight/food'; import BaseFoodChecker from 'parser/shared/modules/items/FoodChecker'; const LOWER_FOOD_IDS: number[] = [ - // Shadowlands Food - SHADOWLANDS_SPELLS.SURPRISINGLY_PALATABLE_FEAST_INT.id, - SHADOWLANDS_SPELLS.SURPRISINGLY_PALATABLE_FEAST_AGI.id, - SHADOWLANDS_SPELLS.SURPRISINGLY_PALATABLE_FEAST_STR.id, - SHADOWLANDS_SPELLS.PICKLED_MEAT_SMOOTHIE.id, - SHADOWLANDS_SPELLS.BUTTERSCOTCH_MARINATED_RIBS.id, - SHADOWLANDS_SPELLS.CINNAMON_BONEFISH_STEW.id, - SHADOWLANDS_SPELLS.MEATY_APPLE_DUMPLINGS.id, - SHADOWLANDS_SPELLS.SWEET_SILVERGILL_SAUSAGES.id, - SHADOWLANDS_SPELLS.FEAST_OF_GLUTTONOUS_HEDONISM_INT.id, - SHADOWLANDS_SPELLS.FEAST_OF_GLUTTONOUS_HEDONISM_AGI.id, - SHADOWLANDS_SPELLS.FEAST_OF_GLUTTONOUS_HEDONISM_STR.id, - SHADOWLANDS_SPELLS.BANANA_BEEF_PUDDING.id, - SHADOWLANDS_SPELLS.SPINEFIN_SOUFFLE_AND_FRIES.id, - SHADOWLANDS_SPELLS.TENEBROUS_CROWN_ROAST_ASPIC.id, - SHADOWLANDS_SPELLS.IRIDESCENT_RAVIOLI_WITH_APPLE_SAUCE.id, - SHADOWLANDS_SPELLS.STEAK_A_LA_MODE.id, // Dragonflight SPELLS.CHURNBELLY_TEA.id, ]; diff --git a/src/parser/retail/modules/items/dragonflight/EchoingTyrstone.tsx b/src/parser/retail/modules/items/dragonflight/EchoingTyrstone.tsx new file mode 100644 index 00000000000..a22767e5dd3 --- /dev/null +++ b/src/parser/retail/modules/items/dragonflight/EchoingTyrstone.tsx @@ -0,0 +1,189 @@ +import ITEMS from 'common/ITEMS'; +import SPELLS from 'common/SPELLS'; +import { formatNumber, formatPercentage } from 'common/format'; +import ItemLink from 'interface/ItemLink'; +import { CooldownIcon, HasteIcon } from 'interface/icons'; +import Analyzer, { Options, SELECTED_PLAYER } from 'parser/core/Analyzer'; +import Events, { ApplyBuffEvent, HealEvent, Item } from 'parser/core/Events'; +import BoringSpellValueText from 'parser/ui/BoringItemValueText'; +import ItemPercentHealingDone from 'parser/ui/ItemPercentHealingDone'; +import STATISTIC_CATEGORY from 'parser/ui/STATISTIC_CATEGORY'; +import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER'; +import Statistic from 'parser/ui/Statistic'; +import { calculateEffectScaling, calculateSecondaryStatDefault } from 'parser/core/stats'; + +const ECHOING_TYRSTONE_COOLDOWN = 120000; // 120sec + +class EchoingTyrstone extends Analyzer { + healAmount: number = 0; + overhealAmount: number = 0; + trinket: Item | undefined; + maxStored: number = 0; + hasteValue: number = 0; + useTracker: EchoingTyrstoneUse[] = []; + timeOnCooldown: number = 0; + + constructor(options: Options) { + super(options); + this.trinket = this.selectedCombatant.getTrinket(ITEMS.ECHOING_TYRSTONE.id); + this.active = this.trinket !== undefined; + + if (!this.active) { + return; + } + const itemLevel = this.trinket?.itemLevel || 421; + + this.maxStored = calculateEffectScaling(437, 229585, itemLevel); + this.hasteValue = calculateSecondaryStatDefault(437, 225, itemLevel); + + this.addEventListener(Events.heal.by(SELECTED_PLAYER), this.onHeal); + + this.addEventListener( + Events.heal.by(SELECTED_PLAYER).spell(SPELLS.ECHOING_TYRSTONE_HEAL), + this.onTyrstoneHeal, + ); + + this.addEventListener( + Events.applybuff.by(SELECTED_PLAYER).spell(SPELLS.ECHOING_TYRSTONE_BUFF), + this.onTyrstoneActivate, + ); + } + + onTyrstoneHeal(event: HealEvent) { + this.healAmount += event.amount + (event.absorbed || 0); + this.overhealAmount += event.overheal || 0; + } + + onHeal(event: HealEvent) { + if (!this.selectedCombatant.hasBuff(SPELLS.ECHOING_TYRSTONE_BUFF.id, event.timestamp)) { + return; + } + + const totalHeal = event.amount + (event.overheal || 0); + + this.useTracker[this.useTracker.length - 1].heal += totalHeal * 0.3; + + if (this.useTracker[this.useTracker.length - 1].heal > this.maxStored) { + this.useTracker[this.useTracker.length - 1].heal = this.maxStored; + } + } + + onTyrstoneActivate(event: ApplyBuffEvent) { + this.useTracker.push({ + timestamp: event.timestamp, + heal: 0, + }); + + if (event.timestamp + ECHOING_TYRSTONE_COOLDOWN < this.owner.fight.end_time) { + this.timeOnCooldown += ECHOING_TYRSTONE_COOLDOWN; + } else { + this.timeOnCooldown += this.owner.fight.end_time - event.timestamp; + } + } + + getCastEfficiency() { + return this.timeOnCooldown / this.owner.fightDuration; + } + + getHasteOverFight() { + const uptime = this.selectedCombatant.getBuffUptime(SPELLS.ECHOING_TYRSTONE_HASTE_BUFF.id); + const averageHaste = (uptime / this.owner.fightDuration) * this.hasteValue; + + return Math.round(averageHaste); + } + + tooltip() { + return ( + <> +

    + was used {this.useTracker.length} times + spending {formatPercentage(this.getCastEfficiency())}% of the fight + either active or on cooldown.{' '} + + This trinket will make use of the healing when it's needed or when it is next triggered, + so it should be used off cooldown. + +

    +

    + A total of {formatNumber(this.healAmount)} healing was done with{' '} + {formatNumber(this.overhealAmount)} overhealing. +

    +

    + Each use of the healing also granted {formatNumber(this.hasteValue)}{' '} + haste for 15 seconds to each member of the raid. This equates to{' '} + {this.getHasteOverFight()} haste each over the length of the fight. +

    + + ); + } + + subStatistic() { + return ( + + +
    + {this.getHasteOverFight()} Haste over time (per raider) +
    + {formatPercentage(this.getCastEfficiency())}% use efficiency +
    + ); + } + + getClass(value: number) { + if (value >= this.maxStored) { + return 'good-mark'; + } else if (value >= this.maxStored / 2) { + return 'ok-mark'; + } + + return 'bad-mark'; + } + + dropdown() { + return ( + <> + + + + + + + + + + {this.useTracker.map((use, index) => ( + + + + + + ))} + +
    UseTimestampHealing Stored
    {index + 1}{this.owner.formatTimestamp(use.timestamp)}{formatNumber(use.heal)}
    + + ); + } + + statistic() { + return ( + + {this.subStatistic()} + + ); + } +} + +export default EchoingTyrstone; + +interface EchoingTyrstoneUse { + /** Cast's timestamp */ + timestamp: number; + /** Heal stored during use */ + heal: number; +} diff --git a/src/parser/retail/modules/items/dragonflight/Fyralath.tsx b/src/parser/retail/modules/items/dragonflight/Fyralath.tsx new file mode 100644 index 00000000000..aa51474360a --- /dev/null +++ b/src/parser/retail/modules/items/dragonflight/Fyralath.tsx @@ -0,0 +1,27 @@ +import Analyzer, { Options } from 'parser/core/Analyzer'; +import ITEMS from 'common/ITEMS/dragonflight/others'; +import SPELLS from 'common/SPELLS/dragonflight/others'; +import Abilities from 'parser/core/modules/Abilities'; +import SPELL_CATEGORY from 'parser/core/SPELL_CATEGORY'; + +const deps = { + abilities: Abilities, +}; +export default class Fyralath extends Analyzer.withDependencies(deps) { + constructor(options: Options) { + super(options); + this.active = this.selectedCombatant.hasMainHand(ITEMS.FYRALATH.id); + if (this.active) { + this.deps.abilities.add({ + spell: SPELLS.RAGE_OF_FYRALATH_1.id, + category: SPELL_CATEGORY.COOLDOWNS, + cooldown: 120, + castEfficiency: { + suggestion: true, + recommendedEfficiency: 0.9, + }, + damageSpellIds: [SPELLS.RAGE_OF_FYRALATH_DAMAGE_1.id, SPELLS.RAGE_OF_FYRALATH_DAMAGE_2.id], + }); + } + } +} diff --git a/src/parser/shared/modules/AlwaysBeCasting.tsx b/src/parser/shared/modules/AlwaysBeCasting.tsx index 6acca2bdf48..526cdf79b95 100644 --- a/src/parser/shared/modules/AlwaysBeCasting.tsx +++ b/src/parser/shared/modules/AlwaysBeCasting.tsx @@ -46,6 +46,13 @@ class AlwaysBeCasting extends Analyzer { /** Gets active time percentage within a specified time segment. * This will not work properly unless the current timestamp advances past the end time. */ getActiveTimePercentageInWindow(start: number, end: number): number { + const windowDuration = end - start; + return this.getActiveTimeMillisecondsInWindow(start, end) / windowDuration; + } + + /** Gets active time milliseconds within a specified time segment. + * This will not work properly unless the current timestamp advances past the end time. */ + getActiveTimeMillisecondsInWindow(start: number, end: number): number { let activeTime = 0; for (let i = 0; i < this.activeTimeSegments.length; i += 1) { const seg = this.activeTimeSegments[i]; @@ -58,8 +65,7 @@ class AlwaysBeCasting extends Analyzer { const overlapEnd = Math.min(end, seg.end); activeTime += Math.max(0, overlapEnd - overlapStart); } - const windowDuration = end - start; - return activeTime / windowDuration; + return activeTime; } activeTime = 0; diff --git a/src/parser/shared/modules/StatTracker.ts b/src/parser/shared/modules/StatTracker.ts index 0bd2518d5c0..4004019bebc 100644 --- a/src/parser/shared/modules/StatTracker.ts +++ b/src/parser/shared/modules/StatTracker.ts @@ -1,7 +1,6 @@ import { formatMilliseconds } from 'common/format'; import SPELLS from 'common/SPELLS'; import CLASSIC_SPELLS from 'common/SPELLS/classic'; -import SHADOWLANDS_SPELLS from 'common/SPELLS/shadowlands/others'; import ITEMS from 'common/ITEMS'; import RACES from 'game/RACES'; import SPECS, { isRetailSpec, specMasteryCoefficient } from 'game/SPECS'; @@ -63,8 +62,6 @@ class StatTracker extends Analyzer { // endregion // region Runes - [SHADOWLANDS_SPELLS.VEILED_AUGMENT_RUNE.id]: primaryStat(18), - [SHADOWLANDS_SPELLS.ETERNAL_AUGMENT_RUNE.id]: primaryStat(18), [SPELLS.DRACONIC_AUGMENT_RUNE.id]: primaryStat(87), // endregion