Skip to content

Commit 834ad83

Browse files
committed
Merge branch 'master' into fix/monk-and-crit-multi
2 parents 8b5b0d4 + ce9bf41 commit 834ad83

14 files changed

Lines changed: 205 additions & 173 deletions

File tree

sim/core/aura_helpers.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,6 @@ func (parentAura *Aura) AttachSpellMod(spellModConfig SpellModConfig) *Aura {
400400
// Attaches a StatDependency to a parent Aura
401401
// Returns parent aura for chaining
402402
func (parentAura *Aura) AttachStatDependency(statDep *stats.StatDependency) *Aura {
403-
404403
parentAura.ApplyOnGain(func(_ *Aura, sim *Simulation) {
405404
parentAura.Unit.EnableBuildPhaseStatDep(sim, statDep)
406405
})
@@ -409,6 +408,10 @@ func (parentAura *Aura) AttachStatDependency(statDep *stats.StatDependency) *Aur
409408
parentAura.Unit.DisableBuildPhaseStatDep(sim, statDep)
410409
})
411410

411+
if parentAura.IsActive() {
412+
parentAura.Unit.StatDependencyManager.EnableDynamicStatDep(statDep)
413+
}
414+
412415
return parentAura
413416
}
414417

sim/core/avoid_dr.go

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,49 @@
11
package core
22

33
import (
4+
"github.com/wowsims/mop/sim/core/proto"
45
"github.com/wowsims/mop/sim/core/stats"
56
)
67

7-
// Could be in constants.go, but they won't be used anywhere else
8-
// C values are divided by 100 so that we are working with 1% = 0.01
9-
// TODO: UPDATE FOR MOP
10-
// Reference for Cata values: https://web.archive.org/web/20130127084642/http://elitistjerks.com/f15/t29453-combat_ratings_level_85_cataclysm/
11-
const Diminish_k_Druid = 0.972
12-
const Diminish_k_Nondruid = 0.956
13-
const Diminish_Cd_Druid = 116.890707 / 100
14-
const Diminish_Cd_Nondruid = 65.631440 / 100
15-
const Diminish_Cp = 65.631440 / 100
16-
const Diminish_kCd_Druid = (Diminish_k_Druid * Diminish_Cd_Druid)
17-
const Diminish_kCd_Nondruid = (Diminish_k_Nondruid * Diminish_Cd_Nondruid)
18-
const Diminish_kCp = (Diminish_k_Nondruid * Diminish_Cp)
8+
type DiminishingReturnsConstants struct {
9+
k, c_p, c_d, c_b float64
10+
}
11+
12+
// https://github.com/raethkcj/MistsDiminishingReturns
13+
var AvoidanceDRByClass = map[proto.Class]DiminishingReturnsConstants{
14+
proto.Class_ClassWarrior: {0.956, 237.186, 90.6425, 150.376},
15+
proto.Class_ClassPaladin: {0.886, 237.186, 66.5675, 150.376},
16+
proto.Class_ClassHunter: {0.988, 0, 145.560, 0},
17+
proto.Class_ClassRogue: {0.988, 145.560, 145.560, 0},
18+
proto.Class_ClassPriest: {0.983, 0, 150.376, 0},
19+
proto.Class_ClassDeathKnight: {0.956, 237.186, 90.6425, 0},
20+
proto.Class_ClassShaman: {0.988, 145.560, 145.560, 0},
21+
proto.Class_ClassMonk: {1.422, 90.6425, 501.253, 0},
22+
proto.Class_ClassMage: {0.983, 0, 150.376, 0},
23+
proto.Class_ClassWarlock: {0.983, 0, 150.376, 0},
24+
proto.Class_ClassDruid: {1.222, 0, 150.376, 0},
25+
}
1926

2027
// Diminishing Returns for tank avoidance
2128
// Non-diminishing sources are added separately in spell outcome funcs
2229

