diff --git a/spec/System/TestItemTools_spec.lua b/spec/System/TestItemTools_spec.lua new file mode 100644 index 00000000..eef55cb7 --- /dev/null +++ b/spec/System/TestItemTools_spec.lua @@ -0,0 +1,48 @@ +local applyRangeTests = { + -- Number without range + [{ "+10 to maximum Life", 1.0, 1.0 }] = "+10 to maximum Life", + [{ "+10 to maximum Life", 1.0, 1.5 }] = "+15 to maximum Life", + [{ "+10 to maximum Life", 0.5, 1.0 }] = "+10 to maximum Life", + [{ "+10 to maximum Life", 0.5, 1.5 }] = "+15 to maximum Life", + -- One range + [{ "+(10-20) to maximum Life", 1.0, 1.0 }] = "+20 to maximum Life", + [{ "+(10-20) to maximum Life", 1.0, 1.5 }] = "+30 to maximum Life", + [{ "+(10-20) to maximum Life", 0.5, 1.0 }] = "+15 to maximum Life", + [{ "+(10-20) to maximum Life", 0.5, 1.5 }] = "+22 to maximum Life", + -- Two ranges + [{ "Adds (60-80) to (270-300) Physical Damage", 1.0, 1.0 }] = "Adds 80 to 300 Physical Damage", + [{ "Adds (60-80) to (270-300) Physical Damage", 1.0, 1.5 }] = "Adds 120 to 450 Physical Damage", + [{ "Adds (60-80) to (270-300) Physical Damage", 0.5, 1.0 }] = "Adds 70 to 285 Physical Damage", + [{ "Adds (60-80) to (270-300) Physical Damage", 0.5, 1.5 }] = "Adds 105 to 427 Physical Damage", + -- Range with increased/reduced + [{ "(10--10)% increased Charges per use", 1.0, 1.0 }] = "10% reduced Charges per use", + [{ "(10--10)% increased Charges per use", 1.0, 1.5 }] = "15% reduced Charges per use", + [{ "(10--10)% increased Charges per use", 0.5, 1.0 }] = "0% increased Charges per use", + [{ "(10--10)% increased Charges per use", 0.5, 1.5 }] = "0% increased Charges per use", + [{ "(10--10)% increased Charges per use", 0.0, 1.0 }] = "10% increased Charges per use", + [{ "(10--10)% increased Charges per use", 0.0, 1.5 }] = "15% increased Charges per use", + -- Range with constant numbers after + [{ "(15-20)% increased Cold Damage per 1% Cold Resistance above 75%", 1.0, 1.0 }] = "20% increased Cold Damage per 1% Cold Resistance above 75%", + [{ "(15-20)% increased Cold Damage per 1% Cold Resistance above 75%", 1.0, 1.5 }] = "30% increased Cold Damage per 1% Cold Resistance above 75%", + [{ "(15-20)% increased Cold Damage per 1% Cold Resistance above 75%", 0.5, 1.0 }] = "18% increased Cold Damage per 1% Cold Resistance above 75%", + [{ "(15-20)% increased Cold Damage per 1% Cold Resistance above 75%", 0.5, 1.5 }] = "27% increased Cold Damage per 1% Cold Resistance above 75%", + -- High precision range + [{ "Regenerate (66.7-75) Life per second", 1.0, 1.0 }] = "Regenerate 75 Life per second", + [{ "Regenerate (66.7-75) Life per second", 1.0, 1.5 }] = "Regenerate 112.5 Life per second", + [{ "Regenerate (66.7-75) Life per second", 0.5, 1.0 }] = "Regenerate 70.9 Life per second", + [{ "Regenerate (66.7-75) Life per second", 0.5, 1.5 }] = "Regenerate 106.3 Life per second", + -- Range with plus sign that is removed when negative + [{ "+(-25-50)% to Fire Resistance", 1.0, 1.0 }] = "+50% to Fire Resistance", + [{ "+(-25-50)% to Fire Resistance", 1.0, 1.5 }] = "+75% to Fire Resistance", + [{ "+(-25-50)% to Fire Resistance", 0.0, 1.0 }] = "-25% to Fire Resistance", + [{ "+(-25-50)% to Fire Resistance", 0.0, 1.5 }] = "-37% to Fire Resistance", +} + +describe("TestItemTools", function() + for args, expected in pairs(applyRangeTests) do + it(string.format("tests applyRange('%s', %.2f, %.2f)", unpack(args)), function() + local result = itemLib.applyRange(unpack(args)) + assert.are.equals(expected, result) + end) + end +end) \ No newline at end of file diff --git a/src/Data/Rares.lua b/src/Data/Rares.lua index ea43bab1..3ddc4c36 100644 --- a/src/Data/Rares.lua +++ b/src/Data/Rares.lua @@ -563,9 +563,9 @@ Suffix: FireResist4 Suffix: ColdResist4 Suffix: LightningResist4 Implicits: 3 -{variant:1}+(12 to 16)% to Fire and Cold Resistances -{variant:2}+(12 to 16)% to Cold and Lightning Resistances -{variant:3}+(12 to 16)% to Fire and Lightning Resistances +{variant:1}+(12-16)% to Fire and Cold Resistances +{variant:2}+(12-16)% to Cold and Lightning Resistances +{variant:3}+(12-16)% to Fire and Lightning Resistances ]],[[ Ring Unset Ring diff --git a/src/Modules/ItemTools.lua b/src/Modules/ItemTools.lua index 105691f7..93c51f60 100644 --- a/src/Modules/ItemTools.lua +++ b/src/Modules/ItemTools.lua @@ -59,18 +59,39 @@ function itemLib.getLineRangeMinMax(line) return rangeMin, rangeMax end --- Apply range value (0 to 1) to a modifier that has a range: (x to x) or (x-x to x-x) +local antonyms = { + ["increased"] = "reduced", + ["reduced"] = "increased", + ["more"] = "less", + ["less"] = "more", +} + +-- Apply range value (0 to 1) to a modifier that has a range: "(x-x)" or "(x-x) to (x-x)" function itemLib.applyRange(line, range, valueScalar) - local numbers = 0 - local precision = nil + local precisionSame = true -- Create a line with ranges removed to check if the mod is a high precision mod. - local testLine = line:gsub("%((%d+)%-(%d+) to (%d+)%-(%d+)%)", "(%1-%2) to (%3-%4)") - :gsub("(%+?)%((%-?%d+) to (%d+)%)", "%1(%2-%3)") - :gsub("(%+?)%((%-?%d+%.?%d*)%-(%-?%d+%.?%d*)%)", function(plus, min, max) return plus.."1" end) - :gsub("%-(%d+%%) increased", function(num) return num.." reduced" end) - :gsub("%-(%d+%%) reduced", function(num) return num.." increased" end) - :gsub("%-(%d+%%) more", function(num) return num.." less" end) - :gsub("%-(%d+%%) less", function(num) return num.." more" end) + local testLine = not line:find("-", 1, true) and line or + line:gsub("(%+?)%((%-?%d+%.?%d*)%-(%-?%d+%.?%d*)%)", + function(plus, min, max) + min = tonumber(min) + local maxPrecision = min + range * (tonumber(max) - min) + local minPrecision = m_floor(maxPrecision + 0.5) + if minPrecision ~= maxPrecision then + precisionSame = false + end + return (minPrecision < 0 and "" or plus) .. tostring(minPrecision) + end) + :gsub("%-(%d+%%) (%a+)", + function(num, word) + local antonym = antonyms[word] + return antonym and (num.." "..antonym) or ("-"..num.." "..word) + end) + + if precisionSame and (not valueScalar or valueScalar == 1) then + return testLine + end + + local precision = nil local modList, extra = modLib.parseMod(testLine) if modList and not extra then for _, mod in pairs(modList) do @@ -86,27 +107,25 @@ function itemLib.applyRange(line, range, valueScalar) if not precision and line:match("(%d+%.%d*)") then precision = data.defaultHighPrecision end - line = line:gsub("%((%d+)%-(%d+) to (%d+)%-(%d+)%)", "(%1-%2) to (%3-%4)") - :gsub("(%+?)%((%-?%d+) to (%d+)%)", "%1(%2-%3)") - :gsub("(%+?)%((%-?%d+%.?%d*)%-(%-?%d+%.?%d*)%)", + + local numbers = 0 + line = line:gsub("(%+?)%((%-?%d+%.?%d*)%-(%-?%d+%.?%d*)%)", function(plus, min, max) numbers = numbers + 1 local power = 10 ^ (precision or 0) local numVal = m_floor((tonumber(min) + range * (tonumber(max) - tonumber(min))) * power + 0.5) / power - if numVal < 0 then - if plus == "+" then - plus = "" - end - end - return plus .. tostring(numVal) + return (numVal < 0 and "" or plus) .. tostring(numVal) end) - :gsub("%-(%d+%%) increased", function(num) return num.." reduced" end) - :gsub("%-(%d+%%) reduced", function(num) return num.." increased" end) - :gsub("%-(%d+%%) more", function(num) return num.." less" end) - :gsub("%-(%d+%%) less", function(num) return num.." more" end) - if numbers == 0 and line:match("(%d+%.?%d*)%%? ") then --If a mod contains x or x% and is not already a ranged value, then only the first number will be scalable as any following numbers will always be conditions or unscalable values. - numbers = 1 - end + :gsub("%-(%d+%%) (%a+)", + function(num, word) + local antonym = antonyms[word] + return antonym and (num.." "..antonym) or ("-"..num.." "..word) + end) + + if numbers == 0 and line:match("(%d+%.?%d*)%%? ") then --If a mod contains x or x% and is not already a ranged value, then only the first number will be scalable as any following numbers will always be conditions or unscalable values. + numbers = 1 + end + return itemLib.applyValueScalar(line, valueScalar, numbers, precision) end