Skip to content

Commit

Permalink
[Devastation] Season 4 prep (WoWAnalyzer#6732)
Browse files Browse the repository at this point in the history
* Remove Empower hack since we now have normalized Empowers

* Fix timeline for guide section and use proper EB SpellLink

* Rename T30 module and make active with S4 tier

* Update Essence Burst SpellLink for No Wasted Procs section

* Add Blazing Shards to Buffs

* changelog
  • Loading branch information
Krealle authored Apr 21, 2024
1 parent 5d35642 commit 7049d61
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 49 deletions.
1 change: 1 addition & 0 deletions src/analysis/retail/evoker/devastation/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import SPELLS from 'common/SPELLS/evoker';
import RESOURCE_TYPES from 'game/RESOURCE_TYPES';

export default [
change(date(2024, 4, 19), 'Update modules for 10.2.6', Vollmer),
change(date(2024, 4, 6), 'Normalize Empower behavior to make analysis more consistent.', Vollmer),
change(date(2024, 4, 1), <>Added analysis for <SpellLink spell={TALENTS.RENEWING_BLAZE_TALENT} />, <SpellLink spell={TALENTS.OBSIDIAN_SCALES_TALENT} /> and <SpellLink spell={TALENTS.TWIN_GUARDIAN_TALENT} />.</>, Vollmer),
change(date(2024, 3, 30), <>Fix prepull <SpellLink spell={SPELLS.LIVING_FLAME_CAST} /> casts to properly display channel time.</>, Vollmer),
Expand Down
4 changes: 2 additions & 2 deletions src/analysis/retail/evoker/devastation/CombatLogParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import DragonRage from './modules/abilities/DragonRage';
import CastLinkNormalizer from './modules/normalizers/CastLinkNormalizer';
import EssenceBurstNormalizer from './modules/normalizers/EssenceBurstNormalizer';
import Snapfire from './modules/abilities/Snapfire';
import T30DevaTier4P from './modules/dragonflight/tier/T30DevaTier4P';
import T30DevaTier from './modules/dragonflight/tier/T30DevaTier';
import CooldownThroughputTracker from './modules/features/CooldownThroughputTracker';
import Catalyze from './modules/talents/Catalyze';
import Scintillation from './modules/talents/Scintillation';
Expand Down Expand Up @@ -111,7 +111,7 @@ class CombatLogParser extends MainCombatLogParser {
dragonRage: DragonRage,

// tier
T30devaTier4P: T30DevaTier4P,
T30devaTier: T30DevaTier,
T31devaTier: T31DevaTier,
};

Expand Down
5 changes: 5 additions & 0 deletions src/analysis/retail/evoker/devastation/modules/Buffs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ class Buffs extends CoreAuras {
timelineHighlight: true,
enabled: combatant.has4PieceByTier(TIERS.DF3),
},
{
spellId: SPELLS.BLAZING_SHARDS.id,
timelineHighlight: true,
enabled: combatant.has4PieceByTier(TIERS.DF2) || combatant.has4PieceByTier(TIERS.DF4),
},
// Defensive
{
spellId: TALENTS.OBSIDIAN_SCALES_TALENT.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Analyzer, { Options, SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events, {
ApplyBuffEvent,
CastEvent,
EmpowerEndEvent,
FightEndEvent,
RemoveBuffEvent,
} from 'parser/core/Events';
Expand All @@ -17,7 +18,7 @@ const {
ESSENCE_BURST_DEV_BUFF,
} = SPELLS;

const { DRAGONRAGE_TALENT, RUBY_ESSENCE_BURST_TALENT, PYRE_TALENT } = TALENTS_EVOKER;
const { DRAGONRAGE_TALENT, PYRE_TALENT } = TALENTS_EVOKER;

export type RageWindowCounter = {
start: number;
Expand Down Expand Up @@ -60,9 +61,7 @@ class DragonRage extends Analyzer {
});

this.addEventListener(
Events.applybuff
.by(SELECTED_PLAYER)
.spell([ESSENCE_BURST_DEV_BUFF, RUBY_ESSENCE_BURST_TALENT]),
Events.applybuff.by(SELECTED_PLAYER).spell(ESSENCE_BURST_DEV_BUFF),
() => {
if (!this.inDragonRageWindow) {
return;
Expand All @@ -80,10 +79,18 @@ class DragonRage extends Analyzer {
this.currentRageWindow.disintegrateTicks += 1;
});

this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(PYRE_TALENT), () => {
if (!this.inDragonRageWindow) {
return;
}

this.currentRageWindow.pyres += 1;
});

this.addEventListener(
Events.cast
Events.empowerEnd
.by(SELECTED_PLAYER)
.spell([FIRE_BREATH, FIRE_BREATH_FONT, ETERNITY_SURGE, ETERNITY_SURGE_FONT, PYRE_TALENT]),
.spell([FIRE_BREATH, FIRE_BREATH_FONT, ETERNITY_SURGE, ETERNITY_SURGE_FONT]),
(event) => {
this.onEmpowerCast(event);
},
Expand Down Expand Up @@ -111,20 +118,9 @@ class DragonRage extends Analyzer {
return;
}
this.rageWindowCounters[this.totalCasts].end = event.timestamp;
// Janky solution to fix statistics window outputting more empower cast than actually occoured inside of DR window
// Still shows the spell in windowed timeline
// TODO: Proper solution would be to change empower logic all together so this doesn't happen in the first place
if ((this.currentRageWindow.end - this.currentRageWindow.start) / 1000 < 35) {
if (this.currentRageWindow.fireBreaths > 2) {
this.currentRageWindow.fireBreaths = 2;
}
if (this.currentRageWindow.eternitySurges > 2) {
this.currentRageWindow.eternitySurges = 2;
}
}
}

onEmpowerCast(event: CastEvent) {
onEmpowerCast(event: CastEvent | EmpowerEndEvent) {
if (!this.inDragonRageWindow) {
return;
}
Expand All @@ -136,9 +132,6 @@ class DragonRage extends Analyzer {
case ETERNITY_SURGE.name:
this.currentRageWindow.eternitySurges += 1;
break;
case PYRE_TALENT.name:
this.currentRageWindow.pyres += 1;
break;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type BlazeShardCounters = {
extraDamageProvided: number;
};

class T30DevaTier4P extends Analyzer {
class T30DevaTier extends Analyzer {
inDragonRageWindow: boolean = false;
totalLostUptime: number = 0;
totalCasts: number = 0;
Expand All @@ -51,10 +51,13 @@ class T30DevaTier4P extends Analyzer {
};

windowEntries: BoxRowEntry[] = [];
has4Piece = this.selectedCombatant.has4PieceByTier(TIERS.DF4);

constructor(options: Options) {
super(options);
this.active = this.selectedCombatant.has2PieceByTier(TIERS.DF2);
this.active =
this.selectedCombatant.has2PieceByTier(TIERS.DF2) ||
this.selectedCombatant.has2PieceByTier(TIERS.DF4);

this.addEventListener(Events.damage.by(SELECTED_PLAYER).spell(OBSIDIAN_SHARDS), (event) => {
this.onObsidianShardsDamage(event);
Expand Down Expand Up @@ -267,13 +270,13 @@ class T30DevaTier4P extends Analyzer {
color: qualitativePerformanceToColor(QualitativePerformance.Good),
},
{
label: 'Buff overriden with <0.5s left',
label: 'Buff overridden with <0.5s left',
value: ok,
valueTooltip: ok + ' empower casts',
color: qualitativePerformanceToColor(QualitativePerformance.Ok),
},
{
label: 'Buff overriden with >0.5s left',
label: 'Buff overridden with >0.5s left',
value: fail,
valueTooltip: fail + ' empower casts',
color: qualitativePerformanceToColor(QualitativePerformance.Fail),
Expand All @@ -287,7 +290,7 @@ class T30DevaTier4P extends Analyzer {
statistic() {
const damageFrom4Set =
this.obsidianShardsDamDuringBlazing - this.obsidianShardsDamDuringBlazing / 3;
const has4Piece = this.selectedCombatant.has4PieceByTier(TIERS.DF2);

return (
<Statistic
position={STATISTIC_ORDER.OPTIONAL(5)}
Expand All @@ -299,7 +302,7 @@ class T30DevaTier4P extends Analyzer {
<SpellLink spell={OBSIDIAN_SHARDS} /> damage:{' '}
{formatNumber(this.obsidianShardsDam - damageFrom4Set)}
</li>
{has4Piece && (
{this.has4Piece && (
<>
<li>
Wasted <SpellLink spell={BLAZING_SHARDS} /> uptime:{' '}
Expand All @@ -318,7 +321,7 @@ class T30DevaTier4P extends Analyzer {
<BoringValueText label="Obsidian Secrets (T30 Set Bonus)">
<h4>2 Piece</h4>
<ItemDamageDone amount={this.obsidianShardsDam - damageFrom4Set} />
{has4Piece && (
{this.has4Piece && (
<>
<h4>4 Piece</h4>
<ItemDamageDone amount={damageFrom4Set} />
Expand All @@ -330,4 +333,4 @@ class T30DevaTier4P extends Analyzer {
}
}

export default T30DevaTier4P;
export default T30DevaTier;
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ function NoWastedProcsSubsection({ modules, info }: GuideProps<typeof CombatLogP
explanationPercent={EXPLANATION_PERCENTAGE}
explanation={
<p>
<SpellLink spell={TALENTS_EVOKER.RUBY_ESSENCE_BURST_TALENT} /> procs are essential
because they help you cast your primary damaging spells,
<SpellLink spell={SPELLS.ESSENCE_BURST_BUFF} /> procs are essential because they help
you cast your primary damaging spells,
<SpellLink spell={SPELLS.DISINTEGRATE} /> and{' '}
<SpellLink spell={TALENTS_EVOKER.PYRE_TALENT} />, for free. None should go to waste.
</p>
Expand Down Expand Up @@ -243,7 +243,7 @@ function ShatteringStarSubsection({ modules, info }: GuideProps<typeof CombatLog
}

function BlazeShardsSubsection({ modules, info }: GuideProps<typeof CombatLogParser>) {
if (!info.combatant.has4PieceByTier(TIERS.DF2)) {
if (!info.combatant.has4PieceByTier(TIERS.DF2) && !info.combatant.has4PieceByTier(TIERS.DF4)) {
return null;
}

Expand All @@ -260,7 +260,7 @@ function BlazeShardsSubsection({ modules, info }: GuideProps<typeof CombatLogPar
to maximize uptime of <SpellLink spell={SPELLS.BLAZING_SHARDS} />.
</p>
<p>
Total uptime lost is: <strong>{modules.T30devaTier4P.lostUptime.toFixed(2)}s</strong>.
Total uptime lost is: <strong>{modules.T30devaTier.lostUptime.toFixed(2)}s</strong>.
</p>
<ExplanationAndDataSubSection
explanationPercent={EXPLANATION_PERCENTAGE}
Expand All @@ -269,13 +269,13 @@ function BlazeShardsSubsection({ modules, info }: GuideProps<typeof CombatLogPar
<strong>Buff breakdown</strong>
<small> Try not to override Blazing Shards!</small>

<PerformanceBoxRow values={modules.T30devaTier4P.windowEntries} />
<PerformanceBoxRow values={modules.T30devaTier.windowEntries} />
</RoundedPanel>
}
data={
<div>
<strong>Summary</strong>
<DonutChart items={modules.T30devaTier4P.donutItems} />
<DonutChart items={modules.T30devaTier.donutItems} />
</div>
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ export function DragonRageSection({ modules, events, info }: GuideProps<typeof C
contributes to a large portion of your DPS. Because this window gives us our mastery{' '}
<SpellLink spell={SPELLS.GIANT_SLAYER_MASTERY} /> with{' '}
<SpellLink spell={TALENTS_EVOKER.TYRANNY_TALENT} /> and guaranteed{' '}
<SpellLink spell={TALENTS_EVOKER.RUBY_ESSENCE_BURST_TALENT} /> procs, we need to utilize the
talent <SpellLink spell={TALENTS_EVOKER.ANIMOSITY_TALENT} /> to extend the buff duration as
long as possible. We do this by trying to get in more than 2 rounds of{' '}
<SpellLink spell={SPELLS.ESSENCE_BURST_DEV_BUFF} /> procs, we need to utilize the talent{' '}
<SpellLink spell={TALENTS_EVOKER.ANIMOSITY_TALENT} /> to extend the buff duration as long as
possible. We do this by trying to get in more than 2 rounds of{' '}
<SpellLink spell={TALENTS_EVOKER.ETERNITY_SURGE_TALENT} /> and{' '}
<SpellLink spell={SPELLS.FIRE_BREATH} /> by making the most of the talents:{' '}
<SpellLink spell={TALENTS_EVOKER.CAUSALITY_TALENT} /> and{' '}
<SpellLink spell={TALENTS_EVOKER.TIP_THE_SCALES_TALENT} />.
</p>
<p>
To generate <SpellLink spell={TALENTS_EVOKER.RUBY_ESSENCE_BURST_TALENT} /> procs inside of{' '}
To generate <SpellLink spell={SPELLS.ESSENCE_BURST_DEV_BUFF} /> procs inside of{' '}
<SpellLink spell={TALENTS_EVOKER.DRAGONRAGE_TALENT} /> you should be casting{' '}
<SpellLink spell={SPELLS.LIVING_FLAME_CAST} /> with{' '}
<SpellLink spell={SPELLS.BURNOUT_BUFF} /> or <SpellLink spell={SPELLS.IRIDESCENCE_RED} /> or{' '}
Expand All @@ -45,7 +45,7 @@ export function DragonRageSection({ modules, events, info }: GuideProps<typeof C

<SubSection title="Extension Limits">
<p>
You can gaurantee <strong>at least 2 casts</strong> of{' '}
You can guarantee <strong>at least 2 casts</strong> of{' '}
<SpellLink spell={SPELLS.FIRE_BREATH} /> and{' '}
<SpellLink spell={TALENTS_EVOKER.ETERNITY_SURGE_TALENT} /> by holding them if{' '}
<SpellLink spell={TALENTS_EVOKER.DRAGONRAGE_TALENT} /> is coming up in less than 13s.
Expand All @@ -57,10 +57,7 @@ export function DragonRageSection({ modules, events, info }: GuideProps<typeof C
.filter(isApplicableEvent(info?.playerId ?? 0))
.filter(
(event) =>
event.timestamp &&
event.timestamp >= window.start &&
event.timestamp <= window.end &&
event.type === 'cast',
event.timestamp && event.timestamp >= window.start && event.timestamp <= window.end,
);

if (relevantEvents.length === 0) {
Expand Down Expand Up @@ -88,7 +85,6 @@ export function DragonRageSection({ modules, events, info }: GuideProps<typeof C
<SpellTimeline>
<Casts
start={relevantEvents[0].timestamp}
movement={undefined}
secondWidth={60}
events={relevantEvents}
/>
Expand All @@ -115,8 +111,7 @@ function Statistics({ window }: { window: RageWindowCounter }) {
<SpellLink spell={SPELLS.ETERNITY_SURGE} /> - {window.eternitySurges}/2 casts
</li>
<li>
<SpellLink spell={TALENTS_EVOKER.RUBY_ESSENCE_BURST_TALENT} /> - {window.essenceBursts}{' '}
casts
<SpellLink spell={SPELLS.ESSENCE_BURST_DEV_BUFF} /> - {window.essenceBursts} casts
</li>
<li>
<SpellLink spell={SPELLS.DISINTEGRATE} /> - {window.disintegrateTicks} ticks
Expand Down

0 comments on commit 7049d61

Please sign in to comment.