From 6a20ed1c74db4eceebe73c5f859e4f4fc4151ea9 Mon Sep 17 00:00:00 2001 From: NerdEgghead Date: Mon, 15 Apr 2024 19:34:50 -0700 Subject: [PATCH 1/4] Fixed base Attack Power for Druid On branch feral Changes to be committed: modified: sim/core/base_stats.go --- sim/core/base_stats.go | 2 +- sim/druid/forms.go | 1 + sim/druid/{_rake.go => rake.go} | 0 sim/druid/{_rip.go => rip.go} | 0 4 files changed, 2 insertions(+), 1 deletion(-) rename sim/druid/{_rake.go => rake.go} (100%) rename sim/druid/{_rip.go => rip.go} (100%) diff --git a/sim/core/base_stats.go b/sim/core/base_stats.go index 348ba7e28b..5819d1b7c7 100644 --- a/sim/core/base_stats.go +++ b/sim/core/base_stats.go @@ -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, }, } diff --git a/sim/druid/forms.go b/sim/druid/forms.go index 3a26d67826..39f2d20496 100644 --- a/sim/druid/forms.go +++ b/sim/druid/forms.go @@ -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), } diff --git a/sim/druid/_rake.go b/sim/druid/rake.go similarity index 100% rename from sim/druid/_rake.go rename to sim/druid/rake.go diff --git a/sim/druid/_rip.go b/sim/druid/rip.go similarity index 100% rename from sim/druid/_rip.go rename to sim/druid/rip.go From 17378bb99c9290fae0859c3fa7b1ffe634a6cbf6 Mon Sep 17 00:00:00 2001 From: NerdEgghead Date: Mon, 15 Apr 2024 19:36:29 -0700 Subject: [PATCH 2/4] Added Aggression passive for Feral spec On branch feral Changes to be committed: modified: sim/druid/feral/feral.go --- sim/druid/feral/feral.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sim/druid/feral/feral.go b/sim/druid/feral/feral.go index 54ac80aa34..a7c6b5f1e5 100644 --- a/sim/druid/feral/feral.go +++ b/sim/druid/feral/feral.go @@ -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" ) @@ -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) From d154af8cafdeff9a02ea0b96c75b10057c8df1cd Mon Sep 17 00:00:00 2001 From: NerdEgghead Date: Mon, 15 Apr 2024 19:41:31 -0700 Subject: [PATCH 3/4] Implemented Feral Druid Mastery (Razor Claws) On branch feral Changes to be committed: modified: sim/druid/rake.go modified: sim/druid/rip.go modified: sim/druid/talents.go --- sim/druid/rake.go | 26 +++++++++---------- sim/druid/rip.go | 35 +++++++++++++------------- sim/druid/talents.go | 59 +++++++++++++++++++++++++++----------------- 3 files changed, 65 insertions(+), 55 deletions(-) diff --git a/sim/druid/rake.go b/sim/druid/rake.go index 68eb127372..aabc6e4fbc 100644 --- a/sim/druid/rake.go +++ b/sim/druid/rake.go @@ -4,11 +4,10 @@ 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, @@ -16,7 +15,7 @@ func (druid *Druid) registerRakeSpell() { Flags: core.SpellFlagMeleeMetrics | core.SpellFlagIgnoreResists | core.SpellFlagAPL, EnergyCost: core.EnergyCostOptions{ - Cost: 40 - float64(druid.Talents.Ferocity), + Cost: 35, Refund: 0.8, }, Cast: core.CastConfig{ @@ -26,8 +25,8 @@ 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{ @@ -35,7 +34,7 @@ func (druid *Druid) registerRakeSpell() { 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() @@ -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) }, }, @@ -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 { diff --git a/sim/druid/rip.go b/sim/druid/rip.go index 0cc62f7f03..5205287dac 100644 --- a/sim/druid/rip.go +++ b/sim/druid/rip.go @@ -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 @@ -19,6 +18,8 @@ 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, @@ -26,8 +27,8 @@ func (druid *Druid) registerRipSpell() { 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{ @@ -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{ @@ -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) }, }, @@ -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 { diff --git a/sim/druid/talents.go b/sim/druid/talents.go index 555081d9eb..cbcdf340ff 100644 --- a/sim/druid/talents.go +++ b/sim/druid/talents.go @@ -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 @@ -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 From d08f0fa5a92f177b0ff53f8510b539860970a482 Mon Sep 17 00:00:00 2001 From: NerdEgghead Date: Mon, 15 Apr 2024 19:50:30 -0700 Subject: [PATCH 4/4] Added Leather armor specialization bonus for Feral On branch feral Changes to be committed: modified: sim/druid/druid.go --- sim/druid/druid.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sim/druid/druid.go b/sim/druid/druid.go index 68b0bb2c0f..a5d95d658a 100644 --- a/sim/druid/druid.go +++ b/sim/druid/druid.go @@ -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 {