Skip to content

Commit 63cd7f0

Browse files
authored
Merge pull request #69 from wowsims/fix/mop-attack-table
Update for MoP Hit Tables
2 parents 013fef6 + f3fb06e commit 63cd7f0

6 files changed

Lines changed: 90 additions & 115 deletions

File tree

sim/core/buffs.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,27 +367,27 @@ func registerExclusiveMeleeHaste(aura *Aura, value float64) {
367367
}
368368
func UnholyAura(u *Unit) *Aura {
369369
aura := makeExclusiveBuff(u, BuffConfig{"Unholy Aura", ActionID{SpellID: 55610}, nil})
370-
registerExclusiveMeleeHaste(aura, 0.10)
370+
registerExclusiveMeleeHaste(aura, 1.10)
371371
return aura
372372
}
373373
func CacklingHowlAura(u *Unit) *Aura {
374374
aura := makeExclusiveBuff(u, BuffConfig{"Cackling Howl", ActionID{SpellID: 128432}, nil})
375-
registerExclusiveMeleeHaste(aura, 0.10)
375+
registerExclusiveMeleeHaste(aura, 1.10)
376376
return aura
377377
}
378378
func SerpentsSwiftnessAura(u *Unit) *Aura {
379379
aura := makeExclusiveBuff(u, BuffConfig{"Serpent's Swiftness", ActionID{SpellID: 128433}, nil})
380-
registerExclusiveMeleeHaste(aura, 0.10)
380+
registerExclusiveMeleeHaste(aura, 1.10)
381381
return aura
382382
}
383383
func SwiftbladesCunningAura(u *Unit) *Aura {
384384
aura := makeExclusiveBuff(u, BuffConfig{"Swiftblade's Cunning", ActionID{SpellID: 113742}, nil})
385-
registerExclusiveMeleeHaste(aura, 0.10)
385+
registerExclusiveMeleeHaste(aura, 1.10)
386386
return aura
387387
}
388388
func UnleashedRageAura(u *Unit) *Aura {
389389
aura := makeExclusiveBuff(u, BuffConfig{"Unleashed Rage", ActionID{SpellID: 30809}, nil})
390-
registerExclusiveMeleeHaste(aura, 0.10)
390+
registerExclusiveMeleeHaste(aura, 1.10)
391391
return aura
392392
}
393393

sim/core/spell_outcome.go

