Skip to content

Commit 496e6df

Browse files
authored
Merge pull request #106 from wowsims/guardian
Rage mechanics update + more Guardian work
2 parents 8c8ec8c + 09c104d commit 496e6df

14 files changed

Lines changed: 100 additions & 282 deletions

File tree

sim/core/character.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -720,8 +720,7 @@ func (character *Character) MeetsArmorSpecializationRequirement(armorType proto.
720720
return true
721721
}
722722

723-
func (character *Character) ApplyArmorSpecializationEffect(primaryStat stats.Stat, armorType proto.ArmorType, spellID int32) *Aura {
724-
armorSpecializationDependency := character.NewDynamicMultiplyStat(primaryStat, 1.05)
723+
func (character *Character) RegisterArmorSpecializationTracker(armorType proto.ArmorType, spellID int32) *Aura {
725724
isEnabled := character.MeetsArmorSpecializationRequirement(armorType)
726725

727726
aura := character.RegisterAura(Aura{
@@ -731,8 +730,6 @@ func (character *Character) ApplyArmorSpecializationEffect(primaryStat stats.Sta
731730
Duration: NeverExpires,
732731
})
733732

734-
aura.AttachStatDependency(armorSpecializationDependency)
735-
736733
if isEnabled {
737734
aura = MakePermanent(aura)
738735
}
@@ -750,3 +747,10 @@ func (character *Character) ApplyArmorSpecializationEffect(primaryStat stats.Sta
750747

751748
return aura
752749
}
750+
751+
func (character *Character) ApplyArmorSpecializationEffect(primaryStat stats.Stat, armorType proto.ArmorType, spellID int32) *Aura {
752+
armorSpecializationDependency := character.NewDynamicMultiplyStat(primaryStat, 1.05)
753+
trackerAura := character.RegisterArmorSpecializationTracker(armorType, spellID)
754+
trackerAura.AttachStatDependency(armorSpecializationDependency)
755+
return trackerAura
756+
}

sim/core/rage.go

Lines changed: 20 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,27 @@ import (
99
const MaxRage = 100.0
1010
const ThreatPerRageGained = 5
1111

12-
type OnRageGainCB func(sim *Simulation, spell *Spell, result *SpellResult, rage float64) float64
13-
1412
type rageBar struct {
1513
unit *Unit
1614

1715
startingRage float64
1816
currentRage float64
1917

18+
// hitFactor is the quantity which multiplies the base swing speed of a
19+
// MH weapon when calculating the Rage generated by that weapon's
20+
// swings. For OH weapons, hitFactor / 2 is used.
21+
startingHitFactor float64
22+
currentHitFactor float64
23+
2024
RageRefundMetrics *ResourceMetrics
2125
}
2226

2327
type RageBarOptions struct {
24-
StartingRage float64
25-
MHSwingSpeed float64
26-
OHSwingSpeed float64
27-
RageMultiplier float64
28-
29-
// Called when rage is calculated from an OnSpellHitDealt event
30-
// but before it has been applied to the unit
31-
OnHitDealtRageGain OnRageGainCB
32-
33-
// Called when rage is calculated from an OnSpellHitTaken event
34-
// but before it has been applied to the unit
35-
OnHitTakenRageGain OnRageGainCB
28+
StartingRage float64
29+
BaseHitFactor float64
3630
}
3731

3832
func (unit *Unit) EnableRageBar(options RageBarOptions) {
39-
rageFromDamageTakenMetrics := unit.NewRageMetrics(ActionID{OtherID: proto.OtherAction_OtherActionDamageTaken})
40-
4133
unit.SetCurrentPowerBar(RageBar)
4234
unit.RegisterAura(Aura{
4335
Label: "RageBar",
@@ -49,42 +41,24 @@ func (unit *Unit) EnableRageBar(options RageBarOptions) {
4941
if unit.GetCurrentPowerBar() != RageBar {
5042
return
5143
}
52-
if result.Outcome.Matches(OutcomeMiss) {
44+
if !result.Landed() {
5345
return
5446
}
5547

56-
hitFactor := 6.5
48+
hitFactor := unit.rageBar.currentHitFactor
5749
var speed float64
5850
if spell.ProcMask == ProcMaskMeleeMHAuto {
59-
speed = options.MHSwingSpeed
51+
speed = unit.AutoAttacks.MH().SwingSpeed
6052
} else if spell.ProcMask == ProcMaskMeleeOHAuto {
6153
// OH hits generate 50% of the rage they would if they were MH hits
6254
hitFactor /= 2
63-
speed = options.OHSwingSpeed
55+
speed = unit.AutoAttacks.OH().SwingSpeed
6456
} else {
6557
return
6658
}
6759

68-
// Currently, rage does not get doubled for crits in cataclysm
69-
// Leaving the code here for reference with a note.
70-
//if result.Outcome.Matches(OutcomeCrit) {
71-
// hitFactor *= 2
72-
//}
73-
74-
// TODO: Cataclysm dodge/parry behavior
75-
// damage := result.Damage
76-
// if result.Outcome.Matches(OutcomeDodge | OutcomeParry) {
77-
// // Rage is still generated for dodges/parries, based on the damage it WOULD have done.
78-
// damage = result.PreOutcomeDamage
79-
// }
80-
8160
// rage in mop is normalized so it only depends on weapon swing speed and some multipliers
8261
generatedRage := hitFactor * speed
83-
generatedRage *= options.RageMultiplier
84-
85-
if options.OnHitDealtRageGain != nil {
86-
generatedRage = options.OnHitDealtRageGain(sim, spell, result, generatedRage)
87-
}
8862

8963
var metrics *ResourceMetrics
9064
if spell.Cost != nil {
@@ -97,26 +71,6 @@ func (unit *Unit) EnableRageBar(options RageBarOptions) {
9771
}
9872
unit.AddRage(sim, generatedRage, metrics)
9973
},
100-
OnSpellHitTaken: func(aura *Aura, sim *Simulation, spell *Spell, result *SpellResult) {
101-
if unit.GetCurrentPowerBar() != RageBar {
102-
return
103-
}
104-
105-
// Formula taken from simc and verified using in-game
106-
// measurements. The in-game measurements agree closely for
107-
// incoming melee attacks but not for spells, so more work is
108-
// required to determine whether spells use a different formula or
109-
// whether Beta is simply bugged for spell Rage calculations. Note
110-
// that the below formula delivers full Rage even on missed
111-
// attacks! This is intentional and matches in-game behavior.
112-
generatedRage := result.PreOutcomeDamage / result.ResistanceMultiplier * 18.92 / unit.MaxHealth()
113-
114-
if options.OnHitTakenRageGain != nil {
115-
generatedRage = options.OnHitTakenRageGain(sim, spell, result, generatedRage)
116-
}
117-
118-
unit.AddRage(sim, generatedRage, rageFromDamageTakenMetrics)
119-
},
12074
})
12175

12276
// Not a real spell, just holds metrics from rage gain threat.
@@ -127,6 +81,7 @@ func (unit *Unit) EnableRageBar(options RageBarOptions) {
12781
unit.rageBar = rageBar{
12882
unit: unit,
12983
startingRage: max(0, min(options.StartingRage, MaxRage)),
84+
startingHitFactor: options.BaseHitFactor,
13085
RageRefundMetrics: unit.NewRageMetrics(ActionID{OtherID: proto.OtherAction_OtherActionRefund}),
13186
}
13287
}
@@ -139,6 +94,12 @@ func (rb *rageBar) CurrentRage() float64 {
13994
return rb.currentRage
14095
}
14196

97+
// Call this within the OnGain and OnExpire callbacks for Battle Stance, Raging
98+
// Whirlwind, etc.
99+
func (rb *rageBar) MultiplyAutoAttackRageGen(multiplier float64) {
100+
rb.currentHitFactor *= multiplier
101+
}
102+
142103
func (rb *rageBar) AddRage(sim *Simulation, amount float64, metrics *ResourceMetrics) {
143104
if amount < 0 {
144105
panic("Trying to add negative rage!")
@@ -178,6 +139,7 @@ func (rb *rageBar) reset(_ *Simulation) {
178139
}
179140

180141
rb.currentRage = rb.startingRage
142+
rb.currentHitFactor = rb.startingHitFactor
181143
}
182144

183145
func (rb *rageBar) doneIteration() {

sim/druid/barkskin.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ import (
88
)
99

1010
func (druid *Druid) registerBarkskinCD() {
11-
if !druid.InForm(Bear) {
12-
return
13-
}
14-
1511
actionId := core.ActionID{SpellID: 22812}
1612
hasGlyph := druid.HasMajorGlyph(proto.DruidMajorGlyph_GlyphOfBarkskin)
1713

@@ -30,10 +26,6 @@ func (druid *Druid) registerBarkskinCD() {
3026
if hasGlyph {
3127
druid.PseudoStats.ReducedCritTakenChance -= 0.25
3228
}
33-
34-
if druid.T12Feral4pBonus.IsActive() {
35-
druid.SmokescreenAura.Activate(sim)
36-
}
3729
},
3830
})
3931

@@ -43,7 +35,7 @@ func (druid *Druid) registerBarkskinCD() {
4335
Cast: core.CastConfig{
4436
CD: core.Cooldown{
4537
Timer: druid.NewTimer(),
46-
Duration: time.Second * 60.0,
38+
Duration: core.TernaryDuration(druid.Spec == proto.Spec_SpecGuardianDruid, time.Second * 30, time.Second * 60),
4739
},
4840
},
4941
ApplyEffects: func(sim *core.Simulation, _ *core.Unit, _ *core.Spell) {

sim/druid/druid.go

Lines changed: 10 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ type Druid struct {
3333

3434
MHAutoSpell *core.Spell
3535

36-
HotWCatDep *stats.StatDependency
37-
HotWBearDep *stats.StatDependency
38-
3936
Barkskin *DruidSpell
4037
Berserk *DruidSpell
4138
CatCharge *DruidSpell
@@ -94,18 +91,12 @@ type Druid struct {
9491
MoonkinT84PCAura *core.Aura
9592
NaturesGraceProcAura *core.Aura
9693
OwlkinFrenzyAura *core.Aura
97-
PredatoryInstinctsAura *core.Aura
9894
PrimalMadnessAura *core.Aura
99-
PulverizeAura *core.Aura
10095
SavageDefenseAura *core.DamageAbsorptionAura
101-
SavageRoarAura *core.Aura
102-
SmokescreenAura *core.Aura
10396
SolarEclipseProcAura *core.Aura
10497
StampedeCatAura *core.Aura
10598
StampedeBearAura *core.Aura
106-
StrengthOfThePantherAura *core.Aura
10799
SurvivalInstinctsAura *core.Aura
108-
// TigersFuryAura *core.Aura
109100

110101
BleedCategories core.ExclusiveCategoryArray
111102

@@ -123,13 +114,13 @@ type Druid struct {
123114
form DruidForm
124115
disabledMCDs []*core.MajorCooldown
125116

126-
// Leather specialization tracker
127-
LeatherSpec *core.Aura
117+
// Guardian leather specialization is form-specific
118+
GuardianLeatherSpecTracker *core.Aura
119+
GuardianLeatherSpecDep *stats.StatDependency
128120

129121
// Item sets
130122
T11Feral2pBonus *core.Aura
131123
T11Feral4pBonus *core.Aura
132-
T12Feral4pBonus *core.Aura
133124
T13Feral4pBonus *core.Aura
134125
}
135126

@@ -282,11 +273,10 @@ func (druid *Druid) Initialize() {
282273
}
283274
})
284275

285-
// druid.registerFaerieFireSpell()
276+
druid.registerFaerieFireSpell()
286277
// druid.registerRebirthSpell()
287278
// druid.registerInnervateCD()
288279
druid.registerTranquilityCD()
289-
druid.applyOmenOfClarity()
290280
}
291281

292282
func (druid *Druid) RegisterBalanceSpells() {
@@ -319,8 +309,8 @@ func (druid *Druid) RegisterFeralCatSpells() {
319309
// druid.registerRipSpell()
320310
// druid.registerSavageRoarSpell()
321311
// druid.registerShredSpell()
322-
druid.registerSwipeBearSpell()
323-
druid.registerSwipeCatSpell()
312+
//druid.registerSwipeBearSpell()
313+
//druid.registerSwipeCatSpell()
324314
// druid.registerThrashBearSpell()
325315
// druid.registerTigersFurySpell()
326316
}
@@ -329,33 +319,21 @@ func (druid *Druid) RegisterFeralTankSpells() {
329319
druid.registerBarkskinCD()
330320
druid.registerBearFormSpell()
331321
// druid.registerBerserkCD()
332-
druid.registerDemoralizingRoarSpell()
322+
//druid.registerDemoralizingRoarSpell()
333323
// druid.registerEnrageSpell()
334-
druid.registerFrenziedRegenerationCD()
324+
//druid.registerFrenziedRegenerationCD()
335325
// druid.registerMangleBearSpell()
336326
// druid.registerMaulSpell()
337327
// druid.registerLacerateSpell()
338328
// druid.registerPulverizeSpell()
339329
// druid.registerRakeSpell()
340330
// druid.registerRipSpell()
341-
druid.registerSavageDefensePassive()
331+
//druid.registerSavageDefensePassive()
342332
// druid.registerSurvivalInstinctsCD()
343-
druid.registerSwipeBearSpell()
333+
//druid.registerSwipeBearSpell()
344334
// druid.registerThrashBearSpell()
345335
}
346336

347-
func (druid *Druid) RegisterLeatherSpecialization() {
348-
// Druid armor spec behaves differently from other classes because the boosted stats are linked to form rather
349-
// than talents. For this reason, we modify the default tracker Aura to activate at BuildPhaseGear rather than
350-
// BuildPhaseTalents, and also add custom handlers for the cat Agi bonus and the bear Stam bonus in forms.go (the
351-
// Int bonus applies in all forms).
352-
druid.LeatherSpec = druid.ApplyArmorSpecializationEffect(stats.Intellect, proto.ArmorType_ArmorTypeLeather, 87505)
353-
354-
if druid.LeatherSpec.BuildPhase == core.CharacterBuildPhaseTalents {
355-
druid.LeatherSpec.BuildPhase = core.CharacterBuildPhaseGear
356-
}
357-
}
358-
359337
func (druid *Druid) Reset(_ *core.Simulation) {
360338
// druid.eclipseEnergyBar.reset()
361339
druid.BleedsActive = 0
@@ -388,20 +366,6 @@ func New(char *core.Character, form DruidForm, selfBuffs SelfBuffs, talents stri
388366
// Base dodge is unaffected by Diminishing Returns
389367
druid.PseudoStats.BaseDodgeChance += 0.03
390368

391-
druid.RegisterLeatherSpecialization()
392-
393-
// if druid.Talents.ForceOfNature {
394-
// druid.Treants = &Treants{
395-
// Treant1: druid.NewTreant(),
396-
// Treant2: druid.NewTreant(),
397-
// Treant3: druid.NewTreant(),
398-
// }
399-
// }
400-
401-
// if druid.CouldHaveSetBonus(ItemSetObsidianArborweaveRegalia, 2) {
402-
// druid.BurningTreant = druid.NewBurningTreant()
403-
// }
404-
405369
return druid
406370
}
407371

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,31 @@ import (
99
func (druid *Druid) registerFaerieFireSpell() {
1010
actionID := core.ActionID{SpellID: 770}
1111
manaCostOptions := core.ManaCostOptions{
12-
BaseCostPercent: 8,
12+
BaseCostPercent: 7.5,
1313
}
1414
gcd := core.GCDDefault
1515
ignoreHaste := false
1616
cd := core.Cooldown{}
1717
flatThreatBonus := 48.
18-
flags := SpellFlagOmenTrigger
18+
flags := core.SpellFlagAPL
1919
formMask := Humanoid | Moonkin
2020

2121
if druid.InForm(Cat | Bear) {
22-
actionID = core.ActionID{SpellID: 16857}
2322
manaCostOptions = core.ManaCostOptions{}
24-
gcd = time.Second
25-
ignoreHaste = true
26-
flags = core.SpellFlagNone
2723
formMask = Cat | Bear
2824
cd = core.Cooldown{
2925
Timer: druid.NewTimer(),
3026
Duration: time.Second * 6,
3127
}
3228
}
33-
flags |= core.SpellFlagAPL
29+
30+
if druid.InForm(Cat) {
31+
gcd = time.Second
32+
ignoreHaste = true
33+
}
3434

3535
druid.FaerieFireAuras = druid.NewEnemyAuraArray(func(target *core.Unit) *core.Aura {
36-
return core.FaerieFireAura(target)
36+
return core.WeakenedArmorAura(target)
3737
})
3838

3939
druid.FaerieFire = druid.RegisterSpell(formMask, core.SpellConfig{
@@ -60,7 +60,7 @@ func (druid *Druid) registerFaerieFireSpell() {
6060
baseDamage := 0.0
6161
outcome := spell.OutcomeMagicHit
6262
if druid.InForm(Bear) {
63-
baseDamage = 2950 + 0.108*spell.MeleeAttackPower()
63+
baseDamage = 10.0 + 0.302*spell.MeleeAttackPower()
6464
outcome = spell.OutcomeMagicHitAndCrit
6565
}
6666

@@ -84,7 +84,7 @@ func (druid *Druid) TryApplyFaerieFireEffect(sim *core.Simulation, target *core.
8484
aura.Activate(sim)
8585

8686
if aura.IsActive() {
87-
aura.SetStacks(sim, aura.GetStacks()+1+druid.Talents.FeralAggression)
87+
aura.SetStacks(sim, 3)
8888
}
8989
}
9090
}

0 commit comments

Comments
 (0)