From bcaae7c7d34a041556d509257f834f8e4087ea2e Mon Sep 17 00:00:00 2001 From: vigo Date: Tue, 19 Mar 2024 00:22:55 +0100 Subject: [PATCH 01/12] [core] introduce Spell.DefenseType and Spell.CritDamageBonus, intended to replace Spell.CritMultiplier [core] Spell.critMultiplier() currently either returns Spell.CritMultiplier, or the "default multiplier" combined with CritDamageBonus [rogue] switch over to the new system --- sim/core/attack.go | 14 +++++--- sim/core/spell.go | 17 +++++++--- sim/core/spell_outcome.go | 59 +++++++++++++++++++-------------- sim/hunter/hunter.go | 7 ++-- sim/hunter/talents.go | 4 +++ sim/rogue/ambush.go | 2 +- sim/rogue/backstab.go | 4 ++- sim/rogue/between_the_eyes.go | 4 +-- sim/rogue/envenom.go | 3 +- sim/rogue/eviscerate.go | 6 ++-- sim/rogue/expose_armor.go | 1 + sim/rogue/feint.go | 4 +-- sim/rogue/garrote.go | 1 + sim/rogue/ghostly_strike.go | 4 ++- sim/rogue/hemorrhage.go | 8 ++--- sim/rogue/main_gauche.go | 4 ++- sim/rogue/master_of_subtlety.go | 2 +- sim/rogue/mutilate.go | 4 ++- sim/rogue/poisoned_knife.go | 8 ++--- sim/rogue/poisons.go | 5 +-- sim/rogue/quick_draw.go | 4 ++- sim/rogue/rogue.go | 28 ---------------- sim/rogue/rupture.go | 2 +- sim/rogue/saber_slash.go | 4 ++- sim/rogue/shadowstrike.go | 2 +- sim/rogue/shiv.go | 4 ++- sim/rogue/shuriken_toss.go | 5 +-- sim/rogue/sinister_strike.go | 7 ++-- sim/rogue/talents.go | 4 +++ 29 files changed, 119 insertions(+), 102 deletions(-) diff --git a/sim/core/attack.go b/sim/core/attack.go index 26b731d7ce..592971be5d 100644 --- a/sim/core/attack.go +++ b/sim/core/attack.go @@ -363,12 +363,14 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) { unit.AutoAttacks.mh.config = SpellConfig{ ActionID: ActionID{OtherID: proto.OtherAction_OtherActionAttack, Tag: 1}, SpellSchool: options.MainHand.GetSpellSchool(), + DefenseType: DefenseTypeMelee, ProcMask: ProcMaskMeleeMHAuto, Flags: SpellFlagMeleeMetrics | SpellFlagIncludeTargetBonusDamage | SpellFlagNoOnCastComplete, CastType: proto.CastType_CastTypeMainHand, + CritMultiplier: options.MainHand.CritMultiplier, + DamageMultiplier: 1, - CritMultiplier: options.MainHand.CritMultiplier, ThreatMultiplier: 1, ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) { @@ -382,12 +384,14 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) { unit.AutoAttacks.oh.config = SpellConfig{ ActionID: ActionID{OtherID: proto.OtherAction_OtherActionAttack, Tag: 2}, SpellSchool: options.OffHand.GetSpellSchool(), + DefenseType: DefenseTypeMelee, ProcMask: ProcMaskMeleeOHAuto, Flags: SpellFlagMeleeMetrics | SpellFlagIncludeTargetBonusDamage | SpellFlagNoOnCastComplete, CastType: proto.CastType_CastTypeOffHand, + CritMultiplier: options.OffHand.CritMultiplier, + DamageMultiplier: 1, - CritMultiplier: options.OffHand.CritMultiplier, ThreatMultiplier: 1, ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) { @@ -401,13 +405,15 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) { unit.AutoAttacks.ranged.config = SpellConfig{ ActionID: ActionID{OtherID: proto.OtherAction_OtherActionShoot}, SpellSchool: options.Ranged.GetSpellSchool(), + DefenseType: DefenseTypeRanged, ProcMask: ProcMaskRangedAuto, Flags: SpellFlagMeleeMetrics | SpellFlagIncludeTargetBonusDamage, CastType: proto.CastType_CastTypeRanged, MissileSpeed: 24, + CritMultiplier: options.Ranged.CritMultiplier, + DamageMultiplier: 1, - CritMultiplier: options.Ranged.CritMultiplier, ThreatMultiplier: 1, ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) { @@ -441,7 +447,7 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) { func (aa *AutoAttacks) finalize() { if aa.AutoSwingMelee { aa.mh.spell = aa.mh.unit.GetOrRegisterSpell(aa.mh.config) - // Will keep keep the OH spell registered for Item swapping + // Will keep the OH spell registered for Item swapping aa.oh.spell = aa.oh.unit.GetOrRegisterSpell(aa.oh.config) } if aa.AutoSwingRanged { diff --git a/sim/core/spell.go b/sim/core/spell.go index 3d0720ffdf..975b3af855 100644 --- a/sim/core/spell.go +++ b/sim/core/spell.go @@ -18,6 +18,7 @@ type SpellConfig struct { // Used to identify spells with multiple ranks that need to be referenced SpellCode int32 SpellSchool SpellSchool + DefenseType DefenseType ProcMask ProcMask Flags SpellFlag CastType proto.CastType @@ -43,7 +44,9 @@ type SpellConfig struct { DamageMultiplier float64 DamageMultiplierAdditive float64 - CritMultiplier float64 + + CritMultiplier float64 + CritDamageBonus float64 ThreatMultiplier float64 @@ -73,7 +76,8 @@ type Spell struct { // The unit who will perform this spell. Unit *Unit - SpellSchool SpellSchool // Schoolmask of all schools this spell uses. Use Spell.SetSchool() to change this! + SpellSchool SpellSchool // Schoolmask of all schools this spell uses. Use Spell.SetSchool() to change this! + DefenseType DefenseType SchoolIndex stats.SchoolIndex // Use Spell.SetSchool() to change this! SchoolBaseIndices []stats.SchoolIndex // Base school indices for multi schools. Use Spell.SetSchool() to change this! IsMultischool bool // True if school is composed of multiple base schools. Use Spell.SetSchool() to change this! @@ -128,7 +132,9 @@ type Spell struct { CostMultiplier float64 DamageMultiplier float64 DamageMultiplierAdditive float64 - CritMultiplier float64 + + CritMultiplier float64 + CritDamageBonus float64 // Multiplier for all threat generated by this effect. ThreatMultiplier float64 @@ -211,6 +217,7 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { spell := &Spell{ ActionID: config.ActionID, SpellCode: config.SpellCode, + DefenseType: config.DefenseType, Unit: unit, ProcMask: config.ProcMask, Flags: config.Flags, @@ -238,7 +245,9 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { CostMultiplier: 1, DamageMultiplier: config.DamageMultiplier, DamageMultiplierAdditive: config.DamageMultiplierAdditive, - CritMultiplier: config.CritMultiplier, + + CritMultiplier: config.CritMultiplier, + CritDamageBonus: 1 + config.CritDamageBonus, ThreatMultiplier: config.ThreatMultiplier, FlatThreatBonus: config.FlatThreatBonus, diff --git a/sim/core/spell_outcome.go b/sim/core/spell_outcome.go index 92d42ab88c..6c5bb02d28 100644 --- a/sim/core/spell_outcome.go +++ b/sim/core/spell_outcome.go @@ -33,7 +33,7 @@ func (dot *Dot) OutcomeTickCounted(_ *Simulation, result *SpellResult, _ *Attack func (dot *Dot) OutcomeTickPhysicalCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if dot.Spell.PhysicalCritCheck(sim, attackTable) { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier + result.Damage *= dot.Spell.critMultiplier() } else { result.Outcome = OutcomeHit } @@ -42,19 +42,19 @@ func (dot *Dot) OutcomeTickPhysicalCrit(sim *Simulation, result *SpellResult, at func (dot *Dot) OutcomeTickSnapshotCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier + result.Damage *= dot.Spell.critMultiplier() } else { result.Outcome = OutcomeHit } } func (dot *Dot) OutcomeSnapshotCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { - if dot.Spell.CritMultiplier == 0 { + if dot.Spell.critMultiplier() == 0 { panic("Spell " + dot.Spell.ActionID.String() + " missing CritMultiplier") } if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier + result.Damage *= dot.Spell.critMultiplier() dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -63,13 +63,13 @@ func (dot *Dot) OutcomeSnapshotCrit(sim *Simulation, result *SpellResult, _ *Att } func (dot *Dot) OutcomeMagicHitAndSnapshotCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { - if dot.Spell.CritMultiplier == 0 { + if dot.Spell.critMultiplier() == 0 { panic("Spell " + dot.Spell.ActionID.String() + " missing CritMultiplier") } if dot.Spell.MagicHitCheck(sim, attackTable) { if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier + result.Damage *= dot.Spell.critMultiplier() dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -83,13 +83,13 @@ func (dot *Dot) OutcomeMagicHitAndSnapshotCrit(sim *Simulation, result *SpellRes } func (spell *Spell) OutcomeMagicHitAndCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { - if spell.CritMultiplier == 0 { + if spell.critMultiplier() == 0 { panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") } if spell.MagicHitCheck(sim, attackTable) { if spell.MagicCritCheck(sim, result.Target) { result.Outcome = OutcomeCrit - result.Damage *= spell.CritMultiplier + result.Damage *= spell.critMultiplier() spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -103,12 +103,12 @@ func (spell *Spell) OutcomeMagicHitAndCrit(sim *Simulation, result *SpellResult, } func (spell *Spell) OutcomeMagicCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { - if spell.CritMultiplier == 0 { + if spell.critMultiplier() == 0 { panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") } if spell.MagicCritCheck(sim, result.Target) { result.Outcome = OutcomeCrit - result.Damage *= spell.CritMultiplier + result.Damage *= spell.critMultiplier() spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -122,12 +122,12 @@ func (spell *Spell) OutcomeHealing(_ *Simulation, result *SpellResult, _ *Attack } func (spell *Spell) OutcomeHealingCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { - if spell.CritMultiplier == 0 { + if spell.critMultiplier() == 0 { panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") } if spell.HealingCritCheck(sim) { result.Outcome = OutcomeCrit - result.Damage *= spell.CritMultiplier + result.Damage *= spell.critMultiplier() spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -468,7 +468,7 @@ func (result *SpellResult) applyAttackTableGlance(spell *Spell, attackTable *Att } func (result *SpellResult) applyAttackTableCrit(spell *Spell, attackTable *AttackTable, roll float64, chance *float64) bool { - if spell.CritMultiplier == 0 { + if spell.critMultiplier() == 0 { panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") } *chance += spell.PhysicalCritChance(attackTable) @@ -476,31 +476,31 @@ func (result *SpellResult) applyAttackTableCrit(spell *Spell, attackTable *Attac if roll < *chance { result.Outcome = OutcomeCrit spell.SpellMetrics[result.Target.UnitIndex].Crits++ - result.Damage *= spell.CritMultiplier + result.Damage *= spell.critMultiplier() return true } return false } func (result *SpellResult) applyAttackTableCritSeparateRoll(sim *Simulation, spell *Spell, attackTable *AttackTable) bool { - if spell.CritMultiplier == 0 { + if spell.critMultiplier() == 0 { panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") } if spell.PhysicalCritCheck(sim, attackTable) { result.Outcome = OutcomeCrit spell.SpellMetrics[result.Target.UnitIndex].Crits++ - result.Damage *= spell.CritMultiplier + result.Damage *= spell.critMultiplier() return true } return false } func (result *SpellResult) applyAttackTableCritSeparateRollSnapshot(sim *Simulation, dot *Dot) bool { - if dot.Spell.CritMultiplier == 0 { + if dot.Spell.critMultiplier() == 0 { panic("Spell " + dot.Spell.ActionID.String() + " missing CritMultiplier") } if sim.RandomFloat("Physical Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier + result.Damage *= dot.Spell.critMultiplier() dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ return true } @@ -620,35 +620,46 @@ func (spell *Spell) OutcomeExpectedMagicHit(_ *Simulation, result *SpellResult, } func (spell *Spell) OutcomeExpectedMagicCrit(_ *Simulation, result *SpellResult, _ *AttackTable) { - if spell.CritMultiplier == 0 { + if spell.critMultiplier() == 0 { panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") } averageMultiplier := 1.0 - averageMultiplier += spell.SpellCritChance(result.Target) * (spell.CritMultiplier - 1) + averageMultiplier += spell.SpellCritChance(result.Target) * (spell.critMultiplier() - 1) result.Damage *= averageMultiplier } func (spell *Spell) OutcomeExpectedMagicHitAndCrit(_ *Simulation, result *SpellResult, attackTable *AttackTable) { - if spell.CritMultiplier == 0 { + if spell.critMultiplier() == 0 { panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") } averageMultiplier := 1.0 averageMultiplier -= spell.SpellChanceToMiss(attackTable) - averageMultiplier += averageMultiplier * spell.SpellCritChance(result.Target) * (spell.CritMultiplier - 1) + averageMultiplier += averageMultiplier * spell.SpellCritChance(result.Target) * (spell.critMultiplier() - 1) result.Damage *= averageMultiplier } func (dot *Dot) OutcomeExpectedMagicSnapshotCrit(_ *Simulation, result *SpellResult, _ *AttackTable) { - if dot.Spell.CritMultiplier == 0 { + if dot.Spell.critMultiplier() == 0 { panic("Spell " + dot.Spell.ActionID.String() + " missing CritMultiplier") } averageMultiplier := 1.0 - averageMultiplier += dot.SnapshotCritChance * (dot.Spell.CritMultiplier - 1) + averageMultiplier += dot.SnapshotCritChance * (dot.Spell.critMultiplier() - 1) result.Damage *= averageMultiplier } + +func (spell *Spell) critMultiplier() float64 { + switch spell.DefenseType { + case DefenseTypeNone: + return spell.CritMultiplier + case DefenseTypeMagic: + return 1 + 0.5*spell.CritDamageBonus + default: + return 1 + spell.CritDamageBonus + } +} diff --git a/sim/hunter/hunter.go b/sim/hunter/hunter.go index 5fa53a7466..c79e15127f 100644 --- a/sim/hunter/hunter.go +++ b/sim/hunter/hunter.go @@ -96,11 +96,6 @@ func (hunter *Hunter) AddPartyBuffs(_ *proto.PartyBuffs) { } func (hunter *Hunter) Initialize() { - // Update auto crit multipliers now that we have the targets. - hunter.AutoAttacks.MHConfig().CritMultiplier = hunter.critMultiplier(false, hunter.CurrentTarget) - hunter.AutoAttacks.OHConfig().CritMultiplier = hunter.critMultiplier(false, hunter.CurrentTarget) - hunter.AutoAttacks.RangedConfig().CritMultiplier = hunter.critMultiplier(true, hunter.CurrentTarget) - hunter.registerAspectOfTheHawkSpell() hunter.registerAspectOfTheViperSpell() @@ -224,6 +219,8 @@ func NewHunter(character *core.Character, options *proto.Player) *Hunter { return hunter.Hardcast.Expires < sim.CurrentTime } + hunter.AutoAttacks.RangedConfig().CritDamageBonus = hunter.mortalShots() + hunter.AutoAttacks.RangedConfig().ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := hunter.RangedWeaponDamage(sim, spell.RangedAttackPower(target)) + hunter.AmmoDamageBonus + diff --git a/sim/hunter/talents.go b/sim/hunter/talents.go index 22a65d405b..e4eac35f3d 100644 --- a/sim/hunter/talents.go +++ b/sim/hunter/talents.go @@ -169,3 +169,7 @@ func (hunter *Hunter) registerBestialWrathCD() { Type: core.CooldownTypeDPS, }) } + +func (hunter *Hunter) mortalShots() float64 { + return 0.06 * float64(hunter.Talents.MortalShots) +} diff --git a/sim/rogue/ambush.go b/sim/rogue/ambush.go index 77186f64b9..839e02c4b7 100644 --- a/sim/rogue/ambush.go +++ b/sim/rogue/ambush.go @@ -27,6 +27,7 @@ func (rogue *Rogue) registerAmbushSpell() { rogue.Ambush = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | SpellFlagColdBlooded | core.SpellFlagAPL, @@ -47,7 +48,6 @@ func (rogue *Rogue) registerAmbushSpell() { BonusCritRating: 15 * core.CritRatingPerCritChance * float64(rogue.Talents.ImprovedAmbush), DamageMultiplier: 2.5 * []float64{1, 1.04, 1.08, 1.12, 1.16, 1.2}[rogue.Talents.Opportunity], - CritMultiplier: rogue.MeleeCritMultiplier(false), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/backstab.go b/sim/rogue/backstab.go index bbe4580dcb..535636df24 100644 --- a/sim/rogue/backstab.go +++ b/sim/rogue/backstab.go @@ -27,6 +27,7 @@ func (rogue *Rogue) registerBackstabSpell() { rogue.Backstab = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | SpellFlagColdBlooded | core.SpellFlagAPL, @@ -46,8 +47,9 @@ func (rogue *Rogue) registerBackstabSpell() { BonusCritRating: 10 * core.CritRatingPerCritChance * float64(rogue.Talents.ImprovedBackstab), + CritDamageBonus: rogue.lethality(), + DamageMultiplier: 1.5 * []float64{1, 1.04, 1.08, 1.12, 1.16, 1.2}[rogue.Talents.Opportunity], - CritMultiplier: rogue.MeleeCritMultiplier(true), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/between_the_eyes.go b/sim/rogue/between_the_eyes.go index ce7d5df5d7..cc3320f893 100644 --- a/sim/rogue/between_the_eyes.go +++ b/sim/rogue/between_the_eyes.go @@ -11,13 +11,14 @@ func (rogue *Rogue) registerBetweenTheEyes() { if !rogue.HasRune(proto.RogueRune_RuneBetweenTheEyes) { return } - + flatDamage := rogue.RuneAbilityBaseDamage() comboDamageBonus := rogue.RuneAbilityDamagePerCombo() rogue.BetweenTheEyes = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.RogueRune_RuneBetweenTheEyes)}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | rogue.finisherFlags() | core.SpellFlagAPL, MetricSplits: 6, @@ -44,7 +45,6 @@ func (rogue *Rogue) registerBetweenTheEyes() { }, DamageMultiplier: 1, - CritMultiplier: rogue.MeleeCritMultiplier(false), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/envenom.go b/sim/rogue/envenom.go index 721aad0216..248612613b 100644 --- a/sim/rogue/envenom.go +++ b/sim/rogue/envenom.go @@ -28,6 +28,7 @@ func (rogue *Rogue) registerEnvenom() { rogue.Envenom = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.RogueRune_RuneEnvenom)}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, // not core.ProcMaskSpellDamage Flags: core.SpellFlagMeleeMetrics | rogue.finisherFlags() | SpellFlagColdBlooded | core.SpellFlagAPL | core.SpellFlagPoison, MetricSplits: 6, @@ -49,8 +50,6 @@ func (rogue *Rogue) registerEnvenom() { return rogue.ComboPoints() > 0 && target.GetAuraByID(rogue.DeadlyPoison[0].ActionID).IsActive() }, - CritMultiplier: rogue.MeleeCritMultiplier(false), - DamageMultiplier: rogue.getPoisonDamageMultiplier(), ThreatMultiplier: 1, diff --git a/sim/rogue/eviscerate.go b/sim/rogue/eviscerate.go index fd6b8e3aaf..f763b605af 100644 --- a/sim/rogue/eviscerate.go +++ b/sim/rogue/eviscerate.go @@ -38,6 +38,7 @@ func (rogue *Rogue) registerEviscerate() { rogue.Eviscerate = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | rogue.finisherFlags() | SpellFlagColdBlooded | core.SpellFlagAPL, MetricSplits: 6, @@ -60,9 +61,8 @@ func (rogue *Rogue) registerEviscerate() { }, DamageMultiplier: 1 + - []float64{0.0, 0.05, 0.1, 0.15}[rogue.Talents.ImprovedEviscerate] + - 0.02*float64(rogue.Talents.Aggression), - CritMultiplier: rogue.MeleeCritMultiplier(false), + []float64{0, 0.05, 0.10, 0.15}[rogue.Talents.ImprovedEviscerate] + + []float64{0, 0.02, 0.04, 0.06}[rogue.Talents.Aggression], ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/expose_armor.go b/sim/rogue/expose_armor.go index de3b86d335..2cf5cbf03b 100644 --- a/sim/rogue/expose_armor.go +++ b/sim/rogue/expose_armor.go @@ -28,6 +28,7 @@ func (rogue *Rogue) registerExposeArmorSpell() { rogue.ExposeArmor = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | rogue.finisherFlags() | core.SpellFlagAPL, MetricSplits: 6, diff --git a/sim/rogue/feint.go b/sim/rogue/feint.go index 3e6244300f..dd8ea66f10 100644 --- a/sim/rogue/feint.go +++ b/sim/rogue/feint.go @@ -10,7 +10,8 @@ func (rogue *Rogue) registerFeintSpell() { rogue.Feint = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 1966}, SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskEmpty, + DefenseType: core.DefenseTypeMelee, + ProcMask: core.ProcMaskMeleeMH, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ @@ -27,7 +28,6 @@ func (rogue *Rogue) registerFeintSpell() { IgnoreHaste: true, }, - DamageMultiplier: 0, ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/garrote.go b/sim/rogue/garrote.go index f3fea352c6..187995c016 100644 --- a/sim/rogue/garrote.go +++ b/sim/rogue/garrote.go @@ -24,6 +24,7 @@ func (rogue *Rogue) registerGarrote() { rogue.Garrote = rogue.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | SpellFlagBuilder | core.SpellFlagAPL, diff --git a/sim/rogue/ghostly_strike.go b/sim/rogue/ghostly_strike.go index 71ab055288..5178eb7823 100644 --- a/sim/rogue/ghostly_strike.go +++ b/sim/rogue/ghostly_strike.go @@ -29,6 +29,7 @@ func (rogue *Rogue) registerGhostlyStrikeSpell() { rogue.GhostlyStrike = rogue.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | SpellFlagColdBlooded | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ @@ -47,8 +48,9 @@ func (rogue *Rogue) registerGhostlyStrikeSpell() { IgnoreHaste: true, }, + CritDamageBonus: rogue.lethality(), + DamageMultiplier: 1.25, - CritMultiplier: rogue.MeleeCritMultiplier(true), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/hemorrhage.go b/sim/rogue/hemorrhage.go index f2df47b854..d4b7021885 100644 --- a/sim/rogue/hemorrhage.go +++ b/sim/rogue/hemorrhage.go @@ -7,11 +7,6 @@ import ( ) func (rogue *Rogue) registerHemorrhageSpell() { - // Minimum level of 30 to talent Hemorrhage - if rogue.Level < 30 { - return - } - if !rogue.Talents.Hemorrhage { return } @@ -56,8 +51,9 @@ func (rogue *Rogue) registerHemorrhageSpell() { IgnoreHaste: true, }, + CritDamageBonus: rogue.lethality(), + DamageMultiplier: 1, - CritMultiplier: rogue.MeleeCritMultiplier(true), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/main_gauche.go b/sim/rogue/main_gauche.go index 8e8afd98cb..aca69f5fad 100644 --- a/sim/rogue/main_gauche.go +++ b/sim/rogue/main_gauche.go @@ -31,6 +31,7 @@ func (rogue *Rogue) registerMainGaucheSpell() { rogue.MainGauche = rogue.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeOHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | core.SpellFlagAPL | SpellFlagColdBlooded, EnergyCost: core.EnergyCostOptions{ @@ -49,8 +50,9 @@ func (rogue *Rogue) registerMainGaucheSpell() { IgnoreHaste: true, }, + CritDamageBonus: rogue.lethality(), + DamageMultiplier: []float64{1, 1.02, 1.04, 1.06}[rogue.Talents.Aggression], - CritMultiplier: rogue.MeleeCritMultiplier(true), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/master_of_subtlety.go b/sim/rogue/master_of_subtlety.go index 80cd61d890..95524b20fd 100644 --- a/sim/rogue/master_of_subtlety.go +++ b/sim/rogue/master_of_subtlety.go @@ -25,7 +25,7 @@ func (rogue *Rogue) registerMasterOfSubtlety() { rogue.PseudoStats.DamageDealtMultiplier *= 1.1 }, OnExpire: func(aura *core.Aura, sim *core.Simulation) { - rogue.PseudoStats.DamageDealtMultiplier *= 1 / 1.1 + rogue.PseudoStats.DamageDealtMultiplier /= 1.1 }, }) } diff --git a/sim/rogue/mutilate.go b/sim/rogue/mutilate.go index 52c7d752fd..5619230c38 100644 --- a/sim/rogue/mutilate.go +++ b/sim/rogue/mutilate.go @@ -24,15 +24,17 @@ func (rogue *Rogue) newMutilateHitSpell(isMH bool) *core.Spell { return rogue.RegisterSpell(core.SpellConfig{ ActionID: actionID.WithTag(int32(core.Ternary(isMH, 1, 2))), SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: procMask, Flags: core.SpellFlagMeleeMetrics | SpellFlagBuilder | SpellFlagColdBlooded, BonusCritRating: 10 * core.CritRatingPerCritChance * float64(rogue.Talents.ImprovedBackstab), + CritDamageBonus: rogue.lethality(), + DamageMultiplier: 1 * core.TernaryFloat64(isMH, 1, rogue.dwsMultiplier()) * []float64{1, 1.04, 1.08, 1.12, 1.16, 1.2}[rogue.Talents.Opportunity], - CritMultiplier: rogue.MeleeCritMultiplier(true), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/poisoned_knife.go b/sim/rogue/poisoned_knife.go index 2063c93f47..fed36e7006 100644 --- a/sim/rogue/poisoned_knife.go +++ b/sim/rogue/poisoned_knife.go @@ -17,6 +17,7 @@ func (rogue *Rogue) registerPoisonedKnife() { rogue.PoisonedKnife = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.RogueRune_RunePoisonedKnife)}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeOHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | core.SpellFlagAPL, @@ -39,18 +40,17 @@ func (rogue *Rogue) registerPoisonedKnife() { }, CastType: proto.CastType_CastTypeRanged, + CritDamageBonus: rogue.lethality(), + DamageMultiplier: []float64{1, 1.02, 1.04, 1.06}[rogue.Talents.Aggression] * rogue.dwsMultiplier(), - CritMultiplier: rogue.MeleeCritMultiplier(true), ThreatMultiplier: 1, - // Cannot Miss - BonusHitRating: 100 * core.MeleeHitRatingPerHitChance, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { rogue.BreakStealth(sim) baseDamage := spell.Unit.OHNormalizedWeaponDamage(sim, spell.MeleeAttackPower()) + spell.BonusWeaponDamage() // Cannot Miss, Dodge, or Parry as per spell flags - result := spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMeleeSpecialNoBlockDodgeParry) + result := spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMeleeSpecialCritOnly) if result.Landed() { rogue.AddComboPoints(sim, 1, spell.ComboPointMetrics()) diff --git a/sim/rogue/poisons.go b/sim/rogue/poisons.go index 7c64dbd466..817cab857a 100644 --- a/sim/rogue/poisons.go +++ b/sim/rogue/poisons.go @@ -269,11 +269,11 @@ func (rogue *Rogue) makeInstantPoison(procSource PoisonProcSource) *core.Spell { return rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID, Tag: int32(procSource)}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskWeaponProc, Flags: core.SpellFlagPoison, DamageMultiplier: rogue.getPoisonDamageMultiplier(), - CritMultiplier: rogue.SpellCritMultiplier(), ThreatMultiplier: 1, BonusHitRating: core.Ternary[float64](procSource == ShivProc, 100*core.SpellHitRatingPerHitChance, 0), @@ -304,6 +304,7 @@ func (rogue *Rogue) makeDeadlyPoison(procSource PoisonProcSource) *core.Spell { return rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID, Tag: int32(procSource)}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskWeaponProc, Flags: core.SpellFlagPoison, @@ -367,11 +368,11 @@ func (rogue *Rogue) makeWoundPoison(procSource PoisonProcSource) *core.Spell { return rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 13219, Tag: int32(procSource)}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskWeaponProc, Flags: core.SpellFlagPoison, DamageMultiplier: rogue.getPoisonDamageMultiplier(), - CritMultiplier: rogue.SpellCritMultiplier(), ThreatMultiplier: 1, BonusHitRating: core.Ternary[float64](procSource == ShivProc, 100*core.SpellHitRatingPerHitChance, 0), diff --git a/sim/rogue/quick_draw.go b/sim/rogue/quick_draw.go index d048f2c116..2b4ffeeff3 100644 --- a/sim/rogue/quick_draw.go +++ b/sim/rogue/quick_draw.go @@ -26,6 +26,7 @@ func (rogue *Rogue) registerQuickDrawSpell() { rogue.QuickDraw = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 398196}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: SpellFlagBuilder | core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, MissileSpeed: 40, @@ -49,8 +50,9 @@ func (rogue *Rogue) registerQuickDrawSpell() { rogue.Ranged().RangedWeaponType != proto.RangedWeaponType_RangedWeaponTypeUnknown }, + CritDamageBonus: rogue.lethality(), + DamageMultiplier: []float64{1, 1.02, 1.04, 1.06}[rogue.Talents.Aggression], - CritMultiplier: rogue.RangedCritMultiplier(true), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/rogue.go b/sim/rogue/rogue.go index 0d359a03f3..368e2dccc9 100644 --- a/sim/rogue/rogue.go +++ b/sim/rogue/rogue.go @@ -103,10 +103,6 @@ func (rogue *Rogue) ApplyFinisher(sim *core.Simulation, spell *core.Spell) { } func (rogue *Rogue) Initialize() { - // Update auto crit multipliers now that we have the targets. - rogue.AutoAttacks.MHConfig().CritMultiplier = rogue.MeleeCritMultiplier(false) - rogue.AutoAttacks.OHConfig().CritMultiplier = rogue.MeleeCritMultiplier(false) - rogue.registerBackstabSpell() rogue.registerDeadlyPoisonSpell() rogue.registerEviscerate() @@ -139,31 +135,7 @@ func (rogue *Rogue) Reset(_ *core.Simulation) { } } -func (rogue *Rogue) MeleeCritMultiplier(applyLethality bool) float64 { - primaryModifier := 1.0 - var secondaryModifier float64 - if applyLethality { - secondaryModifier += 0.06 * float64(rogue.Talents.Lethality) - } - return rogue.Character.MeleeCritMultiplier(primaryModifier, secondaryModifier) -} - -func (rogue *Rogue) RangedCritMultiplier(applyLethality bool) float64 { - primaryModifier := 1.0 - var secondaryModifier float64 - if applyLethality { - secondaryModifier += 0.06 * float64(rogue.Talents.Lethality) - } - return rogue.Character.MeleeCritMultiplier(primaryModifier, secondaryModifier) -} - -func (rogue *Rogue) SpellCritMultiplier() float64 { - primaryModifier := 1.0 - return rogue.Character.SpellCritMultiplier(primaryModifier, 0) -} - func NewRogue(character *core.Character, options *proto.Player, rogueOptions *proto.RogueOptions) *Rogue { - rogue := &Rogue{ Character: *character, Talents: &proto.RogueTalents{}, diff --git a/sim/rogue/rupture.go b/sim/rogue/rupture.go index 32db4d0753..ce895b302d 100644 --- a/sim/rogue/rupture.go +++ b/sim/rogue/rupture.go @@ -17,6 +17,7 @@ func (rogue *Rogue) registerRupture() { rogue.Rupture = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | rogue.finisherFlags() | core.SpellFlagAPL, MetricSplits: 6, @@ -39,7 +40,6 @@ func (rogue *Rogue) registerRupture() { }, DamageMultiplier: []float64{1, 1.1, 1.2, 1.3}[rogue.Talents.SerratedBlades], - CritMultiplier: rogue.MeleeCritMultiplier(false), ThreatMultiplier: 1, Dot: core.DotConfig{ diff --git a/sim/rogue/saber_slash.go b/sim/rogue/saber_slash.go index 4e2aa2ed63..96206f2048 100644 --- a/sim/rogue/saber_slash.go +++ b/sim/rogue/saber_slash.go @@ -15,6 +15,7 @@ func (rogue *Rogue) registerSaberSlashSpell() { rogue.SaberSlash = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.RogueRune_RuneSaberSlash)}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | SpellFlagColdBlooded | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ @@ -29,8 +30,9 @@ func (rogue *Rogue) registerSaberSlashSpell() { IgnoreHaste: true, }, + CritDamageBonus: rogue.lethality(), + DamageMultiplier: []float64{1, 1.02, 1.04, 1.06}[rogue.Talents.Aggression], - CritMultiplier: rogue.MeleeCritMultiplier(true), ThreatMultiplier: 1, // TODO: Fix bleed so it works properly diff --git a/sim/rogue/shadowstrike.go b/sim/rogue/shadowstrike.go index f0af142d55..68faa6df43 100644 --- a/sim/rogue/shadowstrike.go +++ b/sim/rogue/shadowstrike.go @@ -15,6 +15,7 @@ func (rogue *Rogue) registerShadowstrikeSpell() { rogue.Shadowstrike = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.RogueRune_RuneShadowstrike)}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | SpellFlagColdBlooded | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ @@ -33,7 +34,6 @@ func (rogue *Rogue) registerShadowstrikeSpell() { }, DamageMultiplier: 1.5, - CritMultiplier: rogue.MeleeCritMultiplier(false), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/shiv.go b/sim/rogue/shiv.go index 263917dc8f..7b799c1b8f 100644 --- a/sim/rogue/shiv.go +++ b/sim/rogue/shiv.go @@ -22,6 +22,7 @@ func (rogue *Rogue) registerShivSpell() { rogue.Shiv = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 424799}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeOHSpecial, Flags: core.SpellFlagMeleeMetrics | SpellFlagBuilder | core.SpellFlagAPL, @@ -36,8 +37,9 @@ func (rogue *Rogue) registerShivSpell() { IgnoreHaste: true, }, + CritDamageBonus: rogue.lethality(), + DamageMultiplier: []float64{1, 1.02, 1.04, 1.06}[rogue.Talents.Aggression] * rogue.dwsMultiplier(), - CritMultiplier: rogue.MeleeCritMultiplier(true), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/shuriken_toss.go b/sim/rogue/shuriken_toss.go index 640a678c8e..6d74dc3ea5 100644 --- a/sim/rogue/shuriken_toss.go +++ b/sim/rogue/shuriken_toss.go @@ -7,7 +7,7 @@ import ( "github.com/wowsims/sod/sim/core/proto" ) -const ShurikenTossSpellID int32 = int32(proto.RogueRune_RuneShurikenToss) +const ShurikenTossSpellID = int32(proto.RogueRune_RuneShurikenToss) func (rogue *Rogue) registerShurikenTossSpell() { if !rogue.HasRune(proto.RogueRune_RuneShurikenToss) { @@ -20,6 +20,7 @@ func (rogue *Rogue) registerShurikenTossSpell() { rogue.ShurikenToss = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: ShurikenTossSpellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | core.SpellFlagAPL, @@ -44,7 +45,7 @@ func (rogue *Rogue) registerShurikenTossSpell() { baseDamage := spell.MeleeAttackPower() * 0.15 curTarget := target - for hitIndex := int32(0); hitIndex < int32(numHits); hitIndex++ { + for hitIndex := int32(0); hitIndex < numHits; hitIndex++ { results[hitIndex] = spell.CalcAndDealDamage(sim, curTarget, baseDamage, spell.OutcomeRangedHitAndCrit) curTarget = sim.Environment.NextTargetUnit(curTarget) diff --git a/sim/rogue/sinister_strike.go b/sim/rogue/sinister_strike.go index 0a6e4773bd..898f925c22 100644 --- a/sim/rogue/sinister_strike.go +++ b/sim/rogue/sinister_strike.go @@ -24,6 +24,7 @@ func (rogue *Rogue) registerSinisterStrikeSpell() { rogue.SinisterStrike = rogue.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | SpellFlagBuilder | SpellFlagColdBlooded | core.SpellFlagAPL, @@ -38,9 +39,9 @@ func (rogue *Rogue) registerSinisterStrikeSpell() { IgnoreHaste: true, }, - DamageMultiplier: 1 + - 0.02*float64(rogue.Talents.Aggression), - CritMultiplier: rogue.MeleeCritMultiplier(true), + CritDamageBonus: rogue.lethality(), + + DamageMultiplier: []float64{1, 1.02, 1.04, 1.06}[rogue.Talents.Aggression], ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/talents.go b/sim/rogue/talents.go index 86367483f0..ab8435489e 100644 --- a/sim/rogue/talents.go +++ b/sim/rogue/talents.go @@ -473,6 +473,10 @@ func (rogue *Rogue) registerAdrenalineRushCD() { }) } +func (rogue *Rogue) lethality() float64 { + return 0.06 * float64(rogue.Talents.Lethality) +} + /** Honor Among Thieves (Possible P2 rune) func (rogue *Rogue) registerHonorAmongThieves() { // When anyone in your group critically hits with a damage or healing spell or ability, From 123470ea4b7f0f0fa6a0474cf22dbda028dca49e Mon Sep 17 00:00:00 2001 From: vigo Date: Tue, 19 Mar 2024 00:28:20 +0100 Subject: [PATCH 02/12] [core] remove Weapon.CritMultiplier, since it's redundant now --- sim/_paladin/protection/protection.go | 2 +- sim/_paladin/retribution/retribution.go | 2 +- sim/core/attack.go | 28 ++----- sim/core/item_swaps.go | 6 +- sim/core/target_ai.go | 7 +- sim/druid/balance/balance.go | 2 +- sim/druid/forms.go | 3 +- sim/hunter/hunter.go | 6 +- sim/hunter/pet.go | 7 +- sim/paladin/retribution/retribution.go | 2 +- sim/priest/homunculus_pet.go | 7 +- sim/priest/shadowfiend_pet.go | 1 - sim/rogue/rogue.go | 6 +- sim/shaman/enhancement/enhancement.go | 4 +- sim/warlock/pet.go | 84 ++++++++----------- sim/warlock/tank/tank_warlock.go | 4 +- sim/warrior/_protection/protection_warrior.go | 4 +- sim/warrior/dps/dps_warrior.go | 4 +- 18 files changed, 76 insertions(+), 103 deletions(-) diff --git a/sim/_paladin/protection/protection.go b/sim/_paladin/protection/protection.go index 5a7cf26c10..8ab0e5ec2c 100644 --- a/sim/_paladin/protection/protection.go +++ b/sim/_paladin/protection/protection.go @@ -35,7 +35,7 @@ func NewProtectionPaladin(character *core.Character, options *proto.Player) *Pro prot.PaladinAura = protOptions.Options.Aura prot.EnableAutoAttacks(prot, core.AutoAttackOptions{ - MainHand: prot.WeaponFromMainHand(0), // Set crit multiplier later when we have targets. + MainHand: prot.WeaponFromMainHand(), // Set crit multiplier later when we have targets. AutoSwingMelee: true, }) diff --git a/sim/_paladin/retribution/retribution.go b/sim/_paladin/retribution/retribution.go index 2126646669..99fcde7006 100644 --- a/sim/_paladin/retribution/retribution.go +++ b/sim/_paladin/retribution/retribution.go @@ -36,7 +36,7 @@ func NewRetributionPaladin(character *core.Character, options *proto.Player) *Re ret.PaladinAura = retOptions.Options.Aura ret.EnableAutoAttacks(ret, core.AutoAttackOptions{ - MainHand: ret.WeaponFromMainHand(0), // Set crit multiplier later when we have targets. + MainHand: ret.WeaponFromMainHand(), // Set crit multiplier later when we have targets. AutoSwingMelee: true, }) diff --git a/sim/core/attack.go b/sim/core/attack.go index 592971be5d..edbaa23d91 100644 --- a/sim/core/attack.go +++ b/sim/core/attack.go @@ -21,7 +21,6 @@ type Weapon struct { AttackPowerPerDPS float64 SwingSpeed float64 NormalizedSwingSpeed float64 - CritMultiplier float64 SpellSchool SpellSchool } @@ -32,19 +31,18 @@ func (weapon *Weapon) DPS() float64 { return (weapon.BaseDamageMin + weapon.BaseDamageMax) / 2.0 / weapon.SwingSpeed } -func newWeaponFromUnarmed(critMultiplier float64) Weapon { +func newWeaponFromUnarmed() Weapon { // These numbers are probably wrong but nobody cares. return Weapon{ BaseDamageMin: 0, BaseDamageMax: 0, SwingSpeed: 1, NormalizedSwingSpeed: 1, - CritMultiplier: critMultiplier, AttackPowerPerDPS: DefaultAttackPowerPerDPS, } } -func newWeaponFromItem(item *Item, critMultiplier float64, bonusDps float64) Weapon { +func newWeaponFromItem(item *Item, bonusDps float64) Weapon { normalizedWeaponSpeed := 2.4 if item.WeaponType == proto.WeaponType_WeaponTypeDagger { normalizedWeaponSpeed = 1.7 @@ -59,33 +57,32 @@ func newWeaponFromItem(item *Item, critMultiplier float64, bonusDps float64) Wea BaseDamageMax: item.WeaponDamageMax + bonusDps*item.SwingSpeed, SwingSpeed: item.SwingSpeed, NormalizedSwingSpeed: normalizedWeaponSpeed, - CritMultiplier: critMultiplier, AttackPowerPerDPS: DefaultAttackPowerPerDPS, } } // Returns weapon stats using the main hand equipped weapon. -func (character *Character) WeaponFromMainHand(critMultiplier float64) Weapon { +func (character *Character) WeaponFromMainHand() Weapon { if weapon := character.GetMHWeapon(); weapon != nil { - return newWeaponFromItem(weapon, critMultiplier, character.PseudoStats.BonusMHDps) + return newWeaponFromItem(weapon, character.PseudoStats.BonusMHDps) } else { - return newWeaponFromUnarmed(critMultiplier) + return newWeaponFromUnarmed() } } // Returns weapon stats using the off-hand equipped weapon. -func (character *Character) WeaponFromOffHand(critMultiplier float64) Weapon { +func (character *Character) WeaponFromOffHand() Weapon { if weapon := character.GetOHWeapon(); weapon != nil { - return newWeaponFromItem(weapon, critMultiplier, character.PseudoStats.BonusOHDps) + return newWeaponFromItem(weapon, character.PseudoStats.BonusOHDps) } else { return Weapon{} } } // Returns weapon stats using the ranged equipped weapon. -func (character *Character) WeaponFromRanged(critMultiplier float64) Weapon { +func (character *Character) WeaponFromRanged() Weapon { if weapon := character.GetRangedWeapon(); weapon != nil { - return newWeaponFromItem(weapon, critMultiplier, character.PseudoStats.BonusRangedDps) + return newWeaponFromItem(weapon, character.PseudoStats.BonusRangedDps) } else { return Weapon{} } @@ -251,7 +248,6 @@ func (wa *WeaponAttack) getWeapon() *Weapon { func (wa *WeaponAttack) setWeapon(weapon Weapon) { wa.Weapon = weapon - wa.spell.CritMultiplier = weapon.CritMultiplier wa.updateSwingDuration(wa.curSwingSpeed) } @@ -368,8 +364,6 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) { Flags: SpellFlagMeleeMetrics | SpellFlagIncludeTargetBonusDamage | SpellFlagNoOnCastComplete, CastType: proto.CastType_CastTypeMainHand, - CritMultiplier: options.MainHand.CritMultiplier, - DamageMultiplier: 1, ThreatMultiplier: 1, @@ -389,8 +383,6 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) { Flags: SpellFlagMeleeMetrics | SpellFlagIncludeTargetBonusDamage | SpellFlagNoOnCastComplete, CastType: proto.CastType_CastTypeOffHand, - CritMultiplier: options.OffHand.CritMultiplier, - DamageMultiplier: 1, ThreatMultiplier: 1, @@ -411,8 +403,6 @@ func (unit *Unit) EnableAutoAttacks(agent Agent, options AutoAttackOptions) { CastType: proto.CastType_CastTypeRanged, MissileSpeed: 24, - CritMultiplier: options.Ranged.CritMultiplier, - DamageMultiplier: 1, ThreatMultiplier: 1, diff --git a/sim/core/item_swaps.go b/sim/core/item_swaps.go index 53a647b192..de17113089 100644 --- a/sim/core/item_swaps.go +++ b/sim/core/item_swaps.go @@ -229,11 +229,11 @@ func (swap *ItemSwap) swapWeapon(slot proto.ItemSlot) { switch slot { case proto.ItemSlot_ItemSlotMainHand: if character.AutoAttacks.AutoSwingMelee { - character.AutoAttacks.SetMH(character.WeaponFromMainHand(swap.mhCritMultiplier)) + character.AutoAttacks.SetMH(character.WeaponFromMainHand()) } case proto.ItemSlot_ItemSlotOffHand: if character.AutoAttacks.AutoSwingMelee { - weapon := character.WeaponFromOffHand(swap.ohCritMultiplier) + weapon := character.WeaponFromOffHand() character.AutoAttacks.SetOH(weapon) character.AutoAttacks.IsDualWielding = weapon.SwingSpeed != 0 @@ -241,7 +241,7 @@ func (swap *ItemSwap) swapWeapon(slot proto.ItemSlot) { } case proto.ItemSlot_ItemSlotRanged: if character.AutoAttacks.AutoSwingRanged { - character.AutoAttacks.SetRanged(character.WeaponFromRanged(swap.rangedCritMultiplier)) + character.AutoAttacks.SetRanged(character.WeaponFromRanged()) } } } diff --git a/sim/core/target_ai.go b/sim/core/target_ai.go index d2d52e8f3a..a69d5d0065 100644 --- a/sim/core/target_ai.go +++ b/sim/core/target_ai.go @@ -21,10 +21,9 @@ func (target *Target) initialize(config *proto.Target) { if config.SwingSpeed > 0 { aaOptions := AutoAttackOptions{ MainHand: Weapon{ - BaseDamageMin: config.MinBaseDamage, - SwingSpeed: config.SwingSpeed, - CritMultiplier: 2, - SpellSchool: SpellSchoolFromProto(config.SpellSchool), + BaseDamageMin: config.MinBaseDamage, + SwingSpeed: config.SwingSpeed, + SpellSchool: SpellSchoolFromProto(config.SpellSchool), }, AutoSwingMelee: true, } diff --git a/sim/druid/balance/balance.go b/sim/druid/balance/balance.go index b932572196..f4d1e73ad1 100644 --- a/sim/druid/balance/balance.go +++ b/sim/druid/balance/balance.go @@ -40,7 +40,7 @@ func NewBalanceDruid(character *core.Character, options *proto.Player) *BalanceD // Enable Auto Attacks for this spec moonkin.EnableAutoAttacks(moonkin, core.AutoAttackOptions{ - MainHand: moonkin.WeaponFromMainHand(moonkin.DefaultMeleeCritMultiplier()), + MainHand: moonkin.WeaponFromMainHand(), AutoSwingMelee: true, }) diff --git a/sim/druid/forms.go b/sim/druid/forms.go index 56866b32e5..021612636e 100644 --- a/sim/druid/forms.go +++ b/sim/druid/forms.go @@ -49,7 +49,6 @@ func (druid *Druid) GetCatWeapon(level int32) core.Weapon { BaseDamageMax: 24.5799, SwingSpeed: 1.0, NormalizedSwingSpeed: 1.0, - CritMultiplier: druid.MeleeCritMultiplier(1, 0), AttackPowerPerDPS: core.DefaultAttackPowerPerDPS, } @@ -175,7 +174,7 @@ func (druid *Druid) registerCatFormSpell() { OnExpire: func(aura *core.Aura, sim *core.Simulation) { druid.form = Humanoid - druid.AutoAttacks.SetMH(druid.WeaponFromMainHand(druid.MeleeCritMultiplier(1, 0))) + druid.AutoAttacks.SetMH(druid.WeaponFromMainHand()) druid.PseudoStats.ThreatMultiplier /= 0.71 druid.PseudoStats.BaseDodge -= 0.02 * float64(druid.Talents.FelineSwiftness) diff --git a/sim/hunter/hunter.go b/sim/hunter/hunter.go index c79e15127f..2b729eb257 100644 --- a/sim/hunter/hunter.go +++ b/sim/hunter/hunter.go @@ -141,7 +141,7 @@ func NewHunter(character *core.Character, options *proto.Player) *Hunter { hunter.PseudoStats.CanParry = true - rangedWeapon := hunter.WeaponFromRanged(0) + rangedWeapon := hunter.WeaponFromRanged() if hunter.HasRangedWeapon() { // Ammo @@ -194,8 +194,8 @@ func NewHunter(character *core.Character, options *proto.Player) *Hunter { hunter.EnableAutoAttacks(hunter, core.AutoAttackOptions{ // We don't know crit multiplier until later when we see the target so just // use 0 for now. - MainHand: hunter.WeaponFromMainHand(0), - OffHand: hunter.WeaponFromOffHand(0), + MainHand: hunter.WeaponFromMainHand(), + OffHand: hunter.WeaponFromOffHand(), Ranged: rangedWeapon, ReplaceMHSwing: hunter.TryRaptorStrike, AutoSwingRanged: true, diff --git a/sim/hunter/pet.go b/sim/hunter/pet.go index 67136915ee..50a691d585 100644 --- a/sim/hunter/pet.go +++ b/sim/hunter/pet.go @@ -139,10 +139,9 @@ func (hunter *Hunter) NewHunterPet() *HunterPet { hp.EnableAutoAttacks(hp, core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: baseMinDamage, - BaseDamageMax: baseMaxDamage, - SwingSpeed: attackSpeed, - CritMultiplier: hp.MeleeCritMultiplier(1, 0), + BaseDamageMin: baseMinDamage, + BaseDamageMax: baseMaxDamage, + SwingSpeed: attackSpeed, }, AutoSwingMelee: true, }) diff --git a/sim/paladin/retribution/retribution.go b/sim/paladin/retribution/retribution.go index 3d62d27d9f..91e6211527 100644 --- a/sim/paladin/retribution/retribution.go +++ b/sim/paladin/retribution/retribution.go @@ -34,7 +34,7 @@ func NewRetributionPaladin(character *core.Character, options *proto.Player) *Re } ret.EnableAutoAttacks(ret, core.AutoAttackOptions{ - MainHand: ret.WeaponFromMainHand(ret.DefaultMeleeCritMultiplier()), // Set crit multiplier later when we have targets. + MainHand: ret.WeaponFromMainHand(), // Set crit multiplier later when we have targets. AutoSwingMelee: true, }) diff --git a/sim/priest/homunculus_pet.go b/sim/priest/homunculus_pet.go index 7fff2d259a..3dbcd6f3bc 100644 --- a/sim/priest/homunculus_pet.go +++ b/sim/priest/homunculus_pet.go @@ -58,10 +58,9 @@ func (priest *Priest) NewHomunculus(idx int32, npcID int32) *Homunculus { homunculus.EnableAutoAttacks(homunculus, core.AutoAttackOptions{ MainHand: core.Weapon{ // TODO: Check stats - BaseDamageMin: baseDamageMin, - BaseDamageMax: baseDamageMax, - SwingSpeed: 2, - CritMultiplier: priest.DefaultMeleeCritMultiplier(), + BaseDamageMin: baseDamageMin, + BaseDamageMax: baseDamageMax, + SwingSpeed: 2, }, AutoSwingMelee: true, }) diff --git a/sim/priest/shadowfiend_pet.go b/sim/priest/shadowfiend_pet.go index 24b1775f83..f42beae351 100644 --- a/sim/priest/shadowfiend_pet.go +++ b/sim/priest/shadowfiend_pet.go @@ -78,7 +78,6 @@ func (priest *Priest) NewShadowfiend() *Shadowfiend { BaseDamageMin: baseDamageMin, BaseDamageMax: baseDamageMax, SwingSpeed: 1.5, - CritMultiplier: priest.DefaultMeleeCritMultiplier(), AttackPowerPerDPS: 14.0 / 6.0, // Observed 6 times stronger AP scaling then expected SpellSchool: core.SpellSchoolShadow, }, diff --git a/sim/rogue/rogue.go b/sim/rogue/rogue.go index 368e2dccc9..4e70bf5300 100644 --- a/sim/rogue/rogue.go +++ b/sim/rogue/rogue.go @@ -154,9 +154,9 @@ func NewRogue(character *core.Character, options *proto.Player, rogueOptions *pr rogue.EnableEnergyBar(maxEnergy) rogue.EnableAutoAttacks(rogue, core.AutoAttackOptions{ - MainHand: rogue.WeaponFromMainHand(0), // Set crit multiplier later when we have targets. - OffHand: rogue.WeaponFromOffHand(0), // Set crit multiplier later when we have targets. - Ranged: rogue.WeaponFromRanged(0), // Set crit multiplier later when we have targets. + MainHand: rogue.WeaponFromMainHand(), // Set crit multiplier later when we have targets. + OffHand: rogue.WeaponFromOffHand(), // Set crit multiplier later when we have targets. + Ranged: rogue.WeaponFromRanged(), // Set crit multiplier later when we have targets. AutoSwingMelee: true, }) rogue.applyPoisons() diff --git a/sim/shaman/enhancement/enhancement.go b/sim/shaman/enhancement/enhancement.go index f42702b32e..da9edd063f 100644 --- a/sim/shaman/enhancement/enhancement.go +++ b/sim/shaman/enhancement/enhancement.go @@ -43,8 +43,8 @@ func NewEnhancementShaman(character *core.Character, options *proto.Player) *Enh // Enable Auto Attacks for this spec enh.EnableAutoAttacks(enh, core.AutoAttackOptions{ - MainHand: enh.WeaponFromMainHand(enh.DefaultMeleeCritMultiplier()), - OffHand: enh.WeaponFromOffHand(enh.DefaultMeleeCritMultiplier()), + MainHand: enh.WeaponFromMainHand(), + OffHand: enh.WeaponFromOffHand(), AutoSwingMelee: true, }) diff --git a/sim/warlock/pet.go b/sim/warlock/pet.go index 2360476fe6..e92df2bad5 100644 --- a/sim/warlock/pet.go +++ b/sim/warlock/pet.go @@ -104,10 +104,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 23, - BaseDamageMax: 38, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 23, + BaseDamageMax: 38, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -125,10 +124,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 41, - BaseDamageMax: 61, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 41, + BaseDamageMax: 61, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -146,10 +144,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 41, - BaseDamageMax: 61, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 41, + BaseDamageMax: 61, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -167,10 +164,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 41, - BaseDamageMax: 61, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 41, + BaseDamageMax: 61, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -193,10 +189,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 2, - BaseDamageMax: 7, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 2, + BaseDamageMax: 7, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -214,10 +209,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 5, - BaseDamageMax: 15, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 5, + BaseDamageMax: 15, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -235,10 +229,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 5, - BaseDamageMax: 15, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 5, + BaseDamageMax: 15, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -256,10 +249,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 5, - BaseDamageMax: 15, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 5, + BaseDamageMax: 15, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -282,10 +274,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 24, - BaseDamageMax: 40, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 24, + BaseDamageMax: 40, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -303,10 +294,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 24, - BaseDamageMax: 40, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 24, + BaseDamageMax: 40, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -324,10 +314,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 24, - BaseDamageMax: 40, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 24, + BaseDamageMax: 40, + SwingSpeed: 2, }, AutoSwingMelee: true, } @@ -345,10 +334,9 @@ func (warlock *Warlock) NewWarlockPet() *WarlockPet { } cfg.AutoAttacks = core.AutoAttackOptions{ MainHand: core.Weapon{ - BaseDamageMin: 24, - BaseDamageMax: 40, - SwingSpeed: 2, - CritMultiplier: 2, + BaseDamageMin: 24, + BaseDamageMax: 40, + SwingSpeed: 2, }, AutoSwingMelee: true, } diff --git a/sim/warlock/tank/tank_warlock.go b/sim/warlock/tank/tank_warlock.go index ffee8dd357..e053c0786a 100644 --- a/sim/warlock/tank/tank_warlock.go +++ b/sim/warlock/tank/tank_warlock.go @@ -36,8 +36,8 @@ func NewTankWarlock(character *core.Character, options *proto.Player) *TankWarlo warlock.PseudoStats.CanBlock = false warlock.EnableAutoAttacks(warlock, core.AutoAttackOptions{ - MainHand: warlock.WeaponFromMainHand(warlock.DefaultMeleeCritMultiplier()), - OffHand: warlock.WeaponFromOffHand(warlock.DefaultMeleeCritMultiplier()), + MainHand: warlock.WeaponFromMainHand(), + OffHand: warlock.WeaponFromOffHand(), AutoSwingMelee: true, }) diff --git a/sim/warrior/_protection/protection_warrior.go b/sim/warrior/_protection/protection_warrior.go index afe041dceb..bde68986ac 100644 --- a/sim/warrior/_protection/protection_warrior.go +++ b/sim/warrior/_protection/protection_warrior.go @@ -50,8 +50,8 @@ func NewProtectionWarrior(character *core.Character, options *proto.Player) *Pro war.EnableRageBar(rbo) war.EnableAutoAttacks(war, core.AutoAttackOptions{ - MainHand: war.WeaponFromMainHand(war.DefaultMeleeCritMultiplier()), - OffHand: war.WeaponFromOffHand(war.DefaultMeleeCritMultiplier()), + MainHand: war.WeaponFromMainHand(), + OffHand: war.WeaponFromOffHand(), AutoSwingMelee: true, ReplaceMHSwing: war.TryHSOrCleave, }) diff --git a/sim/warrior/dps/dps_warrior.go b/sim/warrior/dps/dps_warrior.go index 8d62e6be1c..675ee59389 100644 --- a/sim/warrior/dps/dps_warrior.go +++ b/sim/warrior/dps/dps_warrior.go @@ -52,8 +52,8 @@ func NewDpsWarrior(character *core.Character, options *proto.Player) *DpsWarrior war.EnableRageBar(rbo) war.EnableAutoAttacks(war, core.AutoAttackOptions{ - MainHand: war.WeaponFromMainHand(war.DefaultMeleeCritMultiplier()), - OffHand: war.WeaponFromOffHand(war.DefaultMeleeCritMultiplier()), + MainHand: war.WeaponFromMainHand(), + OffHand: war.WeaponFromOffHand(), AutoSwingMelee: true, ReplaceMHSwing: war.TryHSOrCleave, }) From 4ca0a48a27f2d5ae85816eee7f6570a613d09ccd Mon Sep 17 00:00:00 2001 From: vigo Date: Tue, 19 Mar 2024 12:35:44 +0100 Subject: [PATCH 03/12] [hunter] move hunter over, too --- sim/hunter/aimed_shot.go | 4 +- sim/hunter/arcane_shot.go | 5 +- sim/hunter/carve.go | 4 +- sim/hunter/chimera_shot.go | 4 +- sim/hunter/explosive_shot.go | 12 ++-- sim/hunter/explosive_trap.go | 6 +- sim/hunter/flanking_strike.go | 6 +- sim/hunter/immolation_trap.go | 6 +- sim/hunter/multi_shot.go | 10 ++-- sim/hunter/pet_abilities.go | 101 ++-------------------------------- sim/hunter/rapid_fire.go | 6 +- sim/hunter/raptor_strike.go | 12 ++-- sim/hunter/serpent_sting.go | 14 +++-- sim/hunter/steady_shot.go | 10 ++-- sim/hunter/wing_clip.go | 3 +- sim/rogue/shuriken_toss.go | 2 - 16 files changed, 55 insertions(+), 150 deletions(-) diff --git a/sim/hunter/aimed_shot.go b/sim/hunter/aimed_shot.go index 72b7755101..b45f378cdd 100644 --- a/sim/hunter/aimed_shot.go +++ b/sim/hunter/aimed_shot.go @@ -23,6 +23,7 @@ func (hunter *Hunter) getAimedShotConfig(rank int, timer *core.Timer) core.Spell return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, CastType: proto.CastType_CastTypeRanged, @@ -55,8 +56,9 @@ func (hunter *Hunter) getAimedShotConfig(rank int, timer *core.Timer) core.Spell return hunter.DistanceFromTarget >= 8 }, + CritDamageBonus: hunter.mortalShots(), + DamageMultiplier: 1, - CritMultiplier: hunter.critMultiplier(true, hunter.CurrentTarget), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/hunter/arcane_shot.go b/sim/hunter/arcane_shot.go index 5fd7774665..be63a76915 100644 --- a/sim/hunter/arcane_shot.go +++ b/sim/hunter/arcane_shot.go @@ -23,6 +23,7 @@ func (hunter *Hunter) getArcaneShotConfig(rank int, timer *core.Timer) core.Spel return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL, CastType: proto.CastType_CastTypeRanged, @@ -48,9 +49,9 @@ func (hunter *Hunter) getArcaneShotConfig(rank int, timer *core.Timer) core.Spel return hunter.DistanceFromTarget >= 8 }, - BonusCritRating: 0, + CritDamageBonus: hunter.mortalShots(), + DamageMultiplier: 1, - CritMultiplier: hunter.critMultiplier(true, hunter.CurrentTarget), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/hunter/carve.go b/sim/hunter/carve.go index 0a90dbbfbc..5efcdd72fa 100644 --- a/sim/hunter/carve.go +++ b/sim/hunter/carve.go @@ -22,17 +22,18 @@ func (hunter *Hunter) registerCarveSpell() { hunter.CarveOh = hunter.RegisterSpell(core.SpellConfig{ ActionID: actionID.WithTag(1), SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeOHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagNoOnCastComplete, DamageMultiplier: core.TernaryFloat64(hasDwRune, 1.5, 1) * 0.65, - CritMultiplier: hunter.critMultiplier(false, hunter.CurrentTarget), }) } hunter.CarveMh = hunter.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 425711}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL | core.SpellFlagIncludeTargetBonusDamage, @@ -54,7 +55,6 @@ func (hunter *Hunter) registerCarveSpell() { }, DamageMultiplier: 0.65, - CritMultiplier: hunter.critMultiplier(false, hunter.CurrentTarget), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/hunter/chimera_shot.go b/sim/hunter/chimera_shot.go index 0b23686456..b1dec4aadb 100644 --- a/sim/hunter/chimera_shot.go +++ b/sim/hunter/chimera_shot.go @@ -22,6 +22,7 @@ func (hunter *Hunter) registerChimeraShotSpell() { hunter.ChimeraShot = hunter.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 409433}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL | core.SpellFlagIgnoreResists, CastType: proto.CastType_CastTypeRanged, @@ -45,8 +46,9 @@ func (hunter *Hunter) registerChimeraShotSpell() { return hunter.DistanceFromTarget >= 8 }, + CritDamageBonus: hunter.mortalShots(), + DamageMultiplier: 1.2, - CritMultiplier: hunter.critMultiplier(true, hunter.CurrentTarget), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/hunter/explosive_shot.go b/sim/hunter/explosive_shot.go index 32fda4420d..26e5b854ff 100644 --- a/sim/hunter/explosive_shot.go +++ b/sim/hunter/explosive_shot.go @@ -17,7 +17,7 @@ func (hunter *Hunter) registerExplosiveShotSpell(timer *core.Timer) { numHits := hunter.Env.GetNumTargets() level := float64(hunter.GetCharacter().Level) - baseCalc := (2.976264 + 0.641066*level + 0.022519*level*level) + baseCalc := 2.976264 + 0.641066*level + 0.022519*level*level baseLowDamage := baseCalc * 0.36 * 1.15 // Buff from 1/3/2024 - verify with new build and update numbers baseHighDamage := baseCalc * 0.54 * 1.15 @@ -28,6 +28,7 @@ func (hunter *Hunter) registerExplosiveShotSpell(timer *core.Timer) { hunter.ExplosiveShot = hunter.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL | core.SpellFlagIgnoreResists | core.SpellFlagBinary, CastType: proto.CastType_CastTypeRanged, @@ -51,11 +52,10 @@ func (hunter *Hunter) registerExplosiveShotSpell(timer *core.Timer) { return hunter.DistanceFromTarget >= 8 }, - BonusCritRating: 0, - DamageMultiplierAdditive: 1, - DamageMultiplier: 1, - CritMultiplier: hunter.critMultiplier(true, hunter.CurrentTarget), - ThreatMultiplier: 1, + CritDamageBonus: hunter.mortalShots(), + + DamageMultiplier: 1, + ThreatMultiplier: 1, Dot: core.DotConfig{ Aura: core.Aura{ diff --git a/sim/hunter/explosive_trap.go b/sim/hunter/explosive_trap.go index cc558454e1..ffbb5f0998 100644 --- a/sim/hunter/explosive_trap.go +++ b/sim/hunter/explosive_trap.go @@ -21,6 +21,7 @@ func (hunter *Hunter) getExplosiveTrapConfig(rank int, timer *core.Timer) core.S return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, Rank: rank, @@ -41,9 +42,8 @@ func (hunter *Hunter) getExplosiveTrapConfig(rank int, timer *core.Timer) core.S IgnoreHaste: true, // Hunter GCD is locked at 1.5s }, - DamageMultiplierAdditive: 1 + 0.15*float64(hunter.Talents.CleverTraps), - CritMultiplier: hunter.critMultiplier(false, hunter.CurrentTarget), - ThreatMultiplier: 1, + DamageMultiplier: 1 + 0.15*float64(hunter.Talents.CleverTraps), + ThreatMultiplier: 1, Dot: core.DotConfig{ IsAOE: true, diff --git a/sim/hunter/flanking_strike.go b/sim/hunter/flanking_strike.go index dc7a9c7f65..b5faeab1e4 100644 --- a/sim/hunter/flanking_strike.go +++ b/sim/hunter/flanking_strike.go @@ -23,12 +23,11 @@ func (hunter *Hunter) registerFlankingStrikeSpell() { hunter.pet.FlankingStrike = hunter.pet.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 415320}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, - BonusCritRating: 0, DamageMultiplier: 0.45, - CritMultiplier: hunter.pet.MeleeCritMultiplier(1, 0), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := spell.Unit.MHWeaponDamage(sim, spell.MeleeAttackPower()) + @@ -42,6 +41,7 @@ func (hunter *Hunter) registerFlankingStrikeSpell() { hunter.FlankingStrike = hunter.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 415320}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -62,9 +62,7 @@ func (hunter *Hunter) registerFlankingStrikeSpell() { return hunter.DistanceFromTarget <= 5 }, - BonusCritRating: 0, DamageMultiplier: 1, - CritMultiplier: hunter.critMultiplier(false, hunter.CurrentTarget), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := spell.Unit.MHWeaponDamage(sim, spell.MeleeAttackPower()) + diff --git a/sim/hunter/immolation_trap.go b/sim/hunter/immolation_trap.go index 20273ed7af..5c7db25d04 100644 --- a/sim/hunter/immolation_trap.go +++ b/sim/hunter/immolation_trap.go @@ -17,6 +17,7 @@ func (hunter *Hunter) getImmolationTrapConfig(rank int, timer *core.Timer) core. return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, Rank: rank, @@ -37,9 +38,8 @@ func (hunter *Hunter) getImmolationTrapConfig(rank int, timer *core.Timer) core. IgnoreHaste: true, // Hunter GCD is locked at 1.5s }, - DamageMultiplierAdditive: 1 + 0.15*float64(hunter.Talents.CleverTraps), - CritMultiplier: hunter.critMultiplier(false, hunter.CurrentTarget), - ThreatMultiplier: 1, + DamageMultiplier: 1 + 0.15*float64(hunter.Talents.CleverTraps), + ThreatMultiplier: 1, Dot: core.DotConfig{ Aura: core.Aura{ diff --git a/sim/hunter/multi_shot.go b/sim/hunter/multi_shot.go index ce1e7884fc..04da8a2d2f 100644 --- a/sim/hunter/multi_shot.go +++ b/sim/hunter/multi_shot.go @@ -26,6 +26,7 @@ func (hunter *Hunter) getMultiShotConfig(rank int, timer *core.Timer) core.Spell return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, CastType: proto.CastType_CastTypeRanged, @@ -58,11 +59,10 @@ func (hunter *Hunter) getMultiShotConfig(rank int, timer *core.Timer) core.Spell return hunter.DistanceFromTarget >= 8 }, - BonusCritRating: 0, - DamageMultiplierAdditive: 1 + .05*float64(hunter.Talents.Barrage), - DamageMultiplier: 1, - CritMultiplier: hunter.critMultiplier(true, hunter.CurrentTarget), - ThreatMultiplier: 1, + CritDamageBonus: hunter.mortalShots(), + + DamageMultiplier: 1 + .05*float64(hunter.Talents.Barrage), + ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { curTarget := target diff --git a/sim/hunter/pet_abilities.go b/sim/hunter/pet_abilities.go index c89d9d6904..82547f55fa 100644 --- a/sim/hunter/pet_abilities.go +++ b/sim/hunter/pet_abilities.go @@ -70,6 +70,7 @@ func (hp *HunterPet) newClaw() *core.Spell { return hp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, @@ -84,7 +85,6 @@ func (hp *HunterPet) newClaw() *core.Spell { }, DamageMultiplier: 1, - CritMultiplier: hp.DefaultMeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -121,6 +121,7 @@ func (hp *HunterPet) newBite() *core.Spell { return hp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, @@ -139,7 +140,6 @@ func (hp *HunterPet) newBite() *core.Spell { }, DamageMultiplier: 1, - CritMultiplier: hp.DefaultMeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -176,6 +176,7 @@ func (hp *HunterPet) newLightningBreath() *core.Spell { return hp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, FocusCost: core.FocusCostOptions{ @@ -189,7 +190,6 @@ func (hp *HunterPet) newLightningBreath() *core.Spell { }, DamageMultiplier: 1, - CritMultiplier: hp.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -273,6 +273,7 @@ func (hp *HunterPet) newScorpidPoison() *core.Spell { return hp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 55728}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskEmpty, FocusCost: core.FocusCostOptions{ @@ -316,97 +317,3 @@ func (hp *HunterPet) newScorpidPoison() *core.Spell { }, }) } - -func (hp *HunterPet) newSporeCloud() *core.Spell { - //debuffs := hp.NewEnemyAuraArray(core.SporeCloudAura) - return hp.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 53598}, - SpellSchool: core.SpellSchoolNature, - ProcMask: core.ProcMaskSpellDamage, - - FocusCost: core.FocusCostOptions{ - Cost: 20, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: PetGCD, - }, - IgnoreHaste: true, - CD: core.Cooldown{ - Timer: hp.NewTimer(), - Duration: time.Second * 10, - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - - Dot: core.DotConfig{ - IsAOE: true, - Aura: core.Aura{ - Label: "SporeCloud", - }, - NumberOfTicks: 3, - TickLength: time.Second * 3, - OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { - dot.SnapshotBaseDamage = sim.Roll(22, 28) + (0.049/3)*dot.Spell.MeleeAttackPower() - dot.SnapshotBaseDamage *= hp.killCommandMult() - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType]) - }, - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - for _, aoeTarget := range sim.Encounter.TargetUnits { - dot.CalcAndDealPeriodicSnapshotDamage(sim, aoeTarget, dot.OutcomeTick) - } - }, - }, - - ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { - spell.AOEDot().Apply(sim) - //for _, target := range spell.Unit.Env.Encounter.TargetUnits { - //debuffs.Get(target).Activate(sim) - //} - }, - }) -} - -func (hp *HunterPet) newVenomWebSpray() *core.Spell { - return hp.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 55509}, - SpellSchool: core.SpellSchoolNature, - ProcMask: core.ProcMaskEmpty, - - Cast: core.CastConfig{ - CD: core.Cooldown{ - Timer: hp.NewTimer(), - Duration: time.Second * 40, - }, - }, - - DamageMultiplier: 1, - ThreatMultiplier: 1, - - Dot: core.DotConfig{ - Aura: core.Aura{ - Label: "VenomWebSpray", - }, - NumberOfTicks: 4, - TickLength: time.Second * 1, - OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { - dot.SnapshotBaseDamage = 46 + 0.07*dot.Spell.MeleeAttackPower() - dot.SnapshotBaseDamage *= hp.killCommandMult() - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType]) - }, - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeTick) - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - result := spell.CalcAndDealOutcome(sim, target, spell.OutcomeMeleeSpecialHit) - if result.Landed() { - spell.Dot(target).Apply(sim) - } - }, - }) -} diff --git a/sim/hunter/rapid_fire.go b/sim/hunter/rapid_fire.go index 8c88280d9c..e59da2a15d 100644 --- a/sim/hunter/rapid_fire.go +++ b/sim/hunter/rapid_fire.go @@ -13,18 +13,16 @@ func (hunter *Hunter) registerRapidFire() { actionID := core.ActionID{SpellID: 3045} - hasteMultiplier := 1.4 - hunter.RapidFireAura = hunter.RegisterAura(core.Aura{ Label: "Rapid Fire", ActionID: actionID, Duration: time.Second * 15, OnGain: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.MultiplyRangedSpeed(sim, hasteMultiplier) + aura.Unit.MultiplyRangedSpeed(sim, 1.4) }, OnExpire: func(aura *core.Aura, sim *core.Simulation) { - aura.Unit.MultiplyRangedSpeed(sim, 1/hasteMultiplier) + aura.Unit.MultiplyRangedSpeed(sim, 1/1.4) }, }) diff --git a/sim/hunter/raptor_strike.go b/sim/hunter/raptor_strike.go index 9fe6514f8f..74d7791876 100644 --- a/sim/hunter/raptor_strike.go +++ b/sim/hunter/raptor_strike.go @@ -33,26 +33,23 @@ func (hunter *Hunter) getRaptorStrikeConfig(rank int) core.SpellConfig { dwSpecMulti := 1.0 var ohSpell *core.Spell if hasOHSpell { - // Uncomment if this ever gets added back - // if hunter.GetMHWeapon().WeaponType == hunter.GetOHWeapon().WeaponType { - // dwSpecMulti = 1.3 - // } - ohSpell = hunter.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}.WithTag(2), SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeOHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagNoOnCastComplete, - BonusCritRating: float64(hunter.Talents.SavageStrikes) * 10 * core.CritRatingPerCritChance, + BonusCritRating: float64(hunter.Talents.SavageStrikes) * 10 * core.CritRatingPerCritChance, + DamageMultiplier: 1.5 * dwSpecMulti, - CritMultiplier: hunter.critMultiplier(false, hunter.CurrentTarget), }) } spellConfig := core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial | core.ProcMaskMeleeMHAuto, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, Rank: rank, @@ -74,7 +71,6 @@ func (hunter *Hunter) getRaptorStrikeConfig(rank int) core.SpellConfig { BonusCritRating: float64(hunter.Talents.SavageStrikes) * 10 * core.CritRatingPerCritChance, DamageMultiplier: 1 * dwSpecMulti, - CritMultiplier: hunter.critMultiplier(false, hunter.CurrentTarget), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { weaponDamage := 0.0 diff --git a/sim/hunter/serpent_sting.go b/sim/hunter/serpent_sting.go index 4ac8d8721d..1485034b62 100644 --- a/sim/hunter/serpent_sting.go +++ b/sim/hunter/serpent_sting.go @@ -19,6 +19,7 @@ func (hunter *Hunter) getSerpentStingConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagAPL | core.SpellFlagPureDot | core.SpellFlagPoison, CastType: proto.CastType_CastTypeRanged, @@ -40,8 +41,8 @@ func (hunter *Hunter) getSerpentStingConfig(rank int) core.SpellConfig { return hunter.DistanceFromTarget >= 8 }, - DamageMultiplierAdditive: 1 + 0.02*float64(hunter.Talents.ImprovedSerpentSting), - ThreatMultiplier: 1, + DamageMultiplier: 1 + 0.02*float64(hunter.Talents.ImprovedSerpentSting), + ThreatMultiplier: 1, Dot: core.DotConfig{ Aura: core.Aura{ @@ -86,13 +87,16 @@ func (hunter *Hunter) chimeraShotSerpentStingSpell() *core.Spell { return hunter.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 409493}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskEmpty, Flags: core.SpellFlagMeleeMetrics, + BonusCritRating: 1 * float64(hunter.Talents.LethalShots) * core.CritRatingPerCritChance, // This is added manually here because spell uses ProcMaskEmpty - DamageMultiplierAdditive: 1 + 0.02*float64(hunter.Talents.ImprovedSerpentSting), - DamageMultiplier: 1, - CritMultiplier: hunter.critMultiplier(true, hunter.CurrentTarget), + + CritDamageBonus: hunter.mortalShots(), + + DamageMultiplier: 1 + 0.02*float64(hunter.Talents.ImprovedSerpentSting), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/hunter/steady_shot.go b/sim/hunter/steady_shot.go index 904bda712c..577d8d5c93 100644 --- a/sim/hunter/steady_shot.go +++ b/sim/hunter/steady_shot.go @@ -22,6 +22,7 @@ func (hunter *Hunter) registerSteadyShotSpell() { hunter.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 437123}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskRangedSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, CastType: proto.CastType_CastTypeRanged, @@ -48,11 +49,10 @@ func (hunter *Hunter) registerSteadyShotSpell() { return hunter.DistanceFromTarget >= 8 }, - BonusCritRating: 0, - DamageMultiplierAdditive: 1, - DamageMultiplier: 0.75, - CritMultiplier: hunter.critMultiplier(true, hunter.CurrentTarget), - ThreatMultiplier: 1, + CritDamageBonus: hunter.mortalShots(), + + DamageMultiplier: 0.75, + ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := hunter.AutoAttacks.Ranged().CalculateWeaponDamage(sim, spell.RangedAttackPower(target)) + diff --git a/sim/hunter/wing_clip.go b/sim/hunter/wing_clip.go index aaa297d1c6..0d87565ff2 100644 --- a/sim/hunter/wing_clip.go +++ b/sim/hunter/wing_clip.go @@ -13,6 +13,7 @@ func (hunter *Hunter) getWingClipConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, Rank: rank, @@ -32,9 +33,7 @@ func (hunter *Hunter) getWingClipConfig(rank int) core.SpellConfig { return hunter.DistanceFromTarget <= 5 }, - BonusCritRating: 0, DamageMultiplier: 1, - CritMultiplier: hunter.critMultiplier(false, hunter.CurrentTarget), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMeleeWeaponSpecialHitAndCrit) diff --git a/sim/rogue/shuriken_toss.go b/sim/rogue/shuriken_toss.go index 6d74dc3ea5..593549a735 100644 --- a/sim/rogue/shuriken_toss.go +++ b/sim/rogue/shuriken_toss.go @@ -35,8 +35,6 @@ func (rogue *Rogue) registerShurikenTossSpell() { IgnoreHaste: true, }, - CritMultiplier: rogue.RangedCritMultiplier(false), - DamageMultiplier: 1, ThreatMultiplier: 1, From fe41c938e7a328996c2856b905032411cb1492cd Mon Sep 17 00:00:00 2001 From: vigo Date: Thu, 21 Mar 2024 01:16:41 +0100 Subject: [PATCH 04/12] [warrior] move warrior over, too --- sim/warrior/bloodthirst.go | 4 ++- sim/warrior/concussion_blow.go | 48 ----------------------------- sim/warrior/execute.go | 4 ++- sim/warrior/hamstring.go | 4 ++- sim/warrior/heroic_strike_cleave.go | 8 +++-- sim/warrior/mortal_strike.go | 4 ++- sim/warrior/overpower.go | 7 +++-- sim/warrior/quick_strike.go | 4 ++- sim/warrior/raging_blow.go | 4 ++- sim/warrior/revenge.go | 4 ++- sim/warrior/shield_slam.go | 7 +++-- sim/warrior/slam.go | 5 +-- sim/warrior/talents.go | 4 +++ sim/warrior/thunder_clap.go | 4 ++- sim/warrior/warrior.go | 12 -------- sim/warrior/whirlwind.go | 4 ++- 16 files changed, 50 insertions(+), 77 deletions(-) delete mode 100644 sim/warrior/concussion_blow.go diff --git a/sim/warrior/bloodthirst.go b/sim/warrior/bloodthirst.go index c2fb25fd6a..1c508fc540 100644 --- a/sim/warrior/bloodthirst.go +++ b/sim/warrior/bloodthirst.go @@ -14,6 +14,7 @@ func (warrior *Warrior) registerBloodthirstSpell(cdTimer *core.Timer) { warrior.Bloodthirst = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 23894}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL | SpellFlagBloodSurge, @@ -32,8 +33,9 @@ func (warrior *Warrior) registerBloodthirstSpell(cdTimer *core.Timer) { }, }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warrior/concussion_blow.go b/sim/warrior/concussion_blow.go deleted file mode 100644 index 0f107bf86e..0000000000 --- a/sim/warrior/concussion_blow.go +++ /dev/null @@ -1,48 +0,0 @@ -package warrior - -import ( - "time" - - "github.com/wowsims/sod/sim/core" -) - -func (warrior *Warrior) registerConcussionBlowSpell() { - if !warrior.Talents.ConcussionBlow { - return - } - - warrior.ConcussionBlow = warrior.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 12809}, - SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskMeleeMHSpecial, - Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, - - RageCost: core.RageCostOptions{ - Cost: 15 - warrior.FocusedRageDiscount, - Refund: 0.8, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - IgnoreHaste: true, - CD: core.Cooldown{ - Timer: warrior.NewTimer(), - Duration: time.Second * 30, - }, - }, - - DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), - ThreatMultiplier: 2, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseDamage := 0.38 * spell.MeleeAttackPower() - result := spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMeleeSpecialHitAndCrit) - - if !result.Landed() { - spell.IssueRefund(sim) - } - }, - }) -} diff --git a/sim/warrior/execute.go b/sim/warrior/execute.go index 26c25ec2c0..ef4050e989 100644 --- a/sim/warrior/execute.go +++ b/sim/warrior/execute.go @@ -30,6 +30,7 @@ func (warrior *Warrior) registerExecuteSpell() { warrior.Execute = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -47,8 +48,9 @@ func (warrior *Warrior) registerExecuteSpell() { return sim.IsExecutePhase20() }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1.25, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warrior/hamstring.go b/sim/warrior/hamstring.go index 34aff8a64c..f85b2b52bf 100644 --- a/sim/warrior/hamstring.go +++ b/sim/warrior/hamstring.go @@ -22,6 +22,7 @@ func (warrior *Warrior) registerHamstringSpell() { warrior.Hamstring = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -35,8 +36,9 @@ func (warrior *Warrior) registerHamstringSpell() { }, }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warrior/heroic_strike_cleave.go b/sim/warrior/heroic_strike_cleave.go index 8576f2edc0..6d89b4e9d6 100644 --- a/sim/warrior/heroic_strike_cleave.go +++ b/sim/warrior/heroic_strike_cleave.go @@ -22,6 +22,7 @@ func (warrior *Warrior) registerHeroicStrikeSpell() { warrior.HeroicStrike = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial | core.ProcMaskMeleeMHAuto, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagNoOnCastComplete | SpellFlagBloodSurge, @@ -30,8 +31,9 @@ func (warrior *Warrior) registerHeroicStrikeSpell() { Refund: 0.8, }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, FlatThreatBonus: 259, @@ -77,6 +79,7 @@ func (warrior *Warrior) registerCleaveSpell() { warrior.Cleave = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial | core.ProcMaskMeleeMHAuto, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, @@ -84,8 +87,9 @@ func (warrior *Warrior) registerCleaveSpell() { Cost: 20 - warrior.FocusedRageDiscount, }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, FlatThreatBonus: 225, diff --git a/sim/warrior/mortal_strike.go b/sim/warrior/mortal_strike.go index f1d7fb9c96..e8ecfc19b8 100644 --- a/sim/warrior/mortal_strike.go +++ b/sim/warrior/mortal_strike.go @@ -26,6 +26,7 @@ func (warrior *Warrior) registerMortalStrikeSpell(cdTimer *core.Timer) { warrior.MortalStrike = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -44,8 +45,9 @@ func (warrior *Warrior) registerMortalStrikeSpell(cdTimer *core.Timer) { }, }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warrior/overpower.go b/sim/warrior/overpower.go index c102793a1f..184f1edcff 100644 --- a/sim/warrior/overpower.go +++ b/sim/warrior/overpower.go @@ -47,6 +47,7 @@ func (warrior *Warrior) registerOverpowerSpell(cdTimer *core.Timer) { warrior.Overpower = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -68,9 +69,11 @@ func (warrior *Warrior) registerOverpowerSpell(cdTimer *core.Timer) { return warrior.OverpowerAura.IsActive() && warrior.StanceMatches(BattleStance) }, - BonusCritRating: 25 * core.CritRatingPerCritChance * float64(warrior.Talents.ImprovedOverpower), + BonusCritRating: 25 * core.CritRatingPerCritChance * float64(warrior.Talents.ImprovedOverpower), + + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 0.75, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warrior/quick_strike.go b/sim/warrior/quick_strike.go index e582951ba3..dcf4929b0d 100644 --- a/sim/warrior/quick_strike.go +++ b/sim/warrior/quick_strike.go @@ -13,6 +13,7 @@ func (warrior *Warrior) registerQuickStrike() { warrior.QuickStrike = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 429765}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL | SpellFlagBloodSurge, @@ -26,8 +27,9 @@ func (warrior *Warrior) registerQuickStrike() { }, }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warrior/raging_blow.go b/sim/warrior/raging_blow.go index d722e9301b..9c516560bb 100644 --- a/sim/warrior/raging_blow.go +++ b/sim/warrior/raging_blow.go @@ -15,6 +15,7 @@ func (warrior *Warrior) registerRagingBlow() { warrior.RagingBlow = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 402911}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -35,8 +36,9 @@ func (warrior *Warrior) registerRagingBlow() { return warrior.ConsumedByRageAura.IsActive() || warrior.BloodrageAura.IsActive() || warrior.BerserkerRageAura.IsActive() }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warrior/revenge.go b/sim/warrior/revenge.go index 8a1878b428..399a3f2dea 100644 --- a/sim/warrior/revenge.go +++ b/sim/warrior/revenge.go @@ -47,6 +47,7 @@ func (warrior *Warrior) registerRevengeSpell(cdTimer *core.Timer) { warrior.Revenge = warrior.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -68,8 +69,9 @@ func (warrior *Warrior) registerRevengeSpell(cdTimer *core.Timer) { return warrior.StanceMatches(DefensiveStance) && warrior.revengeProcAura.IsActive() }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, FlatThreatBonus: 121, diff --git a/sim/warrior/shield_slam.go b/sim/warrior/shield_slam.go index ddef7b1b11..bcc83d2ea6 100644 --- a/sim/warrior/shield_slam.go +++ b/sim/warrior/shield_slam.go @@ -31,6 +31,7 @@ func (warrior *Warrior) registerShieldSlamSpell() { warrior.ShieldSlam = warrior.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, // TODO: Is this right? Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -52,9 +53,11 @@ func (warrior *Warrior) registerShieldSlamSpell() { return warrior.PseudoStats.CanBlock }, - BonusCritRating: 5 * core.CritRatingPerCritChance, + BonusCritRating: 5 * core.CritRatingPerCritChance, + + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1.3, FlatThreatBonus: 770, diff --git a/sim/warrior/slam.go b/sim/warrior/slam.go index 9fc52ec5cc..edbd1f834f 100644 --- a/sim/warrior/slam.go +++ b/sim/warrior/slam.go @@ -40,6 +40,7 @@ func (warrior *Warrior) registerSlamSpell() { warrior.Slam = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -61,9 +62,9 @@ func (warrior *Warrior) registerSlamSpell() { }, }, - BonusCritRating: 0, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1, FlatThreatBonus: 140, diff --git a/sim/warrior/talents.go b/sim/warrior/talents.go index 61ecda7850..4f3c73c8e6 100644 --- a/sim/warrior/talents.go +++ b/sim/warrior/talents.go @@ -332,3 +332,7 @@ func (warrior *Warrior) registerLastStandCD() { Type: core.CooldownTypeSurvival, }) } + +func (warrior *Warrior) impale() float64 { + return 0.1 * float64(warrior.Talents.Impale) +} diff --git a/sim/warrior/thunder_clap.go b/sim/warrior/thunder_clap.go index e747ec792e..61e95acb61 100644 --- a/sim/warrior/thunder_clap.go +++ b/sim/warrior/thunder_clap.go @@ -31,6 +31,7 @@ func (warrior *Warrior) registerThunderClapSpell() { warrior.ThunderClap = warrior.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: info.spellID}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -51,8 +52,9 @@ func (warrior *Warrior) registerThunderClapSpell() { return hasFuriousThunder || warrior.StanceMatches(BattleStance) }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: core.TernaryFloat64(hasFuriousThunder, 2, 1), - CritMultiplier: warrior.SpellCritMultiplier(1, 0), ThreatMultiplier: core.TernaryFloat64(hasFuriousThunder, 2.5*1.5, 2.5), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warrior/warrior.go b/sim/warrior/warrior.go index 8db0940409..dfe0960ce8 100644 --- a/sim/warrior/warrior.go +++ b/sim/warrior/warrior.go @@ -106,9 +106,6 @@ func (warrior *Warrior) AddPartyBuffs(_ *proto.PartyBuffs) { } func (warrior *Warrior) Initialize() { - warrior.AutoAttacks.MHConfig().CritMultiplier = warrior.autoCritMultiplier() - warrior.AutoAttacks.OHConfig().CritMultiplier = warrior.autoCritMultiplier() - primaryTimer := warrior.NewTimer() overpowerRevengeTimer := warrior.NewTimer() @@ -129,7 +126,6 @@ func (warrior *Warrior) Initialize() { warrior.registerSlamSpell() warrior.registerThunderClapSpell() warrior.registerWhirlwindSpell() - warrior.registerConcussionBlowSpell() warrior.registerRendSpell() warrior.registerHamstringSpell() @@ -167,14 +163,6 @@ func NewWarrior(character *core.Character, talents string, inputs WarriorInputs) return warrior } -func (warrior *Warrior) autoCritMultiplier() float64 { - return warrior.MeleeCritMultiplier(1, 0) -} - -func (warrior *Warrior) critMultiplier() float64 { - return warrior.MeleeCritMultiplier(1, 0.1*float64(warrior.Talents.Impale)) -} - // Agent is a generic way to access underlying warrior on any of the agents. type WarriorAgent interface { GetWarrior() *Warrior diff --git a/sim/warrior/whirlwind.go b/sim/warrior/whirlwind.go index 17ed4a6af5..c8b48623b6 100644 --- a/sim/warrior/whirlwind.go +++ b/sim/warrior/whirlwind.go @@ -18,6 +18,7 @@ func (warrior *Warrior) registerWhirlwindSpell() { warrior.Whirlwind = warrior.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL | SpellFlagBloodSurge, @@ -38,8 +39,9 @@ func (warrior *Warrior) registerWhirlwindSpell() { return warrior.StanceMatches(BerserkerStance) }, + CritDamageBonus: warrior.impale(), + DamageMultiplier: 1, - CritMultiplier: warrior.critMultiplier(), ThreatMultiplier: 1.25, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { From d46881c7c15f3e34294d871db976441192dc883d Mon Sep 17 00:00:00 2001 From: vigo Date: Thu, 21 Mar 2024 23:46:00 +0100 Subject: [PATCH 05/12] [shaman] and shaman as well --- sim/shaman/ancestral_awakening.go | 3 +-- sim/shaman/ancestral_guidance.go | 3 +-- sim/shaman/chain_heal.go | 5 +++-- sim/shaman/electric_spell.go | 5 ++++- sim/shaman/fire_nova.go | 4 +++- sim/shaman/fire_totems.go | 12 +++++++++--- sim/shaman/flametongue_weapon.go | 6 ++++-- sim/shaman/frostbrand_weapon.go | 4 +++- sim/shaman/healing_wave.go | 8 +++++--- sim/shaman/items.go | 2 +- sim/shaman/lava_burst.go | 4 +++- sim/shaman/lava_lash.go | 2 +- sim/shaman/lesser_healing_wave.go | 6 +++--- sim/shaman/molten_blast.go | 4 +++- sim/shaman/shaman.go | 5 ----- sim/shaman/shocks.go | 4 +++- sim/shaman/spirit_wolves.go | 1 - sim/shaman/stormstrike.go | 4 ++-- sim/shaman/talents.go | 4 ++++ sim/shaman/water_totems.go | 2 -- sim/shaman/windfury_weapon.go | 2 +- 21 files changed, 54 insertions(+), 36 deletions(-) diff --git a/sim/shaman/ancestral_awakening.go b/sim/shaman/ancestral_awakening.go index c9d6f779d2..bc7afdd8ff 100644 --- a/sim/shaman/ancestral_awakening.go +++ b/sim/shaman/ancestral_awakening.go @@ -15,11 +15,10 @@ func (shaman *Shaman) applyAncestralAwakening() { shaman.AncestralAwakening = shaman.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.ShamanRune_RuneFeetAncestralAwakening)}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellHealing, Flags: core.SpellFlagHelpful | core.SpellFlagAPL, - CritMultiplier: 1, - DamageMultiplier: 1 * (1 + .02*float64(shaman.Talents.Purification)), ThreatMultiplier: 1, diff --git a/sim/shaman/ancestral_guidance.go b/sim/shaman/ancestral_guidance.go index 2c613f3c5d..a11677c4fe 100644 --- a/sim/shaman/ancestral_guidance.go +++ b/sim/shaman/ancestral_guidance.go @@ -23,11 +23,10 @@ func (shaman *Shaman) applyAncestralGuidance() { agDamageSpell := shaman.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 409337}, // AG Damage has its own Spell ID SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagIgnoreResists, - CritMultiplier: 1, - DamageMultiplier: 1, ThreatMultiplier: 1, }) diff --git a/sim/shaman/chain_heal.go b/sim/shaman/chain_heal.go index 1e4f83388e..72081f196a 100644 --- a/sim/shaman/chain_heal.go +++ b/sim/shaman/chain_heal.go @@ -61,6 +61,7 @@ func (shaman *Shaman) newChainHealSpellConfig(rank int, isOverload bool) core.Sp spell := core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_ShamanChainHeal, + DefenseType: core.DefenseTypeMagic, SpellSchool: core.SpellSchoolNature, ProcMask: core.ProcMaskSpellHealing, Flags: flags, @@ -81,9 +82,9 @@ func (shaman *Shaman) newChainHealSpellConfig(rank int, isOverload bool) core.Sp }, }, - BonusCritRating: float64(shaman.Talents.TidalMastery) * core.CritRatingPerCritChance, + BonusCritRating: float64(shaman.Talents.TidalMastery) * core.CritRatingPerCritChance, + DamageMultiplier: 1 + .02*float64(shaman.Talents.Purification), - CritMultiplier: shaman.DefaultHealingCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/electric_spell.go b/sim/shaman/electric_spell.go index d2a5bf784f..511946fc2a 100644 --- a/sim/shaman/electric_spell.go +++ b/sim/shaman/electric_spell.go @@ -33,6 +33,7 @@ func (shaman *Shaman) newElectricSpellConfig(actionID core.ActionID, baseCost fl spell := core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: flags, MetricSplits: 6, @@ -55,8 +56,10 @@ func (shaman *Shaman) newElectricSpellConfig(actionID core.ActionID, baseCost fl BonusCritRating: 0 + float64(shaman.Talents.TidalMastery)*core.CritRatingPerCritChance + float64(shaman.Talents.CallOfThunder)*core.CritRatingPerCritChance, + + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: shaman.ConcussionMultiplier(), - CritMultiplier: shaman.ElementalCritMultiplier(0), ThreatMultiplier: 1, } diff --git a/sim/shaman/fire_nova.go b/sim/shaman/fire_nova.go index 787ce56c06..fd363514c4 100644 --- a/sim/shaman/fire_nova.go +++ b/sim/shaman/fire_nova.go @@ -46,6 +46,7 @@ func (shaman *Shaman) newFireNovaSpellConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_ShamanFireNova, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagFocusable | core.SpellFlagAPL, @@ -66,8 +67,9 @@ func (shaman *Shaman) newFireNovaSpellConfig(rank int) core.SpellConfig { }, }, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: 1, - CritMultiplier: shaman.ElementalCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/fire_totems.go b/sim/shaman/fire_totems.go index 4fda9d8b0d..2e3122a5f1 100644 --- a/sim/shaman/fire_totems.go +++ b/sim/shaman/fire_totems.go @@ -44,6 +44,7 @@ func (shaman *Shaman) newSearingTotemSpellConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_SearingTotem, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, Flags: SpellFlagTotem | core.SpellFlagAPL, @@ -62,8 +63,9 @@ func (shaman *Shaman) newSearingTotemSpellConfig(rank int) core.SpellConfig { IgnoreHaste: true, }, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: 1 + float64(shaman.Talents.CallOfFlame)*0.05, - CritMultiplier: shaman.ElementalCritMultiplier(0), Dot: core.DotConfig{ Aura: core.Aura{ @@ -133,6 +135,7 @@ func (shaman *Shaman) newMagmaTotemSpellConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_MagmaTotem, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, Flags: SpellFlagTotem | core.SpellFlagAPL, @@ -151,8 +154,9 @@ func (shaman *Shaman) newMagmaTotemSpellConfig(rank int) core.SpellConfig { IgnoreHaste: true, }, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: 1 + float64(shaman.Talents.CallOfFlame)*0.05, - CritMultiplier: shaman.ElementalCritMultiplier(0), Dot: core.DotConfig{ IsAOE: true, @@ -227,6 +231,7 @@ func (shaman *Shaman) newFireNovaTotemSpellConfig(rank int) core.SpellConfig { spell := core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, SpellCode: SpellCode_FireNovaTotem, ProcMask: core.ProcMaskEmpty, Flags: SpellFlagTotem | core.SpellFlagAPL, @@ -250,8 +255,9 @@ func (shaman *Shaman) newFireNovaTotemSpellConfig(rank int) core.SpellConfig { }, }, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: 1 + float64(shaman.Talents.CallOfFlame)*0.05, - CritMultiplier: shaman.ElementalCritMultiplier(0), Dot: core.DotConfig{ IsAOE: true, diff --git a/sim/shaman/flametongue_weapon.go b/sim/shaman/flametongue_weapon.go index 1fc9247d9d..c7af42427f 100644 --- a/sim/shaman/flametongue_weapon.go +++ b/sim/shaman/flametongue_weapon.go @@ -27,12 +27,14 @@ func (shaman *Shaman) newFlametongueImbueSpell(weapon *core.Item) *core.Spell { spellCoeff := .1 return shaman.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: int32(spellID)}, + ActionID: core.ActionID{SpellID: spellID}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskWeaponProc, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: []float64{1, 1.05, 1.1, 1.15}[shaman.Talents.ElementalWeapons], - CritMultiplier: shaman.ElementalCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/frostbrand_weapon.go b/sim/shaman/frostbrand_weapon.go index a148fc52c5..e933b18e0d 100644 --- a/sim/shaman/frostbrand_weapon.go +++ b/sim/shaman/frostbrand_weapon.go @@ -40,10 +40,12 @@ func (shaman *Shaman) newFrostbrandImbueSpell() *core.Spell { return shaman.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFrost, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskWeaponProc, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: []float64{1, 1.05, 1.1, 1.15}[shaman.Talents.ElementalWeapons], - CritMultiplier: shaman.ElementalCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/healing_wave.go b/sim/shaman/healing_wave.go index 66ca1eb420..00bae33b2f 100644 --- a/sim/shaman/healing_wave.go +++ b/sim/shaman/healing_wave.go @@ -58,6 +58,7 @@ func (shaman *Shaman) newHealingWaveSpellConfig(rank int, isOverload bool) core. ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_ShamanHealingWave, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellHealing, Flags: flags, @@ -80,9 +81,10 @@ func (shaman *Shaman) newHealingWaveSpellConfig(rank int, isOverload bool) core. }, BonusCritRating: float64(shaman.Talents.TidalMastery) * 1 * core.CritRatingPerCritChance, - DamageMultiplier: 1 * - (1 + .02*float64(shaman.Talents.Purification)), - CritMultiplier: shaman.DefaultHealingCritMultiplier(), + + CritDamageBonus: shaman.elementalFury(), + + DamageMultiplier: 1 + .02*float64(shaman.Talents.Purification), ThreatMultiplier: 1 - (float64(shaman.Talents.HealingGrace) * 0.05), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/items.go b/sim/shaman/items.go index ffc6a7506a..755fbad1fa 100644 --- a/sim/shaman/items.go +++ b/sim/shaman/items.go @@ -28,6 +28,7 @@ func init() { spell := character.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 436413}, SpellSchool: core.SpellSchoolPlague, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, @@ -39,7 +40,6 @@ func init() { }, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { for _, aoeTarget := range sim.Encounter.TargetUnits { diff --git a/sim/shaman/lava_burst.go b/sim/shaman/lava_burst.go index 30a609d78a..5d4778100f 100644 --- a/sim/shaman/lava_burst.go +++ b/sim/shaman/lava_burst.go @@ -40,6 +40,7 @@ func (shaman *Shaman) newLavaBurstSpellConfig(isOverload bool) core.SpellConfig ActionID: core.ActionID{SpellID: int32(proto.ShamanRune_RuneHandsLavaBurst)}, SpellCode: SpellCode_ShamanLavaBurst, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: flags, MissileSpeed: 20, @@ -62,8 +63,9 @@ func (shaman *Shaman) newLavaBurstSpellConfig(isOverload bool) core.SpellConfig }, }, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: 1, - CritMultiplier: shaman.ElementalCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/lava_lash.go b/sim/shaman/lava_lash.go index adeb55db76..f8d0b3d73b 100644 --- a/sim/shaman/lava_lash.go +++ b/sim/shaman/lava_lash.go @@ -20,6 +20,7 @@ func (shaman *Shaman) applyLavaLash() { shaman.LavaLash = shaman.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.ShamanRune_RuneHandsLavaLash)}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeOHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL | core.SpellFlagIgnoreResists, @@ -39,7 +40,6 @@ func (shaman *Shaman) applyLavaLash() { }, DamageMultiplier: 1.5 * imbueMultiplier * (1 + (.02 * float64(shaman.Talents.WeaponMastery))), - CritMultiplier: shaman.DefaultMeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/lesser_healing_wave.go b/sim/shaman/lesser_healing_wave.go index a959e2d5cd..ab1da1dc4a 100644 --- a/sim/shaman/lesser_healing_wave.go +++ b/sim/shaman/lesser_healing_wave.go @@ -41,6 +41,7 @@ func (shaman *Shaman) newLesserHealingWaveSpellConfig(rank int) core.SpellConfig ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_ShamanLesserHealingWave, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellHealing, Flags: core.SpellFlagHelpful | core.SpellFlagAPL, @@ -61,9 +62,8 @@ func (shaman *Shaman) newLesserHealingWaveSpellConfig(rank int) core.SpellConfig }, BonusCritRating: float64(shaman.Talents.TidalMastery) * 1 * core.CritRatingPerCritChance, - DamageMultiplier: 1 * - (1 + .02*float64(shaman.Talents.Purification)), - CritMultiplier: shaman.DefaultHealingCritMultiplier(), + + DamageMultiplier: 1 + .02*float64(shaman.Talents.Purification), ThreatMultiplier: 1 - (float64(shaman.Talents.HealingGrace) * 0.05), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/molten_blast.go b/sim/shaman/molten_blast.go index 206c280b59..b0b050279e 100644 --- a/sim/shaman/molten_blast.go +++ b/sim/shaman/molten_blast.go @@ -27,6 +27,7 @@ func (shaman *Shaman) applyMoltenBlast() { ActionID: core.ActionID{SpellID: int32(proto.ShamanRune_RuneHandsMoltenBlast)}, SpellCode: SpellCode_ShamanMoltenBlast, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskMeleeOHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL, @@ -45,8 +46,9 @@ func (shaman *Shaman) applyMoltenBlast() { }, }, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: 1, - CritMultiplier: shaman.ElementalCritMultiplier(0), ThreatMultiplier: 2, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/shaman.go b/sim/shaman/shaman.go index 944223bbdf..fcac95eaaa 100644 --- a/sim/shaman/shaman.go +++ b/sim/shaman/shaman.go @@ -243,11 +243,6 @@ func (shaman *Shaman) HasRune(rune proto.ShamanRune) bool { func (shaman *Shaman) Reset(sim *core.Simulation) { } -func (shaman *Shaman) ElementalCritMultiplier(secondary float64) float64 { - critBonus := core.TernaryFloat64(shaman.Talents.ElementalFury, 1, 0) + secondary - return shaman.SpellCritMultiplier(1, critBonus) -} - func (shaman *Shaman) ConcussionMultiplier() float64 { return 1 + 0.01*float64(shaman.Talents.Concussion) } diff --git a/sim/shaman/shocks.go b/sim/shaman/shocks.go index 91b0b95bb7..26a7a2078e 100644 --- a/sim/shaman/shocks.go +++ b/sim/shaman/shocks.go @@ -15,6 +15,7 @@ func (shaman *Shaman) newShockSpellConfig(actionId core.ActionID, spellSchool co return core.SpellConfig{ ActionID: actionId, SpellSchool: spellSchool, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagShock | core.SpellFlagAPL, @@ -32,8 +33,9 @@ func (shaman *Shaman) newShockSpellConfig(actionId core.ActionID, spellSchool co }, }, + CritDamageBonus: shaman.elementalFury(), + DamageMultiplier: shaman.ConcussionMultiplier(), - CritMultiplier: shaman.ElementalCritMultiplier(0), ThreatMultiplier: 1, } } diff --git a/sim/shaman/spirit_wolves.go b/sim/shaman/spirit_wolves.go index 1ac4bc9b45..e407664fae 100644 --- a/sim/shaman/spirit_wolves.go +++ b/sim/shaman/spirit_wolves.go @@ -55,7 +55,6 @@ package shaman // BaseDamageMin: 246, // BaseDamageMax: 372, // SwingSpeed: 1.5, -// CritMultiplier: 2, // }, // AutoSwingMelee: true, // }) diff --git a/sim/shaman/stormstrike.go b/sim/shaman/stormstrike.go index 65af44c19a..0f0d152ca9 100644 --- a/sim/shaman/stormstrike.go +++ b/sim/shaman/stormstrike.go @@ -17,11 +17,11 @@ func (shaman *Shaman) registerStormstrikeSpell() { ohSpell = shaman.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 410156}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeOHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagNoOnCastComplete, DamageMultiplier: shaman.AutoAttacks.OHConfig().DamageMultiplier, - CritMultiplier: shaman.DefaultMeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -34,6 +34,7 @@ func (shaman *Shaman) registerStormstrikeSpell() { shaman.Stormstrike = shaman.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 17364}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagAPL | core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, @@ -52,7 +53,6 @@ func (shaman *Shaman) registerStormstrikeSpell() { }, DamageMultiplier: 1, - CritMultiplier: shaman.DefaultMeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/shaman/talents.go b/sim/shaman/talents.go index dcdeb54270..38801c5f93 100644 --- a/sim/shaman/talents.go +++ b/sim/shaman/talents.go @@ -340,6 +340,10 @@ func (shaman *Shaman) applyFlurry() { }) } +func (shaman *Shaman) elementalFury() float64 { + return core.TernaryFloat64(shaman.Talents.ElementalFury, 1, 0) +} + // func (shaman *Shaman) registerManaTideTotemCD() { // if !shaman.Talents.ManaTideTotem { // return diff --git a/sim/shaman/water_totems.go b/sim/shaman/water_totems.go index bdfc891f58..ffc72c944f 100644 --- a/sim/shaman/water_totems.go +++ b/sim/shaman/water_totems.go @@ -49,8 +49,6 @@ func (shaman *Shaman) newHealingStreamTotemSpellConfig(rank int) core.SpellConfi ProcMask: core.ProcMaskSpellHealing, Flags: core.SpellFlagHelpful | core.SpellFlagNoOnCastComplete | core.SpellFlagNoLogs | core.SpellFlagNoMetrics, - CritMultiplier: 1, - DamageMultiplier: 1 + (.02 * float64(shaman.Talents.Purification)) + 0.05*float64(shaman.Talents.RestorativeTotems), ThreatMultiplier: 1 - (float64(shaman.Talents.HealingGrace) * 0.05), diff --git a/sim/shaman/windfury_weapon.go b/sim/shaman/windfury_weapon.go index 0fdedc81db..4420005746 100644 --- a/sim/shaman/windfury_weapon.go +++ b/sim/shaman/windfury_weapon.go @@ -41,11 +41,11 @@ func (shaman *Shaman) newWindfuryImbueSpell(isMH bool) *core.Spell { spellConfig := core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: procMask | core.ProcMaskWeaponProc, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, DamageMultiplier: damageMultiplier, - CritMultiplier: shaman.DefaultMeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { From ad72cc2a0f573dfed379d59cb4aac7c5641f36b1 Mon Sep 17 00:00:00 2001 From: vigo Date: Thu, 21 Mar 2024 23:47:49 +0100 Subject: [PATCH 06/12] [druid] and most of druid (but ExpectedDamage) [core] update dependencies, including protobuf with a known vulnerability --- go.mod | 14 +++++++------- go.sum | 15 +++++++++++++++ sim/druid/_ferocious_bite.go | 3 ++- sim/druid/_lacerate.go | 2 +- sim/druid/_maul.go | 2 +- sim/druid/_rake.go | 2 +- sim/druid/_swipe.go | 4 ++-- sim/druid/ferocious_bite.go | 4 ++-- sim/druid/forms.go | 3 +-- sim/druid/items.go | 2 +- sim/druid/mangle.go | 4 ++-- sim/druid/moonfire.go | 7 +++++-- sim/druid/rake.go | 2 +- sim/druid/runes.go | 7 +++++-- sim/druid/shred.go | 2 +- sim/druid/starfire.go | 7 +++++-- sim/druid/starsurge.go | 5 +++-- sim/druid/talents.go | 4 ++-- sim/druid/wrath.go | 7 +++++-- sim/warlock/chaos_bolt.go | 2 +- 20 files changed, 63 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index dea9a2223e..051b778145 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,17 @@ module github.com/wowsims/sod go 1.21 require ( - github.com/google/go-cmp v0.5.8 - github.com/google/uuid v1.3.1 - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 - github.com/spf13/cobra v1.7.0 + github.com/google/go-cmp v0.6.0 + github.com/google/uuid v1.6.0 + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c + github.com/spf13/cobra v1.8.0 github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a - golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f - google.golang.org/protobuf v1.31.0 + golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 + google.golang.org/protobuf v1.33.0 ) require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/sys v0.1.0 // indirect + golang.org/x/sys v0.18.0 // indirect ) diff --git a/go.sum b/go.sum index 5f7705fd04..ac889f30d8 100644 --- a/go.sum +++ b/go.sum @@ -1,29 +1,44 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f h1:Al51T6tzvuh3oiwX11vex3QgJ2XTedFPGmbEVh8cdoc= golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sim/druid/_ferocious_bite.go b/sim/druid/_ferocious_bite.go index 446d01f41d..0db25c232a 100644 --- a/sim/druid/_ferocious_bite.go +++ b/sim/druid/_ferocious_bite.go @@ -12,6 +12,7 @@ func (druid *Druid) registerFerociousBiteSpell() { druid.FerociousBite = druid.RegisterSpell(Cat, core.SpellConfig{ ActionID: core.ActionID{SpellID: 48577}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -33,9 +34,9 @@ func (druid *Druid) registerFerociousBiteSpell() { BonusCritRating: 0 + core.TernaryFloat64(druid.HasSetBonus(ItemSetMalfurionsBattlegear, 4), 5*core.CritRatingPerCritChance, 0.0) + core.TernaryFloat64(druid.AssumeBleedActive, 5*float64(druid.Talents.RendAndTear)*core.CritRatingPerCritChance, 0), + DamageMultiplier: (1 + 0.03*float64(druid.Talents.FeralAggression)) * core.TernaryFloat64(druid.HasSetBonus(ItemSetThunderheartHarness, 4), 1.15, 1.0), - CritMultiplier: druid.MeleeCritMultiplier(Cat), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/_lacerate.go b/sim/druid/_lacerate.go index 6b38c50f05..d8333d2d85 100644 --- a/sim/druid/_lacerate.go +++ b/sim/druid/_lacerate.go @@ -25,6 +25,7 @@ func (druid *Druid) registerLacerateSpell() { druid.Lacerate = druid.RegisterSpell(Bear, core.SpellConfig{ ActionID: core.ActionID{SpellID: 48568}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL, @@ -40,7 +41,6 @@ func (druid *Druid) registerLacerateSpell() { }, DamageMultiplier: initialDamageMul, - CritMultiplier: druid.MeleeCritMultiplier(Bear), ThreatMultiplier: 0.5, // FlatThreatBonus: 515.5, // Handled below diff --git a/sim/druid/_maul.go b/sim/druid/_maul.go index 6418d265e4..b7192f3650 100644 --- a/sim/druid/_maul.go +++ b/sim/druid/_maul.go @@ -17,6 +17,7 @@ func (druid *Druid) registerMaulSpell() { druid.Maul = druid.RegisterSpell(Bear, core.SpellConfig{ ActionID: core.ActionID{SpellID: 48480}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial | core.ProcMaskMeleeMHAuto, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagNoOnCastComplete, @@ -26,7 +27,6 @@ func (druid *Druid) registerMaulSpell() { }, DamageMultiplier: 1 + 0.1*float64(druid.Talents.SavageFury), - CritMultiplier: druid.MeleeCritMultiplier(Bear), ThreatMultiplier: 1, FlatThreatBonus: 424, diff --git a/sim/druid/_rake.go b/sim/druid/_rake.go index c14cb9311e..015c0047c7 100644 --- a/sim/druid/_rake.go +++ b/sim/druid/_rake.go @@ -12,6 +12,7 @@ func (druid *Druid) registerRakeSpell() { druid.Rake = druid.RegisterSpell(Cat, core.SpellConfig{ ActionID: core.ActionID{SpellID: 48574}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIgnoreResists | core.SpellFlagAPL, @@ -27,7 +28,6 @@ func (druid *Druid) registerRakeSpell() { }, DamageMultiplier: 1 + 0.1*float64(druid.Talents.SavageFury), - CritMultiplier: druid.MeleeCritMultiplier(Cat), ThreatMultiplier: 1, Dot: core.DotConfig{ diff --git a/sim/druid/_swipe.go b/sim/druid/_swipe.go index cc57fa49ff..decb7ad866 100644 --- a/sim/druid/_swipe.go +++ b/sim/druid/_swipe.go @@ -21,6 +21,7 @@ func (druid *Druid) registerSwipeBearSpell() { druid.SwipeBear = druid.RegisterSpell(Bear, core.SpellConfig{ ActionID: core.ActionID{SpellID: 48562}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -35,7 +36,6 @@ func (druid *Druid) registerSwipeBearSpell() { }, DamageMultiplier: lbdm * thdm * fidm, - CritMultiplier: druid.MeleeCritMultiplier(Bear), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -55,6 +55,7 @@ func (druid *Druid) registerSwipeCatSpell() { druid.SwipeCat = druid.RegisterSpell(Cat, core.SpellConfig{ ActionID: core.ActionID{SpellID: 62078}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -69,7 +70,6 @@ func (druid *Druid) registerSwipeCatSpell() { }, DamageMultiplier: fidm * weaponMulti, - CritMultiplier: druid.MeleeCritMultiplier(Cat), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/ferocious_bite.go b/sim/druid/ferocious_bite.go index 1d5e9cef58..866c8dfdde 100644 --- a/sim/druid/ferocious_bite.go +++ b/sim/druid/ferocious_bite.go @@ -76,6 +76,7 @@ func (druid *Druid) newFerociousBiteSpellConfig(rank FerociousBiteRankInfo) core return core.SpellConfig{ ActionID: core.ActionID{SpellID: rank.id}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -94,8 +95,7 @@ func (druid *Druid) newFerociousBiteSpellConfig(rank FerociousBiteRankInfo) core return druid.ComboPoints() > 0 }, - DamageMultiplier: (1 + 0.03*float64(druid.Talents.FeralAggression)), - CritMultiplier: druid.MeleeCritMultiplier(1, 0), + DamageMultiplier: 1 + 0.03*float64(druid.Talents.FeralAggression), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/forms.go b/sim/druid/forms.go index 021612636e..394d2c5a24 100644 --- a/sim/druid/forms.go +++ b/sim/druid/forms.go @@ -66,7 +66,6 @@ func (druid *Druid) GetCatWeapon(level int32) core.Weapon { // BaseDamageMax: 165, // SwingSpeed: 2.5, // NormalizedSwingSpeed: 2.5, -// CritMultiplier: druid.MeleeCritMultiplier(Bear), // AttackPowerPerDPS: core.DefaultAttackPowerPerDPS, // } // } @@ -310,7 +309,7 @@ func (druid *Druid) registerCatFormSpell() { // }, // OnExpire: func(aura *core.Aura, sim *core.Simulation) { // druid.form = Humanoid -// druid.AutoAttacks.SetMH(druid.WeaponFromMainHand(druid.MeleeCritMultiplier(Humanoid))) +// druid.AutoAttacks.SetMH(druid.WeaponFromMainHand()) // druid.PseudoStats.ThreatMultiplier /= 2.1021 // druid.PseudoStats.SchoolDamageDealtMultiplier[stats.SchoolIndexPhysical] /= 1.0 + 0.02*float64(druid.Talents.MasterShapeshifter) diff --git a/sim/druid/items.go b/sim/druid/items.go index 0d37f0a626..8853c8b25f 100644 --- a/sim/druid/items.go +++ b/sim/druid/items.go @@ -30,12 +30,12 @@ func init() { triggeredDmgSpell := character.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 436481}, SpellSchool: core.SpellSchoolStormstrike, + DefenseType: core.DefenseTypeMelee, // actually has DefenseTypeNone, but is likely using the greatest CritMultiplier available ProcMask: core.ProcMaskEmpty, // TODO: "Causes additional threat" in Tooltip, no clue what the multiplier is. ThreatMultiplier: 1, DamageMultiplier: 1, - CritMultiplier: character.DefaultMeleeCritMultiplier(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { curTarget := target diff --git a/sim/druid/mangle.go b/sim/druid/mangle.go index 738cb047fa..8e67363b24 100644 --- a/sim/druid/mangle.go +++ b/sim/druid/mangle.go @@ -19,6 +19,7 @@ func (druid *Druid) registerMangleBearSpell() { druid.MangleBear = druid.RegisterSpell(Bear, core.SpellConfig{ ActionID: core.ActionID{SpellID: 48564}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -38,7 +39,6 @@ func (druid *Druid) registerMangleBearSpell() { }, DamageMultiplier: (1 + 0.1*float64(druid.Talents.SavageFury)) * 1.15 - CritMultiplier: druid.MeleeCritMultiplier(Bear), ThreatMultiplier: core.TernaryFloat64(druid.HasSetBonus(ItemSetThunderheartHarness, 2), 1.15, 1), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -74,6 +74,7 @@ func (druid *Druid) applyMangleCat() { druid.MangleCat = druid.RegisterSpell(Cat, core.SpellConfig{ ActionID: core.ActionID{SpellID: 409828}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -89,7 +90,6 @@ func (druid *Druid) applyMangleCat() { }, DamageMultiplier: (1 + 0.1*float64(druid.Talents.SavageFury)) * 2.7, - CritMultiplier: druid.MeleeCritMultiplier(1, 0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/moonfire.go b/sim/druid/moonfire.go index e8e6cbf76a..e24fcbad38 100644 --- a/sim/druid/moonfire.go +++ b/sim/druid/moonfire.go @@ -49,6 +49,7 @@ func (druid *Druid) getMoonfireBaseConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, @@ -81,9 +82,11 @@ func (druid *Druid) getMoonfireBaseConfig(rank int) core.SpellConfig { }, }, - BonusCritRating: druid.ImprovedMoonfireCritBonus() * core.SpellCritRatingPerCritChance, + BonusCritRating: druid.ImprovedMoonfireCritBonus() * core.SpellCritRatingPerCritChance, + + CritDamageBonus: druid.vengeance(), + DamageMultiplier: 1, - CritMultiplier: druid.VengeanceCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/rake.go b/sim/druid/rake.go index 870246843f..8f719193da 100644 --- a/sim/druid/rake.go +++ b/sim/druid/rake.go @@ -65,6 +65,7 @@ func (druid *Druid) newRakeSpellConfig(rakeRank RakeRankInfo) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: rakeRank.id}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIgnoreResists | core.SpellFlagAPL, @@ -80,7 +81,6 @@ func (druid *Druid) newRakeSpellConfig(rakeRank RakeRankInfo) core.SpellConfig { }, DamageMultiplier: 1 + 0.1*float64(druid.Talents.SavageFury), - CritMultiplier: druid.MeleeCritMultiplier(1, 0), ThreatMultiplier: 1, Dot: core.DotConfig{ diff --git a/sim/druid/runes.go b/sim/druid/runes.go index 1f31092053..215a103c6c 100644 --- a/sim/druid/runes.go +++ b/sim/druid/runes.go @@ -178,6 +178,7 @@ func (druid *Druid) applySunfire() { druid.Sunfire = druid.RegisterSpell(Humanoid|Moonkin, core.SpellConfig{ ActionID: core.ActionID{SpellID: 414684}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, @@ -208,9 +209,11 @@ func (druid *Druid) applySunfire() { }, }, - BonusCritRating: druid.ImprovedMoonfireCritBonus() * core.SpellCritRatingPerCritChance, + BonusCritRating: druid.ImprovedMoonfireCritBonus() * core.SpellCritRatingPerCritChance, + + CritDamageBonus: druid.vengeance(), + DamageMultiplier: 1, - CritMultiplier: druid.VengeanceCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/shred.go b/sim/druid/shred.go index c7c290b0c4..fd47d226a5 100644 --- a/sim/druid/shred.go +++ b/sim/druid/shred.go @@ -24,6 +24,7 @@ func (druid *Druid) registerShredSpell() { 60: 9830, }[druid.Level]}, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -42,7 +43,6 @@ func (druid *Druid) registerShredSpell() { }, DamageMultiplier: shredDamageMultiplier, - CritMultiplier: druid.MeleeCritMultiplier(1, 0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/starfire.go b/sim/druid/starfire.go index ee153a165a..bf453b839c 100644 --- a/sim/druid/starfire.go +++ b/sim/druid/starfire.go @@ -39,6 +39,7 @@ func (druid *Druid) newStarfireSpellConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_DruidStarfire, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, @@ -56,9 +57,11 @@ func (druid *Druid) newStarfireSpellConfig(rank int) core.SpellConfig { CastTime: druid.NaturesGraceCastTime(), }, + BonusCritRating: core.TernaryFloat64(druid.HasSetBonus(item_sets.ItemSetInsulatedSorcerorLeather, 3), 2, 0) * core.CritRatingPerCritChance, + + CritDamageBonus: druid.vengeance(), + DamageMultiplier: 1, - CritMultiplier: druid.VengeanceCritMultiplier(), - BonusCritRating: core.TernaryFloat64(druid.HasSetBonus(item_sets.ItemSetInsulatedSorcerorLeather, 3), 2, 0) * core.CritRatingPerCritChance, ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/starsurge.go b/sim/druid/starsurge.go index 09fa590f5e..ab21b7565e 100644 --- a/sim/druid/starsurge.go +++ b/sim/druid/starsurge.go @@ -54,6 +54,7 @@ func (druid *Druid) applyStarsurge() { ActionID: actionID, SpellCode: SpellCode_DruidStarsurge, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, @@ -73,9 +74,9 @@ func (druid *Druid) applyStarsurge() { }, }, + CritDamageBonus: druid.vengeance(), + DamageMultiplier: 1, - CritMultiplier: druid.VengeanceCritMultiplier(), - BonusCritRating: 0, ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/druid/talents.go b/sim/druid/talents.go index 7e5585e6f6..4e793a4ae3 100644 --- a/sim/druid/talents.go +++ b/sim/druid/talents.go @@ -332,6 +332,6 @@ func (druid *Druid) MoonfuryDamageMultiplier() float64 { return 1 + 0.02*float64(druid.Talents.Moonfury) } -func (druid *Druid) VengeanceCritMultiplier() float64 { - return druid.SpellCritMultiplier(1, 0.2*float64(druid.Talents.Vengeance)) +func (druid *Druid) vengeance() float64 { + return 0.2 * float64(druid.Talents.Vengeance) } diff --git a/sim/druid/wrath.go b/sim/druid/wrath.go index 71ca22781a..996beb7d83 100644 --- a/sim/druid/wrath.go +++ b/sim/druid/wrath.go @@ -41,6 +41,7 @@ func (druid *Druid) newWrathSpellConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_DruidWrath, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, @@ -59,9 +60,11 @@ func (druid *Druid) newWrathSpellConfig(rank int) core.SpellConfig { CastTime: druid.NaturesGraceCastTime(), }, + BonusCritRating: core.TernaryFloat64(druid.HasSetBonus(item_sets.ItemSetInsulatedSorcerorLeather, 3), 2, 0) * core.CritRatingPerCritChance, + + CritDamageBonus: druid.vengeance(), + DamageMultiplier: 1 + core.Ternary(druid.Ranged().ID == IdolOfWrath, .02, 0), - CritMultiplier: druid.VengeanceCritMultiplier(), - BonusCritRating: core.TernaryFloat64(druid.HasSetBonus(item_sets.ItemSetInsulatedSorcerorLeather, 3), 2, 0) * core.CritRatingPerCritChance, ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warlock/chaos_bolt.go b/sim/warlock/chaos_bolt.go index d7f1c70c86..0defa7404d 100644 --- a/sim/warlock/chaos_bolt.go +++ b/sim/warlock/chaos_bolt.go @@ -14,7 +14,7 @@ func (warlock *Warlock) registerChaosBoltSpell() { } spellCoeff := 0.714 level := float64(warlock.GetCharacter().Level) - baseCalc := (6.568597 + 0.672028*level + 0.031721*level*level) + baseCalc := 6.568597 + 0.672028*level + 0.031721*level*level baseLowDamage := baseCalc * 5.22 baseHighDamage := baseCalc * 6.62 From 6ab06bc0010cd235f2f97948d5a9a7794db701a2 Mon Sep 17 00:00:00 2001 From: vigo Date: Fri, 22 Mar 2024 09:05:11 +0100 Subject: [PATCH 07/12] [warlock] and most of warlock (but ExpectedDamage) --- sim/warlock/_soul_fire.go | 5 ++++- sim/warlock/chaos_bolt.go | 7 +++++-- sim/warlock/conflagrate.go | 7 +++++-- sim/warlock/haunt.go | 7 +++---- sim/warlock/immolate.go | 9 ++++++--- sim/warlock/incinerate.go | 7 +++++-- sim/warlock/items.go | 2 +- sim/warlock/pet_abilities.go | 12 +++++++----- sim/warlock/rain_of_fire.go | 1 - sim/warlock/searing_pain.go | 4 +++- sim/warlock/shadow_cleave.go | 12 +++++++----- sim/warlock/shadowbolt.go | 12 +++++++----- sim/warlock/shadowburn.go | 12 +++++++----- sim/warlock/shadowflame.go | 7 +++++-- sim/warlock/talents.go | 6 +++++- 15 files changed, 70 insertions(+), 40 deletions(-) diff --git a/sim/warlock/_soul_fire.go b/sim/warlock/_soul_fire.go index 46d7b7ca21..dea3da11be 100644 --- a/sim/warlock/_soul_fire.go +++ b/sim/warlock/_soul_fire.go @@ -10,6 +10,7 @@ func (warlock *Warlock) registerSoulFireSpell() { warlock.SoulFire = warlock.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 47825}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, MissileSpeed: 24, @@ -28,10 +29,12 @@ func (warlock *Warlock) registerSoulFireSpell() { BonusCritRating: 0 + core.TernaryFloat64(warlock.Talents.Devastation, 5*core.CritRatingPerCritChance, 0) + core.TernaryFloat64(warlock.HasSetBonus(ItemSetDarkCovensRegalia, 2), 5*core.CritRatingPerCritChance, 0), + + CritDamageBonus: warlock.ruin(), + DamageMultiplierAdditive: 1 + warlock.GrandFirestoneBonus() + 0.03*float64(warlock.Talents.Emberstorm), - CritMultiplier: warlock.SpellCritMultiplier(1, float64(warlock.Talents.Ruin)/5), ThreatMultiplier: 1 - 0.1*float64(warlock.Talents.DestructiveReach), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warlock/chaos_bolt.go b/sim/warlock/chaos_bolt.go index 0defa7404d..8d2f1b005f 100644 --- a/sim/warlock/chaos_bolt.go +++ b/sim/warlock/chaos_bolt.go @@ -21,6 +21,7 @@ func (warlock *Warlock) registerChaosBoltSpell() { warlock.ChaosBolt = warlock.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 403629}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, @@ -39,10 +40,12 @@ func (warlock *Warlock) registerChaosBoltSpell() { }, }, - BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, + BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, + + CritDamageBonus: warlock.ruin(), + DamageMultiplier: 1 + 0.02*float64(warlock.Talents.Emberstorm), DamageMultiplierAdditive: 1, - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warlock/conflagrate.go b/sim/warlock/conflagrate.go index 62ceafd67f..d9c2f2403c 100644 --- a/sim/warlock/conflagrate.go +++ b/sim/warlock/conflagrate.go @@ -18,6 +18,7 @@ func (warlock *Warlock) getConflagrateConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, Rank: rank, @@ -40,9 +41,11 @@ func (warlock *Warlock) getConflagrateConfig(rank int) core.SpellConfig { return warlock.Immolate.Dot(target).IsActive() || (warlock.Shadowflame != nil && warlock.Shadowflame.Dot(target).IsActive()) }, - BonusCritRating: float64(warlock.Talents.Devastation) * core.CritRatingPerCritChance, + BonusCritRating: float64(warlock.Talents.Devastation) * core.CritRatingPerCritChance, + + CritDamageBonus: warlock.ruin(), + DamageMultiplierAdditive: 1 + 0.02*float64(warlock.Talents.Emberstorm), - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warlock/haunt.go b/sim/warlock/haunt.go index eaccd74266..e97ba0984e 100644 --- a/sim/warlock/haunt.go +++ b/sim/warlock/haunt.go @@ -38,6 +38,7 @@ func (warlock *Warlock) registerHauntSpell() { warlock.Haunt = warlock.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, MissileSpeed: 20, @@ -55,10 +56,8 @@ func (warlock *Warlock) registerHauntSpell() { }, }, - DamageMultiplierAdditive: 1 + - 0.02*float64(warlock.Talents.ShadowMastery), - CritMultiplier: warlock.SpellCritMultiplier(1, 0), - ThreatMultiplier: 1, + DamageMultiplierAdditive: 1 + 0.02*float64(warlock.Talents.ShadowMastery), + ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := sim.Roll(baseLowDamage, baseHighDamage) + spellCoeff*spell.SpellDamage() diff --git a/sim/warlock/immolate.go b/sim/warlock/immolate.go index 5c800995d8..090de4a608 100644 --- a/sim/warlock/immolate.go +++ b/sim/warlock/immolate.go @@ -21,6 +21,7 @@ func (warlock *Warlock) getImmolateConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, Rank: rank, @@ -37,10 +38,11 @@ func (warlock *Warlock) getImmolateConfig(rank int) core.SpellConfig { }, }, - BonusHitRating: 0, - BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, + BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, + + CritDamageBonus: warlock.ruin(), + DamageMultiplier: 1 + 0.02*float64(warlock.Talents.Emberstorm), - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), ThreatMultiplier: 1, Dot: core.DotConfig{ @@ -106,6 +108,7 @@ func (warlock *Warlock) registerImmolateSpell() { // warlock.Immolate = warlock.RegisterSpell(core.SpellConfig{ // ActionID: core.ActionID{SpellID: 47811}, // SpellSchool: core.SpellSchoolFire, +// DefenseType: core.DefenseTypeMagic, // ProcMask: core.ProcMaskSpellDamage, // Flags: core.SpellFlagAPL, diff --git a/sim/warlock/incinerate.go b/sim/warlock/incinerate.go index ae210c9d7a..1a029daaeb 100644 --- a/sim/warlock/incinerate.go +++ b/sim/warlock/incinerate.go @@ -34,6 +34,7 @@ func (warlock *Warlock) registerIncinerateSpell() { warlock.Incinerate = warlock.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 412758}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagBinary, MissileSpeed: 24, @@ -49,10 +50,12 @@ func (warlock *Warlock) registerIncinerateSpell() { }, }, - BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, + BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, + + CritDamageBonus: warlock.ruin(), + DamageMultiplier: 1 + 0.02*float64(warlock.Talents.Emberstorm), DamageMultiplierAdditive: 1, - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warlock/items.go b/sim/warlock/items.go index 8ceb1e0972..1b50332716 100644 --- a/sim/warlock/items.go +++ b/sim/warlock/items.go @@ -38,6 +38,7 @@ func init() { spell := warlock.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 436479}, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, @@ -49,7 +50,6 @@ func init() { }, DamageMultiplier: 1, - CritMultiplier: warlock.DefaultSpellCritMultiplier(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { // The spell is also affected by fire school mods because it's shadow + fire school. diff --git a/sim/warlock/pet_abilities.go b/sim/warlock/pet_abilities.go index 99bb423993..72964457aa 100644 --- a/sim/warlock/pet_abilities.go +++ b/sim/warlock/pet_abilities.go @@ -29,6 +29,7 @@ func (wp *WarlockPet) registerFireboltSpell() { wp.primaryAbility = wp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Rank: rank, RequiredLevel: level, @@ -43,8 +44,7 @@ func (wp *WarlockPet) registerFireboltSpell() { }, }, - DamageMultiplier: (1 + 0.1*float64(wp.owner.Talents.ImprovedImp)), - CritMultiplier: wp.DefaultSpellCritMultiplier(), + DamageMultiplier: 1 + 0.1*float64(wp.owner.Talents.ImprovedImp), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -77,6 +77,7 @@ func (wp *WarlockPet) registerLashOfPainSpell() { wp.primaryAbility = wp.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, RequiredLevel: level, Rank: rank, @@ -96,7 +97,6 @@ func (wp *WarlockPet) registerLashOfPainSpell() { }, DamageMultiplier: 1, - CritMultiplier: wp.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -112,6 +112,7 @@ func (wp *WarlockPet) registerLashOfPainSpell() { // wp.primaryAbility = wp.RegisterSpell(core.SpellConfig{ // ActionID: core.ActionID{SpellID: 47994}, // SpellSchool: core.SpellSchoolPhysical, +// DefenseType: core.DefenseTypeMelee, // ProcMask: core.ProcMaskMeleeMHSpecial, // Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage, @@ -130,7 +131,6 @@ func (wp *WarlockPet) registerLashOfPainSpell() { // }, // DamageMultiplier: 1, -// CritMultiplier: 2, // ThreatMultiplier: 1, // ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -163,6 +163,7 @@ func (wp *WarlockPet) registerLashOfPainSpell() { // wp.primaryAbility = wp.RegisterSpell(core.SpellConfig{ // ActionID: actionID, // SpellSchool: core.SpellSchoolShadow, +// DefenseType: core.DefenseTypeMagic, // ProcMask: core.ProcMaskSpellDamage, // ManaCost: core.ManaCostOptions{ @@ -180,8 +181,9 @@ func (wp *WarlockPet) registerLashOfPainSpell() { // }, // }, +// BonusCritDamage: wp.owner.ruin(), + // DamageMultiplier: 1 + 0.03*float64(wp.owner.Talents.ShadowMastery), -// CritMultiplier: 1.5 + 0.1*float64(wp.owner.Talents.Ruin), // ThreatMultiplier: 1, // ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warlock/rain_of_fire.go b/sim/warlock/rain_of_fire.go index 45816c50f6..a0f1396d52 100644 --- a/sim/warlock/rain_of_fire.go +++ b/sim/warlock/rain_of_fire.go @@ -23,7 +23,6 @@ func (warlock *Warlock) getRainOfFireBaseConfig(rank int) core.SpellConfig { RequiredLevel: level, Rank: rank, - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), DamageMultiplier: 1, ThreatMultiplier: 1, diff --git a/sim/warlock/searing_pain.go b/sim/warlock/searing_pain.go index b6fd0b52a3..b0e2976617 100644 --- a/sim/warlock/searing_pain.go +++ b/sim/warlock/searing_pain.go @@ -17,6 +17,7 @@ func (warlock *Warlock) getSearingPainBaseConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, RequiredLevel: level, @@ -43,9 +44,10 @@ func (warlock *Warlock) getSearingPainBaseConfig(rank int) core.SpellConfig { float64(warlock.Talents.Devastation)*core.CritRatingPerCritChance + 2.0*float64(warlock.Talents.ImprovedSearingPain)*core.CritRatingPerCritChance, + CritDamageBonus: warlock.ruin(), + DamageMultiplier: 1 + 0.02*float64(warlock.Talents.Emberstorm), DamageMultiplierAdditive: 1, - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), ThreatMultiplier: 2, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warlock/shadow_cleave.go b/sim/warlock/shadow_cleave.go index 6555fe66c7..8747436634 100644 --- a/sim/warlock/shadow_cleave.go +++ b/sim/warlock/shadow_cleave.go @@ -20,6 +20,7 @@ func (warlock *Warlock) getShadowCleaveBaseConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, RequiredLevel: level, @@ -42,11 +43,12 @@ func (warlock *Warlock) getShadowCleaveBaseConfig(rank int) core.SpellConfig { }, BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, - DamageMultiplierAdditive: 1 + - 0.02*float64(warlock.Talents.ShadowMastery), - DamageMultiplier: 1, - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), - ThreatMultiplier: 1, + + CritDamageBonus: warlock.ruin(), + + DamageMultiplierAdditive: 1 + 0.02*float64(warlock.Talents.ShadowMastery), + DamageMultiplier: 1, + ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { curTarget := target diff --git a/sim/warlock/shadowbolt.go b/sim/warlock/shadowbolt.go index 304e58eaf0..18ad3a215e 100644 --- a/sim/warlock/shadowbolt.go +++ b/sim/warlock/shadowbolt.go @@ -23,6 +23,7 @@ func (warlock *Warlock) getShadowBoltBaseConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, RequiredLevel: level, @@ -43,11 +44,12 @@ func (warlock *Warlock) getShadowBoltBaseConfig(rank int) core.SpellConfig { }, BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, - DamageMultiplierAdditive: 1 + - 0.02*float64(warlock.Talents.ShadowMastery), - DamageMultiplier: damageMulti, - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), - ThreatMultiplier: 1, + + CritDamageBonus: warlock.ruin(), + + DamageMultiplierAdditive: 1 + 0.02*float64(warlock.Talents.ShadowMastery), + DamageMultiplier: damageMulti, + ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { curTarget := target diff --git a/sim/warlock/shadowburn.go b/sim/warlock/shadowburn.go index b31e3c5346..baba0e538a 100644 --- a/sim/warlock/shadowburn.go +++ b/sim/warlock/shadowburn.go @@ -17,6 +17,7 @@ func (warlock *Warlock) registerShadowBurnBaseConfig(rank int) core.SpellConfig return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing | core.SpellFlagBinary, RequiredLevel: level, @@ -36,11 +37,12 @@ func (warlock *Warlock) registerShadowBurnBaseConfig(rank int) core.SpellConfig }, BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, - DamageMultiplierAdditive: 1 + - 0.02*float64(warlock.Talents.ShadowMastery), - DamageMultiplier: 1, - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), - ThreatMultiplier: 1, + + CritDamageBonus: warlock.ruin(), + + DamageMultiplierAdditive: 1 + 0.02*float64(warlock.Talents.ShadowMastery), + DamageMultiplier: 1, + ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := sim.Roll(baseDamage[0], baseDamage[1]) + spellCoeff*spell.SpellDamage() diff --git a/sim/warlock/shadowflame.go b/sim/warlock/shadowflame.go index 5511ed2919..c5e822ae71 100644 --- a/sim/warlock/shadowflame.go +++ b/sim/warlock/shadowflame.go @@ -66,6 +66,7 @@ func (warlock *Warlock) registerShadowflameSpell() { warlock.Shadowflame = warlock.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 426320}, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | core.SpellFlagResetAttackSwing, @@ -83,10 +84,12 @@ func (warlock *Warlock) registerShadowflameSpell() { }, }, - BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, + BonusCritRating: float64(warlock.Talents.Devastation) * core.SpellCritRatingPerCritChance, + + CritDamageBonus: warlock.ruin(), + DamageMultiplier: 1, DamageMultiplierAdditive: 1, - CritMultiplier: warlock.SpellCritMultiplier(1, core.TernaryFloat64(warlock.Talents.Ruin, 1, 0)), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/warlock/talents.go b/sim/warlock/talents.go index 8893cf3ae1..e3cefd0c27 100644 --- a/sim/warlock/talents.go +++ b/sim/warlock/talents.go @@ -276,9 +276,9 @@ func (warlock *Warlock) applyFirestone() { fireProcSpell := warlock.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, - CritMultiplier: warlock.DefaultSpellCritMultiplier(), DamageMultiplier: firestoneMulti, ThreatMultiplier: 1, DamageMultiplierAdditive: 1, @@ -352,6 +352,10 @@ func (warlock *Warlock) applyNightfall() { }) } +func (warlock *Warlock) ruin() float64 { + return core.TernaryFloat64(warlock.Talents.Ruin, 1, 0) +} + // func (warlock *Warlock) setupPyroclasm() { // if warlock.Talents.Pyroclasm <= 0 { // return From 96d9be38b3b73dd3dfca87295a5752f674afe325 Mon Sep 17 00:00:00 2001 From: vigo Date: Fri, 22 Mar 2024 12:12:04 +0100 Subject: [PATCH 08/12] [paladin] and paladins ;) --- sim/paladin/crusader_strike.go | 4 ++-- sim/paladin/divine_storm.go | 3 ++- sim/paladin/exorcism.go | 5 +++-- sim/paladin/holy_shock.go | 6 ++++-- sim/paladin/soc.go | 7 ++++--- sim/paladin/som.go | 4 ++-- sim/paladin/sor.go | 7 ++++--- sim/warlock/immolate.go | 4 +++- 8 files changed, 24 insertions(+), 16 deletions(-) diff --git a/sim/paladin/crusader_strike.go b/sim/paladin/crusader_strike.go index ba323d3874..1effb035bc 100644 --- a/sim/paladin/crusader_strike.go +++ b/sim/paladin/crusader_strike.go @@ -21,6 +21,7 @@ func (paladin *Paladin) registerCrusaderStrikeSpell() { paladin.CrusaderStrike = paladin.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, Cast: core.CastConfig{ @@ -33,9 +34,8 @@ func (paladin *Paladin) registerCrusaderStrikeSpell() { Duration: time.Second * 6, }, }, - // We expect this spell to still target melee defense, and therefore benefit from physical dmg modifiers. + DamageMultiplier: 0.75 * paladin.getWeaponSpecializationModifier(), - CritMultiplier: paladin.MeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/paladin/divine_storm.go b/sim/paladin/divine_storm.go index 5801d8b48d..76074d4cbf 100644 --- a/sim/paladin/divine_storm.go +++ b/sim/paladin/divine_storm.go @@ -25,6 +25,7 @@ func (paladin *Paladin) registerDivineStormSpell() { paladin.DivineStorm = paladin.RegisterSpell(core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIncludeTargetBonusDamage | core.SpellFlagAPL, @@ -43,8 +44,8 @@ func (paladin *Paladin) registerDivineStormSpell() { }, DamageMultiplier: 1.1, - CritMultiplier: paladin.MeleeCritMultiplier(), ThreatMultiplier: 1, + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { curTarget := target totalDamageDealt := 0.0 diff --git a/sim/paladin/exorcism.go b/sim/paladin/exorcism.go index 631f61dcf6..601ba160e9 100644 --- a/sim/paladin/exorcism.go +++ b/sim/paladin/exorcism.go @@ -40,6 +40,7 @@ func (paladin *Paladin) getExorcismBaseConfig(rank int, guaranteed_crit bool) co return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL, RequiredLevel: level, @@ -61,10 +62,10 @@ func (paladin *Paladin) getExorcismBaseConfig(rank int, guaranteed_crit bool) co CD: *paladin.ExorcismCooldown, }, + BonusCritRating: paladin.getBonusCritChanceFromHolyPower(), + DamageMultiplier: 1, ThreatMultiplier: 1, - CritMultiplier: paladin.SpellCritMultiplier(), - BonusCritRating: paladin.getBonusCritChanceFromHolyPower(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := sim.Roll(baseDamageMin, baseDamageMax) + spellCoeff*spell.SpellDamage() diff --git a/sim/paladin/holy_shock.go b/sim/paladin/holy_shock.go index e502d28d6d..e6e0ade0ab 100644 --- a/sim/paladin/holy_shock.go +++ b/sim/paladin/holy_shock.go @@ -40,6 +40,7 @@ func (paladin *Paladin) getHolyShockBaseConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL, RequiredLevel: level, @@ -57,10 +58,11 @@ func (paladin *Paladin) getHolyShockBaseConfig(rank int) core.SpellConfig { CD: *paladin.HolyShockCooldown, }, + BonusCritRating: paladin.getBonusCritChanceFromHolyPower(), + DamageMultiplier: damageMultiplier, ThreatMultiplier: 1, - CritMultiplier: paladin.SpellCritMultiplier(), - BonusCritRating: paladin.getBonusCritChanceFromHolyPower(), + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := sim.Roll(baseDamageLow, baseDamageHigh) + spellCoeff*spell.SpellDamage() result := spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeMagicHitAndCrit) diff --git a/sim/paladin/soc.go b/sim/paladin/soc.go index 9bf350a3b5..111d68c4e4 100644 --- a/sim/paladin/soc.go +++ b/sim/paladin/soc.go @@ -59,14 +59,15 @@ func (paladin *Paladin) applySealOfCommandSpellAndAuraBaseConfig(rank int) { onJudgementProc := paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellIDJudge}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | SpellFlagSecondaryJudgement, SpellCode: SpellCode_PaladinJudgementOfCommand, + BonusCritRating: paladin.getBonusCritChanceFromHolyPower(), + DamageMultiplier: 1.0, ThreatMultiplier: 1, - CritMultiplier: paladin.MeleeCritMultiplier(), - BonusCritRating: paladin.getBonusCritChanceFromHolyPower(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := sim.Roll(judgeMinDamage, judgeMaxDamage) + socJudgeSpellCoeff*spell.SpellDamage() @@ -77,13 +78,13 @@ func (paladin *Paladin) applySealOfCommandSpellAndAuraBaseConfig(rank int) { onSwingProc := paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellIDProc}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial | core.ProcMaskSuppressedExtraAttackAura, Flags: core.SpellFlagMeleeMetrics, RequiredLevel: level, DamageMultiplier: 0.7 * paladin.getWeaponSpecializationModifier(), ThreatMultiplier: 1.0, - CritMultiplier: paladin.MeleeCritMultiplier(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := -1 + spell.Unit.MHWeaponDamage(sim, spell.MeleeAttackPower()) diff --git a/sim/paladin/som.go b/sim/paladin/som.go index c559f14dbd..f5e164a144 100644 --- a/sim/paladin/som.go +++ b/sim/paladin/som.go @@ -20,11 +20,11 @@ func (paladin *Paladin) registerSealOfMartyrdomSpellAndAura() { onJudgementProc := paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 407803}, // Judgement of Righteousness. SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, Flags: core.SpellFlagMeleeMetrics | SpellFlagSecondaryJudgement, DamageMultiplier: 0.85 * paladin.getWeaponSpecializationModifier(), - CritMultiplier: paladin.MeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -36,13 +36,13 @@ func (paladin *Paladin) registerSealOfMartyrdomSpellAndAura() { onSwingProc := paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 407799}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial | core.ProcMaskSuppressedExtraAttackAura, Flags: core.SpellFlagMeleeMetrics, RequiredLevel: 1, DamageMultiplier: 0.5 * paladin.getWeaponSpecializationModifier(), ThreatMultiplier: 1.0, - CritMultiplier: paladin.MeleeCritMultiplier(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := multiplier*spell.Unit.MHNormalizedWeaponDamage(sim, spell.MeleeAttackPower()) + spell.BonusWeaponDamage() diff --git a/sim/paladin/sor.go b/sim/paladin/sor.go index c4a5596aba..f0af1494f9 100644 --- a/sim/paladin/sor.go +++ b/sim/paladin/sor.go @@ -85,13 +85,14 @@ func (paladin *Paladin) applySealOfRighteousnessSpellAndAuraBaseConfig(rank int) onJudgementProc := paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: jorSpellID}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, Flags: core.SpellFlagMeleeMetrics | SpellFlagSecondaryJudgement, + BonusCritRating: paladin.getBonusCritChanceFromHolyPower(), + DamageMultiplier: 1, - CritMultiplier: paladin.SpellCritMultiplier(), ThreatMultiplier: 1, - BonusCritRating: paladin.getBonusCritChanceFromHolyPower(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { baseDamage := sim.Roll(baseJoRMinDamage, baseJoRMaxDamage) + jorBonusCoefficient*spell.SpellDamage() @@ -100,9 +101,9 @@ func (paladin *Paladin) applySealOfRighteousnessSpellAndAuraBaseConfig(rank int) }) onSwingProc := paladin.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: spellIdProc}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, Flags: core.SpellFlagMeleeMetrics, RequiredLevel: level, diff --git a/sim/warlock/immolate.go b/sim/warlock/immolate.go index 090de4a608..4c18e946cb 100644 --- a/sim/warlock/immolate.go +++ b/sim/warlock/immolate.go @@ -125,13 +125,15 @@ func (warlock *Warlock) registerImmolateSpell() { // BonusCritRating: 0 + // core.TernaryFloat64(warlock.Talents.Devastation, 5*core.CritRatingPerCritChance, 0), + +// CritDamageBonus: warlock.ruin(), + // DamageMultiplierAdditive: 1 + // warlock.GrandFirestoneBonus() + // 0.03*float64(warlock.Talents.Emberstorm) + // 0.1*float64(warlock.Talents.ImprovedImmolate) + // core.TernaryFloat64(warlock.HasSetBonus(ItemSetDeathbringerGarb, 2), 0.1, 0) + // core.TernaryFloat64(warlock.HasSetBonus(ItemSetGuldansRegalia, 4), 0.1, 0), -// CritMultiplier: warlock.SpellCritMultiplier(1, float64(warlock.Talents.Ruin)/5), // ThreatMultiplier: 1 - 0.1*float64(warlock.Talents.DestructiveReach), // Dot: core.DotConfig{ From 72aed39cc03b062327d1de6a3bfee75b3cbb5d64 Mon Sep 17 00:00:00 2001 From: vigo Date: Fri, 22 Mar 2024 17:00:51 +0100 Subject: [PATCH 09/12] [priest] .. and priests, [mage] mages... [common] ... and some items [core] cleanup ItemSwap --- sim/common/sod/enchant_effects.go | 3 +-- sim/common/sod/item_effects/phase_2.go | 2 +- sim/core/character.go | 2 +- sim/core/item_swaps.go | 23 +++++++---------------- sim/mage/arcane_blast.go | 4 ++-- sim/mage/arcane_explosion.go | 2 +- sim/mage/arcane_missiles.go | 3 ++- sim/mage/arcane_surge.go | 2 +- sim/mage/blast_wave.go | 2 +- sim/mage/fire_blast.go | 5 +++-- sim/mage/fireball.go | 2 +- sim/mage/flamestrike.go | 5 +++-- sim/mage/frostbolt.go | 2 +- sim/mage/frostfire_bolt.go | 2 +- sim/mage/ice_lance.go | 2 +- sim/mage/ignite.go | 1 + sim/mage/living_bomb.go | 4 ++-- sim/mage/mage.go | 7 ------- sim/mage/pyroblast.go | 2 +- sim/mage/runes.go | 14 +++++++++++++- sim/mage/scorch.go | 5 +++-- sim/mage/spellfrost_bolt.go | 2 +- sim/mage/talents.go | 4 ++-- sim/priest/circle_of_healing.go | 3 ++- sim/priest/flash_heal.go | 3 ++- sim/priest/greater_heal.go | 3 ++- sim/priest/holy_fire.go | 5 +++-- sim/priest/mind_blast.go | 7 ++++--- sim/priest/mind_sear.go | 3 +-- sim/priest/mind_spike.go | 9 +++++---- sim/priest/penance.go | 9 +++------ sim/priest/prayer_of_healing.go | 3 ++- sim/priest/prayer_of_mending.go | 3 ++- sim/priest/shadow_word_death.go | 3 +-- sim/priest/smite.go | 5 +++-- sim/rogue/rogue.go | 5 ++--- 36 files changed, 82 insertions(+), 79 deletions(-) diff --git a/sim/common/sod/enchant_effects.go b/sim/common/sod/enchant_effects.go index 9ebce6252e..894cbbfe17 100644 --- a/sim/common/sod/enchant_effects.go +++ b/sim/common/sod/enchant_effects.go @@ -16,10 +16,9 @@ func init() { procSpell := character.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 439164}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, - CritMultiplier: character.DefaultSpellCritMultiplier(), - DamageMultiplier: 1, ThreatMultiplier: 1, diff --git a/sim/common/sod/item_effects/phase_2.go b/sim/common/sod/item_effects/phase_2.go index bc596b64a1..bbd0927f3a 100644 --- a/sim/common/sod/item_effects/phase_2.go +++ b/sim/common/sod/item_effects/phase_2.go @@ -35,11 +35,11 @@ func init() { forkedLightning := character.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 11828}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, Flags: core.SpellFlagNoOnCastComplete, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, _ *core.Unit, spell *core.Spell) { diff --git a/sim/core/character.go b/sim/core/character.go index e40117a401..bd53521319 100644 --- a/sim/core/character.go +++ b/sim/core/character.go @@ -190,7 +190,7 @@ func NewCharacter(party *Party, partyIndex int, player *proto.Player) Character character.PseudoStats.InFrontOfTarget = player.InFrontOfTarget if player.EnableItemSwap && player.ItemSwap != nil { - character.enableItemSwap(player.ItemSwap, character.DefaultMeleeCritMultiplier(), character.DefaultMeleeCritMultiplier(), 0) + character.enableItemSwap(player.ItemSwap) } return character diff --git a/sim/core/item_swaps.go b/sim/core/item_swaps.go index de17113089..176dc640f2 100644 --- a/sim/core/item_swaps.go +++ b/sim/core/item_swaps.go @@ -15,10 +15,6 @@ type ItemSwap struct { character *Character onSwapCallbacks []OnSwapItem - mhCritMultiplier float64 - ohCritMultiplier float64 - rangedCritMultiplier float64 - // Which slots to actually swap. slots []proto.ItemSlot @@ -27,12 +23,10 @@ type ItemSwap struct { swapped bool } -/* -TODO All the extra parameters here and the code in multiple places for handling the Weapon struct is really messy, +// TODO All the extra parameters here and the code in multiple places for handling the Weapon struct is really messy, +// we'll need to figure out something cleaner as this will be quite error-prone - we'll need to figure out something cleaner as this will be quite error-prone -*/ -func (character *Character) enableItemSwap(itemSwap *proto.ItemSwap, mhCritMultiplier float64, ohCritMultiplier float64, rangedCritMultiplier float64) { +func (character *Character) enableItemSwap(itemSwap *proto.ItemSwap) { var slots []proto.ItemSlot hasMhSwap := itemSwap.MhItem != nil && itemSwap.MhItem.Id != 0 hasOhSwap := itemSwap.OhItem != nil && itemSwap.OhItem.Id != 0 @@ -69,13 +63,10 @@ func (character *Character) enableItemSwap(itemSwap *proto.ItemSwap, mhCritMulti } character.ItemSwap = ItemSwap{ - character: character, - mhCritMultiplier: mhCritMultiplier, - ohCritMultiplier: ohCritMultiplier, - rangedCritMultiplier: rangedCritMultiplier, - slots: slots, - unEquippedItems: swapItems, - swapped: false, + character: character, + slots: slots, + unEquippedItems: swapItems, + swapped: false, } } diff --git a/sim/mage/arcane_blast.go b/sim/mage/arcane_blast.go index cf85d056af..bd31f9361c 100644 --- a/sim/mage/arcane_blast.go +++ b/sim/mage/arcane_blast.go @@ -17,7 +17,7 @@ func (mage *Mage) registerArcaneBlastSpell() { } level := float64(mage.GetCharacter().Level) - baseCalc := (13.828124 + 0.018012*level + 0.044141*level*level) + baseCalc := 13.828124 + 0.018012*level + 0.044141*level*level baseLowDamage := baseCalc * 4.53 baseHighDamage := baseCalc * 5.27 spellCoeff := .714 @@ -76,6 +76,7 @@ func (mage *Mage) registerArcaneBlastSpell() { ActionID: core.ActionID{SpellID: 400574}, SpellCode: SpellCode_MageArcaneBlast, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, @@ -90,7 +91,6 @@ func (mage *Mage) registerArcaneBlastSpell() { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/arcane_explosion.go b/sim/mage/arcane_explosion.go index c4f289c603..92c44cd79d 100644 --- a/sim/mage/arcane_explosion.go +++ b/sim/mage/arcane_explosion.go @@ -36,6 +36,7 @@ func (mage *Mage) newArcaneExplosionSpellConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_MageArcaneExplosion, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, @@ -52,7 +53,6 @@ func (mage *Mage) newArcaneExplosionSpellConfig(rank int) core.SpellConfig { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/arcane_missiles.go b/sim/mage/arcane_missiles.go index aa404d9a3d..e461a95eeb 100644 --- a/sim/mage/arcane_missiles.go +++ b/sim/mage/arcane_missiles.go @@ -51,6 +51,7 @@ func (mage *Mage) getArcaneMissilesSpellConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_MageArcaneMissiles, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL | core.SpellFlagChanneled | core.SpellFlagNoMetrics, @@ -112,12 +113,12 @@ func (mage *Mage) getArcaneMissilesTickSpell(rank int) *core.Spell { return mage.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}.WithTag(1), SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskProc | core.ProcMaskNotInSpellbook, Flags: SpellFlagMage, MissileSpeed: 20, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/arcane_surge.go b/sim/mage/arcane_surge.go index e22dd56ae7..2981fcf240 100644 --- a/sim/mage/arcane_surge.go +++ b/sim/mage/arcane_surge.go @@ -43,6 +43,7 @@ func (mage *Mage) registerArcaneSurgeSpell() { ActionID: actionID, SpellCode: SpellCode_MageArcaneSurge, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, @@ -60,7 +61,6 @@ func (mage *Mage) registerArcaneSurgeSpell() { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/blast_wave.go b/sim/mage/blast_wave.go index 844912b4ed..e033be3a21 100644 --- a/sim/mage/blast_wave.go +++ b/sim/mage/blast_wave.go @@ -43,6 +43,7 @@ func (mage *Mage) newBlastWaveSpellConfig(rank int, cooldownTimer *core.Timer) c return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, @@ -63,7 +64,6 @@ func (mage *Mage) newBlastWaveSpellConfig(rank int, cooldownTimer *core.Timer) c }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/fire_blast.go b/sim/mage/fire_blast.go index 8323ae8f73..6e36aceea1 100644 --- a/sim/mage/fire_blast.go +++ b/sim/mage/fire_blast.go @@ -39,6 +39,7 @@ func (mage *Mage) newFireBlastSpellConfig(rank int, cdTimer *core.Timer) core.Sp ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_MageFireBlast, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, @@ -59,9 +60,9 @@ func (mage *Mage) newFireBlastSpellConfig(rank int, cdTimer *core.Timer) core.Sp }, }, - BonusCritRating: 2 * float64(mage.Talents.Incinerate) * core.SpellCritRatingPerCritChance, + BonusCritRating: 2 * float64(mage.Talents.Incinerate) * core.SpellCritRatingPerCritChance, + DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ExpectedInitialDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult { diff --git a/sim/mage/fireball.go b/sim/mage/fireball.go index fd9eebb199..1a0056cfdf 100644 --- a/sim/mage/fireball.go +++ b/sim/mage/fireball.go @@ -48,6 +48,7 @@ func (mage *Mage) newFireballSpellConfig(rank int) core.SpellConfig { ActionID: actionID, SpellCode: SpellCode_MageFireball, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | SpellFlagMage, MissileSpeed: 24, @@ -82,7 +83,6 @@ func (mage *Mage) newFireballSpellConfig(rank int) core.SpellConfig { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/flamestrike.go b/sim/mage/flamestrike.go index b9c4583a67..663b722f9e 100644 --- a/sim/mage/flamestrike.go +++ b/sim/mage/flamestrike.go @@ -47,6 +47,7 @@ func (mage *Mage) newFlamestrikeSpellConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, @@ -63,9 +64,9 @@ func (mage *Mage) newFlamestrikeSpellConfig(rank int) core.SpellConfig { }, }, - BonusCritRating: float64(5 * mage.Talents.ImprovedFlamestrike * core.CritRatingPerCritChance), + BonusCritRating: float64(5 * mage.Talents.ImprovedFlamestrike * core.CritRatingPerCritChance), + DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, Dot: core.DotConfig{ diff --git a/sim/mage/frostbolt.go b/sim/mage/frostbolt.go index 30e14c6b68..71bba07003 100644 --- a/sim/mage/frostbolt.go +++ b/sim/mage/frostbolt.go @@ -40,6 +40,7 @@ func (mage *Mage) getFrostboltConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_MageFrostbolt, SpellSchool: core.SpellSchoolFrost, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | SpellFlagMage | SpellFlagChillSpell, MissileSpeed: 28, @@ -58,7 +59,6 @@ func (mage *Mage) getFrostboltConfig(rank int) core.SpellConfig { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/frostfire_bolt.go b/sim/mage/frostfire_bolt.go index 7360b28a30..b7269d7af1 100644 --- a/sim/mage/frostfire_bolt.go +++ b/sim/mage/frostfire_bolt.go @@ -30,6 +30,7 @@ func (mage *Mage) registerFrostfireBoltSpell() { ActionID: actionID, SpellCode: SpellCode_MageFrostfireBolt, SpellSchool: core.SpellSchoolFrostfire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | SpellFlagChillSpell | core.SpellFlagAPL, MissileSpeed: 28, @@ -62,7 +63,6 @@ func (mage *Mage) registerFrostfireBoltSpell() { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/ice_lance.go b/sim/mage/ice_lance.go index a3413cf1d4..0f4ae0dece 100644 --- a/sim/mage/ice_lance.go +++ b/sim/mage/ice_lance.go @@ -23,6 +23,7 @@ func (mage *Mage) registerIceLanceSpell() { mage.IceLance = mage.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.MageRune_RuneHandsIceLance)}, SpellSchool: core.SpellSchoolFrost, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, MissileSpeed: 38, @@ -37,7 +38,6 @@ func (mage *Mage) registerIceLanceSpell() { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/ignite.go b/sim/mage/ignite.go index d19189c503..b52b5ed4b0 100644 --- a/sim/mage/ignite.go +++ b/sim/mage/ignite.go @@ -43,6 +43,7 @@ func (mage *Mage) applyIgnite() { mage.Ignite = mage.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 12654}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskProc, Flags: SpellFlagMage | core.SpellFlagIgnoreModifiers, diff --git a/sim/mage/living_bomb.go b/sim/mage/living_bomb.go index 356579c1f5..c27a55423a 100644 --- a/sim/mage/living_bomb.go +++ b/sim/mage/living_bomb.go @@ -18,7 +18,7 @@ func (mage *Mage) registerLivingBombSpell() { actionID := core.ActionID{SpellID: int32(proto.MageRune_RuneHandsLivingBomb)} level := float64(mage.GetCharacter().Level) - baseCalc := (13.828124 + 0.018012*level + 0.044141*level*level) + baseCalc := 13.828124 + 0.018012*level + 0.044141*level*level baseDotDamage := baseCalc * .85 baseExplosionDamage := baseCalc * 1.71 dotCoeff := .20 @@ -32,11 +32,11 @@ func (mage *Mage) registerLivingBombSpell() { ActionID: actionID.WithTag(1), SpellCode: SpellCode_MageLivingBomb, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/mage.go b/sim/mage/mage.go index e15f6ba324..959b7125da 100644 --- a/sim/mage/mage.go +++ b/sim/mage/mage.go @@ -83,8 +83,6 @@ type Mage struct { HotStreakAura *core.Aura ImprovedScorchAuras core.AuraArray MissileBarrageAura *core.Aura - - CritDebuffCategories core.ExclusiveCategoryArray } // Agent is a generic way to access underlying mage on any of the agents. @@ -154,8 +152,3 @@ func NewMage(character *core.Character, options *proto.Player) *Mage { func (mage *Mage) HasRune(rune proto.MageRune) bool { return mage.HasRuneById(int32(rune)) } - -func (mage *Mage) MageCritMultiplier(secondary float64) float64 { - critBonus := core.TernaryFloat64(mage.HasRune(proto.MageRune_RuneFeetSpellPower), .5, 0) + secondary - return mage.SpellCritMultiplier(1, critBonus) -} diff --git a/sim/mage/pyroblast.go b/sim/mage/pyroblast.go index 004ed6f2f1..74ef42b5ee 100644 --- a/sim/mage/pyroblast.go +++ b/sim/mage/pyroblast.go @@ -54,6 +54,7 @@ func (mage *Mage) newPyroblastSpellConfig(rank int) core.SpellConfig { spellConfig := core.SpellConfig{ ActionID: actionID, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | core.SpellFlagAPL, MissileSpeed: 24, @@ -72,7 +73,6 @@ func (mage *Mage) newPyroblastSpellConfig(rank int) core.SpellConfig { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, Dot: core.DotConfig{ diff --git a/sim/mage/runes.go b/sim/mage/runes.go index fcfb2d3e25..9eabddd04f 100644 --- a/sim/mage/runes.go +++ b/sim/mage/runes.go @@ -34,7 +34,7 @@ func (mage *Mage) ApplyRunes() { // Feet mage.applyBrainFreeze() - // Spell Power Nothing to do + mage.applySpellPower() } func (mage *Mage) applyBurnout() { @@ -349,3 +349,15 @@ func (mage *Mage) applyBrainFreeze() { }, }) } + +func (mage *Mage) applySpellPower() { + if !mage.HasRune(proto.MageRune_RuneFeetSpellPower) { + return + } + + mage.OnSpellRegistered(func(spell *core.Spell) { + if spell.Flags.Matches(SpellFlagMage) { + spell.CritDamageBonus += 0.5 + } + }) +} diff --git a/sim/mage/scorch.go b/sim/mage/scorch.go index e940355aa2..4c6b49ae87 100644 --- a/sim/mage/scorch.go +++ b/sim/mage/scorch.go @@ -39,6 +39,7 @@ func (mage *Mage) getScorchConfig(rank int) core.SpellConfig { ActionID: core.ActionID{SpellID: spellId}, SpellCode: SpellCode_MageScorch, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL | SpellFlagMage, @@ -55,9 +56,9 @@ func (mage *Mage) getScorchConfig(rank int) core.SpellConfig { }, }, - BonusCritRating: 2 * float64(mage.Talents.Incinerate) * core.SpellCritRatingPerCritChance, + BonusCritRating: 2 * float64(mage.Talents.Incinerate) * core.SpellCritRatingPerCritChance, + DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/spellfrost_bolt.go b/sim/mage/spellfrost_bolt.go index 57d9ee00eb..9d7bd1b843 100644 --- a/sim/mage/spellfrost_bolt.go +++ b/sim/mage/spellfrost_bolt.go @@ -25,6 +25,7 @@ func (mage *Mage) registerSpellfrostBolt() { ActionID: core.ActionID{SpellID: int32(proto.MageRune_RuneBeltSpellfrostBolt)}, SpellCode: SpellCode_MageSpellfrostBolt, SpellSchool: core.SpellSchoolSpellFrost, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: SpellFlagMage | SpellFlagChillSpell | core.SpellFlagAPL, MissileSpeed: 28, @@ -41,7 +42,6 @@ func (mage *Mage) registerSpellfrostBolt() { }, DamageMultiplier: 1, - CritMultiplier: mage.MageCritMultiplier(0), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/mage/talents.go b/sim/mage/talents.go index 4c1ef08575..1fd27af493 100644 --- a/sim/mage/talents.go +++ b/sim/mage/talents.go @@ -128,7 +128,7 @@ func (mage *Mage) applyFrostTalents() { critBonus := .20 * float64(mage.Talents.IceShards) mage.OnSpellRegistered(func(spell *core.Spell) { if spell.SpellSchool.Matches(core.SpellSchoolFrost) && spell.Flags.Matches(SpellFlagMage) { - spell.CritMultiplier = mage.MageCritMultiplier(critBonus) + spell.CritDamageBonus += critBonus } }) } @@ -209,7 +209,7 @@ func (mage *Mage) applyArcaneConcentration() { procChance := 0.02 * float64(mage.Talents.ArcaneConcentration) - // TODO: Classic verify arcane missle proc chance + // TODO: Classic verify arcane missile proc chance // Arcane Missile ticks can proc CC, just at a low rate of about 1.5% with 5/5 Arcane Concentration // if spell == mage.ArcaneMissilesTickSpell { // procChance *= 0.15 diff --git a/sim/priest/circle_of_healing.go b/sim/priest/circle_of_healing.go index 8434b746d9..5bcaebf903 100644 --- a/sim/priest/circle_of_healing.go +++ b/sim/priest/circle_of_healing.go @@ -6,6 +6,7 @@ package priest // priest.CircleOfHealing = priest.RegisterSpell(core.SpellConfig{ // ActionID: core.ActionID{SpellID: 401946}, // SpellSchool: core.SpellSchoolHoly, +// DefenseType: core.DefenseTypeMagic, // ProcMask: core.ProcMaskSpellHealing, // Flags: core.SpellFlagHelpful | core.SpellFlagAPL, @@ -24,8 +25,8 @@ package priest // }, // BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, + // DamageMultiplier: 1 + .02*float64(priest.Talents.SpiritualHealing), -// CritMultiplier: priest.DefaultHealingCritMultiplier(), // ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], // ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/priest/flash_heal.go b/sim/priest/flash_heal.go index 95e842266c..11f462be79 100644 --- a/sim/priest/flash_heal.go +++ b/sim/priest/flash_heal.go @@ -6,6 +6,7 @@ package priest // priest.FlashHeal = priest.RegisterSpell(core.SpellConfig{ // ActionID: core.ActionID{SpellID: 10917}, // SpellSchool: core.SpellSchoolHoly, +// DefenseType: core.DefenseTypeMagic, // ProcMask: core.ProcMaskSpellHealing, // Flags: core.SpellFlagHelpful | core.SpellFlagAPL, @@ -20,8 +21,8 @@ package priest // }, // BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, + // DamageMultiplier: 1 + .02*float64(priest.Talents.SpiritualHealing), -// CritMultiplier: priest.DefaultHealingCritMultiplier(), // ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], // ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/priest/greater_heal.go b/sim/priest/greater_heal.go index b1183324a0..55b6c872eb 100644 --- a/sim/priest/greater_heal.go +++ b/sim/priest/greater_heal.go @@ -6,6 +6,7 @@ package priest // priest.GreaterHeal = priest.RegisterSpell(core.SpellConfig{ // ActionID: core.ActionID{SpellID: 48063}, // SpellSchool: core.SpellSchoolHoly, +// DefenseType: core.DefenseTypeMagic, // ProcMask: core.ProcMaskSpellHealing, // Flags: core.SpellFlagHelpful | core.SpellFlagAPL, @@ -21,8 +22,8 @@ package priest // }, // BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, + // DamageMultiplier: 1 + .02*float64(priest.Talents.SpiritualHealing), -// CritMultiplier: priest.DefaultHealingCritMultiplier(), // ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], // ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/priest/holy_fire.go b/sim/priest/holy_fire.go index 71f0eb2d8a..54f551139e 100644 --- a/sim/priest/holy_fire.go +++ b/sim/priest/holy_fire.go @@ -43,6 +43,7 @@ func (priest *Priest) getHolyFireConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, RequiredLevel: level, @@ -59,9 +60,9 @@ func (priest *Priest) getHolyFireConfig(rank int) core.SpellConfig { }, }, - BonusCritRating: priest.holySpecCritRating() + priest.forceOfWillCritRating(), + BonusCritRating: priest.holySpecCritRating() + priest.forceOfWillCritRating(), + DamageMultiplier: priest.searingLightDamageModifier() * priest.forceOfWillDamageModifier(), - CritMultiplier: priest.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, Dot: core.DotConfig{ diff --git a/sim/priest/mind_blast.go b/sim/priest/mind_blast.go index 714d374729..a1d0f9ddd9 100644 --- a/sim/priest/mind_blast.go +++ b/sim/priest/mind_blast.go @@ -42,6 +42,7 @@ func (priest *Priest) getMindBlastBaseConfig(rank int, cdTimer *core.Timer) core return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, @@ -63,10 +64,10 @@ func (priest *Priest) getMindBlastBaseConfig(rank int, cdTimer *core.Timer) core }, }, - BonusCritRating: priest.forceOfWillCritRating(), - BonusHitRating: priest.shadowHitModifier(), + BonusCritRating: priest.forceOfWillCritRating(), + BonusHitRating: priest.shadowHitModifier(), + DamageMultiplier: priest.forceOfWillDamageModifier(), - CritMultiplier: priest.DefaultSpellCritMultiplier(), ThreatMultiplier: priest.shadowThreatModifier(), ExpectedInitialDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult { diff --git a/sim/priest/mind_sear.go b/sim/priest/mind_sear.go index dad743275c..96053041dd 100644 --- a/sim/priest/mind_sear.go +++ b/sim/priest/mind_sear.go @@ -96,13 +96,12 @@ func (priest *Priest) newMindSearTickSpell(numTicks int32) *core.Spell { return priest.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 413260}.WithTag(numTicks), SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskProc | core.ProcMaskNotInSpellbook, BonusHitRating: 1, // Not an independent hit once initial lands BonusCritRating: priest.forceOfWillCritRating(), - CritMultiplier: priest.DefaultSpellCritMultiplier(), - DamageMultiplier: priest.forceOfWillDamageModifier(), ThreatMultiplier: priest.shadowThreatModifier(), diff --git a/sim/priest/mind_spike.go b/sim/priest/mind_spike.go index 49a19029c2..3d4fdb1e6a 100644 --- a/sim/priest/mind_spike.go +++ b/sim/priest/mind_spike.go @@ -17,7 +17,7 @@ func (priest *Priest) registerMindSpikeSpell() { func (priest *Priest) newMindSpikeSpellConfig() core.SpellConfig { level := float64(priest.GetCharacter().Level) - baseDamage := (9.456667 + 0.635108*level + 0.039063*level*level) + baseDamage := 9.456667 + 0.635108*level + 0.039063*level*level // 2024-02-22 tuning 10% buff baseDamageLow := baseDamage * 1.11 * 1.1 baseDamageHigh := baseDamage * 1.29 * 1.1 @@ -32,6 +32,7 @@ func (priest *Priest) newMindSpikeSpellConfig() core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.PriestRune_RuneWaistMindSpike)}, SpellSchool: core.SpellSchoolShadowfrost, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, @@ -46,10 +47,10 @@ func (priest *Priest) newMindSpikeSpellConfig() core.SpellConfig { }, }, - BonusHitRating: priest.shadowHitModifier(), + BonusHitRating: priest.shadowHitModifier(), + BonusCritRating: priest.forceOfWillCritRating(), + DamageMultiplier: priest.forceOfWillDamageModifier() * priest.darknessDamageModifier(), - BonusCritRating: priest.forceOfWillCritRating(), - CritMultiplier: priest.DefaultSpellCritMultiplier(), ThreatMultiplier: priest.shadowThreatModifier(), ExpectedInitialDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult { diff --git a/sim/priest/penance.go b/sim/priest/penance.go index 10662a2ef0..b8587625a8 100644 --- a/sim/priest/penance.go +++ b/sim/priest/penance.go @@ -37,6 +37,7 @@ func (priest *Priest) makePenanceSpell(isHeal bool) *core.Spell { return priest.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 402284}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMagic, ProcMask: procMask, Flags: flags, RequiredLevel: 1, @@ -54,13 +55,9 @@ func (priest *Priest) makePenanceSpell(isHeal bool) *core.Spell { }, }, - BonusCritRating: priest.holySpecCritRating() + priest.forceOfWillCritRating(), + BonusCritRating: priest.holySpecCritRating() + priest.forceOfWillCritRating(), + DamageMultiplier: 1, - CritMultiplier: core.TernaryFloat64( - isHeal, - priest.DefaultHealingCritMultiplier(), - priest.DefaultSpellCritMultiplier(), - ), ThreatMultiplier: 0, Dot: core.Ternary(!isHeal, core.DotConfig{ diff --git a/sim/priest/prayer_of_healing.go b/sim/priest/prayer_of_healing.go index b378381b91..06cbfd0da3 100644 --- a/sim/priest/prayer_of_healing.go +++ b/sim/priest/prayer_of_healing.go @@ -4,6 +4,7 @@ package priest // priest.PrayerOfHealing = priest.RegisterSpell(core.SpellConfig{ // ActionID: core.ActionID{SpellID: 48072}, // SpellSchool: core.SpellSchoolHoly, +// DefenseType: core.DefenseTypeMagic, // ProcMask: core.ProcMaskSpellHealing, // Flags: core.SpellFlagHelpful | core.SpellFlagAPL, @@ -19,8 +20,8 @@ package priest // }, // BonusCritRating: float64(priest.Talents.HolySpecialization), + // DamageMultiplier: 1 + .02*float64(priest.Talents.SpiritualHealing), -// CritMultiplier: priest.DefaultHealingCritMultiplier(), // ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], // ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/priest/prayer_of_mending.go b/sim/priest/prayer_of_mending.go index ae58d35703..7723f46b31 100644 --- a/sim/priest/prayer_of_mending.go +++ b/sim/priest/prayer_of_mending.go @@ -48,6 +48,7 @@ package priest // priest.PrayerOfMending = priest.RegisterSpell(core.SpellConfig{ // ActionID: actionID, // SpellSchool: core.SpellSchoolHoly, +// DefenseType: core.DefenseTypeMagic, // ProcMask: core.ProcMaskSpellHealing, // Flags: core.SpellFlagHelpful | core.SpellFlagAPL, @@ -66,8 +67,8 @@ package priest // }, // BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, + // DamageMultiplier: 1 + .02*float64(priest.Talents.SpiritualHealing), -// CritMultiplier: priest.DefaultHealingCritMultiplier(), // ThreatMultiplier: 1, // ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/priest/shadow_word_death.go b/sim/priest/shadow_word_death.go index 4a9ac8d897..bcfb514465 100644 --- a/sim/priest/shadow_word_death.go +++ b/sim/priest/shadow_word_death.go @@ -24,6 +24,7 @@ func (priest *Priest) registerShadowWordDeathSpell() { priest.ShadowWordDeath = priest.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 401955}, SpellSchool: core.SpellSchoolShadow, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, @@ -43,8 +44,6 @@ func (priest *Priest) registerShadowWordDeathSpell() { BonusHitRating: priest.shadowHitModifier(), BonusCritRating: priest.forceOfWillCritRating(), - CritMultiplier: priest.DefaultSpellCritMultiplier(), - DamageMultiplier: priest.forceOfWillDamageModifier(), ThreatMultiplier: priest.shadowThreatModifier(), diff --git a/sim/priest/smite.go b/sim/priest/smite.go index 04f66c5b14..ce5422da7a 100644 --- a/sim/priest/smite.go +++ b/sim/priest/smite.go @@ -39,6 +39,7 @@ func (priest *Priest) getSmiteBaseConfig(rank int) core.SpellConfig { return core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: core.SpellSchoolHoly, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, Flags: core.SpellFlagAPL, @@ -55,9 +56,9 @@ func (priest *Priest) getSmiteBaseConfig(rank int) core.SpellConfig { }, }, - BonusCritRating: priest.holySpecCritRating() + priest.forceOfWillCritRating(), + BonusCritRating: priest.holySpecCritRating() + priest.forceOfWillCritRating(), + DamageMultiplier: priest.searingLightDamageModifier() * priest.forceOfWillDamageModifier(), - CritMultiplier: priest.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/rogue/rogue.go b/sim/rogue/rogue.go index 4e70bf5300..3ae312ced6 100644 --- a/sim/rogue/rogue.go +++ b/sim/rogue/rogue.go @@ -200,12 +200,11 @@ func (rogue *Rogue) HasRune(rune proto.RogueRune) bool { } func (rogue *Rogue) RuneAbilityBaseDamage() float64 { - level := rogue.Level - return 5.741530 - 0.255683*float64(level) + 0.032656*float64(level*level) + return 5.741530 - 0.255683*float64(rogue.Level) + 0.032656*float64(rogue.Level*rogue.Level) } func (rogue *Rogue) RuneAbilityDamagePerCombo() float64 { - return 8.740728 - 0.415787*float64(rogue.Level) + 0.051973*float64(rogue.Level)*float64(rogue.Level) + return 8.740728 - 0.415787*float64(rogue.Level) + 0.051973*float64(rogue.Level*rogue.Level) } func (rogue *Rogue) getImbueProcMask(imbue proto.WeaponImbue) core.ProcMask { From d26510cf0ff83afef85a12b3ec47493b8d9dbabc Mon Sep 17 00:00:00 2001 From: vigo Date: Fri, 22 Mar 2024 18:07:00 +0100 Subject: [PATCH 10/12] [...] remove remaining SpellConfig.CritMultiplier and Spell.CritMultiplier instances [core] spell.CritMultiplier() now panics if used with spells w/ DefenseTypeNone, which more or less replaces the former checks in the various Outcome methods --- sim/common/itemhelpers/weaponprocs.go | 6 -- sim/common/sod/item_effects/phase_2.go | 14 ++--- sim/common/vanilla/enchant_effects.go | 2 +- sim/common/vanilla/items_sets/melee_sets.go | 2 +- sim/common/vanilla/melee_items.go | 15 ++--- sim/core/consumes.go | 13 ++-- sim/core/spell.go | 32 +++++----- sim/core/spell_outcome.go | 68 +++++---------------- sim/druid/rake.go | 2 +- sim/druid/shred.go | 2 +- sim/encounters/naxxramas/patchwerk10_ai.go | 3 +- sim/encounters/naxxramas/patchwerk25_ai.go | 3 +- sim/warlock/apl_values.go | 4 +- 13 files changed, 59 insertions(+), 107 deletions(-) diff --git a/sim/common/itemhelpers/weaponprocs.go b/sim/common/itemhelpers/weaponprocs.go index c0f1eba839..235f000656 100644 --- a/sim/common/itemhelpers/weaponprocs.go +++ b/sim/common/itemhelpers/weaponprocs.go @@ -13,18 +13,12 @@ func CreateWeaponProcDamage(itemId int32, itemName string, ppm float64, spellId core.NewItemEffect(itemId, func(agent core.Agent) { character := agent.GetCharacter() - critMultiplier := character.DefaultSpellCritMultiplier() - if defType == core.DefenseTypeMelee || defType == core.DefenseTypeRanged { - critMultiplier = character.DefaultMeleeCritMultiplier() - } - sc := core.SpellConfig{ ActionID: core.ActionID{SpellID: spellId}, SpellSchool: school, ProcMask: core.ProcMaskEmpty, DamageMultiplier: 1, - CritMultiplier: critMultiplier, ThreatMultiplier: 1, } diff --git a/sim/common/sod/item_effects/phase_2.go b/sim/common/sod/item_effects/phase_2.go index bbd0927f3a..b15a9cfd62 100644 --- a/sim/common/sod/item_effects/phase_2.go +++ b/sim/common/sod/item_effects/phase_2.go @@ -246,10 +246,10 @@ func init() { return character.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 435169}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, Dot: core.DotConfig{ @@ -262,7 +262,6 @@ func init() { OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) { dot.SnapshotBaseDamage = 30 attackTable := dot.Spell.Unit.AttackTables[target.UnitIndex][dot.Spell.CastType] - dot.SnapshotCritChance = 0 dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable) }, @@ -288,11 +287,12 @@ func init() { actionID := core.ActionID{SpellID: 434488} fireStrike := character.GetOrRegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 434488}, - SpellSchool: core.SpellSchoolFire, - ProcMask: core.ProcMaskSpellDamage, + ActionID: core.ActionID{SpellID: 434488}, + SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, + ProcMask: core.ProcMaskSpellDamage, + DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { spell.CalcAndDealDamage(sim, target, 7.0, spell.OutcomeMagicHitAndCrit) @@ -348,10 +348,10 @@ func init() { return character.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 434841}, SpellSchool: core.SpellSchoolArcane, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/common/vanilla/enchant_effects.go b/sim/common/vanilla/enchant_effects.go index 6f2b6cde5b..d06755b71e 100644 --- a/sim/common/vanilla/enchant_effects.go +++ b/sim/common/vanilla/enchant_effects.go @@ -18,10 +18,10 @@ func init() { procSpell := character.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 6296}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/common/vanilla/items_sets/melee_sets.go b/sim/common/vanilla/items_sets/melee_sets.go index 5291c3af8c..9a6645469b 100644 --- a/sim/common/vanilla/items_sets/melee_sets.go +++ b/sim/common/vanilla/items_sets/melee_sets.go @@ -15,10 +15,10 @@ var ItemSetStormshroud = core.NewItemSet(core.ItemSet{ proc := char.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 18980}, SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, DamageMultiplier: 1, - CritMultiplier: char.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/common/vanilla/melee_items.go b/sim/common/vanilla/melee_items.go index 28c10b12bc..9ed595948a 100644 --- a/sim/common/vanilla/melee_items.go +++ b/sim/common/vanilla/melee_items.go @@ -19,10 +19,10 @@ func init() { return character.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 18796}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, Dot: core.DotConfig{ @@ -62,10 +62,10 @@ func init() { return character.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 29638}, SpellSchool: core.SpellSchoolFire, + DefenseType: core.DefenseTypeRanged, ProcMask: core.ProcMaskEmpty, DamageMultiplier: 1, - CritMultiplier: character.DefaultMeleeCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { @@ -81,11 +81,12 @@ func init() { auraActionID := core.ActionID{SpellID: 433801} ravegerBladestormTickSpell := character.GetOrRegisterSpell(core.SpellConfig{ - ActionID: tickActionID, - SpellSchool: core.SpellSchoolPhysical, - ProcMask: core.ProcMaskMeleeMHSpecial, + ActionID: tickActionID, + SpellSchool: core.SpellSchoolPhysical, + DefenseType: core.DefenseTypeMelee, + ProcMask: core.ProcMaskMeleeMHSpecial, + DamageMultiplier: 1, - CritMultiplier: character.DefaultMeleeCritMultiplier(), ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { damage := 5.0 + @@ -179,10 +180,10 @@ func init() { singleTargetSpell := character.RegisterSpell(core.SpellConfig{ ActionID: procActionID.WithTag(1), SpellSchool: core.SpellSchoolNature, + DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ThreatMultiplier: 0.5, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/core/consumes.go b/sim/core/consumes.go index a91ec63b27..1d340836e2 100644 --- a/sim/core/consumes.go +++ b/sim/core/consumes.go @@ -325,10 +325,10 @@ func registerShadowOil(character *Character, isMh bool, icd Cooldown) { procSpell := character.GetOrRegisterSpell(SpellConfig{ ActionID: ActionID{SpellID: 1382}, SpellSchool: SpellSchoolShadow, + DefenseType: DefenseTypeMagic, ProcMask: ProcMaskSpellDamage, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) { @@ -373,10 +373,10 @@ func registerFrostOil(character *Character, isMh bool) { procSpell := character.GetOrRegisterSpell(SpellConfig{ ActionID: ActionID{SpellID: 1191}, SpellSchool: SpellSchoolFrost, + DefenseType: DefenseTypeMagic, ProcMask: ProcMaskSpellDamage, DamageMultiplier: 1, - CritMultiplier: character.DefaultSpellCritMultiplier(), ThreatMultiplier: 1, ApplyEffects: func(sim *Simulation, target *Unit, spell *Spell) { @@ -471,11 +471,10 @@ func DragonBreathChiliAura(character *Character) *Aura { procSpell := character.RegisterSpell(SpellConfig{ ActionID: ActionID{SpellID: 15851}, SpellSchool: SpellSchoolFire, + DefenseType: DefenseTypeMagic, ProcMask: ProcMaskEmpty, Flags: SpellFlagNone, - CritMultiplier: character.DefaultSpellCritMultiplier(), - DamageMultiplier: 1, ThreatMultiplier: 1, @@ -516,6 +515,7 @@ func (character *Character) newBasicExplosiveSpellConfig(sharedTimer *Timer, act return SpellConfig{ ActionID: actionID, SpellSchool: school, + DefenseType: DefenseTypeMagic, ProcMask: ProcMaskEmpty, Flags: SpellFlagCastTimeNoGCD, @@ -532,8 +532,6 @@ func (character *Character) newBasicExplosiveSpellConfig(sharedTimer *Timer, act // Explosives always have 1% resist chance, so just give them hit cap. BonusHitRating: 100 * SpellHitRatingPerHitChance, - CritMultiplier: character.DefaultSpellCritMultiplier(), - DamageMultiplier: 1, ThreatMultiplier: 1, @@ -571,6 +569,7 @@ func (character *Character) newRadiationBombSpellConfig(sharedTimer *Timer, acti return SpellConfig{ ActionID: actionID, SpellSchool: SpellSchoolFire, + DefenseType: DefenseTypeMagic, ProcMask: ProcMaskEmpty, Flags: SpellFlagCastTimeNoGCD, @@ -589,8 +588,6 @@ func (character *Character) newRadiationBombSpellConfig(sharedTimer *Timer, acti // Explosives always have 1% resist chance, so just give them hit cap. BonusHitRating: 100 * SpellHitRatingPerHitChance, - CritMultiplier: character.DefaultSpellCritMultiplier(), - DamageMultiplier: 1, ThreatMultiplier: 1, diff --git a/sim/core/spell.go b/sim/core/spell.go index 975b3af855..baba747362 100644 --- a/sim/core/spell.go +++ b/sim/core/spell.go @@ -42,12 +42,11 @@ type SpellConfig struct { BonusExpertiseRating float64 BonusArmorPenRating float64 + CritDamageBonus float64 + DamageMultiplier float64 DamageMultiplierAdditive float64 - CritMultiplier float64 - CritDamageBonus float64 - ThreatMultiplier float64 FlatThreatBonus float64 @@ -133,7 +132,6 @@ type Spell struct { DamageMultiplier float64 DamageMultiplierAdditive float64 - CritMultiplier float64 CritDamageBonus float64 // Multiplier for all threat generated by this effect. @@ -147,8 +145,8 @@ type Spell struct { initialBonusSpellPower float64 initialDamageMultiplier float64 initialDamageMultiplierAdditive float64 - initialCritMultiplier float64 initialThreatMultiplier float64 + initialCritDamageBonus float64 // Note that bonus expertise and armor pen are static, so we don't bother resetting them. resultCache SpellResult @@ -236,19 +234,19 @@ func (unit *Unit) RegisterSpell(config SpellConfig) *Spell { expectedInitialDamageInternal: config.ExpectedInitialDamage, expectedTickDamageInternal: config.ExpectedTickDamage, - BonusHitRating: config.BonusHitRating, - BonusCritRating: config.BonusCritRating, - BonusSpellPower: config.BonusSpellPower, - BonusExpertiseRating: config.BonusExpertiseRating, - BonusArmorPenRating: config.BonusArmorPenRating, - CastTimeMultiplier: 1, - CostMultiplier: 1, - DamageMultiplier: config.DamageMultiplier, - DamageMultiplierAdditive: config.DamageMultiplierAdditive, + BonusHitRating: config.BonusHitRating, + BonusCritRating: config.BonusCritRating, + BonusSpellPower: config.BonusSpellPower, + BonusExpertiseRating: config.BonusExpertiseRating, + BonusArmorPenRating: config.BonusArmorPenRating, + CastTimeMultiplier: 1, + CostMultiplier: 1, - CritMultiplier: config.CritMultiplier, CritDamageBonus: 1 + config.CritDamageBonus, + DamageMultiplier: config.DamageMultiplier, + DamageMultiplierAdditive: config.DamageMultiplierAdditive, + ThreatMultiplier: config.ThreatMultiplier, FlatThreatBonus: config.FlatThreatBonus, @@ -399,8 +397,8 @@ func (spell *Spell) finalize() { spell.initialBonusSpellPower = spell.BonusSpellPower spell.initialDamageMultiplier = spell.DamageMultiplier spell.initialDamageMultiplierAdditive = spell.DamageMultiplierAdditive - spell.initialCritMultiplier = spell.CritMultiplier spell.initialThreatMultiplier = spell.ThreatMultiplier + spell.initialCritDamageBonus = spell.CritDamageBonus if len(spell.splitSpellMetrics) > 1 && spell.ActionID.Tag != 0 { panic(spell.ActionID.String() + " has split metrics and a non-zero tag, can only have one!") @@ -425,9 +423,9 @@ func (spell *Spell) reset(_ *Simulation) { spell.BonusSpellPower = spell.initialBonusSpellPower spell.CastTimeMultiplier = 1 spell.CostMultiplier = 1 + spell.CritDamageBonus = spell.initialCritDamageBonus spell.DamageMultiplier = spell.initialDamageMultiplier spell.DamageMultiplierAdditive = spell.initialDamageMultiplierAdditive - spell.CritMultiplier = spell.initialCritMultiplier spell.ThreatMultiplier = spell.initialThreatMultiplier } diff --git a/sim/core/spell_outcome.go b/sim/core/spell_outcome.go index 6c5bb02d28..ddecfc6838 100644 --- a/sim/core/spell_outcome.go +++ b/sim/core/spell_outcome.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "github.com/wowsims/sod/sim/core/stats" ) @@ -33,7 +34,7 @@ func (dot *Dot) OutcomeTickCounted(_ *Simulation, result *SpellResult, _ *Attack func (dot *Dot) OutcomeTickPhysicalCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if dot.Spell.PhysicalCritCheck(sim, attackTable) { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.critMultiplier() + result.Damage *= dot.Spell.CritMultiplier() } else { result.Outcome = OutcomeHit } @@ -42,19 +43,16 @@ func (dot *Dot) OutcomeTickPhysicalCrit(sim *Simulation, result *SpellResult, at func (dot *Dot) OutcomeTickSnapshotCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.critMultiplier() + result.Damage *= dot.Spell.CritMultiplier() } else { result.Outcome = OutcomeHit } } func (dot *Dot) OutcomeSnapshotCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { - if dot.Spell.critMultiplier() == 0 { - panic("Spell " + dot.Spell.ActionID.String() + " missing CritMultiplier") - } if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.critMultiplier() + result.Damage *= dot.Spell.CritMultiplier() dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -63,13 +61,10 @@ func (dot *Dot) OutcomeSnapshotCrit(sim *Simulation, result *SpellResult, _ *Att } func (dot *Dot) OutcomeMagicHitAndSnapshotCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { - if dot.Spell.critMultiplier() == 0 { - panic("Spell " + dot.Spell.ActionID.String() + " missing CritMultiplier") - } if dot.Spell.MagicHitCheck(sim, attackTable) { if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.critMultiplier() + result.Damage *= dot.Spell.CritMultiplier() dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -83,13 +78,10 @@ func (dot *Dot) OutcomeMagicHitAndSnapshotCrit(sim *Simulation, result *SpellRes } func (spell *Spell) OutcomeMagicHitAndCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { - if spell.critMultiplier() == 0 { - panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") - } if spell.MagicHitCheck(sim, attackTable) { if spell.MagicCritCheck(sim, result.Target) { result.Outcome = OutcomeCrit - result.Damage *= spell.critMultiplier() + result.Damage *= spell.CritMultiplier() spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -103,12 +95,9 @@ func (spell *Spell) OutcomeMagicHitAndCrit(sim *Simulation, result *SpellResult, } func (spell *Spell) OutcomeMagicCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { - if spell.critMultiplier() == 0 { - panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") - } if spell.MagicCritCheck(sim, result.Target) { result.Outcome = OutcomeCrit - result.Damage *= spell.critMultiplier() + result.Damage *= spell.CritMultiplier() spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -122,12 +111,9 @@ func (spell *Spell) OutcomeHealing(_ *Simulation, result *SpellResult, _ *Attack } func (spell *Spell) OutcomeHealingCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { - if spell.critMultiplier() == 0 { - panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") - } if spell.HealingCritCheck(sim) { result.Outcome = OutcomeCrit - result.Damage *= spell.critMultiplier() + result.Damage *= spell.CritMultiplier() spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -468,39 +454,30 @@ func (result *SpellResult) applyAttackTableGlance(spell *Spell, attackTable *Att } func (result *SpellResult) applyAttackTableCrit(spell *Spell, attackTable *AttackTable, roll float64, chance *float64) bool { - if spell.critMultiplier() == 0 { - panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") - } *chance += spell.PhysicalCritChance(attackTable) if roll < *chance { result.Outcome = OutcomeCrit spell.SpellMetrics[result.Target.UnitIndex].Crits++ - result.Damage *= spell.critMultiplier() + result.Damage *= spell.CritMultiplier() return true } return false } func (result *SpellResult) applyAttackTableCritSeparateRoll(sim *Simulation, spell *Spell, attackTable *AttackTable) bool { - if spell.critMultiplier() == 0 { - panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") - } if spell.PhysicalCritCheck(sim, attackTable) { result.Outcome = OutcomeCrit spell.SpellMetrics[result.Target.UnitIndex].Crits++ - result.Damage *= spell.critMultiplier() + result.Damage *= spell.CritMultiplier() return true } return false } func (result *SpellResult) applyAttackTableCritSeparateRollSnapshot(sim *Simulation, dot *Dot) bool { - if dot.Spell.critMultiplier() == 0 { - panic("Spell " + dot.Spell.ActionID.String() + " missing CritMultiplier") - } if sim.RandomFloat("Physical Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.critMultiplier() + result.Damage *= dot.Spell.CritMultiplier() dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ return true } @@ -587,7 +564,6 @@ func (result *SpellResult) applyEnemyAttackTableParry(spell *Spell, attackTable } func (result *SpellResult) applyEnemyAttackTableCrit(spell *Spell, _ *AttackTable, roll float64, chance *float64) bool { - critRating := spell.Unit.stats[stats.MeleeCrit] + spell.BonusCritRating critChance := critRating / (CritRatingPerCritChance * 100) critChance -= result.Target.stats[stats.Defense] * DefenseRatingToChanceReduction @@ -620,43 +596,31 @@ func (spell *Spell) OutcomeExpectedMagicHit(_ *Simulation, result *SpellResult, } func (spell *Spell) OutcomeExpectedMagicCrit(_ *Simulation, result *SpellResult, _ *AttackTable) { - if spell.critMultiplier() == 0 { - panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") - } - averageMultiplier := 1.0 - averageMultiplier += spell.SpellCritChance(result.Target) * (spell.critMultiplier() - 1) + averageMultiplier += spell.SpellCritChance(result.Target) * (spell.CritMultiplier() - 1) result.Damage *= averageMultiplier } func (spell *Spell) OutcomeExpectedMagicHitAndCrit(_ *Simulation, result *SpellResult, attackTable *AttackTable) { - if spell.critMultiplier() == 0 { - panic("Spell " + spell.ActionID.String() + " missing CritMultiplier") - } - averageMultiplier := 1.0 averageMultiplier -= spell.SpellChanceToMiss(attackTable) - averageMultiplier += averageMultiplier * spell.SpellCritChance(result.Target) * (spell.critMultiplier() - 1) + averageMultiplier += averageMultiplier * spell.SpellCritChance(result.Target) * (spell.CritMultiplier() - 1) result.Damage *= averageMultiplier } func (dot *Dot) OutcomeExpectedMagicSnapshotCrit(_ *Simulation, result *SpellResult, _ *AttackTable) { - if dot.Spell.critMultiplier() == 0 { - panic("Spell " + dot.Spell.ActionID.String() + " missing CritMultiplier") - } - averageMultiplier := 1.0 - averageMultiplier += dot.SnapshotCritChance * (dot.Spell.critMultiplier() - 1) + averageMultiplier += dot.SnapshotCritChance * (dot.Spell.CritMultiplier() - 1) result.Damage *= averageMultiplier } -func (spell *Spell) critMultiplier() float64 { +func (spell *Spell) CritMultiplier() float64 { switch spell.DefenseType { case DefenseTypeNone: - return spell.CritMultiplier + panic(fmt.Sprintf("using CritMultiplier() for spellID %d which has no DefenseType", spell.SpellID)) case DefenseTypeMagic: return 1 + 0.5*spell.CritDamageBonus default: diff --git a/sim/druid/rake.go b/sim/druid/rake.go index 8f719193da..b0ac0f8fdc 100644 --- a/sim/druid/rake.go +++ b/sim/druid/rake.go @@ -122,7 +122,7 @@ func (druid *Druid) newRakeSpellConfig(rakeRank RakeRankInfo) core.SpellConfig { attackTable := spell.Unit.AttackTables[target.UnitIndex][spell.CastType] critChance := spell.PhysicalCritChance(attackTable) - critMod := (critChance * (spell.CritMultiplier - 1)) + critMod := (critChance * (spell.CritMultiplier() - 1)) initial.Damage *= 1 + critMod return initial }, diff --git a/sim/druid/shred.go b/sim/druid/shred.go index fd47d226a5..523efae1a7 100644 --- a/sim/druid/shred.go +++ b/sim/druid/shred.go @@ -91,7 +91,7 @@ func (druid *Druid) registerShredSpell() { attackTable := spell.Unit.AttackTables[target.UnitIndex][spell.CastType] critChance := spell.PhysicalCritChance(attackTable) - critMod := (critChance * (spell.CritMultiplier - 1)) + critMod := (critChance * (spell.CritMultiplier() - 1)) baseres.Damage *= (1 + critMod) diff --git a/sim/encounters/naxxramas/patchwerk10_ai.go b/sim/encounters/naxxramas/patchwerk10_ai.go index 84e424fdc1..47aeee0a0d 100644 --- a/sim/encounters/naxxramas/patchwerk10_ai.go +++ b/sim/encounters/naxxramas/patchwerk10_ai.go @@ -79,11 +79,10 @@ func (ai *Patchwerk10AI) registerHatefulStrikeSpell(target *core.Target) { }, }, - CritMultiplier: 1, - DamageMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + // TODO cannot crit baseDamage := sim.Roll(27750, 32250) spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeEnemyMeleeWhite) }, diff --git a/sim/encounters/naxxramas/patchwerk25_ai.go b/sim/encounters/naxxramas/patchwerk25_ai.go index a1fea835d8..04845ae61f 100644 --- a/sim/encounters/naxxramas/patchwerk25_ai.go +++ b/sim/encounters/naxxramas/patchwerk25_ai.go @@ -80,11 +80,10 @@ func (ai *Patchwerk25AI) registerHatefulStrikeSpell(target *core.Target) { }, }, - CritMultiplier: 1, - DamageMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + // TODO cannot crit baseDamage := sim.Roll(79000, 81000) spell.CalcAndDealDamage(sim, target, baseDamage, spell.OutcomeEnemyMeleeWhite) }, diff --git a/sim/warlock/apl_values.go b/sim/warlock/apl_values.go index 622a59bdc8..801ecfb9ec 100644 --- a/sim/warlock/apl_values.go +++ b/sim/warlock/apl_values.go @@ -116,11 +116,11 @@ func (value *APLValueWarlockShouldRefreshCorruption) GetBool(sim *core.Simulatio // check if reapplying corruption is worthwhile snapshotCrit := dot.SnapshotCritChance - snapshotMult := dot.SnapshotAttackerMultiplier * (snapshotCrit*(warlock.Corruption.CritMultiplier-1) + 1) + snapshotMult := dot.SnapshotAttackerMultiplier * (snapshotCrit*(warlock.Corruption.CritMultiplier()-1) + 1) attackTable := warlock.AttackTables[target.UnitIndex][dot.Spell.CastType] curCrit := warlock.Corruption.SpellCritChance(target) - curDmg := dot.Spell.AttackerDamageMultiplier(attackTable) * (curCrit*(warlock.Corruption.CritMultiplier-1) + 1) + curDmg := dot.Spell.AttackerDamageMultiplier(attackTable) * (curCrit*(warlock.Corruption.CritMultiplier()-1) + 1) relDmgInc := curDmg / snapshotMult From 258bf7aafdca4a1ea405f55c2c2298cec9e453f2 Mon Sep 17 00:00:00 2001 From: vigo Date: Fri, 22 Mar 2024 21:28:55 +0100 Subject: [PATCH 11/12] [various] remove remaining SpellConfig.CritMultiplier and Spell.CritMultiplier instances [various] remove the various helper functions for CritMultiplier calculation [core] spell.CritMultiplier() now panics if used with spells w/ DefenseTypeNone, which more or less replaces the former checks in the various Outcome methods --- sim/common/vanilla/enchant_effects.go | 2 +- sim/core/character.go | 30 +-------------------------- sim/core/spell_outcome.go | 3 +++ sim/hunter/talents.go | 19 ----------------- sim/paladin/talents.go | 8 ------- 5 files changed, 5 insertions(+), 57 deletions(-) diff --git a/sim/common/vanilla/enchant_effects.go b/sim/common/vanilla/enchant_effects.go index d06755b71e..0eb023ad13 100644 --- a/sim/common/vanilla/enchant_effects.go +++ b/sim/common/vanilla/enchant_effects.go @@ -98,10 +98,10 @@ func init() { // procSpell := character.RegisterSpell(core.SpellConfig{ // ActionID: core.ActionID{SpellID: 13898}, // SpellSchool: core.SpellSchoolFire, + // DefenseType: core.DefenseTypeMagic, // ProcMask: core.ProcMaskSpellDamage, // DamageMultiplier: 1, - // CritMultiplier: character.DefaultSpellCritMultiplier(), // ThreatMultiplier: 1, // ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { diff --git a/sim/core/character.go b/sim/core/character.go index bd53521319..19817dccf3 100644 --- a/sim/core/character.go +++ b/sim/core/character.go @@ -388,37 +388,9 @@ func (character *Character) GetBaseStats() stats.Stats { return character.baseStats } -// Returns the crit multiplier for a spell. -// https://web.archive.org/web/20081014064638/http://elitistjerks.com/f31/t12595-relentless_earthstorm_diamond_-_melee_only/p4/ -// https://github.com/TheGroxEmpire/TBC_DPS_Warrior_Sim/issues/30 -// TODO "primaryModifiers" could be modelled as a PseudoStat, since they're unit-specific. "secondaryModifiers" apply to a specific set of spells. -func (character *Character) calculateCritMultiplier(normalCritDamage float64, primaryModifiers float64, secondaryModifiers float64) float64 { - return 1.0 + (normalCritDamage*primaryModifiers-1.0)*(1.0+secondaryModifiers) -} -func (character *Character) calculateHealingCritMultiplier(normalCritDamage float64, primaryModifiers float64, secondaryModifiers float64) float64 { - return 1.0 + (normalCritDamage*primaryModifiers-1.0)*(1.0+secondaryModifiers) -} -func (character *Character) SpellCritMultiplier(primaryModifiers float64, secondaryModifiers float64) float64 { - return character.calculateCritMultiplier(1.5, primaryModifiers, secondaryModifiers) -} -func (character *Character) MeleeCritMultiplier(primaryModifiers float64, secondaryModifiers float64) float64 { - return character.calculateCritMultiplier(2.0, primaryModifiers, secondaryModifiers) -} -func (character *Character) HealingCritMultiplier(primaryModifiers float64, secondaryModifiers float64) float64 { - return character.calculateHealingCritMultiplier(1.5, primaryModifiers, secondaryModifiers) -} -func (character *Character) DefaultSpellCritMultiplier() float64 { - return character.SpellCritMultiplier(1, 0) -} -func (character *Character) DefaultMeleeCritMultiplier() float64 { - return character.MeleeCritMultiplier(1, 0) -} -func (character *Character) DefaultHealingCritMultiplier() float64 { - return character.HealingCritMultiplier(1, 0) -} - func (character *Character) AddRaidBuffs(_ *proto.RaidBuffs) { } + func (character *Character) AddPartyBuffs(partyBuffs *proto.PartyBuffs) { switch character.MainHand().ID { diff --git a/sim/core/spell_outcome.go b/sim/core/spell_outcome.go index ddecfc6838..b554e3fe52 100644 --- a/sim/core/spell_outcome.go +++ b/sim/core/spell_outcome.go @@ -617,6 +617,9 @@ func (dot *Dot) OutcomeExpectedMagicSnapshotCrit(_ *Simulation, result *SpellRes result.Damage *= averageMultiplier } +// CritMultiplier() returns the damage multiplier for critical strikes, based on CritDamageBonus and DefenseType. +// https://web.archive.org/web/20081014064638/http://elitistjerks.com/f31/t12595-relentless_earthstorm_diamond_-_melee_only/p4/ +// https://github.com/TheGroxEmpire/TBC_DPS_Warrior_Sim/issues/30 func (spell *Spell) CritMultiplier() float64 { switch spell.DefenseType { case DefenseTypeNone: diff --git a/sim/hunter/talents.go b/sim/hunter/talents.go index e4eac35f3d..a490fcaf70 100644 --- a/sim/hunter/talents.go +++ b/sim/hunter/talents.go @@ -70,25 +70,6 @@ func (hunter *Hunter) ApplyTalents() { } } -func (hunter *Hunter) critMultiplier(isRanged bool, target *core.Unit) float64 { - primaryModifier := 1.0 - secondaryModifier := 0.0 - - monsterMultiplier := 1.0 + 0.01*float64(hunter.Talents.MonsterSlaying) - humanoidMultiplier := 1.0 + 0.01*float64(hunter.Talents.HumanoidSlaying) - if target.MobType == proto.MobType_MobTypeBeast || target.MobType == proto.MobType_MobTypeGiant || target.MobType == proto.MobType_MobTypeDragonkin { - primaryModifier *= monsterMultiplier - } else if target.MobType == proto.MobType_MobTypeHumanoid { - primaryModifier *= humanoidMultiplier - } - - if isRanged { - secondaryModifier += 0.06 * float64(hunter.Talents.MortalShots) - } - - return hunter.MeleeCritMultiplier(primaryModifier, secondaryModifier) -} - func (hunter *Hunter) applyFrenzy() { if hunter.Talents.Frenzy == 0 { return diff --git a/sim/paladin/talents.go b/sim/paladin/talents.go index bf6fd19610..38014fced8 100644 --- a/sim/paladin/talents.go +++ b/sim/paladin/talents.go @@ -141,14 +141,6 @@ func (paladin *Paladin) getBonusCritChanceFromHolyPower() float64 { // }) // } -// Below are placeholders in case of any subsequent phase runes giving paladins crit damage. -func (paladin *Paladin) MeleeCritMultiplier() float64 { - return paladin.DefaultMeleeCritMultiplier() -} -func (paladin *Paladin) SpellCritMultiplier() float64 { - return paladin.DefaultSpellCritMultiplier() -} - func (paladin *Paladin) getWeaponSpecializationModifier() float64 { mhWeapon := paladin.GetMHWeapon() if mhWeapon == nil { From e98f61f282755dc8a2da66e49d915efd88cb7f95 Mon Sep 17 00:00:00 2001 From: vigo Date: Fri, 22 Mar 2024 21:49:08 +0100 Subject: [PATCH 12/12] [core] add CritMultiplier (default 1) to AttackTable, and use it to model hunters' "Monster Slaying" and "Humanoid Slaying", rogues' "Murder", and trolls' "Beastslaying" --- sim/core/racials.go | 1 + sim/core/spell_outcome.go | 48 +++++++++++++++++++-------------------- sim/core/target.go | 6 +++++ sim/druid/rake.go | 2 +- sim/druid/shred.go | 2 +- sim/hunter/talents.go | 2 ++ sim/rogue/talents.go | 6 ++--- sim/warlock/apl_values.go | 11 +++++---- 8 files changed, 43 insertions(+), 35 deletions(-) diff --git a/sim/core/racials.go b/sim/core/racials.go index a483ce7b0f..c462216620 100644 --- a/sim/core/racials.go +++ b/sim/core/racials.go @@ -121,6 +121,7 @@ func applyRaceEffects(agent Agent) { if t.MobType == proto.MobType_MobTypeBeast { for _, at := range character.AttackTables[t.UnitIndex] { at.DamageDealtMultiplier *= 1.05 + at.CritMultiplier *= 1.05 } } } diff --git a/sim/core/spell_outcome.go b/sim/core/spell_outcome.go index b554e3fe52..7d6a1771cd 100644 --- a/sim/core/spell_outcome.go +++ b/sim/core/spell_outcome.go @@ -34,7 +34,7 @@ func (dot *Dot) OutcomeTickCounted(_ *Simulation, result *SpellResult, _ *Attack func (dot *Dot) OutcomeTickPhysicalCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if dot.Spell.PhysicalCritCheck(sim, attackTable) { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier() + result.Damage *= dot.Spell.CritMultiplier(attackTable) } else { result.Outcome = OutcomeHit } @@ -43,16 +43,16 @@ func (dot *Dot) OutcomeTickPhysicalCrit(sim *Simulation, result *SpellResult, at func (dot *Dot) OutcomeTickSnapshotCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier() + result.Damage *= dot.Spell.CritMultiplier(attackTable) } else { result.Outcome = OutcomeHit } } -func (dot *Dot) OutcomeSnapshotCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { +func (dot *Dot) OutcomeSnapshotCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier() + result.Damage *= dot.Spell.CritMultiplier(attackTable) dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -64,7 +64,7 @@ func (dot *Dot) OutcomeMagicHitAndSnapshotCrit(sim *Simulation, result *SpellRes if dot.Spell.MagicHitCheck(sim, attackTable) { if sim.RandomFloat("Snapshot Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier() + result.Damage *= dot.Spell.CritMultiplier(attackTable) dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -81,7 +81,7 @@ func (spell *Spell) OutcomeMagicHitAndCrit(sim *Simulation, result *SpellResult, if spell.MagicHitCheck(sim, attackTable) { if spell.MagicCritCheck(sim, result.Target) { result.Outcome = OutcomeCrit - result.Damage *= spell.CritMultiplier() + result.Damage *= spell.CritMultiplier(attackTable) spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -94,10 +94,10 @@ func (spell *Spell) OutcomeMagicHitAndCrit(sim *Simulation, result *SpellResult, } } -func (spell *Spell) OutcomeMagicCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { +func (spell *Spell) OutcomeMagicCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if spell.MagicCritCheck(sim, result.Target) { result.Outcome = OutcomeCrit - result.Damage *= spell.CritMultiplier() + result.Damage *= spell.CritMultiplier(attackTable) spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -110,10 +110,10 @@ func (spell *Spell) OutcomeHealing(_ *Simulation, result *SpellResult, _ *Attack spell.SpellMetrics[result.Target.UnitIndex].Hits++ } -func (spell *Spell) OutcomeHealingCrit(sim *Simulation, result *SpellResult, _ *AttackTable) { +func (spell *Spell) OutcomeHealingCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable) { if spell.HealingCritCheck(sim) { result.Outcome = OutcomeCrit - result.Damage *= spell.CritMultiplier() + result.Damage *= spell.CritMultiplier(attackTable) spell.SpellMetrics[result.Target.UnitIndex].Crits++ } else { result.Outcome = OutcomeHit @@ -309,7 +309,7 @@ func (dot *Dot) OutcomeRangedHitAndCritSnapshot(sim *Simulation, result *SpellRe if dot.Spell.Unit.PseudoStats.InFrontOfTarget { if !result.applyAttackTableMissNoDWPenalty(dot.Spell, attackTable, roll, &chance) { - if result.applyAttackTableCritSeparateRollSnapshot(sim, dot) { + if result.applyAttackTableCritSeparateRollSnapshot(sim, dot, attackTable) { result.applyAttackTableBlock(dot.Spell, attackTable, roll, &chance) } else { if !result.applyAttackTableBlock(dot.Spell, attackTable, roll, &chance) { @@ -319,7 +319,7 @@ func (dot *Dot) OutcomeRangedHitAndCritSnapshot(sim *Simulation, result *SpellRe } } else { if !result.applyAttackTableMissNoDWPenalty(dot.Spell, attackTable, roll, &chance) && - !result.applyAttackTableCritSeparateRollSnapshot(sim, dot) { + !result.applyAttackTableCritSeparateRollSnapshot(sim, dot, attackTable) { result.applyAttackTableHit(dot.Spell) } } @@ -459,7 +459,7 @@ func (result *SpellResult) applyAttackTableCrit(spell *Spell, attackTable *Attac if roll < *chance { result.Outcome = OutcomeCrit spell.SpellMetrics[result.Target.UnitIndex].Crits++ - result.Damage *= spell.CritMultiplier() + result.Damage *= spell.CritMultiplier(attackTable) return true } return false @@ -469,15 +469,15 @@ func (result *SpellResult) applyAttackTableCritSeparateRoll(sim *Simulation, spe if spell.PhysicalCritCheck(sim, attackTable) { result.Outcome = OutcomeCrit spell.SpellMetrics[result.Target.UnitIndex].Crits++ - result.Damage *= spell.CritMultiplier() + result.Damage *= spell.CritMultiplier(attackTable) return true } return false } -func (result *SpellResult) applyAttackTableCritSeparateRollSnapshot(sim *Simulation, dot *Dot) bool { +func (result *SpellResult) applyAttackTableCritSeparateRollSnapshot(sim *Simulation, dot *Dot, attackTable *AttackTable) bool { if sim.RandomFloat("Physical Crit Roll") < dot.SnapshotCritChance { result.Outcome = OutcomeCrit - result.Damage *= dot.Spell.CritMultiplier() + result.Damage *= dot.Spell.CritMultiplier(attackTable) dot.Spell.SpellMetrics[result.Target.UnitIndex].Crits++ return true } @@ -595,9 +595,9 @@ func (spell *Spell) OutcomeExpectedMagicHit(_ *Simulation, result *SpellResult, result.Damage *= averageMultiplier } -func (spell *Spell) OutcomeExpectedMagicCrit(_ *Simulation, result *SpellResult, _ *AttackTable) { +func (spell *Spell) OutcomeExpectedMagicCrit(_ *Simulation, result *SpellResult, attackTable *AttackTable) { averageMultiplier := 1.0 - averageMultiplier += spell.SpellCritChance(result.Target) * (spell.CritMultiplier() - 1) + averageMultiplier += spell.SpellCritChance(result.Target) * (spell.CritMultiplier(attackTable) - 1) result.Damage *= averageMultiplier } @@ -605,14 +605,14 @@ func (spell *Spell) OutcomeExpectedMagicCrit(_ *Simulation, result *SpellResult, func (spell *Spell) OutcomeExpectedMagicHitAndCrit(_ *Simulation, result *SpellResult, attackTable *AttackTable) { averageMultiplier := 1.0 averageMultiplier -= spell.SpellChanceToMiss(attackTable) - averageMultiplier += averageMultiplier * spell.SpellCritChance(result.Target) * (spell.CritMultiplier() - 1) + averageMultiplier += averageMultiplier * spell.SpellCritChance(result.Target) * (spell.CritMultiplier(attackTable) - 1) result.Damage *= averageMultiplier } -func (dot *Dot) OutcomeExpectedMagicSnapshotCrit(_ *Simulation, result *SpellResult, _ *AttackTable) { +func (dot *Dot) OutcomeExpectedMagicSnapshotCrit(_ *Simulation, result *SpellResult, attackTable *AttackTable) { averageMultiplier := 1.0 - averageMultiplier += dot.SnapshotCritChance * (dot.Spell.CritMultiplier() - 1) + averageMultiplier += dot.SnapshotCritChance * (dot.Spell.CritMultiplier(attackTable) - 1) result.Damage *= averageMultiplier } @@ -620,13 +620,13 @@ func (dot *Dot) OutcomeExpectedMagicSnapshotCrit(_ *Simulation, result *SpellRes // CritMultiplier() returns the damage multiplier for critical strikes, based on CritDamageBonus and DefenseType. // https://web.archive.org/web/20081014064638/http://elitistjerks.com/f31/t12595-relentless_earthstorm_diamond_-_melee_only/p4/ // https://github.com/TheGroxEmpire/TBC_DPS_Warrior_Sim/issues/30 -func (spell *Spell) CritMultiplier() float64 { +func (spell *Spell) CritMultiplier(at *AttackTable) float64 { switch spell.DefenseType { case DefenseTypeNone: panic(fmt.Sprintf("using CritMultiplier() for spellID %d which has no DefenseType", spell.SpellID)) case DefenseTypeMagic: - return 1 + 0.5*spell.CritDamageBonus + return 1 + (1.5*at.CritMultiplier-1)*spell.CritDamageBonus default: - return 1 + spell.CritDamageBonus + return 1 + (2.0*at.CritMultiplier-1)*spell.CritDamageBonus } } diff --git a/sim/core/target.go b/sim/core/target.go index 730632bcdf..5e7522fd80 100644 --- a/sim/core/target.go +++ b/sim/core/target.go @@ -260,6 +260,10 @@ type AttackTable struct { MeleeCritSuppression float64 SpellCritSuppression float64 + // All "Apply Aura: Mod All Damage Done Against Creature" effects in Vanilla and TBC also increase the CritMultiplier. + // Explicitly for hunters' "Monster Slaying" and "Humanoid Slaying", but likewise for rogues' "Murder", or trolls' "Beastslaying". + CritMultiplier float64 + DamageDealtMultiplier float64 // attacker buff, applied in applyAttackerModifiers() DamageTakenMultiplier float64 // defender debuff, applied in applyTargetModifiers() NatureDamageTakenMultiplier float64 @@ -274,6 +278,8 @@ func NewAttackTable(attacker *Unit, defender *Unit, weapon *Item) *AttackTable { Defender: defender, Weapon: weapon, + CritMultiplier: 1, + DamageDealtMultiplier: 1, DamageTakenMultiplier: 1, NatureDamageTakenMultiplier: 1, diff --git a/sim/druid/rake.go b/sim/druid/rake.go index b0ac0f8fdc..aababc0b63 100644 --- a/sim/druid/rake.go +++ b/sim/druid/rake.go @@ -122,7 +122,7 @@ func (druid *Druid) newRakeSpellConfig(rakeRank RakeRankInfo) core.SpellConfig { attackTable := spell.Unit.AttackTables[target.UnitIndex][spell.CastType] critChance := spell.PhysicalCritChance(attackTable) - critMod := (critChance * (spell.CritMultiplier() - 1)) + critMod := critChance * (spell.CritMultiplier(attackTable) - 1) initial.Damage *= 1 + critMod return initial }, diff --git a/sim/druid/shred.go b/sim/druid/shred.go index 523efae1a7..08f842efac 100644 --- a/sim/druid/shred.go +++ b/sim/druid/shred.go @@ -91,7 +91,7 @@ func (druid *Druid) registerShredSpell() { attackTable := spell.Unit.AttackTables[target.UnitIndex][spell.CastType] critChance := spell.PhysicalCritChance(attackTable) - critMod := (critChance * (spell.CritMultiplier() - 1)) + critMod := (critChance * (spell.CritMultiplier(attackTable) - 1)) baseres.Damage *= (1 + critMod) diff --git a/sim/hunter/talents.go b/sim/hunter/talents.go index a490fcaf70..a00537ec95 100644 --- a/sim/hunter/talents.go +++ b/sim/hunter/talents.go @@ -31,11 +31,13 @@ func (hunter *Hunter) ApplyTalents() { multiplier := []float64{1, 1.01, 1.02, 1.03}[hunter.Talents.HumanoidSlaying] for _, at := range hunter.AttackTables[t.UnitIndex] { at.DamageDealtMultiplier *= multiplier + at.CritMultiplier *= multiplier } case proto.MobType_MobTypeBeast, proto.MobType_MobTypeGiant, proto.MobType_MobTypeDragonkin: multiplier := []float64{1, 1.01, 1.02, 1.03}[hunter.Talents.MonsterSlaying] for _, at := range hunter.AttackTables[t.UnitIndex] { at.DamageDealtMultiplier *= multiplier + at.CritMultiplier *= multiplier } } } diff --git a/sim/rogue/talents.go b/sim/rogue/talents.go index ab8435489e..acc2b68d91 100644 --- a/sim/rogue/talents.go +++ b/sim/rogue/talents.go @@ -65,17 +65,15 @@ func (rogue *Rogue) applyMurder() { return } - multiplier := []float64{1, 1.01, 1.02}[rogue.Talents.Murder] - - // TODO Murder, Monster Slaying, Humanoid Slaying, and Beast Slaying (Troll) all affect critical strike damage as well - // post finalize, since attack tables need to be setup rogue.Env.RegisterPostFinalizeEffect(func() { for _, t := range rogue.Env.Encounter.Targets { switch t.MobType { case proto.MobType_MobTypeHumanoid, proto.MobType_MobTypeGiant, proto.MobType_MobTypeBeast, proto.MobType_MobTypeDragonkin: + multiplier := []float64{1, 1.01, 1.02}[rogue.Talents.Murder] for _, at := range rogue.AttackTables[t.UnitIndex] { at.DamageDealtMultiplier *= multiplier + at.CritMultiplier *= multiplier } } } diff --git a/sim/warlock/apl_values.go b/sim/warlock/apl_values.go index 801ecfb9ec..ce58b68c6d 100644 --- a/sim/warlock/apl_values.go +++ b/sim/warlock/apl_values.go @@ -23,7 +23,7 @@ type APLValueWarlockShouldRecastDrainSoul struct { warlock *Warlock } -func (warlock *Warlock) newValueWarlockShouldRecastDrainSoul(rot *core.APLRotation, config *proto.APLValueWarlockShouldRecastDrainSoul) core.APLValue { +func (warlock *Warlock) newValueWarlockShouldRecastDrainSoul(_ *core.APLRotation, _ *proto.APLValueWarlockShouldRecastDrainSoul) core.APLValue { return &APLValueWarlockShouldRecastDrainSoul{ warlock: warlock, } @@ -114,19 +114,20 @@ func (value *APLValueWarlockShouldRefreshCorruption) GetBool(sim *core.Simulatio return true } + attackTable := warlock.AttackTables[target.UnitIndex][dot.Spell.CastType] + // check if reapplying corruption is worthwhile snapshotCrit := dot.SnapshotCritChance - snapshotMult := dot.SnapshotAttackerMultiplier * (snapshotCrit*(warlock.Corruption.CritMultiplier()-1) + 1) + snapshotMult := dot.SnapshotAttackerMultiplier * (snapshotCrit*(warlock.Corruption.CritMultiplier(attackTable)-1) + 1) - attackTable := warlock.AttackTables[target.UnitIndex][dot.Spell.CastType] curCrit := warlock.Corruption.SpellCritChance(target) - curDmg := dot.Spell.AttackerDamageMultiplier(attackTable) * (curCrit*(warlock.Corruption.CritMultiplier()-1) + 1) + curDmg := dot.Spell.AttackerDamageMultiplier(attackTable) * (curCrit*(warlock.Corruption.CritMultiplier(attackTable)-1) + 1) relDmgInc := curDmg / snapshotMult snapshotDmg := warlock.Corruption.ExpectedTickDamageFromCurrentSnapshot(sim, target) snapshotDmg *= float64(sim.GetRemainingDuration()) / float64(dot.TickPeriod()) - snapshotDmg *= (relDmgInc - 1) + snapshotDmg *= relDmgInc - 1 snapshotDmg -= warlock.Corruption.ExpectedTickDamageFromCurrentSnapshot(sim, target) //if sim.Log != nil {