From db7cdb0954132e7fe37561aa86f92e26ae1eac1d Mon Sep 17 00:00:00 2001 From: Justin W Date: Fri, 27 Jun 2025 09:01:20 -0700 Subject: [PATCH 1/5] wip --- sim/core/dot.go | 4 + sim/core/spell.go | 8 ++ sim/priest/_flash_heal.go | 45 --------- sim/priest/_renew.go | 93 ------------------- .../{_binding_heal.go => binding_heal.go} | 24 +++-- sim/priest/flash_heal.go | 40 ++++++++ ...er_word_shield.go => power_word_shield.go} | 51 +++------- ...yer_of_mending.go => prayer_of_mending.go} | 24 ++--- sim/priest/priest.go | 6 ++ sim/priest/renew.go | 86 +++++++++++++++++ ui/index.html | 2 +- 11 files changed, 175 insertions(+), 208 deletions(-) delete mode 100644 sim/priest/_flash_heal.go delete mode 100644 sim/priest/_renew.go rename sim/priest/{_binding_heal.go => binding_heal.go} (52%) create mode 100644 sim/priest/flash_heal.go rename sim/priest/{_power_word_shield.go => power_word_shield.go} (52%) rename sim/priest/{_prayer_of_mending.go => prayer_of_mending.go} (72%) create mode 100644 sim/priest/renew.go diff --git a/sim/core/dot.go b/sim/core/dot.go index 41ca38e982..2e8def84d3 100644 --- a/sim/core/dot.go +++ b/sim/core/dot.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "math" "strconv" "time" @@ -77,6 +78,7 @@ func (dot *Dot) TakeSnapshot(sim *Simulation, doRollover bool) { // If the Dot is already active it's duration will be refreshed and the last tick from the previous application will be // transfered to the new one func (dot *Dot) Apply(sim *Simulation) { + fmt.Println("dot", dot) if dot.Spell.Flags&SpellFlagSupressDoTApply > 0 { return } @@ -415,7 +417,9 @@ 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 { + fmt.Println(isHot, caster.IsOpponent(target)) if isHot != caster.IsOpponent(target) { dot.Aura = target.GetOrRegisterAura(auraConfig) spell.dots[target.UnitIndex] = newDot(dot) diff --git a/sim/core/spell.go b/sim/core/spell.go index aaed2c05f5..ca2529aa4e 100644 --- a/sim/core/spell.go +++ b/sim/core/spell.go @@ -400,6 +400,14 @@ func (spell *Spell) AOEDot() *Dot { return spell.aoeDot } func (spell *Spell) Hot(target *Unit) *Dot { + fmt.Println(target.Label, target.UnitIndex) + for _, unit := range spell.dots { + if unit != nil { + fmt.Println(unit.Label) + } + } + fmt.Println(spell.dots) + fmt.Println(spell.dots.Get(target)) if spell.dots == nil { return nil } 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/_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 similarity index 52% rename from sim/priest/_binding_heal.go rename to sim/priest/binding_heal.go index 9c084304e1..da35ab919d 100644 --- a/sim/priest/_binding_heal.go +++ b/sim/priest/binding_heal.go @@ -7,16 +7,19 @@ import ( ) func (priest *Priest) registerBindingHealSpell() { - spellCoeff := 0.8057 + 0.04*float64(priest.Talents.EmpoweredHealing) + + bindingHealVariance := 0.25 + bindingHealScaling := 9.494 + bindingHealCoefficient := .899 priest.BindingHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 48120}, + ActionID: core.ActionID{SpellID: 32546}, SpellSchool: core.SpellSchoolHoly, ProcMask: core.ProcMaskSpellHealing, Flags: core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ - BaseCost: 0.27, + BaseCostPercent: 5.4, }, Cast: core.CastConfig{ DefaultCast: core.Cast{ @@ -25,22 +28,17 @@ func (priest *Priest) registerBindingHealSpell() { }, }, - 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)), + BonusCoefficient: bindingHealCoefficient, + DamageMultiplier: 1, CritMultiplier: priest.DefaultCritMultiplier(), - ThreatMultiplier: 0.5 * (1 - []float64{0, .07, .14, .20}[priest.Talents.SilentResolve]), + ThreatMultiplier: 0.5, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - healFromSP := spellCoeff * spell.HealingPower(target) - selfHealing := sim.Roll(1959, 2516) + healFromSP + selfHealing := priest.CalcAndRollDamageRange(sim, bindingHealScaling, bindingHealVariance) spell.CalcAndDealHealing(sim, &priest.Unit, selfHealing, spell.OutcomeHealingCrit) - targetHealing := sim.Roll(1959, 2516) + healFromSP + 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..b8cee5195b --- /dev/null +++ b/sim/priest/flash_heal.go @@ -0,0 +1,40 @@ +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, + 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/_power_word_shield.go b/sim/priest/power_word_shield.go similarity index 52% rename from sim/priest/_power_word_shield.go rename to sim/priest/power_word_shield.go index 6a858f9829..fede465432 100644 --- a/sim/priest/_power_word_shield.go +++ b/sim/priest/power_word_shield.go @@ -8,52 +8,31 @@ import ( ) 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, - } - } + coeff := 18.515 var glyphHeal *core.Spell priest.PowerWordShield = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 48066}, + ActionID: core.ActionID{SpellID: 17}, 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), + BaseCostPercent: 6.1, }, 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], + DamageMultiplier: 1, + CritMultiplier: priest.DefaultCritMultiplier(), + ThreatMultiplier: 1, Shield: core.ShieldConfig{ Aura: core.Aura{ @@ -63,12 +42,12 @@ func (priest *Priest) registerPowerWordShieldSpell() { }, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - shieldAmount := 2230.0 + coeff*spell.HealingPower(target) + shieldAmount := 2 + coeff*spell.HealingPower(target) shield := spell.Shield(target) shield.Apply(sim, shieldAmount) weakenedSoul := priest.WeakenedSouls.Get(target) - weakenedSoul.Duration = wsDuration + weakenedSoul.Duration = time.Second * 15 weakenedSoul.Activate(sim) if glyphHeal != nil { @@ -87,23 +66,17 @@ func (priest *Priest) registerPowerWordShieldSpell() { if priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfPowerWordShield) { glyphHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{ItemID: 42408}, + 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 * - (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], + DamageMultiplier: 0.2, + ThreatMultiplier: 1, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - baseHealing := 2230 + coeff*spell.HealingPower(target) + baseHealing := 2 + coeff*spell.HealingPower(target) spell.CalcAndDealHealing(sim, target, baseHealing, spell.OutcomeAlwaysHit) }, }) diff --git a/sim/priest/_prayer_of_mending.go b/sim/priest/prayer_of_mending.go similarity index 72% rename from sim/priest/_prayer_of_mending.go rename to sim/priest/prayer_of_mending.go index 442598057f..ea9c1f0d5c 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) @@ -59,10 +59,7 @@ func (priest *Priest) registerPrayerOfMendingSpell() { 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 +67,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 7b3cd52585..12aaef3851 100644 --- a/sim/priest/priest.go +++ b/sim/priest/priest.go @@ -90,6 +90,12 @@ func (priest *Priest) Initialize() { priest.registerPowerInfusionSpell() priest.newMindSearSpell() + // Healing + priest.registerFlashHealSpell() + priest.registerBindingHealSpell() + priest.registerPowerWordShieldSpell() + priest.registerRenewSpell() + priest.ApplyGlyphs() } diff --git a/sim/priest/renew.go b/sim/priest/renew.go new file mode 100644 index 0000000000..d209191a22 --- /dev/null +++ b/sim/priest/renew.go @@ -0,0 +1,86 @@ +package priest + +import ( + "fmt" + "time" + + "github.com/wowsims/mop/sim/core" +) + +func (priest *Priest) registerRenewSpell() { + + coeff := .207 + // scaling := 2.051 + + actionID := core.ActionID{SpellID: 139} + + // 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, + + // 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{ + BaseCostPercent: 2.6, + }, + Cast: core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + }, + }, + + DamageMultiplier: 1, + ThreatMultiplier: 1, + + Hot: core.DotConfig{ + Aura: core.Aura{ + Label: "Renew", + }, + NumberOfTicks: 4, + TickLength: time.Second * 3, + OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, _ bool) { + dot.SnapshotBaseDamage = coeff * 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) { + fmt.Println("zorp") + fmt.Println(spell.Hot(target)) + spell.Hot(target).Activate(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) +// } diff --git a/ui/index.html b/ui/index.html index c63219a235..b2d9b255c5 100644 --- a/ui/index.html +++ b/ui/index.html @@ -149,7 +149,7 @@

Mists of Pandaria

Priest Holy - Not Supported + I'm trying ok?!!?
From b7ee722d4f82cfb890092420e2a754afe51111bc Mon Sep 17 00:00:00 2001 From: Justin W Date: Thu, 10 Jul 2025 20:46:19 -0700 Subject: [PATCH 2/5] Some very basic healing spells + spiritual healing --- sim/core/dot.go | 4 --- sim/core/spell.go | 8 ----- sim/priest/_circle_of_healing.go | 56 -------------------------------- sim/priest/_greater_heal.go | 45 ------------------------- sim/priest/flash_heal.go | 9 ++--- sim/priest/greater_heal.go | 46 ++++++++++++++++++++++++++ sim/priest/heal.go | 46 ++++++++++++++++++++++++++ sim/priest/power_word_shield.go | 2 +- sim/priest/priest.go | 1 + sim/priest/renew.go | 45 ++++--------------------- sim/priest/spiritual_healing.go | 19 +++++++++++ 11 files changed, 124 insertions(+), 157 deletions(-) delete mode 100644 sim/priest/_circle_of_healing.go delete mode 100644 sim/priest/_greater_heal.go create mode 100644 sim/priest/greater_heal.go create mode 100644 sim/priest/heal.go create mode 100644 sim/priest/spiritual_healing.go diff --git a/sim/core/dot.go b/sim/core/dot.go index 83356927b8..55f1689bbb 100644 --- a/sim/core/dot.go +++ b/sim/core/dot.go @@ -1,7 +1,6 @@ package core import ( - "fmt" "math" "strconv" "time" @@ -80,11 +79,9 @@ func (dot *Dot) TakeSnapshot(sim *Simulation, doRollover bool) { // If the Dot is already active it's duration will be refreshed and the last tick from the previous application will be // transfered to the new one func (dot *Dot) Apply(sim *Simulation) { - fmt.Println("dot", dot) if dot.Spell.Flags&SpellFlagSupressDoTApply > 0 { return } - dot.TakeSnapshot(sim, false) dot.recomputeAuraDuration(sim) dot.Activate(sim) @@ -442,7 +439,6 @@ func (spell *Spell) createDots(config DotConfig, isHot bool) { } for _, target := range caster.Env.AllUnits { - fmt.Println(isHot, caster.IsOpponent(target)) if isHot != caster.IsOpponent(target) { dot.Aura = target.GetOrRegisterAura(auraConfig) spell.dots[target.UnitIndex] = newDot(dot) diff --git a/sim/core/spell.go b/sim/core/spell.go index 81daf9a1ff..1c3379686e 100644 --- a/sim/core/spell.go +++ b/sim/core/spell.go @@ -404,14 +404,6 @@ func (spell *Spell) AOEDot() *Dot { return spell.aoeDot } func (spell *Spell) Hot(target *Unit) *Dot { - fmt.Println(target.Label, target.UnitIndex) - for _, unit := range spell.dots { - if unit != nil { - fmt.Println(unit.Label) - } - } - fmt.Println(spell.dots) - fmt.Println(spell.dots.Get(target)) if spell.dots == nil { return nil } 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/_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/flash_heal.go b/sim/priest/flash_heal.go index b8cee5195b..59cf1fa970 100644 --- a/sim/priest/flash_heal.go +++ b/sim/priest/flash_heal.go @@ -12,10 +12,11 @@ func (priest *Priest) registerFlashHealSpell() { flashHealCoefficient := 1.314 priest.FlashHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 2061}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + ActionID: core.ActionID{SpellID: 2061}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellFlashHeal, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCostPercent: 5.9, diff --git a/sim/priest/greater_heal.go b/sim/priest/greater_heal.go new file mode 100644 index 0000000000..08a46e5320 --- /dev/null +++ b/sim/priest/greater_heal.go @@ -0,0 +1,46 @@ +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, + 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..fa48c32ba6 --- /dev/null +++ b/sim/priest/heal.go @@ -0,0 +1,46 @@ +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, + 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/power_word_shield.go b/sim/priest/power_word_shield.go index fede465432..16d3a9798f 100644 --- a/sim/priest/power_word_shield.go +++ b/sim/priest/power_word_shield.go @@ -37,7 +37,7 @@ func (priest *Priest) registerPowerWordShieldSpell() { Shield: core.ShieldConfig{ Aura: core.Aura{ Label: "Power Word Shield", - Duration: time.Second * 30, + Duration: time.Second * 15, }, }, diff --git a/sim/priest/priest.go b/sim/priest/priest.go index 73b4efa081..fc0777d159 100644 --- a/sim/priest/priest.go +++ b/sim/priest/priest.go @@ -87,6 +87,7 @@ func (priest *Priest) Initialize() { // priest.registerDispersionSpell() + priest.registerSpiritualHealing() priest.registerPowerInfusionSpell() priest.newMindSearSpell() diff --git a/sim/priest/renew.go b/sim/priest/renew.go index d209191a22..75ff97584b 100644 --- a/sim/priest/renew.go +++ b/sim/priest/renew.go @@ -1,7 +1,6 @@ package priest import ( - "fmt" "time" "github.com/wowsims/mop/sim/core" @@ -10,32 +9,10 @@ import ( func (priest *Priest) registerRenewSpell() { coeff := .207 - // scaling := 2.051 + scaling := 2.051 actionID := core.ActionID{SpellID: 139} - // 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, - - // 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, @@ -58,11 +35,11 @@ func (priest *Priest) registerRenewSpell() { Aura: core.Aura{ Label: "Renew", }, - NumberOfTicks: 4, - TickLength: time.Second * 3, + NumberOfTicks: 4, + TickLength: time.Second * 3, + BonusCoefficient: coeff, OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, _ bool) { - dot.SnapshotBaseDamage = coeff * dot.Spell.HealingPower(target) - dot.SnapshotAttackerMultiplier = dot.Spell.CasterHealingMultiplier() + dot.Snapshot(target, priest.CalcScalingSpellDmg(scaling)) }, OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { dot.CalcAndDealPeriodicSnapshotHealing(sim, target, dot.OutcomeTick) @@ -70,17 +47,7 @@ func (priest *Priest) registerRenewSpell() { }, ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { - fmt.Println("zorp") - fmt.Println(spell.Hot(target)) - spell.Hot(target).Activate(sim) - - // if priest.EmpoweredRenew != nil { - // priest.EmpoweredRenew.Cast(sim, target) - // } + spell.Hot(target).Apply(sim) }, }) } - -// func (priest *Priest) renewTicks() int32 { -// return 5 - core.TernaryInt32(priest.HasMajorGlyph(proto.PriestMajorGlyph_GlyphOfRenew), 1, 0) -// } diff --git a/sim/priest/spiritual_healing.go b/sim/priest/spiritual_healing.go new file mode 100644 index 0000000000..d9aa1b7de4 --- /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, + FloatValue: 0.25, + Kind: core.SpellMod_DamageDone_Pct, + }) +} From 9ea3fc504b28019dcc85dc544110444c55d302b1 Mon Sep 17 00:00:00 2001 From: Justin W Date: Thu, 10 Jul 2025 20:48:21 -0700 Subject: [PATCH 3/5] ClassSpellMasks for all! --- sim/priest/binding_heal.go | 9 +++++---- sim/priest/greater_heal.go | 9 +++++---- sim/priest/heal.go | 9 +++++---- sim/priest/power_word_shield.go | 9 +++++---- sim/priest/prayer_of_mending.go | 9 +++++---- sim/priest/priest.go | 1 + sim/priest/renew.go | 9 +++++---- 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/sim/priest/binding_heal.go b/sim/priest/binding_heal.go index da35ab919d..878032cb2e 100644 --- a/sim/priest/binding_heal.go +++ b/sim/priest/binding_heal.go @@ -13,10 +13,11 @@ func (priest *Priest) registerBindingHealSpell() { bindingHealCoefficient := .899 priest.BindingHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 32546}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + ActionID: core.ActionID{SpellID: 32546}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellBindingHeal, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCostPercent: 5.4, diff --git a/sim/priest/greater_heal.go b/sim/priest/greater_heal.go index 08a46e5320..18e2018cef 100644 --- a/sim/priest/greater_heal.go +++ b/sim/priest/greater_heal.go @@ -18,10 +18,11 @@ func (priest *Priest) registerGreaterHealSpell() { greaterHealCoefficient := 2.19 priest.GreaterHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 2060}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + ActionID: core.ActionID{SpellID: 2060}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellGreaterHeal, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCostPercent: 5.9, diff --git a/sim/priest/heal.go b/sim/priest/heal.go index fa48c32ba6..fc01be5915 100644 --- a/sim/priest/heal.go +++ b/sim/priest/heal.go @@ -18,10 +18,11 @@ func (priest *Priest) registerHealSpell() { healCoefficient := 1.024 priest.GreaterHeal = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 2050}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + ActionID: core.ActionID{SpellID: 2050}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellHeal, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCostPercent: 1.9, diff --git a/sim/priest/power_word_shield.go b/sim/priest/power_word_shield.go index 16d3a9798f..a56c46781d 100644 --- a/sim/priest/power_word_shield.go +++ b/sim/priest/power_word_shield.go @@ -13,10 +13,11 @@ func (priest *Priest) registerPowerWordShieldSpell() { var glyphHeal *core.Spell priest.PowerWordShield = priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 17}, - SpellSchool: core.SpellSchoolHoly, - ProcMask: core.ProcMaskSpellHealing, - Flags: core.SpellFlagHelpful | core.SpellFlagAPL, + ActionID: core.ActionID{SpellID: 17}, + SpellSchool: core.SpellSchoolHoly, + ProcMask: core.ProcMaskSpellHealing, + ClassSpellMask: PriestSpellPowerWordShield, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCostPercent: 6.1, diff --git a/sim/priest/prayer_of_mending.go b/sim/priest/prayer_of_mending.go index ea9c1f0d5c..2f4631bbf7 100644 --- a/sim/priest/prayer_of_mending.go +++ b/sim/priest/prayer_of_mending.go @@ -53,10 +53,11 @@ 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{ BaseCostPercent: 3.5, diff --git a/sim/priest/priest.go b/sim/priest/priest.go index fc0777d159..2cb29cc772 100644 --- a/sim/priest/priest.go +++ b/sim/priest/priest.go @@ -174,6 +174,7 @@ const ( PriestSpellGreaterHeal PriestSpellGuardianSpirit PriestSpellHalo + PriestSpellHeal PriestSpellHolyFire PriestSpellHolyNova PriestSpellHolyWordChastise diff --git a/sim/priest/renew.go b/sim/priest/renew.go index 75ff97584b..517775bd40 100644 --- a/sim/priest/renew.go +++ b/sim/priest/renew.go @@ -14,10 +14,11 @@ func (priest *Priest) registerRenewSpell() { actionID := core.ActionID{SpellID: 139} priest.Renew = 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: PriestSpellRenew, + Flags: core.SpellFlagHelpful | core.SpellFlagAPL, ManaCost: core.ManaCostOptions{ BaseCostPercent: 2.6, From 2be510a1b04d325b9dc034ed5f891ce3e3112f6f Mon Sep 17 00:00:00 2001 From: Justin W Date: Thu, 10 Jul 2025 21:07:51 -0700 Subject: [PATCH 4/5] Prayer and Circle of healing --- sim/priest/holy/circle_of_healing.go | 50 +++++++++++++++++++++++++++ sim/priest/holy/holy.go | 6 ++-- sim/priest/prayer_of_healing.go | 51 ++++++++++++++++++++++++++++ sim/priest/priest.go | 1 + 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 sim/priest/holy/circle_of_healing.go create mode 100644 sim/priest/prayer_of_healing.go 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..43d7b41c96 100644 --- a/sim/priest/holy/holy.go +++ b/sim/priest/holy/holy.go @@ -47,8 +47,10 @@ 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() // holyPriest.RegisterHolyFireSpell() // holyPriest.RegisterSmiteSpell() 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/priest.go b/sim/priest/priest.go index 2cb29cc772..681ca9d83c 100644 --- a/sim/priest/priest.go +++ b/sim/priest/priest.go @@ -95,6 +95,7 @@ func (priest *Priest) Initialize() { priest.registerFlashHealSpell() priest.registerBindingHealSpell() priest.registerPowerWordShieldSpell() + priest.registerPrayerOfHealingSpell() priest.registerRenewSpell() priest.ApplyGlyphs() From 621855d0105f941a9ea4934ef133627c8dd09593 Mon Sep 17 00:00:00 2001 From: Justin W Date: Thu, 10 Jul 2025 23:15:08 -0700 Subject: [PATCH 5/5] Serendipity, spiritual healing all spells, rapid renew minus the on cast heal --- sim/priest/_prayer_of_healing.go | 84 -------------------------------- sim/priest/holy/holy.go | 3 ++ sim/priest/holy/serendipity.go | 58 ++++++++++++++++++++++ sim/priest/priest.go | 1 + sim/priest/renew.go | 13 +++-- sim/priest/spiritual_healing.go | 2 +- 6 files changed, 73 insertions(+), 88 deletions(-) delete mode 100644 sim/priest/_prayer_of_healing.go create mode 100644 sim/priest/holy/serendipity.go 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/holy/holy.go b/sim/priest/holy/holy.go index 43d7b41c96..47ccf6b797 100644 --- a/sim/priest/holy/holy.go +++ b/sim/priest/holy/holy.go @@ -41,6 +41,8 @@ func NewHolyPriest(character *core.Character, options *proto.Player) *HolyPriest type HolyPriest struct { *priest.Priest + + SerendipityAura *core.Aura } func (holyPriest *HolyPriest) GetPriest() *priest.Priest { @@ -51,6 +53,7 @@ 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/priest.go b/sim/priest/priest.go index 681ca9d83c..280aa7f737 100644 --- a/sim/priest/priest.go +++ b/sim/priest/priest.go @@ -97,6 +97,7 @@ func (priest *Priest) Initialize() { priest.registerPowerWordShieldSpell() priest.registerPrayerOfHealingSpell() priest.registerRenewSpell() + priest.registerGreaterHealSpell() priest.ApplyGlyphs() } diff --git a/sim/priest/renew.go b/sim/priest/renew.go index 517775bd40..ddabae3ef1 100644 --- a/sim/priest/renew.go +++ b/sim/priest/renew.go @@ -4,6 +4,7 @@ import ( "time" "github.com/wowsims/mop/sim/core" + "github.com/wowsims/mop/sim/core/proto" ) func (priest *Priest) registerRenewSpell() { @@ -13,6 +14,10 @@ func (priest *Priest) registerRenewSpell() { 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, @@ -25,11 +30,10 @@ func (priest *Priest) registerRenewSpell() { }, Cast: core.CastConfig{ DefaultCast: core.Cast{ - GCD: core.GCDDefault, + GCD: renewGCD, }, }, - - DamageMultiplier: 1, + DamageMultiplier: renewHealingMultiplier, ThreatMultiplier: 1, Hot: core.DotConfig{ @@ -48,6 +52,9 @@ func (priest *Priest) registerRenewSpell() { }, 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 index d9aa1b7de4..31d74b1959 100644 --- a/sim/priest/spiritual_healing.go +++ b/sim/priest/spiritual_healing.go @@ -12,7 +12,7 @@ func (priest *Priest) registerSpiritualHealing() { } priest.AddStaticMod(core.SpellModConfig{ - ClassMask: PriestSpellFlashHeal, + ClassMask: PriestSpellFlashHeal | PriestSpellBindingHeal | PriestSpellRenew | PriestSpellPrayerOfMending, FloatValue: 0.25, Kind: core.SpellMod_DamageDone_Pct, })