Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Modules/Data/Data.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ dataFunctionRefs = {
["AvoidanceBoss"] = function() return Data:GetAvoidance(enemyLevel) end,
["DefenseRating"] = function() return ECS.IsClassic and 0 or Data:GetDefenseRating() end,
["DefenseValue"] = function() return Data:GetDefenseValue() end,
["DodgeChance"] = function() return Data:GetDodgeChance() end,
["ParryChance"] = function() return Data:GetParryChance() end,
["BlockChance"] = function() return Data:GetBlockChance() end,
["DodgeChance"] = function() return Data:GetDodgeChance(playerLevel) end,
["ParryChance"] = function() return Data:GetParryChance(playerLevel) end,
["BlockChance"] = function() return Data:GetBlockChance(playerLevel) end,
["BlockValue"] = function() return Data:GetBlockValue() end,
["ResilienceValue"] = function() return ECS.IsClassic and 0 or Data:GetResilienceRating() end,
-- Spell
Expand Down
37 changes: 24 additions & 13 deletions Modules/Data/Defense.lua
Original file line number Diff line number Diff line change
Expand Up @@ -143,37 +143,45 @@ function _Defense:GetEnemyMissChance(enemyLevel)
return miss
end

---@param enemyLevel number
---@return number
function _Defense:GetBlockChance()
function _Defense:GetBlockChance(enemyLevel)
local block = 0
if C_SpellBook.IsSpellKnown(107) and C_PaperDollInfo.OffhandHasShield() then
block = GetBlockChance()
block = GetBlockChance() + ((UnitLevel("player") - enemyLevel) * .20)
end
return block
end

---@param enemyLevel number
---@return number
function _Defense:GetParryChance()
function _Defense:GetParryChance(enemyLevel)
local parry = 0
if C_SpellBook.IsSpellKnown(3127) or C_SpellBook.IsSpellKnown(18848) or C_SpellBook.IsSpellKnown(3124) then
parry = GetParryChance()
-- In theory we should compare the player's base defense skill with
-- the attacker's weapon skill. Unfortunately there's no API function
-- to retrieve the former. The following formula leads to the same
-- results except when the player just gained a level and his/her
-- defense skill did not catch up yet.
Comment on lines +161 to +165

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't Data:GetDefenseValue() suffice here? We use it for enemy miss chance as well 🤔

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately Data:GetDefenseValue() is based on UnitDefense() which takes talents into account. Specifically when testing on my level 70 paladin, this function returns 370 and not 350, because of talent Anticipation 5/5. However the parry chance penalty that should be applied must be computed by comparing the player's base Defense (without gear nor talents) with the attacker's base weapon skill.
I looked for an API function which would return the base Defense value, without talent modifiers, but could not find any. If you know of a way to obtain this value, please let me know.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, your use of Data:GetDefenseValue() to compute the chance to be critically hit and the chance to be missed, is correct, because this function adds both values returned by Data:GetDefenseValue(). While each value is individually incorrect (the talents contribution should be in the second value, not the first value in my opinion), the sum is right.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The simulator is using full defense here https://github.com/wowsims/tbc-new/blob/aa7b0e67211802856ef7e78e9d16be8498b5cff8/sim/core/unit.go#L913

But method ‎Unit.GetTotalAvoidanceChance is not called anywhere, so this is all effectively dead code. I can't see how that code could be correct anyway as the enemy's attack skill is not even factored in.

OTOH, I tested my gear in the online simulator at https://www.wowsims.com/tbc/paladin/protection/ and it displays the same (same-level) Dodge chance %, Parry chance % and Block chance % as the current ECS code and the default WoW BC interface.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So @jdelvare @Alessandro-Barbieri are we fine with the current implementation of the fix then?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think the proposed fix should be applied.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No Blizzard is using full defense in the paperdoll https://github.com/Gethe/wow-ui-source/blob/4cca594e4db26f8addc25b0c08aba144b00d2b67/Interface/AddOns/Blizzard_CharacterFrame/TBC/PaperDollFrame.lua#L598

This function is only used to display extra details for the Defense skill in the paperdoll view. It tells the player how much Defense contributes to Dodge, Parry and Dodge chance. It is not used to compute the Dodge, Parry and Block chance values, because the contribution from Defense is already included in the values returned by GetDodgeChance(), GetParryChance() and GetBlockChance(). It is thus irrelevant to this pull request, and more generally to the functions this pull request is modifying.

I would add that function GetDodgeBlockParryChanceFromDefense() in Blizzard's UI does not actually use the full defense. It starts from the full defense value, yes, but then subtracts UnitLevel("player")*5, which is essentially equal to the base defense (except during leveling). So in practice, this function uses the defense from gear and consumables to compute the contribution to Dodge, Parry and Dodge chance, not the full defense value. As a matter of fact, if you display the Blizzard paperdoll tooltip for Defense on a non-tank character (no defense gear), the value displayed is 0.00%, even though the base defense Skill is not 0.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Afterall I got at the same formula you used but from different premises
See #452 (comment)
I only ask you to remove the comment above because it's misleading, the formula should be correct even if you have unleveled defense.

parry = GetParryChance() + ((UnitLevel("player") - enemyLevel) * .20)
end
return parry
end

---@param enemyLevel number
---@return number
function _Defense:GetDodgeChance()
function _Defense:GetDodgeChance(enemyLevel)
local dodge = 0
if C_SpellBook.IsSpellKnown(81) then
dodge = GetDodgeChance()
dodge = GetDodgeChance() + ((UnitLevel("player") - enemyLevel) * .20)
end
return dodge
end

---@param enemyLevel number
---@return number
function _Defense:GetAvoidance(enemyLevel)
return _Defense:GetEnemyMissChance(enemyLevel) + _Defense:GetBlockChance() + _Defense:GetParryChance() + _Defense:GetDodgeChance()
return _Defense:GetEnemyMissChance(enemyLevel) + _Defense:GetBlockChance(enemyLevel) + _Defense:GetParryChance(enemyLevel) + _Defense:GetDodgeChance(enemyLevel)
end

---@return number
Expand All @@ -191,19 +199,22 @@ function Data:GetDefenseValue()
return skillRank + skillModifier
end

---@param enemyLevel number
---@return string
function Data:GetDodgeChance()
return DataUtils:Round(_Defense:GetDodgeChance(), 2) .. "%"
function Data:GetDodgeChance(enemyLevel)
return DataUtils:Round(_Defense:GetDodgeChance(enemyLevel), 2) .. "%"
end

---@param enemyLevel number
---@return string
function Data:GetParryChance()
return DataUtils:Round(_Defense:GetParryChance(), 2) .. "%"
function Data:GetParryChance(enemyLevel)
return DataUtils:Round(_Defense:GetParryChance(enemyLevel), 2) .. "%"
end

---@param enemyLevel number
---@return string
function Data:GetBlockChance()
return DataUtils:Round(_Defense:GetBlockChance(), 2) .. "%"
function Data:GetBlockChance(enemyLevel)
return DataUtils:Round(_Defense:GetBlockChance(enemyLevel), 2) .. "%"
end

---@param enemyLevel number
Expand Down