diff --git a/sim/core/apl.go b/sim/core/apl.go index 17a90700aa..7b0f568cab 100644 --- a/sim/core/apl.go +++ b/sim/core/apl.go @@ -234,10 +234,6 @@ func (apl *APLRotation) getNextAction(sim *Simulation) *APLAction { func (apl *APLRotation) shouldInterruptChannel(sim *Simulation) bool { channeledDot := apl.unit.ChanneledDot - if channeledDot == nil { - // Cast was started by a different APL action (not Channel) so is non-interruptible. - return false - } if channeledDot.MaxTicksRemaining() == 0 { // Channel has ended, but apl.unit.ChanneledDot hasn't been cleared yet meaning the aura is still active. diff --git a/sim/core/apl_actions_casting.go b/sim/core/apl_actions_casting.go index 76894867a7..e5041680b2 100644 --- a/sim/core/apl_actions_casting.go +++ b/sim/core/apl_actions_casting.go @@ -2,7 +2,6 @@ package core import ( "fmt" - "github.com/wowsims/wotlk/sim/core/proto" ) diff --git a/sim/priest/mind_flay.go b/sim/priest/mind_flay.go index 2976c8d147..b96cbf8d94 100644 --- a/sim/priest/mind_flay.go +++ b/sim/priest/mind_flay.go @@ -20,7 +20,6 @@ func (priest *Priest) getMindFlayTickSpell(numTicks int32) *core.Spell { ActionID: core.ActionID{SpellID: 58381}.WithTag(numTicks), SpellSchool: core.SpellSchoolShadow, ProcMask: core.ProcMaskProc | core.ProcMaskNotInSpellbook, - Flags: core.SpellFlagNoLogs, BonusHitRating: float64(priest.Talents.ShadowFocus) * 1 * core.SpellHitRatingPerHitChance, BonusCritRating: 0 + float64(priest.Talents.MindMelt)*2*core.CritRatingPerCritChance + diff --git a/sim/priest/mind_sear.go b/sim/priest/mind_sear.go index 6b414ca72f..0648c0af56 100644 --- a/sim/priest/mind_sear.go +++ b/sim/priest/mind_sear.go @@ -8,8 +8,43 @@ import ( "github.com/wowsims/wotlk/sim/core/proto" ) -// TODO see Mind Flay: Mind Sear (53023) now "periodically triggers" Mind Sear (53022). -// Since Mind Flay no longer is a binary spell, Mind Sear likely isn't, either. +func (priest *Priest) getMindSearMiseryCoefficient() float64 { + return 0.2861 * (1 + 0.05*float64(priest.Talents.Misery)) +} + +func (priest *Priest) getMindSearBaseConfig() core.SpellConfig { + return core.SpellConfig{ + SpellSchool: core.SpellSchoolShadow, + ProcMask: core.ProcMaskProc, + BonusHitRating: float64(priest.Talents.ShadowFocus) * 1 * core.SpellHitRatingPerHitChance, + BonusCritRating: float64(priest.Talents.MindMelt) * 2 * core.CritRatingPerCritChance, + DamageMultiplier: 1 + + 0.02*float64(priest.Talents.Darkness) + + 0.01*float64(priest.Talents.TwinDisciplines), + ThreatMultiplier: 1 - 0.08*float64(priest.Talents.ShadowAffinity), + CritMultiplier: priest.DefaultSpellCritMultiplier(), + } +} + +func (priest *Priest) getMindSearTickSpell(numTicks int32) *core.Spell { + hasGlyphOfShadow := priest.HasGlyph(int32(proto.PriestMajorGlyph_GlyphOfShadow)) + miseryCoeff := priest.getMindSearMiseryCoefficient() + + config := priest.getMindSearBaseConfig() + config.ActionID = core.ActionID{SpellID: 49821}.WithTag(numTicks) + config.ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + damage := sim.Roll(212, 228) + miseryCoeff*spell.SpellPower() + result := spell.CalcAndDealDamage(sim, target, damage, spell.OutcomeMagicHitAndCrit) + + if result.Landed() { + priest.AddShadowWeavingStack(sim) + } + if result.DidCrit() && hasGlyphOfShadow { + priest.ShadowyInsightAura.Activate(sim) + } + } + return priest.GetOrRegisterSpell(config) +} func (priest *Priest) newMindSearSpell(numTicksIdx int32) *core.Spell { numTicks := numTicksIdx @@ -20,74 +55,46 @@ func (priest *Priest) newMindSearSpell(numTicksIdx int32) *core.Spell { } channelTime := time.Second * time.Duration(numTicks) - miseryCoeff := 0.2861 * (1 + 0.05*float64(priest.Talents.Misery)) - hasGlyphOfShadow := priest.HasGlyph(int32(proto.PriestMajorGlyph_GlyphOfShadow)) + miseryCoeff := priest.getMindSearMiseryCoefficient() + mindSearTickSpell := priest.getMindSearTickSpell(numTicksIdx) - return priest.RegisterSpell(core.SpellConfig{ - ActionID: core.ActionID{SpellID: 53023, Tag: numTicksIdx}, - SpellSchool: core.SpellSchoolShadow, - ProcMask: core.ProcMaskSpellDamage, - Flags: flags, - - ManaCost: core.ManaCostOptions{ - BaseCost: 0.28, - Multiplier: 1 - 0.05*float64(priest.Talents.FocusedMind), - }, - Cast: core.CastConfig{ - DefaultCast: core.Cast{ - GCD: core.GCDDefault, - ChannelTime: channelTime, - }, + config := priest.getMindSearBaseConfig() + config.ActionID = core.ActionID{SpellID: 53023}.WithTag(numTicksIdx) + config.Flags = flags + config.ManaCost = core.ManaCostOptions{ + BaseCost: 0.28, + Multiplier: 1 - 0.05*float64(priest.Talents.FocusedMind), + } + config.Cast = core.CastConfig{ + DefaultCast: core.Cast{ + GCD: core.GCDDefault, + ChannelTime: channelTime, }, - - BonusHitRating: float64(priest.Talents.ShadowFocus) * 1 * core.SpellHitRatingPerHitChance, - BonusCritRating: float64(priest.Talents.MindMelt) * 2 * core.CritRatingPerCritChance, - DamageMultiplier: 1 + - 0.02*float64(priest.Talents.Darkness) + - 0.01*float64(priest.Talents.TwinDisciplines), - ThreatMultiplier: 1 - 0.08*float64(priest.Talents.ShadowAffinity), - CritMultiplier: priest.DefaultSpellCritMultiplier(), - Dot: core.DotConfig{ - Aura: core.Aura{ - Label: "MindSear-" + strconv.Itoa(int(numTicksIdx)), - }, - NumberOfTicks: numTicks, - TickLength: time.Second, - AffectedByCastSpeed: true, - - OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, _ bool) { - dot.SnapshotBaseDamage = sim.Roll(212, 228) + miseryCoeff*dot.Spell.SpellPower() - dot.SnapshotCritChance = dot.Spell.SpellCritChance(target) - dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(dot.Spell.Unit.AttackTables[target.UnitIndex]) - }, - OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { - result := dot.CalcSnapshotDamage(sim, target, dot.OutcomeMagicHitAndSnapshotCrit) - dot.Spell.DealDamage(sim, result) - - if result.Landed() { - priest.AddShadowWeavingStack(sim) - } - if result.DidCrit() && hasGlyphOfShadow { - priest.ShadowyInsightAura.Activate(sim) - } - }, + } + config.Dot = core.DotConfig{ + Aura: core.Aura{ + Label: "MindSear-" + strconv.Itoa(int(numTicksIdx)), }, - ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + NumberOfTicks: numTicks, + TickLength: time.Second, + AffectedByCastSpeed: true, + OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) { for _, aoeTarget := range sim.Encounter.TargetUnits { - if aoeTarget != sim.Encounter.TargetUnits[0] { - - result := spell.CalcOutcome(sim, aoeTarget, spell.OutcomeMagicHit) - if result.Landed() { - spell.SpellMetrics[aoeTarget.UnitIndex].Hits-- - spell.Dot(aoeTarget).Apply(sim) - } - spell.DealOutcome(sim, result) + if aoeTarget != target { + mindSearTickSpell.Cast(sim, aoeTarget) } } }, - ExpectedTickDamage: func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult { - baseDamage := sim.Roll(212, 228) + miseryCoeff*spell.SpellPower() - return spell.CalcPeriodicDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicCrit) - }, - }) + } + config.ApplyEffects = func(sim *core.Simulation, target *core.Unit, spell *core.Spell) { + result := spell.CalcAndDealOutcome(sim, target, spell.OutcomeMagicHit) + if result.Landed() { + spell.Dot(target).Apply(sim) + } + } + config.ExpectedTickDamage = func(sim *core.Simulation, target *core.Unit, spell *core.Spell, _ bool) *core.SpellResult { + baseDamage := sim.Roll(212, 228) + miseryCoeff*spell.SpellPower() + return spell.CalcPeriodicDamage(sim, target, baseDamage, spell.OutcomeExpectedMagicCrit) + } + return priest.GetOrRegisterSpell(config) }