Skip to content

Commit

Permalink
Merge pull request wowsims#84 from wowsims/feral
Browse files Browse the repository at this point in the history
Mastery and specialization passives for Feral Druid
  • Loading branch information
NerdEgghead authored Apr 16, 2024
2 parents 3bcc2a2 + 473b027 commit 9e484de
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 56 deletions.
2 changes: 1 addition & 1 deletion sim/core/base_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ var ClassBaseStats = map[proto.Class]stats.Stats{
stats.Intellect: 165,
stats.Spirit: 173,
stats.Stamina: 106,
stats.AttackPower: -20,
stats.AttackPower: float64(CharacterLevel)*3.0 - 10,
},
}

Expand Down
3 changes: 3 additions & 0 deletions sim/druid/druid.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ func (druid *Druid) RegisterSpell(formMask DruidForm, config core.SpellConfig) *
}

func (druid *Druid) Initialize() {
if druid.Spec == proto.Spec_SpecFeralDruid {
druid.EnableArmorSpecialization(stats.Agility, proto.ArmorType_ArmorTypeLeather)
}
// druid.BleedCategories = druid.GetEnemyExclusiveCategories(core.BleedEffectCategory)

// if druid.Talents.PrimalPrecision > 0 {
Expand Down
6 changes: 6 additions & 0 deletions sim/druid/feral/feral.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/wowsims/cata/sim/core"
"github.com/wowsims/cata/sim/core/proto"
"github.com/wowsims/cata/sim/core/stats"
"github.com/wowsims/cata/sim/druid"
)

Expand Down Expand Up @@ -95,6 +96,11 @@ func (cat *FeralDruid) Initialize() {
cat.RegisterFeralCatSpells()
}

func (cat *FeralDruid) ApplyTalents() {
cat.Druid.ApplyTalents()
cat.MultiplyStat(stats.AttackPower, 1.25) // Aggression passive
}

func (cat *FeralDruid) Reset(sim *core.Simulation) {
cat.Druid.Reset(sim)
cat.Druid.ClearForm(sim)
Expand Down
1 change: 1 addition & 0 deletions sim/druid/forms.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func (druid *Druid) registerCatFormSpell() {
srm := druid.getSavageRoarMultiplier()

statBonus := stats.Stats{
stats.AttackPower: -20, // This offset is needed because the first 10 points of Agility do not contribute any Attack Power.
stats.MeleeCrit: core.TernaryFloat64(druid.Talents.MasterShapeshifter, 4.0 * core.CritRatingPerCritChance, 0.0),
}

Expand Down
26 changes: 11 additions & 15 deletions sim/druid/_rake.go → sim/druid/rake.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ import (
"time"

"github.com/wowsims/cata/sim/core"
"github.com/wowsims/cata/sim/core/stats"
)

func (druid *Druid) registerRakeSpell() {
dotCanCrit := druid.HasSetBonus(ItemSetLasherweaveBattlegear, 4)

druid.Rake = druid.RegisterSpell(Cat, core.SpellConfig{
ActionID: core.ActionID{SpellID: 48574},
SpellSchool: core.SpellSchoolPhysical,
ProcMask: core.ProcMaskMeleeMHSpecial,
Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIgnoreResists | core.SpellFlagAPL,

EnergyCost: core.EnergyCostOptions{
Cost: 40 - float64(druid.Talents.Ferocity),
Cost: 35,
Refund: 0.8,
},
Cast: core.CastConfig{
Expand All @@ -26,16 +25,16 @@ func (druid *Druid) registerRakeSpell() {
IgnoreHaste: true,
},

DamageMultiplier: 1 + 0.1*float64(druid.Talents.SavageFury),
CritMultiplier: druid.MeleeCritMultiplier(Cat),
DamageMultiplier: druid.RazorClawsMultiplier(druid.GetStat(stats.Mastery)),
CritMultiplier: druid.DefaultMeleeCritMultiplier(),
ThreatMultiplier: 1,

Dot: core.DotConfig{
Aura: druid.applyRendAndTear(core.Aura{
Label: "Rake",
Duration: time.Second * 9,
}),
NumberOfTicks: 3 + core.TernaryInt32(druid.HasSetBonus(ItemSetMalfurionsBattlegear, 2), 1, 0),
NumberOfTicks: 3 + druid.Talents.EndlessCarnage,
TickLength: time.Second * 3,
OnSnapshot: func(sim *core.Simulation, target *core.Unit, dot *core.Dot, isRollover bool) {
dot.SnapshotBaseDamage = 358 + 0.06*dot.Spell.MeleeAttackPower()
Expand All @@ -44,11 +43,7 @@ func (druid *Druid) registerRakeSpell() {
dot.SnapshotAttackerMultiplier = dot.Spell.AttackerDamageMultiplier(attackTable)
},
OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) {
if dotCanCrit {
dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit)
} else {
dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.Spell.OutcomeAlwaysHit)
}
dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit)
},
},

Expand Down Expand Up @@ -85,14 +80,15 @@ func (druid *Druid) registerRakeSpell() {
attackTable := spell.Unit.AttackTables[target.UnitIndex]
critChance := spell.PhysicalCritChance(attackTable)
critMod := (critChance * (spell.CritMultiplier - 1))

if dotCanCrit {
ticks.Damage *= 1 + critMod
}
ticks.Damage *= 1 + critMod

return ticks
},
})

druid.AddOnMasteryStatChanged(func(sim *core.Simulation, oldMastery float64, newMastery float64) {
druid.Rake.DamageMultiplier *= druid.RazorClawsMultiplier(newMastery) / druid.RazorClawsMultiplier(oldMastery)
})
}

