Skip to content

Commit

Permalink
Merge pull request wowsims#83 from wowsims/on-apply-effects-callback
Browse files Browse the repository at this point in the history
Add aura OnApplyEffects callback
  • Loading branch information
rosenrusinov authored Apr 15, 2024
2 parents 1cd82bc + d823017 commit 3bcc2a2
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 17 deletions.
28 changes: 27 additions & 1 deletion sim/core/aura.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type Aura struct {

active bool
activeIndex int32 // Position of this aura's index in the activeAuras array.
onApplyEffectsIndex int32 // Position of this aura's index in the onApplyEffectsAuras array.
onCastCompleteIndex int32 // Position of this aura's index in the onCastCompleteAuras array.
onSpellHitDealtIndex int32 // Position of this aura's index in the onSpellHitAuras array.
onSpellHitTakenIndex int32 // Position of this aura's index in the onSpellHitAuras array.
Expand All @@ -85,7 +86,8 @@ type Aura struct {
OnExpire OnExpire
OnStacksChange OnStacksChange // Invoked when the number of stacks of this aura changes.

OnCastComplete OnCastComplete // Invoked when a spell cast completes casting, before results are calculated.
OnApplyEffects OnApplyEffects // Invoked when a spell cast is completing, before apply effects are called
OnCastComplete OnCastComplete // Invoked when a spell cast completes casting, after apply effects.
OnSpellHitDealt OnSpellHit // Invoked when a spell hits and this unit is the caster.
OnSpellHitTaken OnSpellHit // Invoked when a spell hits and this unit is the target.
OnPeriodicDamageDealt OnPeriodicDamage // Invoked when a dot tick occurs and this unit is the caster.
Expand Down Expand Up @@ -290,6 +292,7 @@ type auraTracker struct {
minExpires time.Duration

// Auras that have a non-nil XXX function set and are currently active.
onApplyEffectsAuras []*Aura
onCastCompleteAuras []*Aura
onSpellHitDealtAuras []*Aura
onSpellHitTakenAuras []*Aura
Expand Down Expand Up @@ -365,6 +368,7 @@ func (at *auraTracker) registerAura(unit *Unit, aura Aura) *Aura {
newAura.Icd = aura.Icd
newAura.metrics.ID = aura.ActionID
newAura.activeIndex = Inactive
newAura.onApplyEffectsIndex = Inactive
newAura.onCastCompleteIndex = Inactive
newAura.onSpellHitDealtIndex = Inactive
newAura.onSpellHitTakenIndex = Inactive
Expand Down Expand Up @@ -455,6 +459,7 @@ func (at *auraTracker) RegisterResetEffect(resetEffect ResetEffect) {

func (at *auraTracker) reset(sim *Simulation) {
at.activeAuras = at.activeAuras[:0]
at.onApplyEffectsAuras = at.onApplyEffectsAuras[:0]
at.onCastCompleteAuras = at.onCastCompleteAuras[:0]
at.onSpellHitDealtAuras = at.onSpellHitDealtAuras[:0]
at.onSpellHitTakenAuras = at.onSpellHitTakenAuras[:0]
Expand Down Expand Up @@ -565,6 +570,11 @@ func (aura *Aura) Activate(sim *Simulation) {
aura.Unit.activeAuras = append(aura.Unit.activeAuras, aura)
}

if aura.OnApplyEffects != nil {
aura.onApplyEffectsIndex = int32(len(aura.Unit.onApplyEffectsAuras))
aura.Unit.onApplyEffectsAuras = append(aura.Unit.onApplyEffectsAuras, aura)
}

if aura.OnCastComplete != nil {
aura.onCastCompleteIndex = int32(len(aura.Unit.onCastCompleteAuras))
aura.Unit.onCastCompleteAuras = append(aura.Unit.onCastCompleteAuras, aura)
Expand Down Expand Up @@ -649,6 +659,15 @@ func (aura *Aura) Deactivate(sim *Simulation) {
aura.activeIndex = Inactive
}

if aura.onApplyEffectsIndex != Inactive {
removeOnApplyEffectsIndex := aura.onApplyEffectsIndex
aura.Unit.onApplyEffectsAuras = removeBySwappingToBack(aura.Unit.onApplyEffectsAuras, removeOnApplyEffectsIndex)
if removeOnApplyEffectsIndex < int32(len(aura.Unit.onApplyEffectsAuras)) {
aura.Unit.onApplyEffectsAuras[removeOnApplyEffectsIndex].onApplyEffectsIndex = removeOnApplyEffectsIndex
}
aura.onApplyEffectsIndex = Inactive
}

if aura.onCastCompleteIndex != Inactive {
removeOnCastCompleteIndex := aura.onCastCompleteIndex
aura.Unit.onCastCompleteAuras = removeBySwappingToBack(aura.Unit.onCastCompleteAuras, removeOnCastCompleteIndex)
Expand Down Expand Up @@ -751,6 +770,13 @@ func removeBySwappingToBack[T any, U constraints.Integer](arr []T, removeIdx U)
return arr[:len(arr)-1]
}

// Invokes the OnApplyEffects event for all tracked Auras.
func (at *auraTracker) OnApplyEffects(sim *Simulation, target *Unit, spell *Spell) {
for _, aura := range at.onApplyEffectsAuras {
aura.OnApplyEffects(aura, sim, target, spell)
}
}

// Invokes the OnCastComplete event for all tracked Auras.
func (at *auraTracker) OnCastComplete(sim *Simulation, spell *Spell) {
for _, aura := range at.onCastCompleteAuras {
Expand Down
28 changes: 28 additions & 0 deletions sim/core/aura_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
CallbackOnHealDealt
CallbackOnPeriodicHealDealt
CallbackOnCastComplete
CallbackOnApplyEffects
)

type ProcHandler func(sim *Simulation, spell *Spell, result *SpellResult)
Expand Down Expand Up @@ -141,6 +142,33 @@ func ApplyProcTriggerCallback(unit *Unit, aura *Aura, config ProcTrigger) {
handler(sim, spell, nil)
}
}
if config.Callback.Matches(CallbackOnApplyEffects) {
aura.OnApplyEffects = func(aura *Aura, sim *Simulation, target *Unit, spell *Spell) {
if config.SpellFlags != SpellFlagNone && !spell.Flags.Matches(config.SpellFlags) {
return
}
if config.ClassSpellMask > 0 && config.ClassSpellMask&spell.ClassSpellMask == 0 {
return
}
if config.ProcMask != ProcMaskUnknown && !spell.ProcMask.Matches(config.ProcMask) {
return
}
if config.ProcMaskExclude != ProcMaskUnknown && spell.ProcMask.Matches(config.ProcMaskExclude) {
return
}
if icd.Duration != 0 && !icd.IsReady(sim) {
return
}
if config.ProcChance != 1 && sim.RandomFloat(config.Name) > config.ProcChance {
return
}

if icd.Duration != 0 {
icd.Use(sim)
}
handler(sim, spell, &SpellResult{Target: target})
}
}
}

func MakeProcTriggerAura(unit *Unit, config ProcTrigger) *Aura {
Expand Down
2 changes: 1 addition & 1 deletion sim/core/metrics_aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (distMetrics *DistributionMetrics) doneIteration(sim *Simulation) {
distMetrics.minSeed = sim.rand.GetSeed()
}

dpsRounded := int32(math.Round(dps/10) * 10)
dpsRounded := int32(math.Round(dps/25) * 25)
distMetrics.hist[dpsRounded]++
}

Expand Down
4 changes: 2 additions & 2 deletions sim/core/racials.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ func applyRaceEffects(agent Agent) {
character.AddStat(stats.MeleeCrit, CritRatingPerCritChance)
character.AddStat(stats.SpellCrit, CritRatingPerCritChance)
case proto.Race_RaceGoblin:
character.AddStat(stats.MeleeHaste, HasteRatingPerHastePercent)
character.AddStat(stats.SpellHaste, HasteRatingPerHastePercent)
character.PseudoStats.MeleeSpeedMultiplier *= 1.01
character.PseudoStats.CastSpeedMultiplier *= 1.01
}
}

Expand Down
8 changes: 8 additions & 0 deletions sim/core/spell.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/wowsims/cata/sim/core/stats"
)

type OnApplyEffects func(aura *Aura, sim *Simulation, target *Unit, spell *Spell)
type ApplySpellResults func(sim *Simulation, target *Unit, spell *Spell)
type ExpectedDamageCalculator func(sim *Simulation, target *Unit, spell *Spell, useSnapshot bool) *SpellResult
type CanCastCondition func(sim *Simulation, target *Unit) bool
Expand Down Expand Up @@ -507,6 +508,13 @@ func (spell *Spell) applyEffects(sim *Simulation, target *Unit) {
spell.SpellMetrics[target.UnitIndex].Casts++
spell.casts++

// Not sure if we want to split this flag into its own?
// Both are used to optimize away unneccesery calls and 99%
// of the time are gonna be used together. For now just in one
if !spell.Flags.Matches(SpellFlagNoOnCastComplete) {
spell.Unit.OnApplyEffects(sim, target, spell)
}

spell.ApplyEffects(sim, target, spell)
}

Expand Down
8 changes: 0 additions & 8 deletions sim/death_knight/diseases.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,6 @@ func (dk *DeathKnight) registerFrostFever() {
},

ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
if dk.Talents.EbonPlaguebringer > 0 {
dk.EbonPlagueBringerAura.Get(target).Activate(sim)
}

dot := spell.Dot(target)
dot.Apply(sim)
},
Expand Down Expand Up @@ -137,10 +133,6 @@ func (dk *DeathKnight) registerBloodPlague() {
},

ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
if dk.Talents.EbonPlaguebringer > 0 {
dk.EbonPlagueBringerAura.Get(target).Activate(sim)
}

spell.Dot(target).Apply(sim)
},
})
Expand Down
7 changes: 2 additions & 5 deletions sim/death_knight/pestilence.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ var PestilenceActionID = core.ActionID{SpellID: 50842}
func (dk *DeathKnight) registerPestilenceSpell() {
hasReaping := dk.Inputs.Spec == proto.Spec_SpecUnholyDeathKnight

// This becomes too involved to move to a spell mod because we dont have
// correct events to react to the pesti cast
contagionBonus := 1.0 + 0.5*float64(dk.Talents.Contagion)
pestiHandler := func(sim *core.Simulation, spell *core.Spell, target *core.Unit) {
spell.DamageMultiplier *= 0.5 * contagionBonus
spell.DamageMultiplier *= 0.5
spell.Cast(sim, target)
spell.DamageMultiplier /= 0.5 * contagionBonus
spell.DamageMultiplier /= 0.5
}

dk.Pestilence = dk.RegisterSpell(core.SpellConfig{
Expand Down
38 changes: 38 additions & 0 deletions sim/death_knight/talents_unholy.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func (dk *DeathKnight) ApplyUnholyTalents() {
})
}

// Contagion
dk.applyContagion()

// Rage of Rivendare
if dk.Talents.RageOfRivendare > 0 {
dk.AddStaticMod(core.SpellModConfig{
Expand Down Expand Up @@ -68,6 +71,32 @@ func (dk *DeathKnight) ApplyUnholyTalents() {
dk.applyDarkTransformation(shadowInfusionAura)
}

func (dk *DeathKnight) applyContagion() {
contagionMod := dk.AddDynamicMod(core.SpellModConfig{
Kind: core.SpellMod_DamageDone_Pct,
FloatValue: 0.5 * float64(dk.Talents.Contagion),
ClassMask: DeathKnightSpellDisease,
})

core.MakeProcTriggerAura(&dk.Unit, core.ProcTrigger{
Name: "Contagion Activate",
Callback: core.CallbackOnApplyEffects,
ClassSpellMask: DeathKnightSpellPestilence,
Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
contagionMod.Activate()
},
})

core.MakeProcTriggerAura(&dk.Unit, core.ProcTrigger{
Name: "Contagion Deactivate",
Callback: core.CallbackOnCastComplete,
ClassSpellMask: DeathKnightSpellPestilence,
Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
contagionMod.Deactivate()
},
})
}

func (dk *DeathKnight) applyRunicEmpowerementCorruption() {
var handler func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult)
if dk.Talents.RunicCorruption > 0 {
Expand Down Expand Up @@ -189,6 +218,15 @@ func (dk *DeathKnight) applyEbonPlaguebringer() {
dk.FrostFeverSpell.RelatedAuras = append(dk.FrostFeverSpell.RelatedAuras, dk.EbonPlagueBringerAura)
dk.BloodPlagueSpell.RelatedAuras = append(dk.BloodPlagueSpell.RelatedAuras, dk.EbonPlagueBringerAura)
})

core.MakeProcTriggerAura(&dk.Unit, core.ProcTrigger{
Name: "Ebon Plague Activate",
Callback: core.CallbackOnApplyEffects,
ClassSpellMask: DeathKnightSpellDisease,
Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
dk.EbonPlagueBringerAura.Get(result.Target).Activate(sim)
},
})
}

func (dk *DeathKnight) applySuddenDoom() {
Expand Down

0 comments on commit 3bcc2a2

Please sign in to comment.