Skip to content

Commit

Permalink
[Evoker] Update MajorDefensive module for Lifecinders & Hardened Scal…
Browse files Browse the repository at this point in the history
…es (WoWAnalyzer#7004)

* add Hardened Scales multiplier to ObsidianScales

* prevent innocent removebuff events from being removed

* update castlinks

* custom trigger to avoid external buff

* use generic getter everywhere

* update generic getter

* update structure to include partnerAmount

* show partner amount in CooldownDetails

* changelogs
  • Loading branch information
Krealle authored Sep 10, 2024
1 parent 767567c commit 4c34d83
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 60 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, 9, 6), <>Update MajorDefensive module for <SpellLink spell={TALENTS.LIFECINDERS_TALENT}/> and <SpellLink spell={TALENTS.HARDENED_SCALES_TALENT}/></>, Vollmer),
change(date(2024, 9, 6), <>Implement <SpellLink spell={TALENTS.SLIPSTREAM_TALENT}/> module</>, Vollmer),
change(date(2024, 9, 6), <>Implement <SpellLink spell={TALENTS.EXTENDED_BATTLE_TALENT}/> module</>, Vollmer),
change(date(2024, 8, 14), <>Implement <SpellLink spell={TALENTS.DIVERTED_POWER_TALENT}/> module</>, Vollmer),
Expand Down
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 @@ -5,6 +5,7 @@ import { TALENTS_EVOKER } from 'common/TALENTS/evoker';
import SPELLS from 'common/SPELLS/evoker';

