diff --git a/spec/System/TestItemsTab_spec.lua b/spec/System/TestItemsTab_spec.lua index a5dd31920e..4ef9bfe091 100644 --- a/spec/System/TestItemsTab_spec.lua +++ b/spec/System/TestItemsTab_spec.lua @@ -16,6 +16,39 @@ describe("TestItemsTab", function() runCallback("OnFrame") end) + it("colours complete multiline rune modifiers without joining normal and Bonded lines", function() + local firstLine = { line = "Increases and Reductions to Spell Damage also", bonded = false } + local continuation = { line = " apply to Attacks", bonded = false } + local supported = { line = "+10 to maximum Life", bonded = false } + local function bonded(modLine) + return { line = modLine.line, bonded = true } + end + local blue, red = colorCodes.MAGIC, colorCodes.UNSUPPORTED + local cases = { + { lines = { firstLine, continuation, supported }, colours = { blue, blue, blue } }, + { lines = { firstLine, continuation }, displayLines = { "First display line", "Continuation display line" }, colours = { blue, blue } }, + { lines = { bonded(firstLine), bonded(continuation), supported }, colours = { blue, blue, blue } }, + { lines = { firstLine, bonded(continuation) }, colours = { red, red } }, + { lines = { bonded(firstLine), continuation }, colours = { red, red } }, + { lines = { firstLine, supported, bonded(supported), continuation }, colours = { red, blue, blue, red } }, + } + local comparison = stub(build.itemsTab, "AddModComparisonTooltip") + for _, case in ipairs(cases) do + local tooltip = new("Tooltip"):Tooltip() + local value = { name = "Test Rune", req = 1, lines = { }, modLines = case.lines } + for _, modLine in ipairs(case.lines) do + table.insert(value.lines, (modLine.bonded and "Bonded: " or "") .. modLine.line) + end + value.lines = case.displayLines or value.lines + build.itemsTab.controls.displayItemRune1.tooltipFunc(tooltip, "HOVER", 1, value) + assert.are.equal(#case.lines + 1, #tooltip.lines) + for index, line in ipairs(value.lines) do + assert.are.equal(case.colours[index] .. line, tooltip.lines[index + 1].text) + end + end + comparison:revert() + end) + it("compares weapons in the skill's assigned set, with Both following the Items tab", function() build.skillsTab:PasteSocketGroup("Spark 20/0 1") local group = build.skillsTab.displayGroup @@ -871,6 +904,10 @@ Ruby]]) assert.are.equals(2, #ticabaRune.lines) assert.are.equals("Hits against you have 50% reduced Critical Damage Bonus", ticabaRune.lines[1]) assert.are.equals("Hits against you have 50% reduced Critical Damage Bonus", ticabaRune.lines[2]) + assert.are.same({ + { line = ticabaRune.lines[1], bonded = false }, + { line = ticabaRune.lines[2], bonded = false }, + }, ticabaRune.modLines) end) it("keeps pure Bonded slot entries and uses the regular rune mod as the dropdown label", function () @@ -886,6 +923,17 @@ Ruby]]) for _, rune in ipairs(build.itemsTab:GetValidRunesForItem(item)) do if rune.name == "Perfect Resolve Rune" then assert.are.equals("+15 to Intelligence", rune.label) + assert.are.equal(#rune.lines, #rune.modLines) + local bondedLines = { } + for index, modLine in ipairs(rune.modLines) do + assert.are.equal((modLine.bonded and "Bonded: " or "") .. modLine.line, rune.lines[index]) + if modLine.bonded then + table.insert(bondedLines, modLine.line) + else + assert.are.equal("+15 to Intelligence", modLine.line) + end + end + assert.are.same({ "+50 to maximum Energy Shield" }, bondedLines) return end end diff --git a/src/Classes/ItemsTab.lua b/src/Classes/ItemsTab.lua index 1ee55268d2..6ae64b84ad 100644 --- a/src/Classes/ItemsTab.lua +++ b/src/Classes/ItemsTab.lua @@ -812,8 +812,29 @@ holding Shift will put it in the second.]]) if value.req > 1 then tooltip:AddLine(14, "^7" .. s_format("Requires: Level %d", value.req)) end - for _, line in ipairs(value.lines) do - tooltip:AddLine(14, colorCodes.MAGIC .. line) + local lineIndex = 1 + while lineIndex <= #value.modLines do + -- Match item parsing: retry unsupported text with its continuation line. + local modLine = value.modLines[lineIndex] + local line = modLine.line:match("^%s*(.-)%s*$") + local modList, extra = modLib.parseMod(line) + local lineCount = 1 + local nextModLine = value.modLines[lineIndex + 1] + if (not modList or extra) and nextModLine then + if modLine.bonded == nextModLine.bonded then + local nextLine = nextModLine.line:match("^%s*(.-)%s*$") + local combinedMods, combinedExtra = modLib.parseMod(line .. " " .. nextLine, true) + if combinedMods and not combinedExtra then + modList, extra = combinedMods, combinedExtra + lineCount = 2 + end + end + end + local colour = (modList and not extra) and colorCodes.MAGIC or colorCodes.UNSUPPORTED + for index = lineIndex, lineIndex + lineCount - 1 do + tooltip:AddLine(14, colour .. value.lines[index]) + end + lineIndex = lineIndex + lineCount end -- Adding Comparison local compLines = { type = "Rune" } @@ -2223,18 +2244,21 @@ function ItemsTabClass:UpdateAffixControls() self:UpdateCustomControls() end -runeModLines = { { name = "None", label = "None", lines = { "None" }, mods = { }, req = 1, order = -1, slot = "None", group = -1, isSocketBound = false } } +runeModLines = { { name = "None", label = "None", lines = { "None" }, modLines = { }, mods = { }, req = 1, order = -1, slot = "None", group = -1, isSocketBound = false } } for name, runeMods in pairs(data.itemMods.Runes) do -- Some runes have multiple mod lines; insert each as separate entry for slotType, runeMod in pairs(runeMods) do -- Bonded stats are stored separately for calculation, but remain part of the -- visible rune description and are prefixed only at this presentation boundary. local lines = { } + local modLines = { } for _, line in ipairs(runeMod) do t_insert(lines, line) + t_insert(modLines, { line = line, bonded = false }) end for _, line in ipairs(runeMod.bonded or { }) do t_insert(lines, "Bonded: " .. line) + t_insert(modLines, { line = line, bonded = true }) end local mods = { } for _, line in ipairs(runeMod) do @@ -2244,7 +2268,7 @@ for name, runeMods in pairs(data.itemMods.Runes) do end end local order = (runeMod.statOrder and runeMod.statOrder[1]) or (runeMod.bonded and runeMod.bonded.statOrder and runeMod.bonded.statOrder[1]) or 0 - t_insert(runeModLines, { name = name, label = runeMod[1], lines = lines, mods = mods, req = runeMod.levelReq, order = order, slot = slotType, type = runeMod.type, group = #lines, isSocketBound = runeMod.isSocketBound, localMod = runeMod.localMod, limit = runeMod.limit, canSocketInChakraSlots = runeMod.canSocketInChakraSlots, canSocketInUniqueItems = runeMod.canSocketInUniqueItems, canSocketInJewellery = runeMod.canSocketInJewellery }) + t_insert(runeModLines, { name = name, label = runeMod[1], lines = lines, modLines = modLines, mods = mods, req = runeMod.levelReq, order = order, slot = slotType, type = runeMod.type, group = #lines, isSocketBound = runeMod.isSocketBound, localMod = runeMod.localMod, limit = runeMod.limit, canSocketInChakraSlots = runeMod.canSocketInChakraSlots, canSocketInUniqueItems = runeMod.canSocketInUniqueItems, canSocketInJewellery = runeMod.canSocketInJewellery }) end end table.sort(runeModLines, function(a, b) @@ -2280,12 +2304,14 @@ function ItemsTabClass:GetValidRunesForItem(item) if not addedRune then addedRune = copyTable(rune, true) addedRune.lines = { } + addedRune.modLines = { } t_insert(runes, addedRune) addedRunes[rune.name] = addedRune end addedRune.label = addedRune.label or rune.label - for _, line in ipairs(rune.lines) do + for index, line in ipairs(rune.lines) do t_insert(addedRune.lines, line) + t_insert(addedRune.modLines, rune.modLines[index]) end end end