Skip to content

Commit

Permalink
Essence Burst abstraction (#3)
Browse files Browse the repository at this point in the history
* Abstract Essence Burst links to new shared file

* Fix missing isActive for PUPIL_OF_ALEXSTRASZA_TALENT cast link

* Move Preservations EBRefreshNormalizer to shared normalizers

* Update import for Preservation

* Update eventGeneratedEB call for Anachronism

* Update function calls for LeapingFlames

* add EssenceBurstCastLinkNormalizer to preservation so LeapingFlames module can function properly

* Update Deva EssenceBurstOrder normalizer to properly catch all leaping EBs

* remove EB_FROM_ARCANE_VIGOR link from deva specific normalizer

* rename EBRefreshNormalizer to EssenceBurstRefreshNormalizer

* Add EB_FROM links to Azure Strike and Emerald Trance

* Add the new castlinks to filter and update variable naming

* add some more documentation

* emerald trance produces first EB after 5seconds

* Emerald trance should take priority over Azure Strike

* jsdoc update

* change logic for leaping hits and pupil links so we can simplify dependencies

* simplify hasNoGenerationLink to make it more streamlined to add future sources
  • Loading branch information
Krealle authored Apr 7, 2024
1 parent 7ba2ceb commit 1d95f7a
Show file tree
Hide file tree
Showing 16 changed files with 411 additions and 244 deletions.
4 changes: 4 additions & 0 deletions src/analysis/retail/evoker/augmentation/CombatLogParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import T31Augmentation4P from './modules/dragonflight/T31Augmentation4P';
import {
LivingFlameNormalizer,
LivingFlamePrePullNormalizer,
EssenceBurstCastLinkNormalizer,
EssenceBurstRefreshNormalizer,
LeapingFlamesNormalizer,
LeapingFlames,
SpellEssenceCost,
Expand All @@ -57,6 +59,8 @@ class CombatLogParser extends MainCombatLogParser {
// Shared
livingFlameNormalizer: LivingFlameNormalizer,
livingFlamePrePullNormalizer: LivingFlamePrePullNormalizer,
essenceBurstRefreshNormalizer: EssenceBurstRefreshNormalizer,
essenceBurstCastLinkNormalizer: EssenceBurstCastLinkNormalizer,
leapingFlamesNormalizer: LeapingFlamesNormalizer,
leapingFlames: LeapingFlames,
spellEssenceCost: SpellEssenceCost,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import SPELLS from 'common/SPELLS/evoker';
import TALENTS from 'common/TALENTS/evoker';
import {
ApplyBuffEvent,
ApplyBuffStackEvent,
ApplyDebuffEvent,
CastEvent,
DamageEvent,
Expand All @@ -18,6 +17,8 @@ import {
import { Options } from 'parser/core/Module';
import EventLinkNormalizer, { EventLink } from 'parser/core/EventLinkNormalizer';
import { encodeEventTargetString } from 'parser/shared/modules/Enemies';
import PrePullCooldowns from 'parser/shared/normalizers/PrePullCooldowns';
import { LEAPING_FLAMES_HITS } from 'analysis/retail/evoker/shared/modules/normalizers/LeapingFlamesNormalizer';

/** So sometimes when Ebon Might should be extended
* it just kinda doesn't? This messes with our analysis so
Expand All @@ -34,8 +35,6 @@ export const BREATH_EBON_APPLY_LINK = 'breathEbonApplyLink';
export const EBON_MIGHT_BUFF_LINKS = 'ebonMightBuffLinks';
export const EBON_MIGHT_APPLY_REMOVE_LINK = 'ebonMightApplyRemoveLink';

export const EB_FROM_PRESCIENCE = 'ebFromPrescience';

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';
Expand Down Expand Up @@ -169,12 +168,18 @@ const EVENT_LINKS: EventLink[] = [
anyTarget: true,
maximumLinks: 1,
forwardBufferMs: PUPIL_OF_ALEXSTRASZA_BUFFER,
isActive(c) {
return c.hasTalent(TALENTS.PUPIL_OF_ALEXSTRASZA_TALENT);
},
additionalCondition(linkingEvent, referencedEvent) {
// No targets so we can't be sure which hit is the correct one, so we just claim it
if (!HasTarget(linkingEvent) && !HasTarget(referencedEvent)) {
return true;
}
return encodeEventTargetString(linkingEvent) !== encodeEventTargetString(referencedEvent);
return (
encodeEventTargetString(linkingEvent) !== encodeEventTargetString(referencedEvent) &&
!HasRelatedEvent(referencedEvent, LEAPING_FLAMES_HITS)
);
},
},
{
Expand All @@ -187,18 +192,6 @@ const EVENT_LINKS: EventLink[] = [
anyTarget: true,
forwardBufferMs: CAST_BUFFER_MS,
},
{
linkRelation: EB_FROM_PRESCIENCE,
reverseLinkRelation: EB_FROM_PRESCIENCE,
linkingEventId: TALENTS.PRESCIENCE_TALENT.id,
linkingEventType: EventType.Cast,
referencedEventId: SPELLS.ESSENCE_BURST_AUGMENTATION_BUFF.id,
referencedEventType: [EventType.ApplyBuff, EventType.ApplyBuffStack, EventType.RefreshBuff],
anyTarget: true,
forwardBufferMs: CAST_BUFFER_MS,
backwardBufferMs: CAST_BUFFER_MS,
maximumLinks: 1,
},
{
linkRelation: FAILED_EXTENSION_LINK,
reverseLinkRelation: FAILED_EXTENSION_LINK,
Expand Down Expand Up @@ -250,12 +243,12 @@ const EVENT_LINKS: EventLink[] = [
];

class CastLinkNormalizer extends EventLinkNormalizer {
// This is set to lower priority than default since
// We depend on prePullCooldowns since
// to create proper links on events fabricated using PrePullCooldownsNormalizer
// We need to ensure this runs after the PrePullCooldownsNormalizer
// We need to ensure this normalizer runs after the PrePullCooldownsNormalizer
// This is necessary if we want BreathOfEons module to function properly
// With pre-pull casts of Breath of Eons
priority = 100;
static dependencies = { ...EventLinkNormalizer.dependencies, prePullCooldowns: PrePullCooldowns };
constructor(options: Options) {
super(options, EVENT_LINKS);
}
Expand Down Expand Up @@ -329,16 +322,6 @@ export function ebonIsFromBreath(event: ApplyBuffEvent | CastEvent) {
return HasRelatedEvent(event, BREATH_EBON_APPLY_LINK);
}

export function generatedEssenceBurst(event: CastEvent) {
const maybeGenerate = GetRelatedEvent(
event,
EB_FROM_PRESCIENCE,
(e): e is ApplyBuffEvent | ApplyBuffStackEvent =>
e.type === EventType.ApplyBuff || e.type === EventType.ApplyBuffStack,
);
return Boolean(maybeGenerate);
}

export function failedEbonMightExtension(event: CastEvent | EmpowerEndEvent) {
return HasRelatedEvent(event, FAILED_EXTENSION_LINK);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { AnyEvent, EventType, HasRelatedEvent } from 'parser/core/Events';
import EventsNormalizer from 'parser/core/EventsNormalizer';
import { EBON_MIGHT_APPLY_REMOVE_LINK, EBON_MIGHT_BUFF_LINKS } from './CastLinkNormalizer';
import CastLinkNormalizer, {
EBON_MIGHT_APPLY_REMOVE_LINK,
EBON_MIGHT_BUFF_LINKS,
} from './CastLinkNormalizer';
import SPELLS from 'common/SPELLS/evoker';

/** This Normalizer fixes an issue that happens very rarely, where external Ebon Might
Expand All @@ -23,10 +26,9 @@ import SPELLS from 'common/SPELLS/evoker';
* */

class EbonMightNormalizer extends EventsNormalizer {
// Set lower priority to ensure this runs after our CastLinkNormalizer
priority = 101;
static dependencies = {
...EventsNormalizer.dependencies,
castLinkNormalizer: CastLinkNormalizer,
};
normalize(events: any[]): any[] {
const fixedEvents: any[] = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AnyEvent, EventType } from 'parser/core/Events';
import EventsNormalizer from 'parser/core/EventsNormalizer';
import { isFromTipTheScales } from './CastLinkNormalizer';
import CastLinkNormalizer, { isFromTipTheScales } from './CastLinkNormalizer';

/**
* Empowers cast with Tip the Scales doesn't produce an EmpowerEnd event, only Cast event
Expand All @@ -10,8 +10,10 @@ import { isFromTipTheScales } from './CastLinkNormalizer';
*/

class EmpowerNormalizer extends EventsNormalizer {
// Set lower priority to ensure this runs after our CastLinkNormalizer
priority = 101;
static dependencies = {
...EventsNormalizer.dependencies,
castLinkNormalizer: CastLinkNormalizer,
};
normalize(events: AnyEvent[]): AnyEvent[] {
const fixedEvents: any[] = [];
events.forEach((event) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AnyEvent, EventType, HasRelatedEvent } from 'parser/core/Events';
import TALENTS from 'common/TALENTS/evoker';
import EventsNormalizer from 'parser/core/EventsNormalizer';
import { PRESCIENCE_APPLY_REMOVE_LINK } from './CastLinkNormalizer';
import CastLinkNormalizer, { PRESCIENCE_APPLY_REMOVE_LINK } from './CastLinkNormalizer';
import Combatants from 'parser/shared/modules/Combatants';
import StatTracker from 'parser/shared/modules/StatTracker';
import {
Expand All @@ -20,10 +20,9 @@ import {
* like to include these in our analysis, so we need to create pre-pull events for it */

class PrescienceNormalizer extends EventsNormalizer {
// Set lower priority to ensure this runs after our CastLinkNormalizer
priority = 101;
static dependencies = {
...EventsNormalizer.dependencies,
castLinkNormalizer: CastLinkNormalizer,
combatants: Combatants,
stats: StatTracker,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import TALENTS from 'common/TALENTS/evoker';

import Analyzer, { Options, SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events, { CastEvent } from 'parser/core/Events';
import { generatedEssenceBurst } from '../normalizers/CastLinkNormalizer';
import { ANACHRONISM_ESSCENCE_CHANCE } from '../../constants';

import Statistic from 'parser/ui/Statistic';
Expand All @@ -12,6 +11,10 @@ import STATISTIC_ORDER from 'parser/ui/STATISTIC_ORDER';
import TalentSpellText from 'parser/ui/TalentSpellText';
import { SpellLink } from 'interface';
import { plotOneVariableBinomChart } from 'parser/shared/modules/helpers/Probability';
import {
EBSource,
eventGeneratedEB,
} from '../../../shared/modules/normalizers/EssenceBurstCastLinkNormalizer';

/**
* Prescience has a 35% chance to grant Essence Burst.
Expand All @@ -32,7 +35,7 @@ class Anachronism extends Analyzer {

onCast(event: CastEvent) {
this.prescienceCasts += 1;
if (generatedEssenceBurst(event)) {
if (eventGeneratedEB(event, EBSource.Prescience)) {
this.essenceBurstGenerated += 1;
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/analysis/retail/evoker/devastation/CombatLogParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import T31DevaTier from './modules/dragonflight/tier/T31DevaTier';
import {
LivingFlameNormalizer,
LivingFlamePrePullNormalizer,
EssenceBurstCastLinkNormalizer,
EssenceBurstRefreshNormalizer,
LeapingFlamesNormalizer,
LeapingFlames,
SpellEssenceCost,
Expand All @@ -53,6 +55,8 @@ class CombatLogParser extends MainCombatLogParser {
// Shared
livingFlameNormalizer: LivingFlameNormalizer,
livingFlamePrePullNormalizer: LivingFlamePrePullNormalizer,
essenceBurstRefreshNormalizer: EssenceBurstRefreshNormalizer,
essenceBurstCastLinkNormalizer: EssenceBurstCastLinkNormalizer,
leapingFlamesNormalizer: LeapingFlamesNormalizer,
leapingFlames: LeapingFlames,
spellEssenceCost: SpellEssenceCost,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export const SNAPFIRE_CONSUME = 'SnapfireConsumption';
export const IRIDESCENCE_RED_CONSUME = 'IridescentRedConsumption';
export const IRIDESCENCE_BLUE_CONSUME = 'IridescentBlueConsumption';
export const DISINTEGRATE_REMOVE_APPLY = 'DisintegrateRemoveApply';
export const EB_FROM_ARCANE_VIGOR = 'ebFromArcaneVigor';

const CAST_BUFFER_MS = 100;
const EVENT_LINKS: EventLink[] = [
Expand Down Expand Up @@ -115,24 +114,6 @@ const EVENT_LINKS: EventLink[] = [
referencedEventType: EventType.ApplyDebuff,
anyTarget: true,
},
{
linkRelation: EB_FROM_ARCANE_VIGOR,
reverseLinkRelation: EB_FROM_ARCANE_VIGOR,
linkingEventId: [SPELLS.SHATTERING_STAR.id],
linkingEventType: EventType.Cast,
referencedEventId: [
TALENTS_EVOKER.RUBY_ESSENCE_BURST_TALENT.id,
SPELLS.ESSENCE_BURST_DEV_BUFF.id,
],
referencedEventType: [EventType.ApplyBuff, EventType.ApplyBuffStack, EventType.RefreshBuff],
anyTarget: true,
forwardBufferMs: CAST_BUFFER_MS,
backwardBufferMs: CAST_BUFFER_MS,
maximumLinks: 1,
isActive(c) {
return c.hasTalent(TALENTS_EVOKER.ARCANE_VIGOR_TALENT);
},
},
];

class CastLinkNormalizer extends EventLinkNormalizer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import SPELLS from 'common/SPELLS/evoker';
import EventOrderNormalizer, { EventOrder } from 'parser/core/EventOrderNormalizer';
import { EventType } from 'parser/core/Events';
import { Options } from 'parser/core/Module';
import { EB_GENERATION_EVENT_TYPES } from '../../../shared/modules/normalizers/EssenceBurstCastLinkNormalizer';

const EVENT_ORDERS: EventOrder[] = [
{
beforeEventId: [SPELLS.SHATTERING_STAR.id, SPELLS.LIVING_FLAME_CAST.id],
beforeEventId: SPELLS.SHATTERING_STAR.id,
beforeEventType: EventType.Cast,
afterEventId: SPELLS.ESSENCE_BURST_DEV_BUFF.id,
afterEventType: [EventType.ApplyBuffStack, EventType.ApplyBuff, EventType.RefreshBuff],
afterEventType: EB_GENERATION_EVENT_TYPES,
bufferMs: 50,
anyTarget: true,
updateTimestamp: true,
Expand All @@ -19,10 +20,27 @@ const EVENT_ORDERS: EventOrder[] = [
* The applybuff from Arcane Vigor is logged before the cast of Shattering Star
* This also happens to Living Flames cast with Burnout
* This normalizes events so that the Shattering Star cast always comes before the EB buff
*
* EventOrderNormalizer only normalizes 1 instance per entry in the EventOrder array
* which means that abilities that can generate multiple EB at once, eg. Living Flame cast with
* Leaping Flames, will only have one event normalized, which can be non ideal. Therefore we will build
* an array with all the different types to make sure we get them all normalized.
**/
class EssenceBurstNormalizer extends EventOrderNormalizer {
constructor(options: Options) {
super(options, EVENT_ORDERS);

EB_GENERATION_EVENT_TYPES.forEach((ebApplyEventType) => {
EVENT_ORDERS.push({
beforeEventId: SPELLS.LIVING_FLAME_CAST.id,
beforeEventType: EventType.Cast,
afterEventId: SPELLS.ESSENCE_BURST_DEV_BUFF.id,
afterEventType: ebApplyEventType,
bufferMs: 50,
anyTarget: true,
updateTimestamp: true,
});
});
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/analysis/retail/evoker/preservation/CombatLogParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@ import {
LivingFlameNormalizer,
LivingFlamePrePullNormalizer,
LeapingFlamesNormalizer,
EssenceBurstRefreshNormalizer,
EssenceBurstCastLinkNormalizer,
LeapingFlames,
SpellEssenceCost,
EssenceTracker,
SourceOfMagic,
PotentMana,
} from '../shared';
import EBRefreshNormalizer from './normalizers/EBRefreshNormalizer';

class CombatLogParser extends CoreCombatLogParser {
static specModules = {
Expand All @@ -67,7 +68,8 @@ class CombatLogParser extends CoreCombatLogParser {
cooldowns: CooldownThroughputTracker,

// Normalizer
ebRefreshNormalizer: EBRefreshNormalizer,
essenceBurstCastLinkNormalizer: EssenceBurstCastLinkNormalizer,
essenceBurstRefreshNormalizer: EssenceBurstRefreshNormalizer,
livingFlameNormalizer: LivingFlameNormalizer,
castLinkNormalizer: CastLinkNormalizer,
hotApplicationNormalizer: HotApplicationNormalizer,
Expand Down
8 changes: 8 additions & 0 deletions src/analysis/retail/evoker/shared/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import SPELLS from 'common/SPELLS/evoker';

export const BASE_ESSENCE_REGEN = 0.2;

export const INNATE_MAGIC_REGEN = 0.05;
Expand All @@ -7,3 +9,9 @@ export const BASE_MAX_ESSENCE = 5;
export const POTENT_MANA_MULTIPLIER = 0.03;

export const BASE_EVOKER_RANGE = 25;

export const EB_BUFF_IDS = [
SPELLS.ESSENCE_BURST_BUFF.id,
SPELLS.ESSENCE_BURST_DEV_BUFF.id,
SPELLS.ESSENCE_BURST_AUGMENTATION_BUFF.id,
];
5 changes: 2 additions & 3 deletions src/analysis/retail/evoker/shared/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
export {
default as LeapingFlamesNormalizer,
eventGeneratedEB,
getGeneratedEBEvents,
isFromLeapingFlames,
getWastedEBEvents,
} from './modules/normalizers/LeapingFlamesNormalizer';
export { default as LivingFlameNormalizer } from './modules/normalizers/LivingFlameNormalizer';
export { default as EssenceBurstCastLinkNormalizer } from './modules/normalizers/EssenceBurstCastLinkNormalizer';
export { default as EssenceBurstRefreshNormalizer } from './modules/normalizers/EssenceBurstRefreshNormalizer';
export { default as LeapingFlames } from './modules/talents/LeapingFlames';
export { default as LivingFlamePrePullNormalizer } from './modules/normalizers/LivingFlamePrePullNormalizer';
export { default as SpellEssenceCost } from './modules/core/essence/SpellEssenceCost';
Expand Down
Loading

0 comments on commit 1d95f7a

Please sign in to comment.