Skip to content

Commit

Permalink
Configure Blood DK Normal and Threat Openers to conditionally skip us…
Browse files Browse the repository at this point in the history
…ing Blood Tap and the subsequent Icy Touch enabled by it.

If the DK has the T10 4pc bonus enabled and does not schedule the first Blood Tap usage outside the time the opener uses Blood Tap + the Blood Tap Cooldown, the noted spells will not be used in either opener scenario.

This change comes with a caveat of potentially delaying scheduled Blood Tap casts if the opener Blood Tap is delayed due to ability misses.
  • Loading branch information
cyzin committed Nov 13, 2023
1 parent 189cd26 commit 5cb836f
Showing 1 changed file with 65 additions and 0 deletions.
65 changes: 65 additions & 0 deletions sim/deathknight/tank/openers.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package tank

import (
"github.com/wowsims/wotlk/sim/core/proto"
"slices"
"time"

"github.com/wowsims/wotlk/sim/core"
"github.com/wowsims/wotlk/sim/deathknight"
)

const threatOpenerCastsBeforeBloodTap = 2
const normalOpenerCastsBeforeBloodTap = 3

func (dk *TankDeathknight) TankRA_BloodSpell(sim *core.Simulation, target *core.Unit, s *deathknight.Sequence) time.Duration {
casted := dk.BloodSpell.Cast(sim, target)
advance := dk.LastOutcome.Matches(core.OutcomeLanded)
Expand All @@ -33,7 +38,38 @@ func (dk *TankDeathknight) TankRA_IT(sim *core.Simulation, target *core.Unit, s
return -1
}

func shouldUseBloodTapInOpener(dk *TankDeathknight) bool {
bloodTapDefensiveCd := dk.GetMajorCooldown(dk.BloodTap.ActionID)
if bloodTapDefensiveCd != nil {
timings := bloodTapDefensiveCd.GetTimings()
slices.Sort(timings)
if len(timings) == 0 ||
(len(timings) > 0 && timings[0] <
dk.BloodTap.CD.Duration+getPlannedOpenerBloodTapUsageTime(dk)) {
return false
} else {
return true
}
}
return true
}

func getPlannedOpenerBloodTapUsageTime(dk *TankDeathknight) time.Duration {
if dk.Rotation.Opener == proto.TankDeathknight_Rotation_Threat {
return threatOpenerCastsBeforeBloodTap * core.GCDDefault
}
return normalOpenerCastsBeforeBloodTap * core.GCDDefault
}

func (dk *TankDeathknight) setupTankRegularERWOpener() {
if shouldUseBloodTapInOpener(dk) {
dk.setupTankRegularERWOpenerWithBloodTap()
} else {
dk.setupTankRegularERWOpenerWithoutBloodTap()
}
}

func (dk *TankDeathknight) setupTankRegularERWOpenerWithBloodTap() {
dk.RotationSequence.
NewAction(dk.TankRA_IT).
NewAction(dk.RotationActionCallback_PS).
Expand All @@ -50,7 +86,30 @@ func (dk *TankDeathknight) setupTankRegularERWOpener() {
NewAction(dk.TankRA_FuSpell)
}

func (dk *TankDeathknight) setupTankRegularERWOpenerWithoutBloodTap() {
dk.RotationSequence.
NewAction(dk.TankRA_IT).
NewAction(dk.RotationActionCallback_PS).
NewAction(dk.TankRA_FuSpell).
NewAction(dk.TankRA_BloodSpell).
NewAction(dk.RotationActionCallback_ERW).
NewAction(dk.RotationActionCallback_Pesti).
NewAction(dk.TankRA_IT).
NewAction(dk.TankRA_IT).
NewAction(dk.TankRA_IT).
NewAction(dk.RotationActionCallback_RD).
NewAction(dk.TankRA_FuSpell)
}

func (dk *TankDeathknight) setupTankThreatERWOpener() {
if shouldUseBloodTapInOpener(dk) {
dk.setupTankThreatERWOpenerWithBloodTap()
} else {
dk.setupTankThreatERWOpenerWithoutBloodTap()
}
}

func (dk *TankDeathknight) setupTankThreatERWOpenerWithBloodTap() {
dk.RotationSequence.
NewAction(dk.TankRA_IT).
NewAction(dk.TankRA_IT).
Expand All @@ -63,3 +122,9 @@ func (dk *TankDeathknight) setupTankThreatERWOpener() {
NewAction(dk.RotationActionCallback_PS).
NewAction(dk.TankRA_BloodSpell)
}

// If maintaining GCD parity is desired, the threat opener without BT should cast DS with
// the GCD previously allocated to the Blood Tapped IT before using ERW
func (dk *TankDeathknight) setupTankThreatERWOpenerWithoutBloodTap() {
dk.setupTankRegularERWOpenerWithoutBloodTap()
}

0 comments on commit 5cb836f

Please sign in to comment.