Lines changed: 64 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,13 @@ func (spell *Spell) outcomeMeleeWhite(sim *Simulation, result *SpellResult, atta
231231
if unit.PseudoStats.InFrontOfTarget {
232232
if !result.applyAttackTableMiss(spell, attackTable, roll, &chance) &&
233233
!result.applyAttackTableDodge(spell, attackTable, roll, &chance) &&
234-
!result.applyAttackTableParry(spell, attackTable, roll, &chance) &&
235-
!result.applyAttackTableGlance(spell, attackTable, roll, &chance) &&
236-
!result.applyAttackTableBlock(spell, attackTable, roll, &chance) &&
237-
!result.applyAttackTableCrit(spell, attackTable, roll, &chance, countHits) {
238-
result.applyAttackTableHit(spell, countHits)
234+
!result.applyAttackTableParry(spell, attackTable, roll, &chance) {
235+
if result.applyAttackTableGlance(spell, attackTable, roll, &chance) ||
236+
result.applyAttackTableCrit(spell, attackTable, roll, &chance, countHits) {
237+
result.applyAttackTableBlock(sim, spell, attackTable)
238+
} else if !result.applyAttackTableBlock(sim, spell, attackTable) {
239+
result.applyAttackTableHit(spell, countHits)
240+
}
239241
}
240242
} else {
241243
if !result.applyAttackTableMiss(spell, attackTable, roll, &chance) &&
@@ -255,10 +257,12 @@ func (spell *Spell) OutcomeMeleeWhiteNoGlance(sim *Simulation, result *SpellResu
255257
if unit.PseudoStats.InFrontOfTarget {
256258
if !result.applyAttackTableMiss(spell, attackTable, roll, &chance) &&
257259
!result.applyAttackTableDodge(spell, attackTable, roll, &chance) &&
258-
!result.applyAttackTableParry(spell, attackTable, roll, &chance) &&
259-
!result.applyAttackTableBlock(spell, attackTable, roll, &chance) &&
260-
!result.applyAttackTableCrit(spell, attackTable, roll, &chance, true) {
261-
result.applyAttackTableHit(spell, true)
260+
!result.applyAttackTableParry(spell, attackTable, roll, &chance) {
261+
if result.applyAttackTableCrit(spell, attackTable, roll, &chance, true) {
262+
result.applyAttackTableBlock(sim, spell, attackTable)
263+
} else if !result.applyAttackTableBlock(sim, spell, attackTable) {
264+
result.applyAttackTableHit(spell, true)
265+
}
262266
}
263267
} else {
264268
if !result.applyAttackTableMiss(spell, attackTable, roll, &chance) &&
@@ -283,7 +287,8 @@ func (spell *Spell) outcomeMeleeSpecialHit(sim *Simulation, result *SpellResult,
283287
if unit.PseudoStats.InFrontOfTarget {
284288
if !result.applyAttackTableMissNoDWPenalty(spell, attackTable, roll, &chance) &&
285289
!result.applyAttackTableDodge(spell, attackTable, roll, &chance) &&
286-
!result.applyAttackTableParry(spell, attackTable, roll, &chance) {
290+
!result.applyAttackTableParry(spell, attackTable, roll, &chance) &&
291+
!result.applyAttackTableBlock(sim, spell, attackTable) {
287292
result.applyAttackTableHit(spell, countHits)
288293
}
289294
} else {
@@ -310,11 +315,9 @@ func (spell *Spell) outcomeMeleeSpecialHitAndCrit(sim *Simulation, result *Spell
310315
!result.applyAttackTableDodge(spell, attackTable, roll, &chance) &&
311316
!result.applyAttackTableParry(spell, attackTable, roll, &chance) {
312317
if result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
313-
result.applyAttackTableBlock(spell, attackTable, roll, &chance)
314-
} else {
315-
if !result.applyAttackTableBlock(spell, attackTable, roll, &chance) {
316-
result.applyAttackTableHit(spell, countHits)
317-
}
318+
result.applyAttackTableBlock(sim, spell, attackTable)
319+
} else if !result.applyAttackTableBlock(sim, spell, attackTable) {
320+
result.applyAttackTableHit(spell, countHits)
318321
}
319322
}
320323
} else {
@@ -342,7 +345,7 @@ func (spell *Spell) outcomeMeleeWeaponSpecialHitAndCrit(sim *Simulation, result
342345
if !result.applyAttackTableMissNoDWPenalty(spell, attackTable, roll, &chance) &&
343346
!result.applyAttackTableDodge(spell, attackTable, roll, &chance) &&
344347
!result.applyAttackTableParry(spell, attackTable, roll, &chance) &&
345-
!result.applyAttackTableBlock(spell, attackTable, roll, &chance) &&
348+
!result.applyAttackTableBlock(sim, spell, attackTable) &&
346349
!result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
347350
result.applyAttackTableHit(spell, countHits)
348351
}
@@ -366,7 +369,7 @@ func (spell *Spell) outcomeMeleeWeaponSpecialNoCrit(sim *Simulation, result *Spe
366369
if !result.applyAttackTableMissNoDWPenalty(spell, attackTable, roll, &chance) &&
367370
!result.applyAttackTableDodge(spell, attackTable, roll, &chance) &&
368371
!result.applyAttackTableParry(spell, attackTable, roll, &chance) &&
369-
!result.applyAttackTableBlock(spell, attackTable, roll, &chance) {
372+
!result.applyAttackTableBlock(sim, spell, attackTable) {
370373
result.applyAttackTableHit(spell, countHits)
371374
}
372375
} else {
@@ -428,11 +431,9 @@ func (spell *Spell) OutcomeMeleeSpecialBlockAndCritNoHitCounter(sim *Simulation,
428431
}
429432
func (spell *Spell) outcomeMeleeSpecialBlockAndCrit(sim *Simulation, result *SpellResult, attackTable *AttackTable, countHits bool) {
430433
if spell.Unit.PseudoStats.InFrontOfTarget {
431-
roll := sim.RandomFloat("White Hit Table")
432-
chance := 0.0
433-
434-
if !result.applyAttackTableBlock(spell, attackTable, roll, &chance) &&
435-
!result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
434+
if result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
435+
result.applyAttackTableBlock(sim, spell, attackTable)
436+
} else if !result.applyAttackTableBlock(sim, spell, attackTable) {
436437
result.applyAttackTableHit(spell, countHits)
437438
}
438439
} else {
@@ -452,7 +453,8 @@ func (spell *Spell) outcomeRangedHit(sim *Simulation, result *SpellResult, attac
452453
roll := sim.RandomFloat("White Hit Table")
453454
chance := 0.0
454455

455-
if !result.applyAttackTableMissNoDWPenalty(spell, attackTable, roll, &chance) {
456+
if !result.applyAttackTableMissNoDWPenalty(spell, attackTable, roll, &chance) &&
457+
!result.applyAttackTableDodge(spell, attackTable, roll, &chance) {
456458
result.applyAttackTableHit(spell, countHits)
457459
}
458460
}
@@ -467,22 +469,12 @@ func (spell *Spell) outcomeRangedHitAndCrit(sim *Simulation, result *SpellResult
467469
roll := sim.RandomFloat("White Hit Table")
468470
chance := 0.0
469471

470-
if spell.Unit.PseudoStats.InFrontOfTarget {
471-
if !result.applyAttackTableMissNoDWPenalty(spell, attackTable, roll, &chance) {
472-
if result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
473-
result.applyAttackTableBlock(spell, attackTable, roll, &chance)
474-
} else {
475-
if !result.applyAttackTableBlock(spell, attackTable, roll, &chance) {
476-
result.applyAttackTableHit(spell, countHits)
477-
}
478-
}
479-
}
480-
} else {
481-
if !result.applyAttackTableMissNoDWPenalty(spell, attackTable, roll, &chance) &&
482-
!result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
483-
result.applyAttackTableHit(spell, countHits)
484-
}
472+
if !result.applyAttackTableMissNoDWPenalty(spell, attackTable, roll, &chance) &&
473+
!result.applyAttackTableDodge(spell, attackTable, roll, &chance) &&
474+
!result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
475+
result.applyAttackTableHit(spell, countHits)
485476
}
477+
486478
}
487479

488480
func (dot *Dot) OutcomeRangedHitAndCritSnapshot(sim *Simulation, result *SpellResult, attackTable *AttackTable) {
@@ -495,21 +487,10 @@ func (dot *Dot) outcomeRangedHitAndCritSnapshot(sim *Simulation, result *SpellRe
495487
roll := sim.RandomFloat("White Hit Table")
496488
chance := 0.0
497489

498-
if dot.Spell.Unit.PseudoStats.InFrontOfTarget {
499-
if !result.applyAttackTableMissNoDWPenalty(dot.Spell, attackTable, roll, &chance) {
500-
if result.applyAttackTableCritSeparateRollSnapshot(sim, dot) {
501-
result.applyAttackTableBlock(dot.Spell, attackTable, roll, &chance)
502-
} else {
503-
if !result.applyAttackTableBlock(dot.Spell, attackTable, roll, &chance) {
504-
result.applyAttackTableHit(dot.Spell, countHits)
505-
}
506-
}
507-
}
508-
} else {
509-
if !result.applyAttackTableMissNoDWPenalty(dot.Spell, attackTable, roll, &chance) &&
510-
!result.applyAttackTableCritSeparateRollSnapshot(sim, dot) {
511-
result.applyAttackTableHit(dot.Spell, countHits)
512-
}
490+
if !result.applyAttackTableMissNoDWPenalty(dot.Spell, attackTable, roll, &chance) &&
491+
!result.applyAttackTableDodge(dot.Spell, attackTable, roll, &chance) &&
492+
!result.applyAttackTableCritSeparateRollSnapshot(sim, dot) {
493+
result.applyAttackTableHit(dot.Spell, countHits)
513494
}
514495
}
515496

@@ -536,22 +517,9 @@ func (spell *Spell) OutcomeRangedCritOnlyNoHitCounter(sim *Simulation, result *S
536517
spell.outcomeRangedCritOnly(sim, result, attackTable, false)
537518
}
538519
func (spell *Spell) outcomeRangedCritOnly(sim *Simulation, result *SpellResult, attackTable *AttackTable, countHits bool) {
539-
// Block already checks for this, but we can skip the RNG roll which is expensive.
540-
if spell.Unit.PseudoStats.InFrontOfTarget {
541-
roll := sim.RandomFloat("White Hit Table")
542-
chance := 0.0
543520

544-
if result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
545-
result.applyAttackTableBlock(spell, attackTable, roll, &chance)
546-
} else {
547-
if !result.applyAttackTableBlock(spell, attackTable, roll, &chance) {
548-
result.applyAttackTableHit(spell, countHits)
549-
}
550-
}
551-
} else {
552-
if !result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
553-
result.applyAttackTableHit(spell, countHits)
554-
}
521+
if !result.applyAttackTableCritSeparateRoll(sim, spell, attackTable, countHits) {
522+
result.applyAttackTableHit(spell, countHits)
555523
}
556524
}
557525

@@ -567,10 +535,12 @@ func (spell *Spell) outcomeEnemyMeleeWhite(sim *Simulation, result *SpellResult,
567535

568536
if !result.applyEnemyAttackTableMiss(spell, attackTable, roll, &chance) &&
569537
!result.applyEnemyAttackTableDodge(spell, attackTable, roll, &chance) &&
570-
!result.applyEnemyAttackTableParry(spell, attackTable, roll, &chance) &&
571-
!result.applyEnemyAttackTableBlock(sim, spell, attackTable, roll, &chance) &&
572-
!result.applyEnemyAttackTableCrit(spell, attackTable, roll, &chance, countHits) {
573-
result.applyAttackTableHit(spell, countHits)
538+
!result.applyEnemyAttackTableParry(spell, attackTable, roll, &chance) {
539+
if result.applyEnemyAttackTableCrit(spell, attackTable, roll, &chance, countHits) {
540+
result.applyEnemyAttackTableBlock(sim, spell, attackTable)
541+
} else if !result.applyEnemyAttackTableBlock(sim, spell, attackTable) {
542+
result.applyAttackTableHit(spell, countHits)
543+
}
574544
}
575545
}
576546

@@ -613,10 +583,10 @@ func (result *SpellResult) applyAttackTableMissNoDWPenalty(spell *Spell, attackT
613583
return false
614584
}
615585

616-
func (result *SpellResult) applyAttackTableBlock(spell *Spell, attackTable *AttackTable, roll float64, chance *float64) bool {
617-
*chance += attackTable.BaseBlockChance
586+
func (result *SpellResult) applyAttackTableBlock(sim *Simulation, spell *Spell, attackTable *AttackTable) bool {
587+
chance := attackTable.BaseBlockChance
618588

619-
if roll < *chance {
589+
if sim.RandomFloat("Block Roll") < chance {
620590
result.Outcome |= OutcomeBlock
621591
if result.DidCrit() {
622592
spell.SpellMetrics[result.Target.UnitIndex].CritBlocks++
@@ -636,7 +606,7 @@ func (result *SpellResult) applyAttackTableDodge(spell *Spell, attackTable *Atta
636606
return false
637607
}
638608

639-
*chance += max(0, attackTable.BaseDodgeChance-spell.DodgeParrySuppression()-spell.Unit.PseudoStats.DodgeReduction)
609+
*chance += max(0, attackTable.BaseDodgeChance-spell.DodgeSuppression())
640610

641611
if roll < *chance {
642612
result.Outcome = OutcomeDodge
@@ -648,7 +618,7 @@ func (result *SpellResult) applyAttackTableDodge(spell *Spell, attackTable *Atta
648618
}
649619

650620
func (result *SpellResult) applyAttackTableParry(spell *Spell, attackTable *AttackTable, roll float64, chance *float64) bool {
651-
*chance += max(0, attackTable.BaseParryChance-spell.DodgeParrySuppression())
621+
*chance += max(0, attackTable.BaseParryChance-spell.ParrySuppression(attackTable))
652622

653623
if roll < *chance {
654624
result.Outcome = OutcomeParry
@@ -739,16 +709,20 @@ func (result *SpellResult) applyEnemyAttackTableMiss(spell *Spell, attackTable *
739709
return false
740710
}
741711

742-
func (result *SpellResult) applyEnemyAttackTableBlock(sim *Simulation, spell *Spell, attackTable *AttackTable, roll float64, chance *float64) bool {
712+
func (result *SpellResult) applyEnemyAttackTableBlock(sim *Simulation, spell *Spell, attackTable *AttackTable) bool {
743713
if !result.Target.PseudoStats.CanBlock || result.Target.PseudoStats.Stunned {
744714
return false
745715
}
746716

747-
*chance += result.Target.GetTotalBlockChanceAsDefender(attackTable)
717+
chance := result.Target.GetTotalBlockChanceAsDefender(attackTable)
748718

749-
if roll < *chance {
719+
if sim.RandomFloat("Player Block") < chance {
750720
result.Outcome |= OutcomeBlock
751-
spell.SpellMetrics[result.Target.UnitIndex].Blocks++
721+
if result.DidCrit() {
722+
spell.SpellMetrics[result.Target.UnitIndex].CritBlocks++
723+
} else {
724+
spell.SpellMetrics[result.Target.UnitIndex].Blocks++
725+
}
752726

753727
if result.Target.Blockhandler != nil {
754728
result.Target.Blockhandler(sim, spell, result)
@@ -767,7 +741,7 @@ func (result *SpellResult) applyEnemyAttackTableDodge(spell *Spell, attackTable
767741
return false
768742
}
769743

770-
*chance += max(result.Target.GetTotalDodgeChanceAsDefender(attackTable)-spell.Unit.PseudoStats.DodgeReduction, 0.0)
744+
*chance += max(result.Target.GetTotalDodgeChanceAsDefender(attackTable), 0.0)
771745

772746
if roll < *chance {
773747
result.Outcome = OutcomeDodge
@@ -850,24 +824,24 @@ func (spell *Spell) OutcomeExpectedMagicHitAndCrit(_ *Simulation, result *SpellR
850824

851825
func (spell *Spell) OutcomeExpectedMeleeWhite(_ *Simulation, result *SpellResult, attackTable *AttackTable) {
852826
missChance := spell.GetPhysicalMissChance(attackTable)
853-
dodgeChance := TernaryFloat64(spell.Flags.Matches(SpellFlagCannotBeDodged), 0, max(0, attackTable.BaseDodgeChance-spell.DodgeParrySuppression()-spell.Unit.PseudoStats.DodgeReduction))
854-
parryChance := TernaryFloat64(spell.Unit.PseudoStats.InFrontOfTarget, max(0, attackTable.BaseParryChance-spell.DodgeParrySuppression()), 0)
827+
dodgeChance := TernaryFloat64(spell.Flags.Matches(SpellFlagCannotBeDodged), 0, max(0, attackTable.BaseDodgeChance-spell.DodgeSuppression()))
828+
parryChance := TernaryFloat64(spell.Unit.PseudoStats.InFrontOfTarget, max(0, attackTable.BaseParryChance-spell.ParrySuppression(attackTable)), 0)
855829
glanceChance := attackTable.BaseGlanceChance
856830
blockChance := TernaryFloat64(spell.Unit.PseudoStats.InFrontOfTarget, attackTable.BaseBlockChance, 0)
857-
whiteCritCap := 1.0 - missChance - dodgeChance - parryChance - glanceChance - blockChance
831+
whiteCritCap := 1.0 - missChance - dodgeChance - parryChance - glanceChance
858832
critChance := min(spell.PhysicalCritChance(attackTable), whiteCritCap)
859-
averageMultiplier := 1.0 - missChance - dodgeChance - parryChance + (spell.CritDamageMultiplier()-1)*critChance - glanceChance*(1.0-attackTable.GlanceMultiplier) - blockChance*result.Target.BlockDamageReduction()
833+
averageMultiplier := (1.0 - missChance - dodgeChance - parryChance + (spell.CritDamageMultiplier()-1)*critChance - glanceChance*(1.0-attackTable.GlanceMultiplier)) * (1.0 - blockChance*result.Target.BlockDamageReduction())
860834
result.Damage *= averageMultiplier
861835
}
862836

863837
func (spell *Spell) OutcomeExpectedMeleeWeaponSpecialHitAndCrit(_ *Simulation, result *SpellResult, attackTable *AttackTable) {
864838
missChance := max(0, attackTable.BaseMissChance-spell.PhysicalHitChance(attackTable))
865-
dodgeChance := TernaryFloat64(spell.Flags.Matches(SpellFlagCannotBeDodged), 0, max(0, attackTable.BaseDodgeChance-spell.DodgeParrySuppression()-spell.Unit.PseudoStats.DodgeReduction))
866-
parryChance := TernaryFloat64(spell.Unit.PseudoStats.InFrontOfTarget, max(0, attackTable.BaseParryChance-spell.DodgeParrySuppression()), 0)
839+
dodgeChance := TernaryFloat64(spell.Flags.Matches(SpellFlagCannotBeDodged), 0, max(0, attackTable.BaseDodgeChance-spell.DodgeSuppression()))
840+
parryChance := TernaryFloat64(spell.Unit.PseudoStats.InFrontOfTarget, max(0, attackTable.BaseParryChance-spell.ParrySuppression(attackTable)), 0)
867841
blockChance := TernaryFloat64(spell.Unit.PseudoStats.InFrontOfTarget, attackTable.BaseBlockChance, 0)
868842
critChance := spell.PhysicalCritChance(attackTable)
869-
averageMultiplier := (1.0 - missChance - dodgeChance - parryChance) * (1.0 + (spell.CritDamageMultiplier()-1)*critChance)
870-
averageMultiplier -= blockChance * ((spell.CritDamageMultiplier()-1)*critChance + result.Target.BlockDamageReduction())
843+
critFactor := (spell.CritDamageMultiplier() - 1) * critChance
844+
averageMultiplier := (1.0 - missChance - dodgeChance - parryChance) * (1.0 + critFactor - blockChance*(critFactor+result.Target.BlockDamageReduction()))
871845
result.Damage *= averageMultiplier
872846
}
873847

sim/core/spell_result.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,18 @@ func (spell *Spell) RangedAttackPower() float64 {
8484
return spell.Unit.stats[stats.RangedAttackPower]
8585
}
8686

87-
func (spell *Spell) DodgeParrySuppression() float64 {
88-
// As of 06/20, Blizzard has changed Expertise to no longer truncate at quarter
89-
// percent intervals. Note that in-game character sheet tooltips will still
90-
// display the truncated values, but it has been tested to behave continuously in
91-
// reality since the patch.
87+
func (spell *Spell) DodgeSuppression() float64 {
9288
expertiseRating := spell.Unit.stats[stats.ExpertiseRating] + spell.BonusExpertiseRating
9389
return expertiseRating / ExpertisePerQuarterPercentReduction / 400
9490
}
9591

92+
// MoP reworked Parry. Rather than being innately ~2x Dodge chance, expertise now applies to Dodge first (down to 0), and then Parry.
93+
// The base chance for Dodge/Parry are both 7.5%, assuming a +3 target. The 7.5% Dodge chance must be fully suppressed before Parry will go down.
94+
// This makes the effect of each point of Expertise linear when attacking from the front
95+
func (spell *Spell) ParrySuppression(attackTable *AttackTable) float64 {
96+
return max(0, spell.DodgeSuppression()-attackTable.BaseDodgeChance)
97+
}
98+
9699
func (spell *Spell) PhysicalHitChance(attackTable *AttackTable) float64 {
97100
hitPercent := spell.Unit.stats[stats.PhysicalHitPercent] + spell.BonusHitPercent
98101
return hitPercent / 100

sim/core/stats/stats.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,6 @@ type PseudoStats struct {
407407

408408
DisableDWMissPenalty bool // Used by Heroic Strike and Cleave
409409
IncreasedMissChance float64 // Insect Swarm and Scorpid Sting
410-
DodgeReduction float64 // Used by Warrior talent 'Weapon Mastery' and SWP boss auras.
411410

412411
ThreatMultiplier float64 // Modulates the threat generated. Affected by things like salv.
413412

0 commit comments

Comments
 (0)