Skip to content

Commit

Permalink
Merge branch 'dragonflight' into dragonflight
Browse files Browse the repository at this point in the history
  • Loading branch information
emallson authored Jan 8, 2024
2 parents d53fc36 + 5eb848e commit d7231ad
Show file tree
Hide file tree
Showing 56 changed files with 3,621 additions and 2,827 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ import SpellLink from 'interface/SpellLink';

// prettier-ignore
export default [
change(date(2024, 1, 7), <>Add checklist support for <ItemLink id={ITEMS.FYRALATH.id} />.</>, ToppleTheNun),
change(date(2024, 1, 4), <>Add statistics for <ItemLink id={ITEMS.ECHOING_TYRSTONE.id}/>.</>, 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),
Expand Down
1 change: 1 addition & 0 deletions src/analysis/retail/demonhunter/havoc/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <SpellLink spell={TALENTS.ACCELERATED_BLADE_TALENT} /> 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 <SpellLink spell={TALENTS.COLLECTIVE_ANGUISH_TALENT} />.</>, ToppleTheNun),
Expand Down
29 changes: 27 additions & 2 deletions src/analysis/retail/demonhunter/havoc/Guide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof CombatLogParser>) {
return (
Expand All @@ -28,12 +31,12 @@ export default function Guide({ modules, events, info }: GuideProps<typeof Comba
);
}

function ResourceUsageSection({ modules }: GuideProps<typeof CombatLogParser>) {
function ResourceUsageSection({ info, modules }: GuideProps<typeof CombatLogParser>) {
const percentAtFuryCap = modules.furyTracker.percentAtCap;
const percentAtFuryCapPerformance = modules.furyTracker.percentAtCapPerformance;
const furyWasted = modules.furyTracker.wasted;
return (
<Section title="Resource Use">
<Section title="Core">
<SubSection title="Fury">
<p>
Havoc's primary resource is <ResourceLink id={RESOURCE_TYPES.FURY.id} />. You should avoid
Expand All @@ -50,6 +53,28 @@ function ResourceUsageSection({ modules }: GuideProps<typeof CombatLogParser>) {
/>
{modules.furyGraph.plot}
</SubSection>
<SubSection title="Active Time">
<p>
<b>
Continuously casting throughout an encounter is the single most important thing for
achieving good DPS.
</b>
<br />
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.
</p>
<p>
Active Time:{' '}
<PerformanceStrong performance={modules.alwaysBeCasting.DowntimePerformance}>
{formatPercentage(modules.alwaysBeCasting.activeTimePercentage, 1)}%
</PerformanceStrong>{' '}
</p>
<ActiveTimeGraph
activeTimeSegments={modules.alwaysBeCasting.activeTimeSegments}
fightStart={info.fightStart}
fightEnd={info.fightEnd}
/>
</SubSection>
</Section>
);
}
Expand Down
2 changes: 0 additions & 2 deletions src/analysis/retail/demonhunter/havoc/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<li>
Expand Down
1 change: 1 addition & 0 deletions src/analysis/retail/demonhunter/shared/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
31 changes: 28 additions & 3 deletions src/analysis/retail/demonhunter/vengeance/Guide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof CombatLogParser>) {
return (
<>
<ResourceUsageSection modules={modules} events={events} info={info} />
<CoreSection modules={modules} events={events} info={info} />
<RotationSection modules={modules} events={events} info={info} />
<MitigationSection />
<CooldownSection modules={modules} events={events} info={info} />
Expand All @@ -32,13 +35,13 @@ export default function Guide({ modules, events, info }: GuideProps<typeof Comba
);
}

function ResourceUsageSection({ modules }: GuideProps<typeof CombatLogParser>) {
function CoreSection({ modules, info }: GuideProps<typeof CombatLogParser>) {
const percentAtFuryCap = modules.furyTracker.percentAtCap;
const percentAtFuryCapPerformance = modules.furyTracker.percentAtCapPerformance;
const furyWasted = modules.furyTracker.wasted;

return (
<Section title="Resource Use">
<Section title="Core">
<SubSection title="Fury">
<p>
Vengeance's primary resource is <ResourceLink id={RESOURCE_TYPES.FURY.id} />. You should
Expand Down Expand Up @@ -68,6 +71,28 @@ function ResourceUsageSection({ modules }: GuideProps<typeof CombatLogParser>) {
</p>
{modules.soulFragmentsGraph.plot}
</SubSection>
<SubSection title="Active Time">
<p>
<b>
Continuously casting throughout an encounter is the single most important thing for
achieving good DPS.
</b>
<br />
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.
</p>
<p>
Active Time:{' '}
<PerformanceStrong performance={modules.alwaysBeCasting.DowntimePerformance}>
{formatPercentage(modules.alwaysBeCasting.activeTimePercentage, 1)}%
</PerformanceStrong>{' '}
</p>
<ActiveTimeGraph
activeTimeSegments={modules.alwaysBeCasting.activeTimeSegments}
fightStart={info.fightStart}
fightEnd={info.fightEnd}
/>
</SubSection>
</Section>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/analysis/retail/druid/restoration/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <SpellLink spell={TALENTS_DRUID.CENARIUS_GUIDANCE_TALENT}/>, 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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions src/analysis/retail/mage/fire/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { Sharrq, ToppleTheNun } from 'CONTRIBUTORS';

// prettier-ignore
export default [
change(date(2024, 1, 3), <>Updated <SpellLink spell={SPELLS.FIREBALL} /> during <SpellLink spell={TALENTS.COMBUSTION_TALENT} /> to disregard casts where the player had a <SpellLink spell={TALENTS.FLAME_ACCELERANT_TALENT} /> proc. Reworded the suggestion to include Double Lust and Flame Accelerant.</>, Sharrq),
change(date(2023, 12, 31), <><SpellLink spell={TALENTS.COMBUSTION_TALENT} /> 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 <SpellLink spell={TALENTS.LIVING_BOMB_TALENT} /> to be acceptable to cast in AOE at 5+ targets.</>, Sharrq),
change(date(2023, 12, 31), <>Fixed the wording on <SpellLink spell={TALENTS.METEOR_TALENT} /> to specify that it has to land during <SpellLink spell={TALENTS.COMBUSTION_TALENT} />.</>, Sharrq),
change(date(2023, 12, 2), <>Fixed an issue that was causing <SpellLink spell={TALENTS.SUN_KINGS_BLESSING_TALENT} /> to not calculate expirations and wasted <SpellLink spell={SPELLS.HOT_STREAK} /> 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 <SpellLink spell={SPELLS.CHARRING_EMBERS_DEBUFF} />, <SpellLink spell={TALENTS.IMPROVED_SCORCH_TALENT} />, and <SpellLink spell={TALENTS.LIVING_BOMB_TALENT} /> to the Checklist.</>, Sharrq),
Expand Down
2 changes: 1 addition & 1 deletion src/analysis/retail/mage/fire/Checklist/Component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const FireMageChecklist = ({ combatant, castEfficiency, thresholds }: ChecklistP
<Requirement
name="Fireball casts during Combustion"
thresholds={thresholds.fireballSpellUsageDuringCombustion}
tooltip="Due to Combustion's short duration, you should never cast Fireball during Combustion, unless your haste is over 100%. Instead, you should use your instant cast abilities like Fireblast and Phoenix Flames. If you run out of instant abilities, cast Scorch instead since it's cast time is shorter."
tooltip="Due to Combustion's short duration, you should only cast Fireball during Combustion if your haste is over 100% or you have a Flame Accelerant proc (if talented). Instead, you should use your instant cast abilities like Fireblast and Phoenix Flames. If you run out of instant abilities, cast Scorch instead since it's cast time is shorter."
/>
<Requirement
name="Combustion Active time"
Expand Down
20 changes: 20 additions & 0 deletions src/analysis/retail/mage/fire/SPELLS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,26 @@ const spells = {
name: 'Improved Scorch',
icon: 'ability_mage_fierypayback',
},
FLAME_ACCELERANT_BUFF: {
id: 203277,
name: 'Flame Accelerant',
icon: 'inv_ember',
},
LIVING_BOMB_TICK_DAMAGE: {
id: 217694,
name: 'Living Bomb',
icon: 'ability_mage_livingbomb',
},
LIVING_BOMB_EXPLODE_DAMAGE: {
id: 44461,
name: 'Living Bomb',
icon: 'ability_mage_livingbomb',
},
LIVING_BOMB_EXPLODE_DEBUFF: {
id: 244813,
name: 'Living Bomb',
icon: 'ability_mage_livingbomb',
},
} satisfies Record<string, Spell>;

export default spells;
36 changes: 19 additions & 17 deletions src/analysis/retail/mage/fire/core/Combustion.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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[] = [];
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -238,31 +243,28 @@ class CombustionCasts extends Analyzer {
</>,
)
.icon(TALENTS.COMBUSTION_TALENT.icon)
.actual(
<Trans id="mage.fire.suggestions.combustion.castDelay">
{formatNumber(actual)}s Avg. Pre-Cast Delay
</Trans>,
)
.actual(`${formatNumber(actual)}s Avg. Pre-Cast Delay`)
.recommended(`${recommended} is recommended`),
);
when(this.fireballDuringCombustionThresholds).addSuggestion((suggest, actual, recommended) =>
suggest(
<>
On average, you cast <SpellLink spell={SPELLS.FIREBALL} />{' '}
{this.fireballCastsDuringCombustion()} times ({actual.toFixed(2)} per Combustion), during{' '}
<SpellLink spell={TALENTS.COMBUSTION_TALENT} />. Combustion has a short duration, so you
are better off using instant abilities like <SpellLink spell={SPELLS.FIRE_BLAST} /> or{' '}
<SpellLink spell={TALENTS.PHOENIX_FLAMES_TALENT} />. If you run out of instant cast
abilities, use <SpellLink spell={SPELLS.SCORCH} /> instead of Fireball since it has a
shorter cast time.
<SpellLink spell={TALENTS.COMBUSTION_TALENT} />. In order to get the most casts (and{' '}
<SpellLink spell={SPELLS.HOT_STREAK} />
s) as possible before Combustion ends, you should use your instant abilities like
<SpellLink spell={SPELLS.FIRE_BLAST} /> or{' '}
<SpellLink spell={TALENTS.PHOENIX_FLAMES_TALENT} />. 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 <SpellLink spell={SPELLS.SCORCH} /> 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{' '}
<SpellLink spell={TALENTS.FLAME_ACCELERANT_TALENT} />.
</>,
)
.icon(TALENTS.COMBUSTION_TALENT.icon)
.actual(
<Trans id="mage.fire.suggestions.combustion.castsPerCombustion">
{this.fireballDuringCombustionThresholds.actual.toFixed(2)} Casts Per Combustion
</Trans>,
)
.actual(`${actual.toFixed(2)} Casts Per Combustion`)
.recommended(`${formatNumber(recommended)} is recommended`),
);
}
Expand Down
32 changes: 14 additions & 18 deletions src/analysis/retail/mage/fire/core/CombustionActiveTime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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() {
Expand All @@ -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{' '}
<SpellLink spell={TALENTS.COMBUSTION_TALENT} />
), not casting anything while <SpellLink spell={TALENTS.COMBUSTION_TALENT} /> was active.
Because a large portion of your damage comes from Combustion, you should ensure that you
Expand Down
Loading

0 comments on commit d7231ad

Please sign in to comment.