From 01c2261d3afac9c7207d5c5c1b5ee7282102370c Mon Sep 17 00:00:00 2001 From: Sam Willis Date: Tue, 26 Mar 2024 15:54:39 -0700 Subject: [PATCH 1/2] Pull target-specific avoidance calculations into their own functions --- sim/core/constants.go | 2 ++ sim/core/spell_outcome.go | 18 ++++-------------- sim/core/unit.go | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/sim/core/constants.go b/sim/core/constants.go index 563a9b6339..cc6a4b108a 100644 --- a/sim/core/constants.go +++ b/sim/core/constants.go @@ -38,3 +38,5 @@ type Hand bool const MainHand Hand = true const OffHand Hand = false + +const CombatTableCoverageCap = 1.024 // 102.4% chance to avoid an attack diff --git a/sim/core/spell_outcome.go b/sim/core/spell_outcome.go index 5553fc5a00..71760d0050 100644 --- a/sim/core/spell_outcome.go +++ b/sim/core/spell_outcome.go @@ -504,7 +504,7 @@ func (result *SpellResult) applyAttackTableHit(spell *Spell) { } func (result *SpellResult) applyEnemyAttackTableMiss(spell *Spell, attackTable *AttackTable, roll float64, chance *float64) bool { - missChance := attackTable.BaseMissChance + spell.Unit.PseudoStats.IncreasedMissChance + result.Target.GetDiminishedMissChance() + result.Target.PseudoStats.ReducedPhysicalHitTakenChance + missChance := result.Target.GetTotalChanceToBeMissedAsDefender(attackTable) + spell.Unit.PseudoStats.IncreasedMissChance if spell.Unit.AutoAttacks.IsDualWielding && !spell.Unit.PseudoStats.DisableDWMissPenalty { missChance += 0.19 } @@ -524,10 +524,7 @@ func (result *SpellResult) applyEnemyAttackTableBlock(spell *Spell, attackTable return false } - blockChance := attackTable.BaseBlockChance + - result.Target.stats[stats.Block]/BlockRatingPerBlockChance/100 + - result.Target.stats[stats.Defense]*DefenseRatingToChanceReduction - *chance += max(0, blockChance) + *chance = result.Target.GetTotalBlockChanceAsDefender(attackTable) if roll < *chance { result.Outcome |= OutcomeBlock @@ -543,11 +540,7 @@ func (result *SpellResult) applyEnemyAttackTableDodge(spell *Spell, attackTable return false } - dodgeChance := attackTable.BaseDodgeChance + - result.Target.PseudoStats.BaseDodge + - result.Target.GetDiminishedDodgeChance() - - spell.Unit.PseudoStats.DodgeReduction - *chance += max(0, dodgeChance) + *chance = result.Target.GetTotalDodgeChanceAsDefender(attackTable) - spell.Unit.PseudoStats.DodgeReduction if roll < *chance { result.Outcome = OutcomeDodge @@ -563,10 +556,7 @@ func (result *SpellResult) applyEnemyAttackTableParry(spell *Spell, attackTable return false } - parryChance := attackTable.BaseParryChance + - result.Target.PseudoStats.BaseParry + - result.Target.GetDiminishedParryChance() - *chance += max(0, parryChance) + *chance = result.Target.GetTotalParryChanceAsDefender(attackTable) if roll < *chance { result.Outcome = OutcomeParry diff --git a/sim/core/unit.go b/sim/core/unit.go index 11202bda7e..bde2bf27e1 100644 --- a/sim/core/unit.go +++ b/sim/core/unit.go @@ -1,6 +1,7 @@ package core import ( + "math" "time" "github.com/wowsims/cata/sim/core/proto" @@ -556,3 +557,39 @@ func (unit *Unit) GetMetadata() *proto.UnitMetadata { func (unit *Unit) ExecuteCustomRotation(sim *Simulation) { panic("Unimplemented ExecuteCustomRotation") } + +func (unit *Unit) GetTotalDodgeChanceAsDefender(atkTable *AttackTable) float64 { + chance := unit.PseudoStats.BaseDodge + + atkTable.BaseDodgeChance + + unit.GetDiminishedDodgeChance() + return math.Max(chance, 0.0) +} + +func (unit *Unit) GetTotalParryChanceAsDefender(atkTable *AttackTable) float64 { + chance := unit.PseudoStats.BaseParry + + atkTable.BaseParryChance + + unit.GetDiminishedParryChance() + return math.Max(chance, 0.0) +} + +func (unit *Unit) GetTotalChanceToBeMissedAsDefender(atkTable *AttackTable) float64 { + chance := atkTable.BaseMissChance + + unit.GetDiminishedMissChance() + + unit.PseudoStats.ReducedPhysicalHitTakenChance + return math.Max(chance, 0.0) +} + +func (unit *Unit) GetTotalBlockChanceAsDefender(atkTable *AttackTable) float64 { + chance := atkTable.BaseBlockChance + + unit.GetStat(stats.Block)/BlockRatingPerBlockChance/100 + + unit.GetStat(stats.Defense)*DefenseRatingToChanceReduction + return math.Max(chance, 0.0) +} + +func (unit *Unit) GetTotalAvoidanceChance(atkTable *AttackTable) float64 { + miss := unit.GetTotalChanceToBeMissedAsDefender(atkTable) + dodge := unit.GetTotalDodgeChanceAsDefender(atkTable) + parry := unit.GetTotalParryChanceAsDefender(atkTable) + block := unit.GetTotalBlockChanceAsDefender(atkTable) + return miss + dodge + parry + block +} From 39c2d551a73042da64d97c2d884169cc68bbea9f Mon Sep 17 00:00:00 2001 From: Sam Willis Date: Tue, 26 Mar 2024 16:00:29 -0700 Subject: [PATCH 2/2] tweak --- sim/core/spell_outcome.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim/core/spell_outcome.go b/sim/core/spell_outcome.go index 71760d0050..c18e4edf75 100644 --- a/sim/core/spell_outcome.go +++ b/sim/core/spell_outcome.go @@ -540,7 +540,7 @@ func (result *SpellResult) applyEnemyAttackTableDodge(spell *Spell, attackTable return false } - *chance = result.Target.GetTotalDodgeChanceAsDefender(attackTable) - spell.Unit.PseudoStats.DodgeReduction + *chance = max(result.Target.GetTotalDodgeChanceAsDefender(attackTable)-spell.Unit.PseudoStats.DodgeReduction, 0.0) if roll < *chance { result.Outcome = OutcomeDodge