@@ -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}
429432func (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
488480func (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}
538519func (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
650620func (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
851825func (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
863837func (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
0 commit comments