func (druid *Druid) CurrentRakeCost() float64 {
Expand Down
35 changes: 17 additions & 18 deletions sim/druid/_rip.go → sim/druid/rip.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import (

"github.com/wowsims/cata/sim/core"
"github.com/wowsims/cata/sim/core/proto"
"github.com/wowsims/cata/sim/core/stats"
)

func (druid *Druid) registerRipSpell() {
ripBaseNumTicks := 6 +
core.TernaryInt32(druid.HasMajorGlyph(proto.DruidMajorGlyph_GlyphOfRip), 2, 0) +
core.TernaryInt32(druid.HasSetBonus(ItemSetDreamwalkerBattlegear, 2), 2, 0)
ripBaseNumTicks := int32(8)

comboPointCoeff := 93.0
if druid.Ranged().ID == 28372 { // Idol of Feral Shadows
Expand All @@ -19,15 +18,17 @@ func (druid *Druid) registerRipSpell() {
comboPointCoeff += 21
}

glyphMulti := core.TernaryFloat64(druid.HasPrimeGlyph(proto.DruidPrimeGlyph_GlyphOfRip), 1.15, 1.0)

druid.Rip = druid.RegisterSpell(Cat, core.SpellConfig{
ActionID: core.ActionID{SpellID: 49800},
SpellSchool: core.SpellSchoolPhysical,
ProcMask: core.ProcMaskMeleeMHSpecial,
Flags: core.SpellFlagMeleeMetrics | core.SpellFlagAPL,

EnergyCost: core.EnergyCostOptions{
Cost: 30 - core.TernaryFloat64(druid.HasSetBonus(ItemSetLasherweaveBattlegear, 2), 10, 0),
Refund: 0.4 * float64(druid.Talents.PrimalPrecision),
Cost: 30,
Refund: 0.8,
RefundMetrics: druid.PrimalPrecisionRecoveryMetrics,
},
Cast: core.CastConfig{
Expand All @@ -40,9 +41,9 @@ func (druid *Druid) registerRipSpell() {
return druid.ComboPoints() > 0
},

BonusCritRating: core.TernaryFloat64(druid.HasSetBonus(ItemSetMalfurionsBattlegear, 4), 5*core.CritRatingPerCritChance, 0.0),
DamageMultiplier: 1 + core.TernaryFloat64(druid.HasSetBonus(ItemSetThunderheartHarness, 4), 0.15, 0),
CritMultiplier: druid.MeleeCritMultiplier(Cat),
BonusCritRating: 0,
DamageMultiplier: glyphMulti * druid.RazorClawsMultiplier(druid.GetStat(stats.Mastery)),
CritMultiplier: druid.DefaultMeleeCritMultiplier(),
ThreatMultiplier: 1,

Dot: core.DotConfig{
Expand All @@ -65,11 +66,7 @@ func (druid *Druid) registerRipSpell() {
}
},
OnTick: func(sim *core.Simulation, target *core.Unit, dot *core.Dot) {
if druid.Talents.PrimalGore {
dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit)
} else {
dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.Spell.OutcomeAlwaysHit)
}
dot.CalcAndDealPeriodicSnapshotDamage(sim, target, dot.OutcomeSnapshotCrit)
},
},

Expand All @@ -87,14 +84,16 @@ func (druid *Druid) registerRipSpell() {
spell.DealOutcome(sim, result)
},
})

druid.AddOnMasteryStatChanged(func(sim *core.Simulation, oldMastery float64, newMastery float64) {
druid.Rip.DamageMultiplier *= druid.RazorClawsMultiplier(newMastery) / druid.RazorClawsMultiplier(oldMastery)
})
}

