Skip to content

Commit

Permalink
feat: attribute binding heals and trail of light healing to lightweav…
Browse files Browse the repository at this point in the history
…er (WoWAnalyzer#7148)

* attribute trail and binding to lightweaver heals

* attribute trail and binding to lightweaver heals

* attribute trail and binding to lightweaver heals

* changelog
  • Loading branch information
fel1n3 authored Oct 24, 2024
1 parent cb05e7c commit 9b32736
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 31 deletions.
1 change: 1 addition & 0 deletions src/analysis/retail/priest/holy/CHANGELOG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Arlie, Hana, Litena, Liavre, Squided, ToppleTheNun, Trevor, Saeldur, xi
import { SpellLink } from 'interface';

export default [
change(date(2024, 10, 20), <>Implement <SpellLink spell={SPELLS.TRAIL_OF_LIGHT_TALENT_HEAL}/> and <SpellLink spell={SPELLS.BINDING_HEALS_TALENT_HEAL}/> healing to Lightweaver module.</>, fel1ne),
change(date(2024, 10, 17), <>Fixed an issue where <SpellLink spell={SPELLS.LIGHTWEAVER_TALENT_BUFF}/> buffed heals were incorrectly flagged as a bad cast if the buff was not consumed due to a bug. </>, fel1ne),
change(date(2024, 10, 11), <>Fixed Prayer of Healing in the Guide section to not give bad advice.</>, Liavre),
change(date(2024, 10, 7), <>Properly hide Circle of Healing analysis if it isn't talented.</>, xizbow),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import ItemHealingDone from 'parser/ui/ItemHealingDone';
import BoringSpellValueText from 'parser/ui/BoringSpellValueText';
import { SpellLink } from 'interface';
import { calculateEffectiveHealing, calculateOverhealing } from 'parser/core/EventCalculateLib';
import { getHeal } from '../../../normalizers/CastLinkNormalizer';
import {
getBindingFromHeal,
getHeal,
getTrailFromHeal,
} from '../../../normalizers/CastLinkNormalizer';
import { explanationAndDataSubsection } from 'interface/guide/components/ExplanationRow';
import { GUIDE_CORE_EXPLANATION_PERCENT } from '../../../Guide';
import GradiatedPerformanceBar from 'interface/guide/components/GradiatedPerformanceBar';
Expand All @@ -19,18 +23,20 @@ import ItemPercentHealingDone from 'parser/ui/ItemPercentHealingDone';

/**
* Flash Heal reduces the cast time of your next Heal
* within 20 sec by 30% and increases its healing done by 15%.
* within 20 sec by 30% and increases its healing done by 25%.
*
* Stacks up to 2 times.
*/

type HealingSources = 'trailHealing' | 'bindingHealing' | 'healHealing';

//Example log: /report/kVQd4LrBb9RW2h6K/9-Heroic+The+Primal+Council+-+Wipe+5+(5:04)/Delipriest/standard/statistics
class Lightweaver extends Analyzer {
static dependencies = {
eolAttrib: EOLAttrib,
};
protected eolAttrib!: EOLAttrib;
healingDoneFromTalent = 0;

overhealingDoneFromTalent = 0;

totalHealCasts = 0;
Expand All @@ -41,8 +47,16 @@ class Lightweaver extends Analyzer {
wastedBuffFlashHealCasts = 0;
highOverhealFlashHealCasts = 0;

trailHealing: number = 0;
bindingHealing: number = 0;
healHealing = 0;

eolContrib = 0;

get totalHealing() {
return this.healHealing + this.eolContrib + this.trailHealing + this.bindingHealing;
}

constructor(options: Options) {
super(options);

Expand All @@ -68,25 +82,42 @@ class Lightweaver extends Analyzer {
return (event.overheal || 0) / rawHealing >= LW_OVERHEAL_THRESHOLD;
}

private calculateHealing(healEvent: HealEvent, castEvent: CastEvent) {
const events: [HealingSources, HealEvent | undefined][] = [
['trailHealing', getTrailFromHeal(castEvent)],
['bindingHealing', getBindingFromHeal(castEvent)],
['healHealing', healEvent],
];

//iterate through each source of lightweaver healing. (trail, binding, heal)
events.forEach(([key, event]) => {
if (event) {
this[key] += calculateEffectiveHealing(event, LW_HEALING_BONUS);
this.eolContrib += this.eolAttrib.getEchoOfLightAmpAttrib(event, LW_HEALING_BONUS);
this.overhealingDoneFromTalent += calculateOverhealing(event, LW_HEALING_BONUS);
}
});
}

onHealCast(event: CastEvent) {
// linked heal event exists
const healEvent = getHeal(event);
if (healEvent) {
this.totalHealCasts += 1;
if (this.selectedCombatant.hasBuff(SPELLS.LIGHTWEAVER_TALENT_BUFF)) {
// calculate effective healing from bonus
this.healingDoneFromTalent += calculateEffectiveHealing(healEvent, LW_HEALING_BONUS);
this.eolContrib += this.eolAttrib.getEchoOfLightAmpAttrib(healEvent, LW_HEALING_BONUS);
this.overhealingDoneFromTalent = calculateOverhealing(healEvent, LW_HEALING_BONUS);
} else {
this.unbuffedHealCasts += 1;
// return early so we are not counting unbuffed heals for high overheal count
return;
}
if (!healEvent) {
return;
}

if (this.isHighOverheal(healEvent)) {
this.highOverhealHealCasts += 1;
}
this.totalHealCasts += 1;

if (!this.selectedCombatant.hasBuff(SPELLS.LIGHTWEAVER_TALENT_BUFF)) {
this.unbuffedHealCasts += 1;
// return early so we are not counting unbuffed heals for high overheal count
return;
}

this.calculateHealing(healEvent, event);

if (this.isHighOverheal(healEvent)) {
this.highOverhealHealCasts += 1;
}
}

Expand Down Expand Up @@ -201,7 +232,10 @@ class Lightweaver extends Analyzer {
statistic() {
const overhealingTooltipString = formatPercentage(
this.overhealingDoneFromTalent /
(this.healingDoneFromTalent + this.overhealingDoneFromTalent),
(this.healHealing +
this.trailHealing +
this.bindingHealing +
this.overhealingDoneFromTalent),
);

return (
Expand All @@ -212,33 +246,32 @@ class Lightweaver extends Analyzer {
<>
{`${overhealingTooltipString}% overhealing`} <br />
<br />
<div>Breakdown: </div>
<div>Breakdown:</div>
<div>
<SpellLink spell={TALENTS_PRIEST.LIGHTWEAVER_TALENT} />:{' '}
<ItemPercentHealingDone amount={this.healingDoneFromTalent}></ItemPercentHealingDone>{' '}
<ItemPercentHealingDone amount={this.healHealing} />{' '}
</div>
<div>
<SpellLink spell={SPELLS.ECHO_OF_LIGHT_MASTERY} />:{' '}
<ItemPercentHealingDone amount={this.eolContrib}></ItemPercentHealingDone> <br />
<ItemPercentHealingDone amount={this.eolContrib} /> <br />
</div>
<div>
<SpellLink spell={SPELLS.TRAIL_OF_LIGHT_TALENT_HEAL} />:{' '}
<ItemPercentHealingDone amount={this.trailHealing} /> <br />
</div>
<br />
<div>
Notably this module currently is missing the contributions to{' '}
<SpellLink spell={TALENTS_PRIEST.BINDING_HEALS_TALENT} /> and{' '}
<SpellLink spell={TALENTS_PRIEST.TRAIL_OF_LIGHT_TALENT} />, which can undervalue it.
<SpellLink spell={SPELLS.BINDING_HEALS_TALENT_HEAL} />:{' '}
<ItemPercentHealingDone amount={this.bindingHealing} /> <br />
</div>
</>
}
>
<BoringSpellValueText spell={TALENTS.LIGHTWEAVER_TALENT}>
<div>
<ItemHealingDone amount={this.healingDoneFromTalent + this.eolContrib} />{' '}
<small> from just the heal amp</small>
<ItemHealingDone amount={this.totalHealing} /> <small> from just the heal amp</small>
</div>
<div>
<ItemHealingDone
amount={(this.healingDoneFromTalent + this.eolContrib) / LW_CAST_TIME_DECREASE}
/>{' '}
<ItemHealingDone amount={this.totalHealing / LW_CAST_TIME_DECREASE} />{' '}
<small> from both the heal amp and doing that healing in less time</small>
</div>
</BoringSpellValueText>
Expand Down
30 changes: 30 additions & 0 deletions src/analysis/retail/priest/holy/normalizers/CastLinkNormalizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export const BENEDICTION_RENEW_HEALS = 'BenedictionRenewHeal';
export const REVIT_PRAYER_RENEW = 'RevitalizingPrayersRenew';
export const HARDCAST_RENEW = 'HardCastRenew';
export const HOLY_TWW_S1_4PC = 'HolyTwwS14pc';
export const HEAL_TRAIL = 'LightweaverTrail';
export const HEAL_BINDING = 'LightweaverBinding';

const EVENT_LINKS: EventLink[] = [
// Link single target heal casts to their heal events.
Expand Down Expand Up @@ -314,6 +316,26 @@ const EVENT_LINKS: EventLink[] = [
backwardBufferMs: CAST_BUFFER_MS,
anyTarget: true,
},
// link heals to trail
{
linkRelation: HEAL_TRAIL,
linkingEventId: SPELLS.GREATER_HEAL.id,
linkingEventType: EventType.Cast,
referencedEventId: SPELLS.TRAIL_OF_LIGHT_TALENT_HEAL.id,
referencedEventType: EventType.Heal,
forwardBufferMs: CAST_BUFFER_MS,
anyTarget: true,
},
// link lightweaver heals to binding heal
{
linkRelation: HEAL_BINDING,
linkingEventId: SPELLS.GREATER_HEAL.id,
linkingEventType: EventType.Cast,
referencedEventId: SPELLS.BINDING_HEALS_TALENT_HEAL.id,
referencedEventType: EventType.Heal,
forwardBufferMs: CAST_BUFFER_MS,
anyTarget: true,
},
];

class CastLinkNormalizer extends EventLinkNormalizer {
Expand Down Expand Up @@ -400,4 +422,12 @@ export function getSOLFlashCast(
).pop();
}

export function getTrailFromHeal(event: CastEvent): HealEvent | undefined {
return GetRelatedEvent(event, HEAL_TRAIL);
}

export function getBindingFromHeal(event: CastEvent): HealEvent | undefined {
return GetRelatedEvent(event, HEAL_BINDING);
}

export default CastLinkNormalizer;

0 comments on commit 9b32736

Please sign in to comment.