2330
func (unit *Unit) GetDiminishedDodgeChance() float64 {
2431
// undiminished Dodge % = D
2532
// diminished Dodge % = (D * Cd)/((k*Cd) + D)
26-
dodgeChance := unit.stats[stats.DodgeRating] / DodgeRatingPerDodgePercent / 100
27-
28-
if unit.PseudoStats.CanParry {
29-
return (dodgeChance * Diminish_Cd_Nondruid) / (Diminish_kCd_Nondruid + dodgeChance)
30-
} else {
31-
return (dodgeChance * Diminish_Cd_Druid) / (Diminish_kCd_Druid + dodgeChance)
32-
}
33+
dodgePercent := unit.stats[stats.DodgeRating] / DodgeRatingPerDodgePercent
34+
return (dodgePercent * unit.avoidanceParams.c_d) / (unit.avoidanceParams.k * unit.avoidanceParams.c_d + dodgePercent) / 100
3335
}
3436

3537
func (unit *Unit) GetDiminishedParryChance() float64 {
3638
// undiminished Parry % = P
3739
// diminished Parry % = (P * Cp)/((k*Cp) + P)
38-
parryChance := unit.stats[stats.ParryRating] / ParryRatingPerParryPercent / 100
39-
return (parryChance * Diminish_Cp) / (Diminish_kCp + parryChance)
40+
parryPercent := unit.stats[stats.ParryRating] / ParryRatingPerParryPercent
41+
return (parryPercent * unit.avoidanceParams.c_p) / (unit.avoidanceParams.k * unit.avoidanceParams.c_p + parryPercent) / 100
4042
}
4143

