diff --git a/spec/System/TestOffence_spec.lua b/spec/System/TestOffence_spec.lua new file mode 100644 index 0000000000..2e8ca720f0 --- /dev/null +++ b/spec/System/TestOffence_spec.lua @@ -0,0 +1,44 @@ +describe("TestOffence", function() + before_each(function() + newBuild() + end) + + teardown(function() + -- newBuild() takes care of resetting everything in setup() + end) + + it("rounds each scaled damage conversion to a whole percent", function() + build.skillsTab:PasteSocketGroup("Fireball 20/0 1") + build.configTab.input.customMods = [[ + 40% of Physical Damage Converted to Lightning Damage + 40% of Physical Damage Converted to Cold Damage + 40% of Physical Damage Converted to Fire Damage + ]] + build.configTab:BuildModList() + runCallback("OnFrame") + + local conversion = build.calcsTab.mainEnv.player.mainSkill.conversionTable.Physical + assert.are.equals(0.33, conversion.Lightning) + assert.are.equals(0.33, conversion.Cold) + assert.are.equals(0.33, conversion.Fire) + assert.is_true(math.abs(conversion.mult - 0.01) < 0.000001) + end) + + it("keeps converted damage fractional until destination calculation", function() + build.itemsTab:CreateDisplayItemFromRaw([[ + New Item + Attuned Wand + Adds 2 to 2 Physical Damage to Spells + ]]) + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Fireball 20/0 1") + build.configTab.input.customMods = [[ + 25% of Physical Damage Converted to Cold Damage + ]] + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(2, build.calcsTab.mainOutput.PhysicalMinBase) + assert.are.equals(0.5, build.calcsTab.mainOutput.ColdSummedMinBase) + end) +end) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 40425570cc..4350d8f3b0 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -81,11 +81,6 @@ local function calcConvertedDamage(activeSkill, output, cfg, damageType) convertedMax = convertedMax + (max or 0) * convMult end end - if convertedMin ~= 0 and convertedMax ~= 0 then - convertedMin = round(convertedMin) - convertedMax = round(convertedMax) - end - return convertedMin, convertedMax end @@ -2390,6 +2385,17 @@ function calcs.offence(env, actor, activeSkill) end end + -- The game stores each final conversion destination as a whole percent. + local convertedTotal = 0 + for toType, amount in pairs(activeSkill.conversionTable[damageType]) do + if toType ~= "mult" then + local conversion = round(amount * 100) + activeSkill.conversionTable[damageType][toType] = conversion / 100 + convertedTotal = convertedTotal + conversion + end + end + activeSkill.conversionTable[damageType].mult = 1 - m_min(convertedTotal / 100, 1) + end -- Configure damage passes @@ -4029,10 +4035,10 @@ function calcs.offence(env, actor, activeSkill) t_insert(breakdown[damageType], "Base damage:") end if convertedMin ~= 0 or convertedMax ~= 0 then - t_insert(breakdown[damageType], s_format("+ %d to %d ^8(damage converted from other damage types)", convertedMin, convertedMax)) + t_insert(breakdown[damageType], s_format("+ %d to %d ^8(damage converted from other damage types)", round(convertedMin), round(convertedMax))) end if gainedMin ~= 0 or gainedMax ~= 0 then - t_insert(breakdown[damageType], s_format("+ %d to %d ^8(damage gained from other damage types)", gainedMin, gainedMax)) + t_insert(breakdown[damageType], s_format("+ %d to %d ^8(damage gained from other damage types)", round(gainedMin), round(gainedMax))) end t_insert(breakdown[damageType], s_format("= %.1f to %.1f", summedMin, summedMax)) end