Skip to content

Commit

Permalink
Merge pull request wowsims#3810 from wowsims/apl
Browse files Browse the repository at this point in the history
Refactor expected damage functions to split initial and tick calcs
  • Loading branch information
jimmyt857 authored Oct 4, 2023
2 parents 17943a4 + 2b93fc0 commit ec3bf25
Show file tree
Hide file tree
Showing 16 changed files with 54 additions and 486 deletions.
28 changes: 19 additions & 9 deletions sim/core/spell.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ type SpellConfig struct {
ApplyEffects ApplySpellResults

// Optional field. Calculates expected average damage.
ExpectedDamage ExpectedDamageCalculator
ExpectedInitialDamage ExpectedDamageCalculator
ExpectedTickDamage ExpectedDamageCalculator

Dot DotConfig
Hot DotConfig
Expand Down Expand Up @@ -98,7 +99,8 @@ type Spell struct {
ApplyEffects ApplySpellResults

// Optional field. Calculates expected average damage.
expectedDamageInternal ExpectedDamageCalculator
expectedInitialDamageInternal ExpectedDamageCalculator
expectedTickDamageInternal ExpectedDamageCalculator

// The current or most recent cast data.
CurCast Cast
Expand Down Expand Up @@ -197,7 +199,8 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell {

ApplyEffects: config.ApplyEffects,

expectedDamageInternal: config.ExpectedDamage,
expectedInitialDamageInternal: config.ExpectedInitialDamage,
expectedTickDamageInternal: config.ExpectedTickDamage,

BonusHitRating: config.BonusHitRating,
BonusCritRating: config.BonusCritRating,
Expand Down Expand Up @@ -535,21 +538,28 @@ func (spell *Spell) ApplyAOEThreat(threatAmount float64) {
spell.ApplyAOEThreatIgnoreMultipliers(threatAmount * spell.Unit.PseudoStats.ThreatMultiplier)
}

func (spell *Spell) expectedDamageHelper(sim *Simulation, target *Unit, useSnapshot bool) float64 {
result := spell.expectedDamageInternal(sim, target, spell, useSnapshot)
func (spell *Spell) finalizeExpectedDamage(result *SpellResult) {
if !spell.SpellSchool.Matches(SpellSchoolPhysical) {
result.Damage /= result.ResistanceMultiplier
result.Damage *= AverageMagicPartialResistMultiplier
result.ResistanceMultiplier = AverageMagicPartialResistMultiplier
}
result.inUse = false
}
func (spell *Spell) ExpectedInitialDamage(sim *Simulation, target *Unit) float64 {
result := spell.expectedInitialDamageInternal(sim, target, spell, false)
spell.finalizeExpectedDamage(result)
return result.Damage
}
func (spell *Spell) ExpectedDamage(sim *Simulation, target *Unit) float64 {
return spell.expectedDamageHelper(sim, target, false)
func (spell *Spell) ExpectedTickDamage(sim *Simulation, target *Unit) float64 {
result := spell.expectedTickDamageInternal(sim, target, spell, false)
spell.finalizeExpectedDamage(result)
return result.Damage
}
func (spell *Spell) ExpectedDamageFromCurrentSnapshot(sim *Simulation, target *Unit) float64 {
return spell.expectedDamageHelper(sim, target, true)
func (spell *Spell) ExpectedTickDamageFromCurrentSnapshot(sim *Simulation, target *Unit) float64 {
result := spell.expectedTickDamageInternal(sim, target, spell, true)
spell.finalizeExpectedDamage(result)
return result.Damage
}

// Time until either the cast is finished or GCD is ready again, whichever is longer
Expand Down
5 changes: 3 additions & 2 deletions sim/druid/feral/rotation.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,9 @@ func (cat *FeralDruid) calcBuilderDpe(sim *core.Simulation) (float64, float64) {
// Calculate current damage-per-Energy of Rake vs. Shred. Used to
// determine whether Rake is worth casting when player stats change upon a
// dynamic proc occurring
shredDpc := cat.Shred.ExpectedDamage(sim, cat.CurrentTarget)
rakeDpc := cat.Rake.ExpectedDamage(sim, cat.CurrentTarget)
shredDpc := cat.Shred.ExpectedInitialDamage(sim, cat.CurrentTarget)
potentialRakeTicks := min(cat.Rake.CurDot().NumberOfTicks, int32(sim.GetRemainingDuration()/time.Second*3))
rakeDpc := cat.Rake.ExpectedInitialDamage(sim, cat.CurrentTarget) + cat.Rake.ExpectedTickDamage(sim, cat.CurrentTarget)*float64(potentialRakeTicks)
return rakeDpc / cat.Rake.DefaultCast.Cost, shredDpc / cat.Shred.DefaultCast.Cost
}

Expand Down
18 changes: 11 additions & 7 deletions sim/druid/rake.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
)

func (druid *Druid) registerRakeSpell() {
numTicks := 3 + core.TernaryInt32(druid.HasSetBonus(ItemSetMalfurionsBattlegear, 2), 1, 0)
dotCanCrit := druid.HasSetBonus(ItemSetLasherweaveBattlegear, 4)

druid.Rake = druid.RegisterSpell(Cat, core.SpellConfig{
Expand Down Expand Up @@ -36,7 +35,7 @@ func (druid *Druid) registerRakeSpell() {
Label: "Rake",
Duration: time.Second * 9,
}),
NumberOfTicks: numTicks,
NumberOfTicks: 3 + core.TernaryInt32(druid.HasSetBonus(ItemSetMalfurionsBattlegear, 2), 1, 0),
TickLength: time.Second * 3,
OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) {
dot.SnapshotBaseDamage = 358 + 0.06*dot.Spell.MeleeAttackPower()
Expand Down Expand Up @@ -69,12 +68,18 @@ func (druid *Druid) registerRakeSpell() {
}
},

ExpectedDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
ExpectedInitialDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
baseDamage := 176 + 0.01*spell.MeleeAttackPower()
potentialTicks := min(numTicks, int32(sim.GetRemainingDuration()/time.Second*3))
tickBase := (358 + 0.06*spell.MeleeAttackPower()) * float64(potentialTicks)

initial := spell.CalcPeriodicDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicAlwaysHit)

attackTable := spell.Unit.AttackTables[target.UnitIndex]
critChance := spell.PhysicalCritChance(attackTable)
critMod := (critChance * (spell.CritMultiplier - 1))
initial.Damage *= 1 + critMod
return initial
},
ExpectedTickDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
tickBase := (358 + 0.06*spell.MeleeAttackPower())
ticks := spell.CalcPeriodicDamage(sim, target, tickBase, spell.OutcomeExpectedMagicAlwaysHit)

attackTable := spell.Unit.AttackTables[target.UnitIndex]
Expand All @@ -85,7 +90,6 @@ func (druid *Druid) registerRakeSpell() {
ticks.Damage *= 1 + critMod
}

ticks.Damage += initial.Damage * (1 + critMod)
return ticks
},
})
Expand Down
2 changes: 1 addition & 1 deletion sim/druid/shred.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (druid *Druid) registerShredSpell() {
spell.IssueRefund(sim)
}
},
ExpectedDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
ExpectedInitialDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
baseDamage := flatDamageBonus + spell.Unit.AutoAttacks.MH.CalculateAverageWeaponDamage(spell.MeleeAttackPower()) + spell.BonusWeaponDamage()

