diff --git a/sim/core/dot.go b/sim/core/dot.go index 8859750a80..55f1689bbb 100644 --- a/sim/core/dot.go +++ b/sim/core/dot.go @@ -82,7 +82,6 @@ func (dot *Dot) Apply(sim *Simulation) { if dot.Spell.Flags&SpellFlagSupressDoTApply > 0 { return } - dot.TakeSnapshot(sim, false) dot.recomputeAuraDuration(sim) dot.Activate(sim) @@ -438,6 +437,7 @@ func (spell *Spell) createDots(config DotConfig, isHot bool) { if spell.dots == nil { spell.dots = make([]*Dot, len(caster.Env.AllUnits)) } + for _, target := range caster.Env.AllUnits { if isHot != caster.IsOpponent(target) { dot.Aura = target.GetOrRegisterAura(auraConfig) diff --git a/sim/priest/_binding_heal.go b/sim/priest/_binding_heal.go deleted file mode 100644 index 9c084304e1..0000000000 --- a/sim/priest/_binding_heal.go +++ /dev/null @@ -1,47 +0,0 @@ -package priest - -import ( - "time" - - "github.com/wowsims/mop/sim/core" -) - -func (priest *Priest) registerBindingHealSpell() { - spellCoeff := 0.8057 + 0.04*float64(priest.Talents.EmpoweredHealing) - - priest.BindingHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 48120}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.27, - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Millisecond * 1500, - }, - }, - - BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, - DamageMultiplier: 1 * - (1 + .02*float64(priest.Talents.SpiritualHealing)) * - (1 + .01*float64(priest.Talents.BlessedResilience)) * - (1 + .02*float64(priest.Talents.FocusedPower)) * - (1 + .02*float64(priest.Talents.DivineProvidence)), - CritMultiplier: priest.DefaultCritMultiplier(), - ThreatMultiplier: 0.5 * (1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve]), - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - healFromSP := spellCoeff * spell.HealingPower(target) - - selfHealing := sim.Roll(1959, 2516) + healFromSP - spell.CalcAndDealHealing(sim, &priest.Unit, selfHealing, spell.OutcomeHealingCrit) - - targetHealing := sim.Roll(1959, 2516) + healFromSP - spell.CalcAndDealHealing(sim, target, targetHealing, spell.OutcomeHealingCrit) - }, - }) -} diff --git a/sim/priest/_circle_of_healing.go b/sim/priest/_circle_of_healing.go deleted file mode 100644 index 97bd9d6bb0..0000000000 --- a/sim/priest/_circle_of_healing.go +++ /dev/null @@ -1,56 +0,0 @@ -package priest - -import ( - "time" - - "github.com/wowsims/mop/sim/core" - "github.com/wowsims/mop/sim/core/proto" -) - -func (priest *Priest) registerCircleOfHealingSpell() { - if !priest.Talents.CircleOfHealing { - return - } - - numTargets := 5 + core.TernaryInt32(priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfCircleOfHealing), 1, 0) - targets := priest.Env.Raid.GetFirstNPlayersOrPets(numTargets) - - priest.CircleOfHealing = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 48089}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.21, - Multiplier: 1 - []float64{0, .04, .07, .10}[priest.Talents.MentalAgility], - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - CD: core.Cooldown{ - Timer: priest.NewTimer(), - Duration: time.Second * 6, - }, - }, - - BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, - DamageMultiplier: 1 * - (1 + .02*float64(priest.Talents.SpiritualHealing)) * - (1 + .01*float64(priest.Talents.BlessedResilience)) * - (1 + .02*float64(priest.Talents.FocusedPower)) * - (1 + .02*float64(priest.Talents.DivineProvidence)) * - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetCrimsonAcolytesRaiment, 4), 1.1, 1), - CritMultiplier: priest.DefaultCritMultiplier(), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - healFromSP := 0.4029 * spell.HealingPower(target) - for _, aoeTarget := range targets { - baseHealing := sim.Roll(958, 1058) + healFromSP - spell.CalcAndDealHealing(sim, aoeTarget, baseHealing, spell.OutcomeHealingCrit) - } - }, - }) -} diff --git a/sim/priest/_flash_heal.go b/sim/priest/_flash_heal.go deleted file mode 100644 index c6af8d336b..0000000000 --- a/sim/priest/_flash_heal.go +++ /dev/null @@ -1,45 +0,0 @@ -package priest - -import ( - "time" - - "github.com/wowsims/mop/sim/core" - "github.com/wowsims/mop/sim/core/proto" -) - -func (priest *Priest) registerFlashHealSpell() { - spellCoeff := 0.8057 + 0.04*float64(priest.Talents.EmpoweredHealing) - - priest.FlashHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 48071}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.18, - Multiplier: 1 - - .05*float64(priest.Talents.ImprovedFlashHeal) - - core.TernaryFloat64(priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfFlashHeal), .1, 0), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Millisecond * 1500, - }, - }, - - BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, - DamageMultiplier: 1 * - (1 + .02*float64(priest.Talents.SpiritualHealing)) * - (1 + .01*float64(priest.Talents.BlessedResilience)) * - (1 + .02*float64(priest.Talents.FocusedPower)), - CritMultiplier: priest.DefaultCritMultiplier(), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseHealing := sim.Roll(1896, 2203) + spellCoeff*spell.HealingPower(target) - spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeHealingCrit) - }, - }) -} diff --git a/sim/priest/_greater_heal.go b/sim/priest/_greater_heal.go deleted file mode 100644 index 689f2df341..0000000000 --- a/sim/priest/_greater_heal.go +++ /dev/null @@ -1,45 +0,0 @@ -package priest - -import ( - "time" - - "github.com/wowsims/mop/sim/core" -) - -func (priest *Priest) registerGreaterHealSpell() { - spellCoeff := 1.6114 + 0.08*float64(priest.Talents.EmpoweredHealing) - - priest.GreaterHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 48063}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.32, - Multiplier: 1 * - (1 - .05*float64(priest.Talents.ImprovedHealing)) * - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetRegaliaOfFaith, 4), .95, 1), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Second*3 - time.Millisecond*100*time.Duration(priest.Talents.DivineFury), - }, - }, - - BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, - DamageMultiplier: 1 * - (1 + .02*float64(priest.Talents.SpiritualHealing)) * - (1 + .01*float64(priest.Talents.BlessedResilience)) * - (1 + .02*float64(priest.Talents.FocusedPower)) * - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetVestmentsOfAbsolution, 4), 1.05, 1), - CritMultiplier: priest.DefaultCritMultiplier(), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseHealing := sim.Roll(3980, 4621) + spellCoeff*spell.HealingPower(target) - spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeHealingCrit) - }, - }) -} diff --git a/sim/priest/_power_word_shield.go b/sim/priest/_power_word_shield.go deleted file mode 100644 index 6a858f9829..0000000000 --- a/sim/priest/_power_word_shield.go +++ /dev/null @@ -1,111 +0,0 @@ -package priest - -import ( - "time" - - "github.com/wowsims/mop/sim/core" - "github.com/wowsims/mop/sim/core/proto" -) - -func (priest *Priest) registerPowerWordShieldSpell() { - coeff := 0.8057 + 0.08*float64(priest.Talents.BorrowedTime) - - wsDuration := time.Second*15 - - core.TernaryDuration(priest.CouldHaveSetBonus(ItemSetGladiatorsInvestiture, 4), time.Second*2, 0) - - core.TernaryDuration(priest.CouldHaveSetBonus(ItemSetGladiatorsRaiment, 4), time.Second*2, 0) - - cd := core.Cooldown{} - if !priest.Talents.SoulWarding { - cd = core.Cooldown{ - Timer: priest.NewTimer(), - Duration: time.Second * 4, - } - } - - var glyphHeal *core.Spell - - priest.PowerWordShield = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 48066}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.23, - Multiplier: 1 - - []float64{0, .04, .07, .10}[priest.Talents.MentalAgility] - - core.TernaryFloat64(priest.Talents.SoulWarding, .15, 0), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - CD: cd, - }, - ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { - return !priest.WeakenedSouls.Get(target).IsActive() - }, - - DamageMultiplier: 1 * - (1 + .05*float64(priest.Talents.ImprovedPowerWordShield)) * - (1 + - .01*float64(priest.Talents.TwinDisciplines) + - .02*float64(priest.Talents.FocusedPower) + - .02*float64(priest.Talents.SpiritualHealing)) * - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetCrimsonAcolytesRaiment, 4), 1.05, 1), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - Shield: core.ShieldConfig{ - Aura: core.Aura{ - Label: "Power Word Shield", - Duration: time.Second * 30, - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - shieldAmount := 2230.0 + coeff*spell.HealingPower(target) - shield := spell.Shield(target) - shield.Apply(sim, shieldAmount) - - weakenedSoul := priest.WeakenedSouls.Get(target) - weakenedSoul.Duration = wsDuration - weakenedSoul.Activate(sim) - - if glyphHeal != nil { - glyphHeal.Cast(sim, target) - } - }, - }) - - priest.WeakenedSouls = priest.NewAllyAuraArray(func(target *core.Unit) *core.Aura { - return target.GetOrRegisterAura(core.Aura{ - Label: "Weakened Soul", - ActionID: core.ActionID{SpellID: 6788}, - Duration: time.Second * 15, - }) - }) - - if priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfPowerWordShield) { - glyphHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{ItemID: 42408}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful, - - // Talent effects are combined differently in this spell compared to PWS, for some reason. - DamageMultiplier: 0.2 * - (1 + .01*float64(priest.Talents.BlessedResilience)) * - (1 + .02*float64(priest.Talents.FocusedPower)) * - (1 + - .05*float64(priest.Talents.ImprovedPowerWordShield) + - .01*float64(priest.Talents.TwinDisciplines)) * - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetCrimsonAcolytesRaiment, 4), 1.05, 1), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseHealing := 2230 + coeff*spell.HealingPower(target) - spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeAlwaysHit) - }, - }) - } -} diff --git a/sim/priest/_prayer_of_healing.go b/sim/priest/_prayer_of_healing.go deleted file mode 100644 index 194a5efcf9..0000000000 --- a/sim/priest/_prayer_of_healing.go +++ /dev/null @@ -1,84 +0,0 @@ -package priest - -import ( - "time" - - "github.com/wowsims/mop/sim/core" - "github.com/wowsims/mop/sim/core/proto" -) - -func (priest *Priest) registerPrayerOfHealingSpell() { - var glyphSpell *core.Spell - - priest.PrayerOfHealing = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 48072}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.48, - Multiplier: 1 - - .1*float64(priest.Talents.HealingPrayers) - - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetVestmentsOfAbsolution, 2), 0.1, 0), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - CastTime: time.Second * 3, - }, - }, - - BonusCritRating: 0 + - 1*float64(priest.Talents.HolySpecialization)*core.CritRatingPerCritChance + - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetSanctificationRegalia, 2), 10*core.CritRatingPerCritChance, 0), - DamageMultiplier: 1 * - (1 + .02*float64(priest.Talents.SpiritualHealing)) * - (1 + .01*float64(priest.Talents.BlessedResilience)) * - (1 + .02*float64(priest.Talents.FocusedPower)) * - (1 + .02*float64(priest.Talents.DivineProvidence)), - CritMultiplier: priest.DefaultCritMultiplier(), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - targetAgent := target.Env.Raid.GetPlayerFromUnitIndex(target.UnitIndex) - party := targetAgent.GetCharacter().Party - - for _, partyAgent := range party.PlayersAndPets { - partyTarget := &partyAgent.GetCharacter().Unit - baseHealing := sim.Roll(2109, 2228) + 0.526*spell.HealingPower(partyTarget) - spell.CalcAndDealHealing(sim, partyTarget, baseHealing, spell.OutcomeHealingCrit) - if glyphSpell != nil { - glyphSpell.Hot(partyTarget).Apply(sim) - } - } - }, - }) - - if priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfPrayerOfHealing) { - glyphSpell = priest.GetOrRegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{ItemID: 42409}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagHelpful, - - DamageMultiplier: priest.PrayerOfHealing.DamageMultiplier * 0.2 / 2, - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - Hot: core.DotConfig{ - Aura: core.Aura{ - Label: "PoH Glyph", - }, - NumberOfTicks: 2, - TickLength: time.Second * 3, - OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, _ bool) { - dot.SnapshotBaseDamage = sim.Roll(2109, 2228) + 0.526*dot.Spell.HealingPower(target) - dot.SnapshotAttackerMultiplier = dot.Spell.CasterHealingMultiplier() - }, - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - dot.CalcAndDealPeriodicSnapshotHealing(sim, target, dot.OutcomeTick) - }, - }, - }) - } -} diff --git a/sim/priest/_renew.go b/sim/priest/_renew.go deleted file mode 100644 index 83a20dfa77..0000000000 --- a/sim/priest/_renew.go +++ /dev/null @@ -1,93 +0,0 @@ -package priest - -import ( - "time" - - "github.com/wowsims/mop/sim/core" - "github.com/wowsims/mop/sim/core/proto" -) - -func (priest *Priest) registerRenewSpell() { - actionID := core.ActionID{SpellID: 48068} - spellCoeff := (1.88 + .05*float64(priest.Talents.EmpoweredRenew)) / 5 - - if priest.Talents.EmpoweredRenew > 0 { - priest.EmpoweredRenew = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 63543}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagNoOnCastComplete | core.SpellFlagHelpful, - - BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, - DamageMultiplier: 1 * - float64(priest.renewTicks()) * - priest.renewHealingMultiplier() * - .05 * float64(priest.Talents.EmpoweredRenew) * - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetZabrasRaiment, 4), 1.1, 1), - CritMultiplier: priest.DefaultCritMultiplier(), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseHealing := 280 + spellCoeff*spell.HealingPower(target) - spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeHealingCrit) - }, - }) - } - - priest.Renew = priest.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.17, - Multiplier: 1 - []float64{0, .04, .07, .10}[priest.Talents.MentalAgility], - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - }, - }, - - DamageMultiplier: priest.renewHealingMultiplier(), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], - - Hot: core.DotConfig{ - Aura: core.Aura{ - Label: "Renew", - }, - NumberOfTicks: priest.renewTicks(), - TickLength: time.Second * 3, - OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, _ bool) { - dot.SnapshotBaseDamage = 280 + spellCoeff*dot.Spell.HealingPower(target) - dot.SnapshotAttackerMultiplier = dot.Spell.CasterHealingMultiplier() - }, - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - dot.CalcAndDealPeriodicSnapshotHealing(sim, target, dot.OutcomeTick) - }, - }, - - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - spell.Hot(target).Apply(sim) - - if priest.EmpoweredRenew != nil { - priest.EmpoweredRenew.Cast(sim, target) - } - }, - }) -} - -func (priest *Priest) renewTicks() int32 { - return 5 - core.TernaryInt32(priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfRenew), 1, 0) -} - -func (priest *Priest) renewHealingMultiplier() float64 { - return 1 * - (1 + .02*float64(priest.Talents.SpiritualHealing)) * - (1 + .01*float64(priest.Talents.BlessedResilience)) * - (1 + .02*float64(priest.Talents.FocusedPower)) * - (1 + .01*float64(priest.Talents.TwinDisciplines)) * - (1 + .05*float64(priest.Talents.ImprovedRenew)) * - core.TernaryFloat64(priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfRenew), 1.25, 1) -} diff --git a/sim/priest/binding_heal.go b/sim/priest/binding_heal.go new file mode 100644 index 0000000000..878032cb2e --- /dev/null +++ b/sim/priest/binding_heal.go @@ -0,0 +1,46 @@ +package priest + +import ( + "time" + + "github.com/wowsims/mop/sim/core" +) + +func (priest *Priest) registerBindingHealSpell() { + + bindingHealVariance := 0.25 + bindingHealScaling := 9.494 + bindingHealCoefficient := .899 + + priest.BindingHeal = priest.RegisterSpell(core.SpellConfig{ + ActionID: core.ActionID{SpellID: 32546}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellBindingHeal, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + + ManaCost: core.ManaCostOptions{ + BaseCostPercent: 5.4, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + CastTime: time.Millisecond * 1500, + }, + }, + + BonusCoefficient: bindingHealCoefficient, + DamageMultiplier: 1, + CritMultiplier: priest.DefaultCritMultiplier(), + ThreatMultiplier: 0.5, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + + selfHealing := priest.CalcAndRollDamageRange(sim, bindingHealScaling, bindingHealVariance) + spell.CalcAndDealHealing(sim, &priest.Unit, selfHealing, spell.OutcomeHealingCrit) + + targetHealing := priest.CalcAndRollDamageRange(sim, bindingHealScaling, bindingHealVariance) + spell.CalcAndDealHealing(sim, target, targetHealing, spell.OutcomeHealingCrit) + }, + }) +} diff --git a/sim/priest/flash_heal.go b/sim/priest/flash_heal.go new file mode 100644 index 0000000000..59cf1fa970 --- /dev/null +++ b/sim/priest/flash_heal.go @@ -0,0 +1,41 @@ +package priest + +import ( + "time" + + "github.com/wowsims/mop/sim/core" +) + +func (priest *Priest) registerFlashHealSpell() { + flashHealVariance := 0.15 + flashHealScaling := 13.0 + flashHealCoefficient := 1.314 + + priest.FlashHeal = priest.RegisterSpell(core.SpellConfig{ + ActionID: core.ActionID{SpellID: 2061}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellFlashHeal, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + + ManaCost: core.ManaCostOptions{ + BaseCostPercent: 5.9, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + CastTime: time.Millisecond * 1500, + }, + }, + + DamageMultiplier: 1, + CritMultiplier: priest.DefaultCritMultiplier(), + ThreatMultiplier: 1, + BonusCoefficient: flashHealCoefficient, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + baseHealing := priest.CalcAndRollDamageRange(sim, flashHealScaling, flashHealVariance) + spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeHealingCrit) + }, + }) +} diff --git a/sim/priest/greater_heal.go b/sim/priest/greater_heal.go new file mode 100644 index 0000000000..18e2018cef --- /dev/null +++ b/sim/priest/greater_heal.go @@ -0,0 +1,47 @@ +package priest + +import ( + "time" + + "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/core/proto" +) + +func (priest *Priest) registerGreaterHealSpell() { + + if priest.Spec == proto.Spec_SpecShadowPriest { + return + } + + greaterHealVariance := 0.15 + greaterHealScaling := 21.658 + greaterHealCoefficient := 2.19 + + priest.GreaterHeal = priest.RegisterSpell(core.SpellConfig{ + ActionID: core.ActionID{SpellID: 2060}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellGreaterHeal, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + + ManaCost: core.ManaCostOptions{ + BaseCostPercent: 5.9, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + CastTime: time.Millisecond * 2500, + }, + }, + + DamageMultiplier: 1, + CritMultiplier: priest.DefaultCritMultiplier(), + ThreatMultiplier: 1, + BonusCoefficient: greaterHealCoefficient, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + baseHealing := priest.CalcAndRollDamageRange(sim, greaterHealScaling, greaterHealVariance) + spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeHealingCrit) + }, + }) +} diff --git a/sim/priest/heal.go b/sim/priest/heal.go new file mode 100644 index 0000000000..fc01be5915 --- /dev/null +++ b/sim/priest/heal.go @@ -0,0 +1,47 @@ +package priest + +import ( + "time" + + "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/core/proto" +) + +func (priest *Priest) registerHealSpell() { + + if priest.Spec == proto.Spec_SpecShadowPriest { + return + } + + healVariance := 0.15 + healScaling := 10.145 + healCoefficient := 1.024 + + priest.GreaterHeal = priest.RegisterSpell(core.SpellConfig{ + ActionID: core.ActionID{SpellID: 2050}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellHeal, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + + ManaCost: core.ManaCostOptions{ + BaseCostPercent: 1.9, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + CastTime: time.Millisecond * 2500, + }, + }, + + DamageMultiplier: 1, + CritMultiplier: priest.DefaultCritMultiplier(), + ThreatMultiplier: 1, + BonusCoefficient: healCoefficient, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + baseHealing := priest.CalcAndRollDamageRange(sim, healScaling, healVariance) + spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeHealingCrit) + }, + }) +} diff --git a/sim/priest/holy/circle_of_healing.go b/sim/priest/holy/circle_of_healing.go new file mode 100644 index 0000000000..654a8f4605 --- /dev/null +++ b/sim/priest/holy/circle_of_healing.go @@ -0,0 +1,50 @@ +package holy + +import ( + "time" + + "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/priest" +) + +func (holy *HolyPriest) registerCircleOfHealingSpell() { + + circleOfHealingVariance := 0.1 + circleOfHealingScaling := 4.613 + circleOfHealingCoefficient := 0.467 + + targets := holy.Env.Raid.GetFirstNPlayersOrPets(5) + + holy.RegisterSpell(core.SpellConfig{ + ActionID: core.ActionID{SpellID: 34861}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: priest.PriestSpellCircleOfHealing, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + + ManaCost: core.ManaCostOptions{ + BaseCostPercent: 3.2, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + }, + CD: core.Cooldown{ + Timer: holy.NewTimer(), + Duration: time.Second * 10, + }, + }, + + DamageMultiplier: 1, + CritMultiplier: holy.DefaultCritMultiplier(), + ThreatMultiplier: 1, + BonusCoefficient: circleOfHealingCoefficient, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + for _, aoeTarget := range targets { + baseHealing := holy.CalcAndRollDamageRange(sim, circleOfHealingScaling, circleOfHealingVariance) + spell.CalcAndDealHealing(sim, aoeTarget, baseHealing, spell.OutcomeHealingCrit) + } + }, + }) +} diff --git a/sim/priest/holy/holy.go b/sim/priest/holy/holy.go index 3985470972..47ccf6b797 100644 --- a/sim/priest/holy/holy.go +++ b/sim/priest/holy/holy.go @@ -41,14 +41,19 @@ func NewHolyPriest(character *core.Character, options *proto.Player) *HolyPriest type HolyPriest struct { *priest.Priest + + SerendipityAura *core.Aura } func (holyPriest *HolyPriest) GetPriest() *priest.Priest { return holyPriest.Priest } -func (holyPriest *HolyPriest) Initialize() { - holyPriest.Priest.Initialize() +func (holy *HolyPriest) Initialize() { + holy.Priest.Initialize() + + holy.registerCircleOfHealingSpell() + holy.registerSerendipity() // holyPriest.RegisterHolyFireSpell() // holyPriest.RegisterSmiteSpell() diff --git a/sim/priest/holy/serendipity.go b/sim/priest/holy/serendipity.go new file mode 100644 index 0000000000..965e79d929 --- /dev/null +++ b/sim/priest/holy/serendipity.go @@ -0,0 +1,58 @@ +package holy + +import ( + "time" + + "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/priest" +) + +func (holy *HolyPriest) registerSerendipity() { + + serendipitySpendSpells := priest.PriestSpellGreaterHeal | priest.PriestSpellPrayerOfHealing + serendipityBuildSpells := priest.PriestSpellBindingHeal | priest.PriestSpellFlashHeal + + serendipityCastTimemod := holy.AddDynamicMod(core.SpellModConfig{ + ClassMask: serendipitySpendSpells, + Kind: core.SpellMod_CastTime_Pct, + FloatValue: -0.2, + }) + serendipityManaCostmod := holy.AddDynamicMod(core.SpellModConfig{ + ClassMask: serendipitySpendSpells, + Kind: core.SpellMod_PowerCost_Pct, + FloatValue: -0.2, + }) + holy.SerendipityAura = holy.RegisterAura(core.Aura{ + Label: "Serendipity", + ActionID: core.ActionID{SpellID: 63735}, + Duration: time.Second * 20, + MaxStacks: 2, + OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks int32, newStacks int32) { + serendipityCastTimemod.UpdateFloatValue(float64(newStacks) * -0.2) + serendipityCastTimemod.Activate() + serendipityManaCostmod.UpdateFloatValue(float64(newStacks) * -0.2) + serendipityManaCostmod.Activate() + }, + OnExpire: func(aura *core.Aura, sim *core.Simulation) { + serendipityCastTimemod.Deactivate() + serendipityManaCostmod.Deactivate() + }, + OnCastComplete: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell) { + if !spell.Matches(serendipitySpendSpells) { + return + } + holy.SerendipityAura.Deactivate(sim) + }, + }) + + core.MakeProcTriggerAura(&holy.Unit, core.ProcTrigger{ + Name: "Serendipity - Trigger", + Callback: core.CallbackOnHealDealt, + Outcome: core.OutcomeLanded, + ClassSpellMask: serendipityBuildSpells, + Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { + holy.SerendipityAura.Activate(sim) + holy.SerendipityAura.AddStack(sim) + }, + }) +} diff --git a/sim/priest/power_word_shield.go b/sim/priest/power_word_shield.go new file mode 100644 index 0000000000..a56c46781d --- /dev/null +++ b/sim/priest/power_word_shield.go @@ -0,0 +1,85 @@ +package priest + +import ( + "time" + + "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/core/proto" +) + +func (priest *Priest) registerPowerWordShieldSpell() { + coeff := 18.515 + + var glyphHeal *core.Spell + + priest.PowerWordShield = priest.RegisterSpell(core.SpellConfig{ + ActionID: core.ActionID{SpellID: 17}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellPowerWordShield, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + + ManaCost: core.ManaCostOptions{ + BaseCostPercent: 6.1, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + }, + }, + ExtraCastCondition: func(sim *core.Simulation, target *core.Unit) bool { + return !priest.WeakenedSouls.Get(target).IsActive() + }, + + DamageMultiplier: 1, + CritMultiplier: priest.DefaultCritMultiplier(), + ThreatMultiplier: 1, + + Shield: core.ShieldConfig{ + Aura: core.Aura{ + Label: "Power Word Shield", + Duration: time.Second * 15, + }, + }, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + shieldAmount := 2 + coeff*spell.HealingPower(target) + shield := spell.Shield(target) + shield.Apply(sim, shieldAmount) + + weakenedSoul := priest.WeakenedSouls.Get(target) + weakenedSoul.Duration = time.Second * 15 + weakenedSoul.Activate(sim) + + if glyphHeal != nil { + glyphHeal.Cast(sim, target) + } + }, + }) + + priest.WeakenedSouls = priest.NewAllyAuraArray(func(target *core.Unit) *core.Aura { + return target.GetOrRegisterAura(core.Aura{ + Label: "Weakened Soul", + ActionID: core.ActionID{SpellID: 6788}, + Duration: time.Second * 15, + }) + }) + + if priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfPowerWordShield) { + glyphHeal = priest.RegisterSpell(core.SpellConfig{ + ActionID: core.ActionID{ItemID: 56160}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + Flags: core.SpellFlagHelpful, + + // Talent effects are combined differently in this spell compared to PWS, for some reason. + DamageMultiplier: 0.2, + ThreatMultiplier: 1, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + baseHealing := 2 + coeff*spell.HealingPower(target) + spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeAlwaysHit) + }, + }) + } +} diff --git a/sim/priest/prayer_of_healing.go b/sim/priest/prayer_of_healing.go new file mode 100644 index 0000000000..74ea067fbe --- /dev/null +++ b/sim/priest/prayer_of_healing.go @@ -0,0 +1,51 @@ +package priest + +import ( + "time" + + "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/core/proto" +) + +func (priest *Priest) registerPrayerOfHealingSpell() { + + if priest.Spec == proto.Spec_SpecShadowPriest { + return + } + + prayerOfHealingVariance := 0.055 + prayerOfHealingScaling := 8.28 + prayerOfHealingCoefficient := 0.838 + + targets := priest.Env.Raid.GetFirstNPlayersOrPets(5) + + priest.RegisterSpell(core.SpellConfig{ + ActionID: core.ActionID{SpellID: 596}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellPrayerOfHealing, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + + ManaCost: core.ManaCostOptions{ + BaseCostPercent: 4.5, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + CastTime: time.Millisecond * 2500, + }, + }, + + DamageMultiplier: 1, + CritMultiplier: priest.DefaultCritMultiplier(), + ThreatMultiplier: 1, + BonusCoefficient: prayerOfHealingCoefficient, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + for _, aoeTarget := range targets { + baseHealing := priest.CalcAndRollDamageRange(sim, prayerOfHealingScaling, prayerOfHealingVariance) + spell.CalcAndDealHealing(sim, aoeTarget, baseHealing, spell.OutcomeHealingCrit) + } + }, + }) +} diff --git a/sim/priest/_prayer_of_mending.go b/sim/priest/prayer_of_mending.go similarity index 68% rename from sim/priest/_prayer_of_mending.go rename to sim/priest/prayer_of_mending.go index 442598057f..2f4631bbf7 100644 --- a/sim/priest/_prayer_of_mending.go +++ b/sim/priest/prayer_of_mending.go @@ -8,7 +8,7 @@ import ( ) func (priest *Priest) registerPrayerOfMendingSpell() { - actionID := core.ActionID{SpellID: 48113} + actionID := core.ActionID{SpellID: 33076} pomAuras := make([]*core.Aura, len(priest.Env.AllUnits)) for _, unit := range priest.Env.AllUnits { @@ -17,12 +17,12 @@ func (priest *Priest) registerPrayerOfMendingSpell() { } } - maxJumps := 5 + core.TernaryInt(priest.CouldHaveSetBonus(ItemSetRegaliaOfFaith, 2), 1, 0) + maxJumps := 5 var curTarget *core.Unit var remainingJumps int priest.ProcPrayerOfMending = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseHealing := 1043 + 0.8057*spell.HealingPower(target) + baseHealing := 800.0 * .571 priest.PrayerOfMending.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeHealingCrit) pomAuras[target.UnitIndex].Deactivate(sim) @@ -53,16 +53,14 @@ func (priest *Priest) registerPrayerOfMendingSpell() { } priest.PrayerOfMending = priest.RegisterSpell(core.SpellConfig{ - ActionID: actionID, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + ActionID: actionID, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellPrayerOfMending, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ - BaseCost: 0.15, - Multiplier: 1 * - (1 - .1*float64(priest.Talents.HealingPrayers)) * - (1 - []float64{0, .04, .07, .10}[priest.Talents.MentalAgility]), + BaseCostPercent: 3.5, }, Cast: core.CastConfig{ DefaultCast: core.Cast{ @@ -70,20 +68,13 @@ func (priest *Priest) registerPrayerOfMendingSpell() { }, CD: core.Cooldown{ Timer: priest.NewTimer(), - Duration: time.Duration(float64(time.Second*10) * (1 - .06*float64(priest.Talents.DivineProvidence))), + Duration: time.Duration(float64(time.Second * 10)), }, }, - BonusCritRating: float64(priest.Talents.HolySpecialization) * 1 * core.CritRatingPerCritChance, - DamageMultiplier: 1 * - (1 + .02*float64(priest.Talents.SpiritualHealing)) * - (1 + .01*float64(priest.Talents.BlessedResilience)) * - (1 + .02*float64(priest.Talents.FocusedPower)) * - (1 + .02*float64(priest.Talents.DivineProvidence)) * - (1 + .01*float64(priest.Talents.TwinDisciplines)) * - core.TernaryFloat64(priest.CouldHaveSetBonus(ItemSetZabrasRaiment, 2), 1.2, 1), + DamageMultiplier: 1, CritMultiplier: priest.DefaultCritMultiplier(), - ThreatMultiplier: 1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve], + ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { if curTarget != nil { diff --git a/sim/priest/priest.go b/sim/priest/priest.go index 11edf5e097..280aa7f737 100644 --- a/sim/priest/priest.go +++ b/sim/priest/priest.go @@ -87,9 +87,18 @@ func (priest *Priest) Initialize() { // priest.registerDispersionSpell() + priest.registerSpiritualHealing() priest.registerPowerInfusionSpell() priest.newMindSearSpell() + // Healing + priest.registerFlashHealSpell() + priest.registerBindingHealSpell() + priest.registerPowerWordShieldSpell() + priest.registerPrayerOfHealingSpell() + priest.registerRenewSpell() + priest.registerGreaterHealSpell() + priest.ApplyGlyphs() } @@ -167,6 +176,7 @@ const ( PriestSpellGreaterHeal PriestSpellGuardianSpirit PriestSpellHalo + PriestSpellHeal PriestSpellHolyFire PriestSpellHolyNova PriestSpellHolyWordChastise diff --git a/sim/priest/renew.go b/sim/priest/renew.go new file mode 100644 index 0000000000..ddabae3ef1 --- /dev/null +++ b/sim/priest/renew.go @@ -0,0 +1,61 @@ +package priest + +import ( + "time" + + "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/core/proto" +) + +func (priest *Priest) registerRenewSpell() { + + coeff := .207 + scaling := 2.051 + + actionID := core.ActionID{SpellID: 139} + + isHolyPriest := priest.Spec == proto.Spec_SpecHolyPriest + renewGCD := core.Ternary(isHolyPriest, core.GCDDefault, time.Second*1) + renewHealingMultiplier := core.Ternary(isHolyPriest, 1.15, 1.0) + + priest.Renew = priest.RegisterSpell(core.SpellConfig{ + ActionID: actionID, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellRenew, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + + ManaCost: core.ManaCostOptions{ + BaseCostPercent: 2.6, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: renewGCD, + }, + }, + DamageMultiplier: renewHealingMultiplier, + ThreatMultiplier: 1, + + Hot: core.DotConfig{ + Aura: core.Aura{ + Label: "Renew", + }, + NumberOfTicks: 4, + TickLength: time.Second * 3, + BonusCoefficient: coeff, + OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, _ bool) { + dot.Snapshot(target, priest.CalcScalingSpellDmg(scaling)) + }, + OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { + dot.CalcAndDealPeriodicSnapshotHealing(sim, target, dot.OutcomeTick) + }, + }, + + ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + // if isHolyPriest { + // // Do 15% of the total healing. + // } + spell.Hot(target).Apply(sim) + }, + }) +} diff --git a/sim/priest/spiritual_healing.go b/sim/priest/spiritual_healing.go new file mode 100644 index 0000000000..31d74b1959 --- /dev/null +++ b/sim/priest/spiritual_healing.go @@ -0,0 +1,19 @@ +package priest + +import ( + "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/core/proto" +) + +func (priest *Priest) registerSpiritualHealing() { + + if priest.Spec == proto.Spec_SpecShadowPriest { + return + } + + priest.AddStaticMod(core.SpellModConfig{ + ClassMask: PriestSpellFlashHeal | PriestSpellBindingHeal | PriestSpellRenew | PriestSpellPrayerOfMending, + FloatValue: 0.25, + Kind: core.SpellMod_DamageDone_Pct, + }) +} diff --git a/ui/index.html b/ui/index.html index 04cb4b487e..8f5efefaa3 100644 --- a/ui/index.html +++ b/ui/index.html @@ -149,7 +149,7 @@

Mists of Pandaria

Priest Holy - Not Supported + I'm trying ok?!!?