42-
func (unit *Unit) GetDiminishedMissChance() float64 {
43-
// Defense Rating is gone in Cata, so there are no diminished sources of Miss
44-
return 0
44+
func (unit *Unit) GetDiminishedBlockChance() float64 {
45+
// undiminished Block % = B
46+
// diminished Block % = (B * Cb)/((k*Cb) + B)
47+
blockPercent := unit.stats[stats.BlockPercent]
48+
return (blockPercent * unit.avoidanceParams.c_b) / (unit.avoidanceParams.k * unit.avoidanceParams.c_b + blockPercent) / 100
4549
}

sim/core/base_stats.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ var ClassBaseStats = map[proto.Class]stats.Stats{
210210
stats.Strength: 104,
211211
stats.Intellect: 169,
212212
stats.Spirit: 188,
213-
stats.Stamina: 119,
213+
stats.Stamina: 114,
214214
stats.AttackPower: float64(CharacterLevel)*3.0 - 10,
215215
},
216216
proto.Class_ClassMonk: {

sim/core/character.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ func NewCharacter(party *Party, partyIndex int, player *proto.Player) Character
101101
Metrics: NewUnitMetrics(),
102102

103103
StatDependencyManager: stats.NewStatDependencyManager(),
104+
avoidanceParams: AvoidanceDRByClass[player.Class],
104105

105106
ReactionTime: time.Duration(max(player.ReactionTimeMs, 10)) * time.Millisecond,
106107
ChannelClipDelay: max(0, time.Duration(player.ChannelClipDelayMs)*time.Millisecond),

sim/core/stats/deps.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ func (sd StatDependency) String() string {
8484
}
8585
}
8686

87+
// Updates the "amount" field for a previously defined dep. Note that if this is
88+
// called after the stats measurement phase, then ApplyStatDependencies() must
89+
// be immediately called afterwards!
90+
func (dep *StatDependency) UpdateValue(newAmount float64) {
91+
dep.amount = newAmount
92+
}
93+
8794
// Manages dependencies between stats.
8895
//
8996
// Some examples:

sim/core/unit.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ type Unit struct {
146146
AttackTables []*AttackTable
147147
DynamicDamageTakenModifiers []DynamicDamageTakenModifier
148148
Blockhandler func(sim *Simulation, spell *Spell, result *SpellResult)
149+
avoidanceParams DiminishingReturnsConstants
149150

150151
GCD *Timer
151152

@@ -364,6 +365,21 @@ func (unit *Unit) DisableDynamicStatDep(sim *Simulation, dep *stats.StatDependen
364365
}
365366
}
366367

368+
func (unit *Unit) UpdateDynamicStatDep(sim *Simulation, dep *stats.StatDependency, newAmount float64) {
369+
dep.UpdateValue(newAmount)
370+
371+
if unit.Env.IsFinalized() {
372+
oldStats := unit.stats
373+
unit.stats = unit.ApplyStatDependencies(unit.statsWithoutDeps)
374+
statsChange := unit.stats.Subtract(oldStats)
375+
unit.processDynamicBonus(sim, statsChange)
376+
377+
if sim.Log != nil {
378+
unit.Log(sim, "Dynamic dep updated (%s): %s", dep.String(), statsChange.FlatString())
379+
}
380+
}
381+
}
382+
367383
func (unit *Unit) EnableBuildPhaseStatDep(sim *Simulation, dep *stats.StatDependency) {
368384
if unit.Env.MeasuringStats && unit.Env.State != Finalized {
369385
unit.StatDependencyManager.EnableDynamicStatDep(dep)
@@ -700,14 +716,13 @@ func (unit *Unit) GetTotalParryChanceAsDefender(atkTable *AttackTable) float64 {
700716

701717
func (unit *Unit) GetTotalChanceToBeMissedAsDefender(atkTable *AttackTable) float64 {
702718
chance := atkTable.BaseMissChance +
703-
unit.GetDiminishedMissChance() +
704719
unit.PseudoStats.ReducedPhysicalHitTakenChance
705720
return math.Max(chance, 0.0)
706721
}
707722

708723
func (unit *Unit) GetTotalBlockChanceAsDefender(atkTable *AttackTable) float64 {
709724
chance := atkTable.BaseBlockChance +
710-
unit.GetStat(stats.BlockPercent)/100
725+
unit.GetDiminishedBlockChance()
711726
return math.Max(chance, 0.0)
712727
}
713728

sim/druid/_enrage.go

Lines changed: 0 additions & 68 deletions
This file was deleted.

sim/druid/druid.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ type Druid struct {
4040
Berserk *DruidSpell
4141
CatCharge *DruidSpell
4242
DemoralizingRoar *DruidSpell
43-
Enrage *DruidSpell
4443
FaerieFire *DruidSpell
4544
FerociousBite *DruidSpell
4645
ForceOfNature *DruidSpell
@@ -88,7 +87,6 @@ type Druid struct {
8887
CatFormAura *core.Aura
8988
ClearcastingAura *core.Aura
9089
DemoralizingRoarAuras core.AuraArray
91-
EnrageAura *core.Aura
9290
FaerieFireAuras core.AuraArray
9391
FrenziedRegenerationAura *core.Aura
9492
LunarEclipseProcAura *core.Aura
@@ -383,11 +381,12 @@ func New(char *core.Character, form DruidForm, selfBuffs SelfBuffs, talents stri
383381
druid.AddStatDependency(stats.Strength, stats.AttackPower, 1)
384382
druid.AddStatDependency(stats.BonusArmor, stats.Armor, 1)
385383
druid.AddStatDependency(stats.Agility, stats.PhysicalCritPercent, core.CritPerAgiMaxLevel[char.Class])
386-
// Druids get 0.0041 dodge per agi (before dr), roughly 1% per 244
387-
druid.AddStatDependency(stats.Agility, stats.DodgeRating, 0.00410000*core.DodgeRatingPerDodgePercent)
384+
385+
// Druids get roughly 1% Dodge per 951.16 Agi at level 90
386+
druid.AddStatDependency(stats.Agility, stats.DodgeRating, 0.00105135 * core.DodgeRatingPerDodgePercent)
388387

389388
// Base dodge is unaffected by Diminishing Returns
390-
druid.PseudoStats.BaseDodgeChance += 0.04951
389+
druid.PseudoStats.BaseDodgeChance += 0.03
391390

392391
druid.RegisterLeatherSpecialization()
393392

sim/druid/forms.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const (
2222
// Converts from 0.009327 to 0.0085
2323
const AnimalSpiritRegenSuppression = 0.911337
2424

25+
// Thick Hide contribution handled separately in talents code for cleanliness
26+
// and UI stats display.
27+
const BaseBearArmorMulti = 2.2
28+
2529
func (form DruidForm) Matches(other DruidForm) bool {
2630
return (form & other) != 0
2731
}
@@ -230,7 +234,9 @@ func (druid *Druid) RegisterBearFormAura() {
230234
}
231235

232236
agiApDep := druid.NewDynamicStatDependency(stats.Agility, stats.AttackPower, 2)
233-
stamDep := druid.NewDynamicMultiplyStat(stats.Stamina, 1.2)
237+
stamDep := druid.NewDynamicMultiplyStat(stats.Stamina, 1.4)
238+
critDep := druid.NewDynamicMultiplyStat(stats.CritRating, 1.5) // TODO: Should this be implemented as EquipScaling instead? Need to check elixirs and procs.
239+
hasteDep := druid.NewDynamicMultiplyStat(stats.HasteRating, 1.5) // TODO: Should this be implemented as EquipScaling instead? Need to check elixirs and procs.
234240
leatherSpecDep := druid.NewDynamicMultiplyStat(stats.Stamina, 1.05)
235241

236242
// Need redundant enabling/disabling of the dep both here and below
@@ -249,7 +255,6 @@ func (druid *Druid) RegisterBearFormAura() {
249255
})
250256

251257
clawWeapon := druid.GetBearWeapon()
252-
baseBearArmorMulti := 2.2 // Thick Hide contribution handled separately in talents code for cleanliness and UI stats display.
253258

254259
druid.BearFormAura = druid.RegisterAura(core.Aura{
255260
Label: "Bear Form",
@@ -267,8 +272,10 @@ func (druid *Druid) RegisterBearFormAura() {
267272
druid.PseudoStats.SpiritRegenMultiplier *= AnimalSpiritRegenSuppression
268273

269274
druid.AddStatsDynamic(sim, statBonus)
270-
druid.ApplyDynamicEquipScaling(sim, stats.Armor, baseBearArmorMulti)
275+
druid.ApplyDynamicEquipScaling(sim, stats.Armor, BaseBearArmorMulti)
271276
druid.EnableBuildPhaseStatDep(sim, agiApDep)
277+
druid.EnableBuildPhaseStatDep(sim, critDep)
278+
druid.EnableBuildPhaseStatDep(sim, hasteDep)
272279

273280
// Preserve fraction of max health when shifting
274281
healthFrac := druid.CurrentHealth() / druid.MaxHealth()
@@ -294,8 +301,10 @@ func (druid *Druid) RegisterBearFormAura() {
294301
druid.PseudoStats.SpiritRegenMultiplier /= AnimalSpiritRegenSuppression
295302

296303
druid.AddStatsDynamic(sim, statBonus.Invert())
297-
druid.RemoveDynamicEquipScaling(sim, stats.Armor, baseBearArmorMulti)
304+
druid.RemoveDynamicEquipScaling(sim, stats.Armor, BaseBearArmorMulti)
298305
druid.DisableBuildPhaseStatDep(sim, agiApDep)
306+
druid.DisableBuildPhaseStatDep(sim, critDep)
307+
druid.DisableBuildPhaseStatDep(sim, hasteDep)
299308

300309
healthFrac := druid.CurrentHealth() / druid.MaxHealth()
301310
druid.DisableBuildPhaseStatDep(sim, stamDep)
@@ -311,7 +320,6 @@ func (druid *Druid) RegisterBearFormAura() {
311320
druid.AutoAttacks.SetMH(druid.WeaponFromMainHand(druid.DefaultCritMultiplier()))
312321
druid.AutoAttacks.EnableAutoSwing(sim)
313322
druid.UpdateManaRegenRates()
314-
druid.EnrageAura.Deactivate(sim)
315323

316324
if druid.PulverizeAura.IsActive() {
317325
druid.PulverizeAura.Deactivate(sim)

0 commit comments

Comments
 (0)