Skip to content

Commit

Permalink
Merge pull request #494 from wowsims/rogue
Browse files Browse the repository at this point in the history
Rogue rotation improvements
  • Loading branch information
jimmyt857 authored Mar 11, 2022
2 parents 2cff4e9 + 303132e commit c6c4802
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 158 deletions.
274 changes: 137 additions & 137 deletions sim/rogue/TestRogue.results

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions sim/rogue/expose_armor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package rogue

import (
"time"

"github.com/wowsims/tbc/sim/core"
)

Expand All @@ -16,6 +18,9 @@ func (rogue *Rogue) newExposeArmorTemplate(_ *core.Simulation) core.SimpleSpellT
if spellEffect.Landed() {
spellEffect.Target.AddAura(sim, core.ExposeArmorAura(sim, spellEffect.Target, rogue.Talents.ImprovedExposeArmor))
rogue.ApplyFinisher(sim, spellCast.ActionID)
if sim.GetRemainingDuration() <= time.Second*30 {
rogue.doneEA = true
}
} else {
if refundAmount > 0 {
rogue.AddEnergy(sim, spellCast.Cost.Value*refundAmount, core.ActionID{SpellID: 31245})
Expand Down Expand Up @@ -50,8 +55,5 @@ func (rogue *Rogue) NewExposeArmor(_ *core.Simulation, target *core.Target) *cor
}

func (rogue *Rogue) MaintainingExpose(target *core.Target) bool {
permaEA := target.AuraExpiresAt(core.ExposeArmorDebuffID) == core.NeverExpires
return rogue.Rotation.MaintainExposeArmor &&
!permaEA &&
(rogue.Talents.ImprovedExposeArmor == 2 || !target.HasAura(core.SunderArmorDebuffID))
return !rogue.doneEA && (rogue.Talents.ImprovedExposeArmor == 2 || !target.HasAura(core.SunderArmorDebuffID))
}
1 change: 1 addition & 0 deletions sim/rogue/poisons.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/wowsims/tbc/sim/core/proto"
)

// Returns whether any Deadly Poisons are being used.
func (rogue *Rogue) applyPoisons() {
hasWFTotem := rogue.HasWFTotem
rogue.applyDeadlyPoison(hasWFTotem)
Expand Down
35 changes: 29 additions & 6 deletions sim/rogue/rogue.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,17 @@ type Rogue struct {
plan int

// Cached values for calculating rotation.
energyPerSecondAvg float64
eaBuildTime time.Duration // Time to build EA following a finisher at ~35 energy
energyPerSecondAvg float64
eaBuildTime time.Duration // Time to build EA following a finisher at ~35 energy
sliceAndDiceDurations [6]time.Duration

doneSND bool // Current SND will last for the rest of the iteration
doneEA bool // Current EA will last for the rest of the iteration, or not using EA

deathmantle4pcProc bool
disabledMCDs []*core.MajorCooldown

shivEnergyCost float64
builderEnergyCost float64
newBuilder func(sim *core.Simulation, target *core.Target) *core.SimpleSpell

Expand Down Expand Up @@ -156,6 +161,7 @@ func (rogue *Rogue) Init(sim *core.Simulation) {
rogue.backstabTemplate = rogue.newBackstabTemplate(sim)
rogue.hemorrhageTemplate = rogue.newHemorrhageTemplate(sim)
rogue.mutilateTemplate = rogue.newMutilateTemplate(sim)
rogue.shivTemplate = rogue.newShivTemplate(sim)

rogue.finishingMoveEffectApplier = rogue.makeFinishingMoveEffectApplier(sim)

Expand All @@ -181,6 +187,10 @@ func (rogue *Rogue) Reset(sim *core.Simulation) {
rogue.plan = PlanOpener
rogue.deathmantle4pcProc = false
rogue.deadlyPoisonStacks = 0
rogue.doneSND = false

permaEA := sim.GetPrimaryTarget().AuraExpiresAt(core.ExposeArmorDebuffID) == core.NeverExpires
rogue.doneEA = !rogue.Rotation.MaintainExposeArmor || permaEA

rogue.disabledMCDs = rogue.DisableAllEnabledCooldowns(core.CooldownTypeUnknown)
}
Expand Down Expand Up @@ -243,29 +253,42 @@ func NewRogue(character core.Character, options proto.Player) *Rogue {
}
}

var newBuilder func(sim *core.Simulation, target *core.Target) *core.SimpleSpell
switch rogue.Rotation.Builder {
case proto.Rogue_Rotation_SinisterStrike:
rogue.builderEnergyCost = rogue.SinisterStrikeEnergyCost()
rogue.newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
return rogue.NewSinisterStrike(sim, target)
}
case proto.Rogue_Rotation_Backstab:
rogue.builderEnergyCost = BackstabEnergyCost
rogue.newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
return rogue.NewBackstab(sim, target)
}
case proto.Rogue_Rotation_Hemorrhage:
rogue.builderEnergyCost = HemorrhageEnergyCost
rogue.newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
return rogue.NewHemorrhage(sim, target)
}
case proto.Rogue_Rotation_Mutilate:
rogue.builderEnergyCost = MutilateEnergyCost
rogue.newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
return rogue.NewMutilate(sim, target)
}
}