modifier := 1.0
Expand Down
2 changes: 1 addition & 1 deletion sim/priest/devouring_plague.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (priest *Priest) registerDevouringPlagueSpell() {
spell.Dot(target).Apply(sim)
}
},
ExpectedDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, useSnapshot bool) *core.SpellResult {
ExpectedTickDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, useSnapshot bool) *core.SpellResult {
if useSnapshot {
dot := spell.Dot(target)
if priest.Talents.Shadowform {
Expand Down
2 changes: 1 addition & 1 deletion sim/priest/mind_blast.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (priest *Priest) registerMindBlastSpell() {
}
}
},
ExpectedDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
ExpectedInitialDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
baseDamage := (997.0+1053.0)/2 + spellCoeff*spell.SpellPower()
return spell.CalcDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicHitAndCrit)
},
Expand Down
3 changes: 1 addition & 2 deletions sim/priest/mind_flay.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,8 @@ func (priest *Priest) newMindFlaySpell(numTicksIdx int32) *core.Spell {
}
spell.DealOutcome(sim, result)
},
ExpectedDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
ExpectedTickDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
baseDamage := 588.0/3 + miseryCoeff*spell.SpellPower()
baseDamage *= float64(numTicks)

if priest.Talents.Shadowform {
return spell.CalcPeriodicDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicCrit)
Expand Down
3 changes: 1 addition & 2 deletions sim/priest/mind_sear.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,8 @@ func (priest *Priest) newMindSearSpell(numTicksIdx int32) *core.Spell {
}
}
},
ExpectedDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
ExpectedTickDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult {
baseDamage := sim.Roll(212, 228) + miseryCoeff*spell.SpellPower()
baseDamage *= float64(numTicks)
return spell.CalcPeriodicDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicCrit)
},
})
Expand Down
Loading

0 comments on commit ec3bf25

Please sign in to comment.