diff --git a/sim/core/spell_result.go b/sim/core/spell_result.go index a577346ac..c953e49ea 100644 --- a/sim/core/spell_result.go +++ b/sim/core/spell_result.go @@ -264,9 +264,9 @@ func (spell *Spell) calcDamageInternal(sim *Simulation, target *Unit, baseDamage result := spell.NewResult(target) result.Damage = baseDamage + result.Damage *= attackerMultiplier if sim.Log == nil { - result.Damage *= attackerMultiplier result.applyResistances(sim, spell, isPeriodic, attackTable) result.applyTargetModifiers(spell, attackTable, isPeriodic) @@ -286,7 +286,6 @@ func (spell *Spell) calcDamageInternal(sim *Simulation, target *Unit, baseDamage spell.ApplyPostOutcomeDamageModifiers(sim, result) } else { - result.Damage *= attackerMultiplier afterAttackMods := result.Damage result.applyResistances(sim, spell, isPeriodic, attackTable) afterResistances := result.Damage @@ -333,7 +332,7 @@ func (spell *Spell) calcDamageInternal(sim *Simulation, target *Unit, baseDamage return result } func (spell *Spell) CalcDamage(sim *Simulation, target *Unit, baseDamage float64, outcomeApplier OutcomeApplier) *SpellResult { - attackerMultiplier := spell.AttackerDamageMultiplier(spell.Unit.AttackTables[target.UnitIndex][spell.CastType]) * spell.ImpactDamageMultiplierAdditive + attackerMultiplier := spell.AttackerDamageMultiplier(spell.Unit.AttackTables[target.UnitIndex][spell.CastType], false) baseDamage *= spell.BaseDamageMultiplierAdditive @@ -346,7 +345,7 @@ func (spell *Spell) CalcDamage(sim *Simulation, target *Unit, baseDamage float64 func (spell *Spell) CalcPeriodicDamage(sim *Simulation, target *Unit, baseDamage float64, outcomeApplier OutcomeApplier) *SpellResult { baseDamage *= spell.BaseDamageMultiplierAdditive - attackerMultiplier := spell.AttackerDamageMultiplier(spell.Unit.AttackTables[target.UnitIndex][spell.CastType]) * spell.PeriodicDamageMultiplierAdditive + attackerMultiplier := spell.AttackerDamageMultiplier(spell.Unit.AttackTables[target.UnitIndex][spell.CastType], true) dot := spell.DotOrAOEDot(target) attackerMultiplier *= dot.DamageMultiplier @@ -372,7 +371,7 @@ func (dot *Dot) Snapshot(target *Unit, baseDamage float64, isRollover bool) { if dot.Spell.Flags.Matches(SpellFlagHelpful) { dot.SnapshotAttackerMultiplier = dot.Spell.CasterHealingMultiplier() } else { - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable) * dot.Spell.PeriodicDamageMultiplierAdditive + dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable, true) } dot.SnapshotAttackerMultiplier *= dot.DamageMultiplier @@ -530,7 +529,7 @@ func (dot *Dot) SnapshotHeal(target *Unit, baseHealing float64, isRollover bool) } attackTable := dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType] - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable) + dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable, true) dot.SnapshotAttackerMultiplier *= dot.DamageMultiplier dot.SnapshotCritChance = dot.Spell.SpellCritChance(target) @@ -596,10 +595,11 @@ func (spell *Spell) WaitTravelTime(sim *Simulation, callback func(*Simulation)) } // Returns the combined attacker modifiers. -func (spell *Spell) AttackerDamageMultiplier(attackTable *AttackTable) float64 { +func (spell *Spell) AttackerDamageMultiplier(attackTable *AttackTable, isPeriodic bool) float64 { return spell.attackerDamageMultiplierInternal(attackTable) * spell.DamageMultiplier * - spell.DamageMultiplierAdditive + spell.DamageMultiplierAdditive * + TernaryFloat64(isPeriodic, spell.PeriodicDamageMultiplierAdditive, spell.ImpactDamageMultiplierAdditive) } func (spell *Spell) attackerDamageMultiplierInternal(attackTable *AttackTable) float64 { if spell.Flags.Matches(SpellFlagIgnoreAttackerModifiers) { diff --git a/sim/core/spell_school_test.go b/sim/core/spell_school_test.go index 911a03a67..f488c874c 100644 --- a/sim/core/spell_school_test.go +++ b/sim/core/spell_school_test.go @@ -375,9 +375,12 @@ func SchoolMultiplierArrayHelper[T stats.SchoolValueArrayValues](t *testing.T, c var highest T = T(highestMult) spell := &Spell{ - DamageMultiplier: 1, - DamageMultiplierAdditive: 1, - Unit: caster, + BaseDamageMultiplierAdditive: 1, + DamageMultiplier: 1, + DamageMultiplierAdditive: 1, + ImpactDamageMultiplierAdditive: 1, + PeriodicDamageMultiplierAdditive: 1, + Unit: caster, } for schoolIndex1 := stats.SchoolIndexPhysical; schoolIndex1 < stats.SchoolLen; schoolIndex1++ { @@ -425,7 +428,7 @@ func Test_MultiSchoolModifiers(t *testing.T) { t.Run("DamageDealt", func(t *testing.T) { SchoolMultiplierArrayHelper(t, caster, target, &caster.PseudoStats.SchoolDamageDealtMultiplier, func(spell *Spell, schoolMask SpellSchool, highest float64) (bool, string) { - mult := spell.AttackerDamageMultiplier(attackTable) + mult := spell.AttackerDamageMultiplier(attackTable, true) if mult != highest { return false, fmt.Sprintf("Damage dealt multiplier for school %d returned %f, expected %f!", schoolMask, mult, highest) } diff --git a/sim/hunter/pet_abilities.go b/sim/hunter/pet_abilities.go index 8ee40d24c..2ff0244a0 100644 --- a/sim/hunter/pet_abilities.go +++ b/sim/hunter/pet_abilities.go @@ -124,7 +124,7 @@ func (hp *HunterPet) newBite() *core.Spell { 60: 17261, }[hp.Owner.Level] - ApCoeff := 2.15/14 + ApCoeff := 2.15 / 14 return hp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, @@ -183,7 +183,7 @@ func (hp *HunterPet) newLightningBreath() *core.Spell { 60: 25012, }[hp.Owner.Level] - ApCoeff := 3.65/14 + ApCoeff := 3.65 / 14 SpCoeff := 0.429 return hp.RegisterSpell(core.SpellConfig{ @@ -237,7 +237,7 @@ func (hp *HunterPet) newScreech() *core.Spell { 60: 24582, }[hp.Owner.Level] - ApCoeff := 1.15/14 + ApCoeff := 1.15 / 14 return hp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, @@ -328,7 +328,7 @@ func (hp *HunterPet) newScorpidPoison() *core.Spell { 60: 24587, }[hp.Owner.Level] - ApCoeff := 0.07/5 + ApCoeff := 0.07 / 5 return hp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, @@ -372,7 +372,7 @@ func (hp *HunterPet) newScorpidPoison() *core.Spell { // only the first stack snapshots the multiplier if dot.GetStacks() == 1 { attackTable := dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType] - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable) + dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable, true) dot.SnapshotBaseDamage = 0 } @@ -413,7 +413,7 @@ func (hp *HunterPet) newLavaBreath() *core.Spell { 60: 444681, }[hp.Owner.Level] - ApCoeff := 3.65/14 + ApCoeff := 3.65 / 14 SpCoeff := 0.429 return hp.RegisterSpell(core.SpellConfig{ diff --git a/sim/mage/ignite.go b/sim/mage/ignite.go index 01f3e528b..89a37d0d7 100644 --- a/sim/mage/ignite.go +++ b/sim/mage/ignite.go @@ -38,15 +38,15 @@ func (mage *Mage) applyIgnite() { Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagPassiveSpell | SpellFlagMage, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { -// result := spell.CalcAndDealOutcome(sim, target, spell.OutcomeMagicHit) - + // result := spell.CalcAndDealOutcome(sim, target, spell.OutcomeMagicHit) + dot := mage.igniteTick.Dot(target) dot.ApplyOrRefresh(sim) - if dot.GetStacks() < dot.MaxStacks{ + if dot.GetStacks() < dot.MaxStacks { dot.AddStack(sim) dot.TakeSnapshot(sim, true) -} - + } + }, }) @@ -67,9 +67,9 @@ func (mage *Mage) applyIgnite() { Dot: core.DotConfig{ Aura: core.Aura{ - Label: "Ignite", + Label: "Ignite", MaxStacks: 5, - Duration: time.Second * 4, + Duration: time.Second * 4, }, NumberOfTicks: IgniteTicks, TickLength: time.Second * 2, @@ -82,15 +82,15 @@ func (mage *Mage) applyIgnite() { // only the first stack snapshots the multiplier if dot.GetStacks() == 1 { attackTable := dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType] - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable) + dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable, true) dot.SnapshotBaseDamage = newIgniteDamage } else { dot.SnapshotBaseDamage += newIgniteDamage - } + } }, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) }, }, }) -} \ No newline at end of file +} diff --git a/sim/rogue/poisons.go b/sim/rogue/poisons.go index 43a2b930e..c7cb99662 100644 --- a/sim/rogue/poisons.go +++ b/sim/rogue/poisons.go @@ -188,7 +188,7 @@ func (rogue *Rogue) registerDeadlyPoisonSpell() { // only the first stack snapshots the multiplier if dot.GetStacks() == 1 { attackTable := dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType] - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable) + dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable, true) dot.SnapshotBaseDamage = 0 } diff --git a/sim/warlock/apl_values.go b/sim/warlock/apl_values.go index 111c8fc2a..0459497fa 100644 --- a/sim/warlock/apl_values.go +++ b/sim/warlock/apl_values.go @@ -135,7 +135,7 @@ func (value *APLValueWarlockShouldRefreshCorruption) GetBool(sim *core.Simulatio snapshotMult := dot.SnapshotAttackerMultiplier * (snapshotCrit*(dot.Spell.CritMultiplier(attackTable)-1) + 1) curCrit := dot.Spell.SpellCritChance(target) - curDmg := dot.Spell.AttackerDamageMultiplier(attackTable) * (curCrit*(dot.Spell.CritMultiplier(attackTable)-1) + 1) + curDmg := dot.Spell.AttackerDamageMultiplier(attackTable, true) * (curCrit*(dot.Spell.CritMultiplier(attackTable)-1) + 1) relDmgInc := curDmg / snapshotMult diff --git a/sim/warrior/deep_wounds.go b/sim/warrior/deep_wounds.go index aef069f07..e9b238865 100644 --- a/sim/warrior/deep_wounds.go +++ b/sim/warrior/deep_wounds.go @@ -37,14 +37,14 @@ func (warrior *Warrior) applyDeepWounds() { TickLength: time.Second * 3, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - attackTable := warrior.AttackTables[target.UnitIndex][proto.CastType_CastTypeMainHand] - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable) // Double dips on attackers mods + attackTable := warrior.AttackTables[target.UnitIndex][proto.CastType_CastTypeMainHand] + dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable, true) // Double dips on attackers mods dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) }, }, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - spell.Dot(target).Apply(sim) //Resets the tick counter with Apply vs ApplyorRefresh + spell.Dot(target).Apply(sim) //Resets the tick counter with Apply vs ApplyorRefresh spell.CalcAndDealOutcome(sim, target, spell.OutcomeAlwaysHitNoHitCounter) }, }) @@ -74,11 +74,11 @@ func (warrior *Warrior) procDeepWounds(sim *core.Simulation, target *core.Unit, var awd float64 if isOh { attackTableOh := warrior.AttackTables[target.UnitIndex][proto.CastType_CastTypeOffHand] - adm := warrior.AutoAttacks.OHAuto().AttackerDamageMultiplier(attackTableOh) + adm := warrior.AutoAttacks.OHAuto().AttackerDamageMultiplier(attackTableOh, true) awd = warrior.AutoAttacks.OH().CalculateAverageWeaponDamage(dot.Spell.MeleeAttackPower()) * 0.5 * adm } else { // MH attackTableMh := warrior.AttackTables[target.UnitIndex][proto.CastType_CastTypeMainHand] - adm := warrior.AutoAttacks.MHAuto().AttackerDamageMultiplier(attackTableMh) + adm := warrior.AutoAttacks.MHAuto().AttackerDamageMultiplier(attackTableMh, true) awd = warrior.AutoAttacks.MH().CalculateAverageWeaponDamage(dot.Spell.MeleeAttackPower()) * adm }