Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions sim/core/apl.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ func (apl *APLRotation) DoNextAction(sim *Simulation) {
return
}

if apl.unit.ChanneledDot != nil {
if apl.unit.IsChanneling() && !apl.unit.ChanneledDot.Spell.Flags.Matches(SpellFlagCastWhileChanneling) {
return
}

Expand Down Expand Up @@ -347,13 +347,7 @@ func (apl *APLRotation) popControllingAction(ca APLActionImpl) {
func (apl *APLRotation) shouldInterruptChannel(sim *Simulation) bool {
channeledDot := apl.unit.ChanneledDot

if channeledDot.remainingTicks == 0 {
// Channel has ended, but apl.unit.ChanneledDot hasn't been cleared yet meaning the aura is still active.
return false
}

if apl.interruptChannelIf == nil || !apl.interruptChannelIf.GetBool(sim) {
// Continue the channel.
if !channeledDot.ChannelCanBeInterrupted(sim) {
return false
}

Expand Down
4 changes: 4 additions & 0 deletions sim/core/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {
return spell.castFailureHelper(sim, "casting/channeling %v for %s, curTime = %s", hc.ActionID, hc.Expires-sim.CurrentTime, sim.CurrentTime)
}

if spell.Unit.IsCastingDuringChannel() && !spell.CanCastDuringChannel(sim) {
return spell.castFailureHelper(sim, "cannot interrupt in-progress channel of %v with a cast of %v", spell.Unit.ChanneledDot.ActionID, spell.ActionID)
}

if effectiveTime := spell.CurCast.EffectiveTime(); effectiveTime != 0 {

// do not add channeled time here as they have variable cast length
Expand Down
18 changes: 18 additions & 0 deletions sim/core/dot.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,24 @@ func (dot *Dot) getChannelClipDelay(sim *Simulation) time.Duration {

return dot.Spell.Unit.ChannelClipDelay
}
func (dot *Dot) ChannelCanBeInterrupted(sim *Simulation) bool {
if !dot.isChanneled {
return false
}

// Channel has ended, but dot.Spell.Unit.ChanneledDot hasn't been cleared yet, meaning the Aura is still active.
if dot.remainingTicks == 0 {
return false
}

// APL specifies that the channel should be continued.
apl := dot.Spell.Unit.Rotation
if (apl.interruptChannelIf == nil) || !apl.interruptChannelIf.GetBool(sim) {
return false
}

return true
}

func newDot(config Dot) *Dot {
dot := &config
Expand Down
1 change: 1 addition & 0 deletions sim/core/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ const (
SpellFlagCannotBeDodged // Ignores dodge in physical hit rolls
SpellFlagBinary // Does not do partial resists and could need a different hit roll.
SpellFlagChanneled // Spell is channeled
SpellFlagCastWhileChanneling // Spell can be cast while channeling. If SpellFlagChanneled and SpellFlagCastWhileChanneling are both set, it means that other spells with the SpellFlagCastWhileChanneling flag can be cast without interrupting the channeled spell.
SpellFlagDisease // Spell is categorized as disease
SpellFlagHelpful // For healing spells / buffs.
SpellFlagMeleeMetrics // Marks a spell as a melee ability for metrics.
Expand Down
15 changes: 14 additions & 1 deletion sim/core/spell.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ func (spell *Spell) CanCast(sim *Simulation, target *Unit) bool {
}

// While casting or channeling, no other action is possible
if spell.Unit.Hardcast.Expires > sim.CurrentTime {
if (spell.Unit.Hardcast.Expires > sim.CurrentTime) || (spell.Unit.IsCastingDuringChannel() && !spell.CanCastDuringChannel(sim)) {
//if sim.Log != nil {
// sim.Log("Cant cast because already casting/channeling")
//}
Expand Down Expand Up @@ -639,6 +639,19 @@ func (spell *Spell) CanCast(sim *Simulation, target *Unit) bool {
return true
}

func (spell *Spell) CanCastDuringChannel(sim *Simulation) bool {
// Don't allow bypassing of channel clip logic for re-casts of the same channel
if spell == spell.Unit.ChanneledDot.Spell {
return false
}

if spell.Flags.Matches(SpellFlagCastWhileChanneling) {
return true
}

return spell.Unit.ChanneledDot.ChannelCanBeInterrupted(sim)
}

func (spell *Spell) Cast(sim *Simulation, target *Unit) bool {
if spell.DefaultCast.EffectiveTime() > 0 {
spell.Unit.CancelQueuedSpell(sim)
Expand Down
16 changes: 16 additions & 0 deletions sim/core/spell_mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,9 @@ const (
// Enables casting while moving
SpellMod_AllowCastWhileMoving

// Enables casting while channeling
SpellMod_AllowCastWhileChanneling

// Add/subtract bonus spell power
// Uses: FloatValue
SpellMod_BonusSpellPower_Flat
Expand Down Expand Up @@ -448,6 +451,11 @@ var spellModMap = map[SpellModType]*SpellModFunctions{
Remove: removeAllowCastWhileMoving,
},

SpellMod_AllowCastWhileChanneling: {
Apply: applyAllowCastWhileChanneling,
Remove: removeAllowCastWhileChanneling,
},

SpellMod_BonusSpellPower_Flat: {
Apply: applyBonusSpellPowerFlat,
Remove: removeBonusSpellPowerFlat,
Expand Down Expand Up @@ -680,6 +688,14 @@ func removeAllowCastWhileMoving(mod *SpellMod, spell *Spell) {
spell.Flags ^= SpellFlagCanCastWhileMoving
}

func applyAllowCastWhileChanneling(mod *SpellMod, spell *Spell) {
spell.Flags |= SpellFlagCastWhileChanneling
}

func removeAllowCastWhileChanneling(mod *SpellMod, spell *Spell) {
spell.Flags ^= SpellFlagCastWhileChanneling
}

func applyBonusSpellPowerFlat(mod *SpellMod, spell *Spell) {
spell.BonusSpellPower += mod.floatValue
}
Expand Down
2 changes: 1 addition & 1 deletion sim/core/spell_queueing.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (spell *Spell) CanQueue(sim *Simulation, target *Unit) bool {
}

// Apply SQW leniency to any pending hardcasts
if spell.Unit.Hardcast.Expires > sim.CurrentTime+MaxSpellQueueWindow {
if (spell.Unit.Hardcast.Expires > sim.CurrentTime+MaxSpellQueueWindow) || (spell.Unit.IsCastingDuringChannel() && !spell.CanCastDuringChannel(sim)) {
return false
}

Expand Down
8 changes: 8 additions & 0 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,14 @@ func (unit *Unit) InitialCastSpeed() float64 {
return unit.initialCastSpeed
}

func (unit *Unit) IsChanneling() bool {
return unit.ChanneledDot != nil
}

func (unit *Unit) IsCastingDuringChannel() bool {
return unit.IsChanneling() && unit.ChanneledDot.Spell.Flags.Matches(SpellFlagCastWhileChanneling)
}

func (unit *Unit) SpellGCD() time.Duration {
return max(GCDMin, unit.ApplyCastSpeed(GCDDefault))
}
Expand Down
72 changes: 36 additions & 36 deletions sim/warrior/arms/TestArms.results
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,8 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Orc-p1_arms_bis-Basic-arms-FullBuffs-9.0yards-LongMultiTarget"
value: {
dps: 815502.44048
tps: 733565.51284
dps: 816625.5827
tps: 734597.01461
}
}
dps_results: {
Expand All @@ -439,15 +439,15 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Orc-p1_arms_bis-Basic-arms-NoBuffs-9.0yards-LongMultiTarget"
value: {
dps: 605318.17578
tps: 546072.39177
dps: 608789.67555
tps: 549770.27992
}
}
dps_results: {
key: "TestArms-Settings-Orc-p1_arms_bis-Basic-arms-NoBuffs-9.0yards-LongSingleTarget"
value: {
dps: 115255.20253
tps: 77660.94882
dps: 114139.37496
tps: 77273.53479
}
}
dps_results: {
Expand Down Expand Up @@ -481,15 +481,15 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Orc-p1_prebis_poor-Basic-arms-NoBuffs-9.0yards-LongMultiTarget"
value: {
dps: 451335.74648
tps: 407629.77861
dps: 455713.88423
tps: 411190.19995
}
}
dps_results: {
key: "TestArms-Settings-Orc-p1_prebis_poor-Basic-arms-NoBuffs-9.0yards-LongSingleTarget"
value: {
dps: 81467.78038
tps: 55545.42702
dps: 80481.95625
tps: 55218.60156
}
}
dps_results: {
Expand All @@ -502,8 +502,8 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Orc-p1_prebis_rich-Basic-arms-FullBuffs-9.0yards-LongMultiTarget"
value: {
dps: 650217.71719
tps: 583916.55449
dps: 649230.41863
tps: 583010.40765
}
}
dps_results: {
Expand All @@ -523,29 +523,29 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Orc-p1_prebis_rich-Basic-arms-NoBuffs-9.0yards-LongMultiTarget"
value: {
dps: 468785.57275
tps: 423021.75843
dps: 470297.39602
tps: 425026.33379
}
}
dps_results: {
key: "TestArms-Settings-Orc-p1_prebis_rich-Basic-arms-NoBuffs-9.0yards-LongSingleTarget"
value: {
dps: 82740.85016
tps: 56685.44122
dps: 81614.73537
tps: 56294.40991
}
}
dps_results: {
key: "TestArms-Settings-Orc-p1_prebis_rich-Basic-arms-NoBuffs-9.0yards-ShortSingleTarget"
value: {
dps: 88081.03733
tps: 56666.25486
dps: 88313.06686
tps: 56821.60559
}
}
dps_results: {
key: "TestArms-Settings-Worgen-p1_arms_bis-Basic-arms-FullBuffs-9.0yards-LongMultiTarget"
value: {
dps: 806507.52547
tps: 728088.95638
dps: 807341.48657
tps: 728789.72235
}
}
dps_results: {
Expand All @@ -565,15 +565,15 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Worgen-p1_arms_bis-Basic-arms-NoBuffs-9.0yards-LongMultiTarget"
value: {
dps: 597856.93282
tps: 540271.32116
dps: 599962.90676
tps: 542635.74019
}
}
dps_results: {
key: "TestArms-Settings-Worgen-p1_arms_bis-Basic-arms-NoBuffs-9.0yards-LongSingleTarget"
value: {
dps: 115269.25831
tps: 77526.62221
dps: 114067.0206
tps: 77151.71549
}
}
dps_results: {
Expand Down Expand Up @@ -607,15 +607,15 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Worgen-p1_prebis_poor-Basic-arms-NoBuffs-9.0yards-LongMultiTarget"
value: {
dps: 444963.21995
tps: 402679.15845
dps: 449481.20297
tps: 406609.42969
}
}
dps_results: {
key: "TestArms-Settings-Worgen-p1_prebis_poor-Basic-arms-NoBuffs-9.0yards-LongSingleTarget"
value: {
dps: 80707.9687
tps: 55072.9703
dps: 79729.00925
tps: 54758.34887
}
}
dps_results: {
Expand All @@ -628,8 +628,8 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Worgen-p1_prebis_rich-Basic-arms-FullBuffs-9.0yards-LongMultiTarget"
value: {
dps: 641392.48667
tps: 577705.4991
dps: 641301.63061
tps: 577309.73844
}
}
dps_results: {
Expand All @@ -649,22 +649,22 @@ dps_results: {
dps_results: {
key: "TestArms-Settings-Worgen-p1_prebis_rich-Basic-arms-NoBuffs-9.0yards-LongMultiTarget"
value: {
dps: 464060.34972
tps: 419973.38632
dps: 465700.56971
tps: 421639.47444
}
}
dps_results: {
key: "TestArms-Settings-Worgen-p1_prebis_rich-Basic-arms-NoBuffs-9.0yards-LongSingleTarget"
value: {
dps: 82435.3786
tps: 56563.67852
dps: 81379.2926
tps: 56196.92275
}
}
dps_results: {
key: "TestArms-Settings-Worgen-p1_prebis_rich-Basic-arms-NoBuffs-9.0yards-ShortSingleTarget"
value: {
dps: 86794.76911
tps: 56243.55992
dps: 86530.29456
tps: 56073.08963
}
}
dps_results: {
Expand Down
Loading
Loading