Skip to content

Commit

Permalink
[Augmentation] Fix some edgecases for Breath of Eons module (WoWAnaly…
Browse files Browse the repository at this point in the history
…zer#7108)

* only count debuff that have an associated remove event

* better calculation of dropped uptime

* resolve issue with mobs sharing HP

* update potions to TWW version

* changelog

* this should be +=
  • Loading branch information
Krealle authored Oct 4, 2024
1 parent 33be06d commit 5ef5a5d
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 23 deletions.
1 change: 1 addition & 0 deletions src/analysis/retail/evoker/augmentation/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { SpellLink } from 'interface';
import TALENTS from 'common/TALENTS/evoker';

export default [
change(date(2024, 10, 4), <>Fix some edgecases for <SpellLink spell={TALENTS.BREATH_OF_EONS_TALENT} /> module</>, Vollmer),
change(date(2024, 9, 16), "Update Buff Helper note gen for Frame Glows WA", Vollmer),
change(date(2024, 9, 10), "Update Ability Filters for Helper Modules for TWW S1", Vollmer),
change(date(2024, 9, 6), <>Implement <SpellLink spell={TALENTS.WINGLEADER_TALENT}/> module</>, Vollmer),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,23 @@ import Events, {
EmpowerEndEvent,
EventType,
GetRelatedEvents,
HasRelatedEvent,
RemoveBuffEvent,
RemoveDebuffEvent,
UpdateSpellUsableEvent,
UpdateSpellUsableType,
} from 'parser/core/Events';
import {
BREATH_EBON_APPLY_LINK,
BREATH_OF_EONS_DEBUFF_LINK,
EBON_MIGHT_BUFF_LINKS,
ebonIsFromBreath,
getBreathOfEonsBuffEvents,
getBreathOfEonsDamageEvents,
getBreathOfEonsDebuffApplyEvents,
} from '../normalizers/CastLinkNormalizer';
import SpellUsable from 'parser/shared/modules/SpellUsable';
import Spell from 'common/SPELLS/dragonflight/potions';
import Potions from 'common/SPELLS/thewarwithin/potions';
import BreathOfEonsSection from './BreathOfEonsSection';
import spells from 'common/SPELLS/dragonflight/trinkets';
import trinkets from 'common/ITEMS/dragonflight/trinkets';
Expand All @@ -43,6 +45,7 @@ type BreathWindowPerformance = {
temporalWoundsCounter: SpellTracker[];
ebonMightDroppedDuringBreath: boolean;
ebonMightDroppedDuration: number;
ebonMightDrops: number[];
ebonMightProblems: SpellTracker[];
possibleTrinkets: number;
trinketUsed: number;
Expand Down Expand Up @@ -136,7 +139,7 @@ class BreathOfEonsRotational extends Analyzer {
spells.MIRROR_OF_FRACTURED_TOMORROWS,
];

trackedPotions = [Spell.ELEMENTAL_POTION_OF_ULTIMATE_POWER, Spell.ELEMENTAL_POTION_OF_POWER];
trackedPotions = [Potions.TEMPERED_POTION];

foundTrinket = this.selectedCombatant.hasTrinket(trinkets.IRIDEUS_FRAGMENT.id)
? spells.IRIDEUS_FRAGMENT.id
Expand Down Expand Up @@ -259,7 +262,7 @@ class BreathOfEonsRotational extends Analyzer {
}
});

let potionReady = this.spellUsable.isAvailable(Spell.ELEMENTAL_POTION_OF_POWER.id) ? 1 : 0;
let potionReady = this.spellUsable.isAvailable(Potions.TEMPERED_POTION.id) ? 1 : 0;
let potionUsed = 0;
// Check if Potion was used pre-breath
this.trackedPotions.forEach((potion) => {
Expand Down Expand Up @@ -298,6 +301,7 @@ class BreathOfEonsRotational extends Analyzer {
temporalWoundsCounter: [],
ebonMightDroppedDuringBreath: false,
ebonMightDroppedDuration: 0,
ebonMightDrops: [],
possibleTrinkets: trinketReady,
trinketUsed: trinketUsed,
possiblePotions: potionReady,
Expand Down Expand Up @@ -374,8 +378,14 @@ class BreathOfEonsRotational extends Analyzer {
event.timestamp !== this.latestEbonMightEvent.timestamp &&
this.latestEbonMightDrop
) {
const droppedDuration = event.timestamp - this.latestEbonMightDrop.timestamp;
this.currentPerformanceBreathWindow.ebonMightDroppedDuration += droppedDuration;
const perfWindow = this.currentPerformanceBreathWindow;
const droppedUptime = perfWindow.ebonMightDrops.reduce(
(acc, timestamp) => acc + (event.timestamp - timestamp) / perfWindow.buffedPlayers.size,
0,
);

perfWindow.ebonMightDrops = [];
perfWindow.ebonMightDroppedDuration += droppedUptime;
}
this.latestEbonMightEvent = event;
this.ebonMightCount.push({ timestamp: event.timestamp, count: this.ebonMightCounter });
Expand All @@ -396,6 +406,7 @@ class BreathOfEonsRotational extends Analyzer {
this.latestEbonMightDrop = event;

const prevProblem = perfWindow.ebonMightProblems[perfWindow.ebonMightProblems.length - 1];
perfWindow.ebonMightDrops.push(event.timestamp);

const ebonMightProblem = {
timestamp: event.timestamp,
Expand Down Expand Up @@ -443,7 +454,9 @@ class BreathOfEonsRotational extends Analyzer {
this.currentBreathWindow.start = event.timestamp;
}

this.activeDebuffs = this.activeDebuffs + 1;
if (HasRelatedEvent(event, BREATH_OF_EONS_DEBUFF_LINK)) {
this.activeDebuffs = this.activeDebuffs + 1;
}

this.currentPerformanceBreathWindow.temporalWoundsCounter.push({
timestamp: event.timestamp,
Expand Down Expand Up @@ -487,18 +500,34 @@ class BreathOfEonsRotational extends Analyzer {
perfWindow.successfulHits += 1;
}

/** In 10.2 blizzard introduced *sparkles* delayed EM buffs *sparkles*
* so now we need to double check whether or not we actually found our buffed players */
if (this.currentPerformanceBreathWindow.buffedPlayers.size === 0) {
const currentBuffedTargets: Map<string, Combatant> = new Map();
const players = Object.values(this.combatants.players);
players.forEach((player) => {
if (player.hasBuff(SPELLS.EBON_MIGHT_BUFF_EXTERNAL.id)) {
currentBuffedTargets.set(player.name, player);
}
});
this.currentPerformanceBreathWindow.buffedPlayers = currentBuffedTargets;
}

if (
this.activeDebuffs === 0 &&
!BREATH_OF_EONS_SPELLS.some((spell) => this.selectedCombatant.hasBuff(spell.id))
) {
this.breathWindowActive = false;

const ebonMightDroppedDuringBreath = perfWindow.ebonMightDroppedDuringBreath;
const ebonMightDroppedDuration = perfWindow.ebonMightDroppedDuration;

if (ebonMightDroppedDuringBreath && ebonMightDroppedDuration === 0) {
const droppedUptime = event.timestamp - this.latestEbonMightDrop.timestamp;
perfWindow.ebonMightDroppedDuration = droppedUptime;
if (ebonMightDroppedDuringBreath && perfWindow.ebonMightDrops.length) {
const droppedUptime = perfWindow.ebonMightDrops.reduce(
(acc, timestamp) => acc + (event.timestamp - timestamp) / perfWindow.buffedPlayers.size,
0,
);

perfWindow.ebonMightDroppedDuration += droppedUptime;
}

breathWindow.breathPerformance = perfWindow;
Expand All @@ -520,19 +549,6 @@ class BreathOfEonsRotational extends Analyzer {
perfWindow.potentialLostDamage =
potentialDamagePerTarget * perfWindow.earlyDeaths * PRIO_MULTIPLIER;
}

/** In 10.2 blizzard introduced *sparkles* delayed EM buffs *sparkles*
* so now we need to double check whether or not we actually found our buffed players */
if (this.currentPerformanceBreathWindow.buffedPlayers.size === 0) {
const currentBuffedTargets: Map<string, Combatant> = new Map();
const players = Object.values(this.combatants.players);
players.forEach((player) => {
if (player.hasBuff(SPELLS.EBON_MIGHT_BUFF_EXTERNAL.id)) {
currentBuffedTargets.set(player.name, player);
}
});
this.currentPerformanceBreathWindow.buffedPlayers = currentBuffedTargets;
}
}

private finalize() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const EBON_MIGHT_APPLY_REMOVE_LINK = 'ebonMightApplyRemoveLink';
export const BREATH_OF_EONS_CAST_DEBUFF_APPLY_LINK = 'breathOfEonsCastDebuffApplyLink';
export const BREATH_OF_EONS_CAST_BUFF_LINK = 'breathOfEonsCastBuffLink';
export const BREATH_OF_EONS_DAMAGE_LINK = 'breathOfEonsDamageLink';
export const BREATH_OF_EONS_DEBUFF_LINK = 'breathOfEonsDebuffLink';

const ERUPTION_CAST_DAM_LINK = 'eruptionCastDamLink';
const ERUPTION_CHITIN_LINK = 'eruptionChitinLink';
Expand All @@ -57,6 +58,7 @@ const BREATH_EBON_BUFFER = 250;
const EBON_MIGHT_BUFFER = 150;
const BREATH_OF_EONS_DEBUFF_APPLY_BUFFER = 8000;
const BREATH_OF_EONS_BUFF_BUFFER = 8000;
const BREATH_OF_EONS_DEBUFF_BUFFER = 14000;
const BREATH_OF_EONS_DAMAGE_BUFFER = 100;
const PUPIL_OF_ALEXSTRASZA_BUFFER = 1000;
const UPHEAVAL_DAMAGE_BUFFER = 800;
Expand Down Expand Up @@ -150,6 +152,37 @@ const EVENT_LINKS: EventLink[] = [
anyTarget: false,
forwardBufferMs: BREATH_OF_EONS_DAMAGE_BUFFER,
},
/**
* So this is *slightly* cursed, but basically fixes an issue with mobs sharing HP eg. Silken Court.
* Essentially will just apply links backwards if no link is already present.
* example log:
* https://www.warcraftlogs.com/reports/zCvY2PKpHtd6MqAW#fight=4&type=auras&pins=0%24Separate%24%23244F4B%24damage%240%240.0.0.Any%24184027896.0.0.Evoker%24true%240.0.0.Any%24false%24409632&hostility=1&spells=debuffs&target=217&ability=409560&view=events&start=4819003&end=4837682
*/
{
linkRelation: BREATH_OF_EONS_DAMAGE_LINK,
reverseLinkRelation: BREATH_OF_EONS_DAMAGE_LINK,
linkingEventId: SPELLS.BREATH_OF_EONS_DAMAGE.id,
linkingEventType: EventType.Damage,
referencedEventId: SPELLS.TEMPORAL_WOUND_DEBUFF.id,
referencedEventType: EventType.RemoveDebuff,
anyTarget: true,
maximumLinks: 1,
backwardBufferMs: BREATH_OF_EONS_DAMAGE_BUFFER,
additionalCondition(linkingEvent, _referencedEvent) {
return !HasRelatedEvent(linkingEvent, BREATH_OF_EONS_DAMAGE_LINK);
},
},
{
linkRelation: BREATH_OF_EONS_DEBUFF_LINK,
reverseLinkRelation: BREATH_OF_EONS_DEBUFF_LINK,
linkingEventId: SPELLS.TEMPORAL_WOUND_DEBUFF.id,
linkingEventType: EventType.ApplyDebuff,
referencedEventId: SPELLS.TEMPORAL_WOUND_DEBUFF.id,
referencedEventType: EventType.RemoveDebuff,
anyTarget: false,
maximumLinks: 1,
forwardBufferMs: BREATH_OF_EONS_DEBUFF_BUFFER,
},
{
linkRelation: PUPIL_OF_ALEXSTRASZA_LINK,
reverseLinkRelation: PUPIL_OF_ALEXSTRASZA_LINK,
Expand Down

0 comments on commit 5ef5a5d

Please sign in to comment.