diff --git a/spec/System/TestOffence_spec.lua b/spec/System/TestOffence_spec.lua index d93047e864..63a08da3f1 100644 --- a/spec/System/TestOffence_spec.lua +++ b/spec/System/TestOffence_spec.lua @@ -50,6 +50,42 @@ describe("TestOffence", function() assert.are.equals(damageWithoutArrowMod, build.calcsTab.mainOutput.AverageDamage) 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.conversion.Lightning) + assert.are.equals(0.33, conversion.conversion.Cold) + assert.are.equals(0.33, conversion.conversion.Fire) + assert.is_true(math.abs(conversion.mult - 0.01) < 0.000001) + end) + + it("rounds damage after the final step of a conversion path", function() + build.itemsTab:CreateDisplayItemFromRaw([[ + New Item + Imbued Wand + Adds 2 to 2 Physical Damage to Spells + ]]) + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Fireball 20/0 1") + build.configTab.input.customMods = [[ + 50% of Physical Damage Converted to Lightning Damage + 50% of Lightning Damage Converted to Cold Damage + ]] + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(9.6, build.calcsTab.calcsOutput.PhysicalMinBase) + assert.are.equals(1, build.calcsTab.calcsOutput.ColdMin) + end) + it("parses more/less/increased/reduced minimum and maximum damage of every type", function() build.itemsTab:CreateDisplayItemFromRaw([[ New Item diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 3fd3f028e3..b85bbcabd5 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -87,11 +87,6 @@ local function calcDamage(activeSkill, output, cfg, breakdown, damageType, typeF addMax = addMax + max * convMult end end - if addMin ~= 0 and addMax ~= 0 then - addMin = round(addMin) - addMax = round(addMax) - end - local baseMin = output[damageType.."MinBase"] local baseMax = output[damageType.."MaxBase"] if baseMin == 0 and baseMax == 0 then @@ -99,13 +94,16 @@ local function calcDamage(activeSkill, output, cfg, breakdown, damageType, typeF if breakdown and (addMin ~= 0 or addMax ~= 0) then t_insert(breakdown.damageTypes, { source = damageType, - convSrc = (addMin ~= 0 or addMax ~= 0) and (addMin .. " to " .. addMax), - total = addMin .. " to " .. addMax, + convSrc = (addMin ~= 0 or addMax ~= 0) and (round(addMin) .. " to " .. round(addMax)), + total = round(addMin) .. " to " .. round(addMax), convDst = convDst and s_format("%d%% to %s", conversionTable[damageType].conversion[convDst] * 100, convDst), gainDst = convDst and s_format("%d%% gained as %s", conversionTable[damageType].gain[convDst] * 100, convDst), }) end - return addMin, addMax + if convDst then + return addMin, addMax + end + return round(addMin), round(addMax) end -- Combine modifiers @@ -125,15 +123,20 @@ local function calcDamage(activeSkill, output, cfg, breakdown, damageType, typeF base = baseMin .. " to " .. baseMax, inc = (inc ~= 1 and "x "..inc), more = (more ~= 1 and "x "..more), - convSrc = (addMin ~= 0 or addMax ~= 0) and (addMin .. " to " .. addMax), - total = (round(baseMin * inc * more) + addMin) .. " to " .. (round(baseMax * inc * more) + addMax), + convSrc = (addMin ~= 0 or addMax ~= 0) and (round(addMin) .. " to " .. round(addMax)), + total = round(baseMin * inc * more + addMin) .. " to " .. round(baseMax * inc * more + addMax), convDst = convDst and conversionTable[damageType].conversion[convDst] > 0 and s_format("%d%% to %s", conversionTable[damageType].conversion[convDst] * 100, convDst), gainDst = convDst and conversionTable[damageType].gain[convDst] > 0 and s_format("%d%% gained as %s", conversionTable[damageType].gain[convDst] * 100, convDst), }) end - return round(((baseMin * inc * more) * genericMoreMinDamage + addMin) * moreMinDamage * incMinDamage), - round(((baseMax * inc * more) * genericMoreMaxDamage + addMax) * moreMaxDamage * incMaxDamage) + local min = ((baseMin * inc * more) * genericMoreMinDamage + addMin) * moreMinDamage * incMinDamage + local max = ((baseMax * inc * more) * genericMoreMaxDamage + addMax) * moreMaxDamage * incMaxDamage + if convDst then + -- Converted paths stay fractional until they reach their final damage type. + return min, max + end + return round(min), round(max) end local function calcAilmentSourceDamage(activeSkill, output, cfg, breakdown, damageType, typeFlags) @@ -1911,12 +1914,16 @@ function calcs.offence(env, actor, activeSkill) globalTotal = globalTotal * factor end local dmgTable = { conversion = { }, gain = { } } + local convertedTotal = 0 for type in pairs(globalConv) do - dmgTable.conversion[type] = (globalConv[type] + skillConv[type]) / 100 + -- The game stores each scaled conversion destination as a whole percent. + local conversion = round(globalConv[type] + skillConv[type]) + dmgTable.conversion[type] = conversion / 100 dmgTable.gain[type] = add[type] / 100 - dmgTable[type] = (globalConv[type] + skillConv[type] + add[type]) / 100 + dmgTable[type] = (conversion + add[type]) / 100 + convertedTotal = convertedTotal + conversion end - dmgTable.mult = 1 - m_min((globalTotal + skillTotal) / 100, 1) + dmgTable.mult = 1 - m_min(convertedTotal / 100, 1) conversionTable[damageType] = dmgTable end conversionTable["Chaos"] = { mult = 1 }