if rogue.Consumes.OffHandImbue == proto.WeaponImbue_WeaponImbueRogueDeadlyPoison {
rogue.newBuilder = func(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
if rogue.deadlyPoison.Effect.DotInput.IsTicking(sim) && rogue.deadlyPoison.Effect.DotInput.TimeRemaining(sim) < time.Second*2 && rogue.CurrentEnergy() >= rogue.shivEnergyCost {
return rogue.NewShiv(sim, target)
} else {
return newBuilder(sim, target)
}
}
} else {
rogue.newBuilder = newBuilder
}

maxEnergy := 100.0
if rogue.Talents.Vigor {
maxEnergy = 110
Expand Down
44 changes: 40 additions & 4 deletions sim/rogue/rotation.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ func (rogue *Rogue) doPlanOpener(sim *core.Simulation) {

// Cast SND as the next finisher, using no more builders than necessary.
func (rogue *Rogue) doPlanSliceASAP(sim *core.Simulation) {
if rogue.doneSND {
rogue.plan = PlanNone
rogue.doPlanNone(sim)
return
}

energy := rogue.CurrentEnergy()
comboPoints := rogue.ComboPoints()
target := sim.GetPrimaryTarget()
Expand Down Expand Up @@ -77,11 +83,29 @@ func (rogue *Rogue) doPlanSliceASAP(sim *core.Simulation) {

// Get the biggest Slice we can, but still leaving time for EA if necessary.
func (rogue *Rogue) doPlanMaximalSlice(sim *core.Simulation) {
if rogue.doneSND {
rogue.plan = PlanNone
rogue.doPlanNone(sim)
return
}

energy := rogue.CurrentEnergy()
comboPoints := rogue.ComboPoints()
target := sim.GetPrimaryTarget()
sndTimeRemaining := rogue.RemainingAuraDuration(sim, SliceAndDiceAuraID)

remainingSimDuration := sim.GetRemainingDuration()
if rogue.sliceAndDiceDurations[comboPoints] >= remainingSimDuration {
if energy >= SliceAndDiceEnergyCost || rogue.deathmantle4pcProc {
if rogue.canPoolEnergy(sim, energy) && sndTimeRemaining > time.Second*2 {
return
}
rogue.castSliceAndDice()
rogue.plan = PlanNone
}
return
}

if sndTimeRemaining <= time.Second && comboPoints > 0 {
if energy >= SliceAndDiceEnergyCost || rogue.deathmantle4pcProc {
rogue.castSliceAndDice()
Expand Down Expand Up @@ -139,6 +163,12 @@ func (rogue *Rogue) doPlanMaximalSlice(sim *core.Simulation) {

// Build towards and cast a 5 pt Expose Armor.
func (rogue *Rogue) doPlanExposeArmor(sim *core.Simulation) {
if rogue.doneEA {
rogue.plan = PlanNone
rogue.doPlanNone(sim)
return
}

energy := rogue.CurrentEnergy()
comboPoints := rogue.ComboPoints()
target := sim.GetPrimaryTarget()
Expand Down Expand Up @@ -199,7 +229,7 @@ func (rogue *Rogue) doPlanFillBeforeSND(sim *core.Simulation) {
target := sim.GetPrimaryTarget()
sndTimeRemaining := rogue.RemainingAuraDuration(sim, SliceAndDiceAuraID)

if rogue.eaBuildTime+buildTimeBuffer > sndTimeRemaining {
if !rogue.doneSND && rogue.eaBuildTime+buildTimeBuffer > sndTimeRemaining {
// Cast our finisher and start prepping for SND.
if comboPoints == 0 {
rogue.plan = PlanMaximalSlice
Expand All @@ -216,7 +246,7 @@ func (rogue *Rogue) doPlanFillBeforeSND(sim *core.Simulation) {
}
}
} else {
if comboPoints == 5 {
if comboPoints == 5 || (comboPoints > 0 && sim.GetRemainingDuration() < time.Second*2) {
rogue.tryUseDamageFinisher(sim, energy)
} else if energy >= rogue.builderEnergyCost {
rogue.newBuilder(sim, target).Cast(sim)
Expand Down Expand Up @@ -245,7 +275,7 @@ func (rogue *Rogue) doPlanNone(sim *core.Simulation) {
sndTimeRemaining := rogue.RemainingAuraDuration(sim, SliceAndDiceAuraID)

if !rogue.MaintainingExpose(target) {
if sndTimeRemaining > rogue.eaBuildTime+buildTimeBuffer {
if rogue.doneSND || sndTimeRemaining > rogue.eaBuildTime+buildTimeBuffer {
rogue.plan = PlanFillBeforeSND
rogue.doPlanFillBeforeSND(sim)
} else {
Expand All @@ -259,7 +289,7 @@ func (rogue *Rogue) doPlanNone(sim *core.Simulation) {
energyForEANext := rogue.builderEnergyCost*float64(5-comboPoints) + ExposeArmorEnergyCost
eaNextBuildTime := core.MaxDuration(0, time.Duration(((energyForEANext-energy)/rogue.energyPerSecondAvg)*float64(time.Second)))
spareTime := core.MaxDuration(0, eaTimeRemaining-eaNextBuildTime)
if spareTime < time.Second*6 {
if spareTime < buildTimeBuffer {
rogue.plan = PlanExposeArmor
rogue.doPlanExposeArmor(sim)
return
Expand All @@ -277,6 +307,12 @@ func (rogue *Rogue) doPlanNone(sim *core.Simulation) {
return
}

if rogue.doneSND {
rogue.plan = PlanFillBeforeSND
rogue.doPlanFillBeforeSND(sim)
return
}

rogue.plan = PlanMaximalSlice
rogue.doPlanMaximalSlice(sim)
}
Expand Down
10 changes: 7 additions & 3 deletions sim/rogue/shiv.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import (
var ShivActionID = core.ActionID{SpellID: 5938}

func (rogue *Rogue) newShivTemplate(_ *core.Simulation) core.SimpleSpellTemplate {
shivEnergyCost := 20 + 10*rogue.GetOHWeapon().SwingSpeed
rogue.shivEnergyCost = 20
if rogue.GetOHWeapon() != nil {
rogue.shivEnergyCost = 20 + 10*rogue.GetOHWeapon().SwingSpeed
}

ability := rogue.newAbility(ShivActionID, shivEnergyCost, SpellFlagBuilder|core.SpellExtrasCannotBeDodged, core.ProcMaskMeleeOHSpecial)
ability := rogue.newAbility(ShivActionID, rogue.shivEnergyCost, SpellFlagBuilder|core.SpellExtrasCannotBeDodged, core.ProcMaskMeleeOHSpecial)
ability.Effect.OnSpellHit = func(sim *core.Simulation, spellCast *core.SpellCast, spellEffect *core.SpellEffect) {
if spellEffect.Landed() {
rogue.AddComboPoints(sim, 1, ShivActionID)
Expand All @@ -35,12 +38,13 @@ func (rogue *Rogue) newShivTemplate(_ *core.Simulation) core.SimpleSpellTemplate
return core.NewSimpleSpellTemplate(ability)
}

func (rogue *Rogue) NewShiv(_ *core.Simulation, target *core.Target) *core.SimpleSpell {
func (rogue *Rogue) NewShiv(sim *core.Simulation, target *core.Target) *core.SimpleSpell {
sh := &rogue.shiv
rogue.shivTemplate.Apply(sh)

// Set dynamic fields, i.e. the stuff we couldn't precompute.
sh.Effect.Target = target
sh.Init(sim)

return sh
}
8 changes: 6 additions & 2 deletions sim/rogue/slice_and_dice.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (rogue *Rogue) initSliceAndDice(sim *core.Simulation) {
if ItemSetNetherblade.CharacterHasSetBonus(&rogue.Character, 2) {
durationBonus = time.Second * 3
}
sliceAndDiceDurations := []time.Duration{
rogue.sliceAndDiceDurations = [6]time.Duration{
0,
time.Duration(float64(time.Second*9+durationBonus) * durationMultiplier),
time.Duration(float64(time.Second*12+durationBonus) * durationMultiplier),
Expand Down Expand Up @@ -54,7 +54,7 @@ func (rogue *Rogue) initSliceAndDice(sim *core.Simulation) {
OnCastComplete: func(sim *core.Simulation, cast *core.Cast) {
numPoints := rogue.ComboPoints()
aura := sliceAndDiceAura
aura.Expires = sim.CurrentTime + sliceAndDiceDurations[numPoints]
aura.Expires = sim.CurrentTime + rogue.sliceAndDiceDurations[numPoints]
if rogue.HasAura(SliceAndDiceAuraID) {
rogue.ReplaceAura(sim, aura)
} else {
Expand All @@ -63,6 +63,10 @@ func (rogue *Rogue) initSliceAndDice(sim *core.Simulation) {
}

rogue.ApplyFinisher(sim, cast.ActionID)

if aura.Expires >= sim.Duration {
rogue.doneSND = true
}
},
},
}
Expand Down
2 changes: 0 additions & 2 deletions ui/smite_priest/sim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,6 @@ export class SmitePriestSimUI extends IndividualSimUI<Spec.SpecSmitePriest> {
WeaponImbue.WeaponImbueSuperiorWizardOil,
],
other: [
IconInputs.DrumsOfBattleConsume,
IconInputs.DrumsOfRestorationConsume,
],
},
// Inputs to include in the 'Rotation' section on the settings tab.
Expand Down

0 comments on commit c6c4802

Please sign in to comment.