func (druid *Druid) MaxRipTicks() int32 {
base := int32(6)
t7bonus := core.TernaryInt32(druid.HasSetBonus(ItemSetDreamwalkerBattlegear, 2), 2, 0)
ripGlyphBonus := core.TernaryInt32(druid.HasMajorGlyph(proto.DruidMajorGlyph_GlyphOfRip), 2, 0)
shredGlyphBonus := core.TernaryInt32(druid.HasMajorGlyph(proto.DruidMajorGlyph_GlyphOfShred), 3, 0)
return base + ripGlyphBonus + shredGlyphBonus + t7bonus
base := int32(8)
shredGlyphBonus := core.TernaryInt32(druid.HasPrimeGlyph(proto.DruidPrimeGlyph_GlyphOfBloodletting), 3, 0)
return base + shredGlyphBonus
}

func (druid *Druid) CurrentRipCost() float64 {
Expand Down
59 changes: 37 additions & 22 deletions sim/druid/talents.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
package druid

import (
"github.com/wowsims/cata/sim/core"
"github.com/wowsims/cata/sim/core/proto"
)

func (druid *Druid) RazorClawsMultiplier(masteryRating float64) float64 {
razorClawsMulti := 1.0

if druid.Spec == proto.Spec_SpecFeralDruid {
razorClawsMulti += 0.25 + 0.03125*core.MasteryRatingToMasteryPoints(masteryRating)
}

return razorClawsMulti
}

func (druid *Druid) ThickHideMultiplier() float64 {
thickHideMulti := 1.0

Expand Down Expand Up @@ -260,29 +275,29 @@ func (druid *Druid) ApplyTalents() {
// })
// }

// // Modifies the Bleed aura to apply the bonus.
// func (druid *Druid) applyRendAndTear(aura core.Aura) core.Aura {
// if druid.FerociousBite == nil || druid.Talents.RendAndTear == 0 || druid.AssumeBleedActive {
// return aura
// }

// bonusCrit := 5.0 * float64(druid.Talents.RendAndTear) * core.CritRatingPerCritChance

// aura.ApplyOnGain(func(aura *core.Aura, sim *core.Simulation) {
// if druid.BleedsActive == 0 {
// druid.FerociousBite.BonusCritRating += bonusCrit
// }
// druid.BleedsActive++
// })
// aura.ApplyOnExpire(func(aura *core.Aura, sim *core.Simulation) {
// druid.BleedsActive--
// if druid.BleedsActive == 0 {
// druid.FerociousBite.BonusCritRating -= bonusCrit
// }
// })
// Modifies the Bleed aura to apply the bonus.
func (druid *Druid) applyRendAndTear(aura core.Aura) core.Aura {
if druid.FerociousBite == nil || druid.Talents.RendAndTear == 0 || druid.AssumeBleedActive {
return aura
}

// return aura
// }
bonusCrit := 5.0 * float64(druid.Talents.RendAndTear) * core.CritRatingPerCritChance

aura.ApplyOnGain(func(aura *core.Aura, sim *core.Simulation) {
if druid.BleedsActive == 0 {
druid.FerociousBite.BonusCritRating += bonusCrit
}
druid.BleedsActive++
})
aura.ApplyOnExpire(func(aura *core.Aura, sim *core.Simulation) {
druid.BleedsActive--
if druid.BleedsActive == 0 {
druid.FerociousBite.BonusCritRating -= bonusCrit
}
})

return aura
}

// func (druid *Druid) applyOmenOfClarity() {
// // Feral 2p needs clearcasting aura
Expand Down

0 comments on commit 9e484de

Please sign in to comment.