export default [
change(date(2024, 9, 6), <>Update MajorDefensive module for <SpellLink spell={TALENTS_EVOKER.LIFECINDERS_TALENT}/> and <SpellLink spell={TALENTS_EVOKER.HARDENED_SCALES_TALENT}/></>, Vollmer),
change(date(2024, 9, 6), <>Implement <SpellLink spell={TALENTS_EVOKER.SLIPSTREAM_TALENT}/> module</>, Vollmer),
change(date(2024, 9, 6), <>Implement <SpellLink spell={TALENTS_EVOKER.EXTENDED_BATTLE_TALENT}/> module</>, Vollmer),
change(date(2024, 8, 14), <>Implement <SpellLink spell={TALENTS_EVOKER.DIVERTED_POWER_TALENT}/> module</>, Vollmer),
Expand Down
1 change: 1 addition & 0 deletions src/analysis/retail/evoker/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const IMMINENT_DESTRUCTION_ESSENCE_REDUCTION = 1;
export const MELT_ARMOR_MULTIPLIER = 0.2;
export const MIGHT_OF_THE_BLACK_DRAGONFLIGHT_MULTIPLIER = 0.2;
export const UNRELENTING_SIEGE_MULTIPLIER_PER_STACK = 0.01;
export const HARDENED_SCALES_MITIGATION = 0.1;

export const MASS_DISINTEGRATE_MULTIPLIER_PER_MISSING_TARGET = 0.15;
export const MASS_ERUPTION_MULTIPLIER_PER_MISSING_TARGET =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ import Events, { DamageEvent } from 'parser/core/Events';
import { SpellLink } from 'interface';
import MajorDefensiveStatistic from 'interface/MajorDefensiveStatistic';
import STATISTIC_CATEGORY from 'parser/ui/STATISTIC_CATEGORY';
import { HARDENED_SCALES_MITIGATION } from '../../constants';

// TWW ScaleCommander hero talent has a +5% buff so just preparing for that.
const BASE_MITIGATION = 0.3;
const HARDENED_SCALES_MITIGATION = 0.05;

class ObsidianScales extends MajorDefensiveBuff {
hasHardenedScales = false;
hasHardenedScales = this.selectedCombatant.hasTalent(TALENTS.HARDENED_SCALES_TALENT);
mitPct: number = BASE_MITIGATION + (this.hasHardenedScales ? HARDENED_SCALES_MITIGATION : 0);

constructor(options: Options) {
Expand All @@ -39,6 +38,13 @@ class ObsidianScales extends MajorDefensiveBuff {
return (
<p>
<SpellLink spell={TALENTS.OBSIDIAN_SCALES_TALENT} /> reduces the damage you take by 30%.
{this.hasHardenedScales && (
<>
<br />
<SpellLink spell={TALENTS.HARDENED_SCALES_TALENT} /> increases this mitigation to{' '}
<strong>{this.mitPct * 100}%</strong>.
</>
)}
</p>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import MajorDefensive, {
} from 'interface/guide/components/MajorDefensives/MajorDefensiveAnalyzer';
import { Options, SELECTED_PLAYER } from 'parser/core/Analyzer';
import TALENTS from 'common/TALENTS/evoker';
import SPELLS from 'common/SPELLS/evoker';
import Events, {
ApplyBuffEvent,
DamageEvent,
GetRelatedEvent,
GetRelatedEvents,
HealEvent,
} from 'parser/core/Events';
import { SpellLink } from 'interface';
Expand All @@ -35,34 +34,43 @@ import BoringValue from 'parser/ui/BoringValueText';
import MAGIC_SCHOOLS, { color } from 'game/MAGIC_SCHOOLS';
import { QualitativePerformance } from 'parser/ui/QualitativePerformance';
import { ReactNode } from 'react';
import {
RENEWING_BLAZE_BUFFS,
RENEWING_BLAZE_HEAL,
} from '../normalizers/DefensiveCastLinkNormalizer';
import { RENEWING_BLAZE_HEAL } from '../normalizers/DefensiveCastLinkNormalizer';

type RenewingBlazeHealBuff = {
start: ApplyBuffEvent;
events: HealEvent[];
amount: number;
overheal: number;
partnerAmount: number;
};

class RenewingBlaze extends MajorDefensiveBuff {
renewingBlazeHealBuffs: RenewingBlazeHealBuff[] = [];
normalizedMitigations: Mitigation[] = [];
hasCinders = false;

constructor(options: Options) {
super(TALENTS.RENEWING_BLAZE_TALENT, buff(TALENTS.RENEWING_BLAZE_TALENT), options);
// Custom trigger since we only want to track mitigation during our
// personal buffs, not any external ones
const trigger = buff(TALENTS.RENEWING_BLAZE_TALENT);
trigger.applyTrigger = Events.applybuff
.spell(TALENTS.RENEWING_BLAZE_TALENT)
.by(SELECTED_PLAYER)
.to(SELECTED_PLAYER);
trigger.removeTrigger = Events.removebuff
.spell(TALENTS.RENEWING_BLAZE_TALENT)
.by(SELECTED_PLAYER)
.to(SELECTED_PLAYER);

super(TALENTS.RENEWING_BLAZE_TALENT, trigger, options);
this.active = this.selectedCombatant.hasTalent(TALENTS.RENEWING_BLAZE_TALENT);

this.hasCinders = this.selectedCombatant.hasTalent(TALENTS.LIFECINDERS_TALENT);

this.addEventListener(Events.damage.to(SELECTED_PLAYER), this.recordDamage);

this.addEventListener(
Events.heal.to(SELECTED_PLAYER).spell(SPELLS.RENEWING_BLAZE_HEAL),
this.recordHeal,
);
this.addEventListener(
Events.applybuff.to(SELECTED_PLAYER).spell(SPELLS.RENEWING_BLAZE_HEAL),
this.applyHealBuff,
Events.applybuff.by(SELECTED_PLAYER).to(SELECTED_PLAYER).spell(TALENTS.RENEWING_BLAZE_TALENT),
this.applyBuff,
);
this.addEventListener(Events.fightend, this.onFightEnd);
}
Expand All @@ -78,29 +86,33 @@ class RenewingBlaze extends MajorDefensiveBuff {
});
}

private recordHeal(event: HealEvent) {
const heal = this.renewingBlazeHealBuffs.find(
(buff) => GetRelatedEvent(event, RENEWING_BLAZE_HEAL) === buff.start,
);
if (!heal) {
console.warn('Unable to find parent buff for Major Defensive analyzer', this.spell, event);
return;
private applyBuff(event: ApplyBuffEvent) {
const heal = {
start: event,
amount: 0,
overheal: 0,
partnerAmount: -1,
};
if (this.hasCinders) {
heal.partnerAmount = 0;
}

heal.events.push(event);
heal.amount += event.amount;
heal.overheal += event.overheal ?? 0;
}
const healEvents = GetRelatedEvents<HealEvent>(event, RENEWING_BLAZE_HEAL);
for (const healEvent of healEvents) {
if (healEvent.targetID !== this.selectedCombatant.id) {
heal.partnerAmount += healEvent.amount;
continue;
}

private applyHealBuff(event: ApplyBuffEvent) {
this.renewingBlazeHealBuffs.push({ start: event, events: [], amount: 0, overheal: 0 });
heal.amount += healEvent.amount;
heal.overheal += healEvent.overheal ?? 0;
}
this.renewingBlazeHealBuffs.push(heal);
}

/** Returns the related Renewing Healing buff, for our Acc buff. */
private healBuff(mit: Mitigation): RenewingBlazeHealBuff | undefined {
return this.renewingBlazeHealBuffs.find(
(buff) => GetRelatedEvent(buff.start, RENEWING_BLAZE_BUFFS) === mit.start,
);
private healBuff(mit: Mitigation | undefined): RenewingBlazeHealBuff | undefined {
return this.renewingBlazeHealBuffs.find((buff) => buff.start === mit?.start);
}

// For some reason healing numbers and damage taken doesn't always
Expand All @@ -119,9 +131,7 @@ class RenewingBlaze extends MajorDefensiveBuff {
}

mitigationSegments(mit: Mitigation): MitigationSegment[] {
const heal = this.renewingBlazeHealBuffs.find(
(buff) => GetRelatedEvent(buff.start, RENEWING_BLAZE_BUFFS) === mit.start,
);
const heal = this.healBuff(mit);

return [
{
Expand Down Expand Up @@ -321,9 +331,7 @@ class RenewingBlaze extends MajorDefensiveBuff {

get cooldownDetailsComponent() {
return ({ analyzer, mit }: CooldownDetailsProps) => {
const heal = this.renewingBlazeHealBuffs.find(
(buff) => GetRelatedEvent(buff.start, RENEWING_BLAZE_BUFFS) === mit?.start,
);
const heal = this.healBuff(mit);
return <CooldownDetails analyzer={analyzer} mit={mit} heal={heal} />;
};
}
Expand Down Expand Up @@ -402,6 +410,26 @@ const CooldownDetails = ({
/>
</TableSegmentContainer>
</tr>

{heal.partnerAmount >= 0 && (
<tr>
<td>Partner healing</td>
<NumericColumn>{formatNumber(heal.partnerAmount)}</NumericColumn>

<TableSegmentContainer>
<MitigationTooltipSegment
color="#4ec04e"
maxWidth={100}
width={Math.min(1, heal.partnerAmount / mit.amount)}
/>
<MitigationTooltipSegment
color="rgba(255, 255, 255, 0.05)"
maxWidth={100}
width={Math.max(0, 1 - heal.partnerAmount / mit.amount)}
/>
</TableSegmentContainer>
</tr>
)}
</>
) : (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ import { Options } from 'parser/core/Module';

export const OBSIDIAN_SCALES = 'obsidianScales'; // links cast to buff apply
export const RENEWING_BLAZE = 'renewingBlaze'; // links cast to buff apply
export const RENEWING_BLAZE_BUFFS = 'renewingBlazeBuffs'; // links acc & heal buffs
export const RENEWING_BLAZE_HEAL = 'renewingBlazeHeal'; // links heal buff and healing
const TWIN_GUARDIAN_PARTNER = 'twinGuardianPartner'; // links external and personal buffs

const CAST_BUFFER = 25;
/** Heal buff gets applied once you first take damage, so there is a non-zero chance it won't apply
* till very late into the acc buff */
const RENEWING_BLAZE_BUFF_BUFFER = 10_000;
/** Heal buff can get applied immediately on use, and keeps getting refreshed on damage until
* main acc buff runs out, so we set this high to make sure we catch all. */
const RENEWING_BLAZE_DURATION = 25_000;
Expand All @@ -37,29 +33,19 @@ const EVENT_LINKS: EventLink[] = [
linkingEventType: EventType.ApplyBuff,
referencedEventId: TALENTS.RENEWING_BLAZE_TALENT.id,
referencedEventType: EventType.Cast,
anyTarget: true, // TODO: Revisit in TWW - Flame shaper can share RB
anyTarget: true,
forwardBufferMs: CAST_BUFFER,
backwardBufferMs: CAST_BUFFER,
},
{
linkRelation: RENEWING_BLAZE_BUFFS,
reverseLinkRelation: RENEWING_BLAZE_BUFFS,
linkingEventId: TALENTS.RENEWING_BLAZE_TALENT.id,
linkingEventType: EventType.ApplyBuff,
referencedEventId: SPELLS.RENEWING_BLAZE_HEAL.id,
referencedEventType: EventType.ApplyBuff,
anyTarget: true, // TODO: Revisit in TWW - Flameshaper can share RB
forwardBufferMs: RENEWING_BLAZE_BUFF_BUFFER,
maximumLinks: 1,
},
{
linkRelation: RENEWING_BLAZE_HEAL,
reverseLinkRelation: RENEWING_BLAZE_HEAL,
linkingEventId: SPELLS.RENEWING_BLAZE_HEAL.id,
linkingEventId: TALENTS.RENEWING_BLAZE_TALENT.id,
linkingEventType: EventType.ApplyBuff,
referencedEventId: SPELLS.RENEWING_BLAZE_HEAL.id,
referencedEventType: EventType.Heal,
anyTarget: true,
anySource: false, // We only want to be tracking our own Buffs, not any external ones
forwardBufferMs: RENEWING_BLAZE_DURATION,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,26 @@ class DefensiveNormalizer extends EventsNormalizer {
continue;
}

const targetID = event.targetID ?? 0; // You never know
if (event.type === EventType.ApplyBuff) {
// fake apply don't push
if (!HasRelatedEvent(event, castLink)) {
continue;
}

// on new "real" apply we push in our last removeBuffEvent
const hasStoredEnd = latestBuffRemoveEvents.get(spellId);
const hasStoredEnd = latestBuffRemoveEvents.get(spellId + targetID);
if (hasStoredEnd) {
fixedEvents.push(hasStoredEnd);
latestBuffRemoveEvents.delete(spellId);
latestBuffRemoveEvents.delete(spellId + targetID);
}
fixedEvents.push(event);
continue;
}

if (event.type === EventType.RemoveBuff) {
// store the latests event so we only push the latests one
latestBuffRemoveEvents.set(spellId, event);
latestBuffRemoveEvents.set(spellId + targetID, event);
continue;
}
}
Expand Down

0 comments on commit 4c34d83

Please sign in to comment.