diff --git a/spec/System/TestItemMods_spec.lua b/spec/System/TestItemMods_spec.lua index 7137e28264..a2797f2e73 100644 --- a/spec/System/TestItemMods_spec.lua +++ b/spec/System/TestItemMods_spec.lua @@ -40,6 +40,70 @@ describe("TetsItemMods", function() assert.are.equals(2, legacyLines) end) + it("toggles modifiers from the display item tooltip", function() + build.itemsTab:CreateDisplayItemFromRaw([[ + Rarity: Rare + Toggle Test + Ring + Implicits: 0 + +100 to maximum Life + ]]) + local item = build.itemsTab.displayItem + + assert.are.equals(100, item.baseModList:Sum("BASE", nil, "Life")) + build.itemsTab:ToggleDisplayItemModLine(item.explicitModLines[1]) + + item = build.itemsTab.displayItem + assert.is_true(item.explicitModLines[1].disabled) + assert.are.equals(0, item.baseModList:Sum("BASE", nil, "Life")) + assert.are.equals(colorCodes.DISABLED.."+100 to maximum Life", itemLib.formatModLine(item.explicitModLines[1])) + local tooltipModLine + for _, line in ipairs(build.itemsTab.displayItemTooltip.lines) do + if line.text and line.text:find("+100 to maximum Life", 1, true) then + tooltipModLine = line.modLine + break + end + end + assert.are.equals(item.explicitModLines[1], tooltipModLine) + + build.itemsTab:ToggleDisplayItemModLine(item.explicitModLines[1]) + assert.is_nil(build.itemsTab.displayItem.explicitModLines[1].disabled) + assert.are.equals(100, build.itemsTab.displayItem.baseModList:Sum("BASE", nil, "Life")) + end) + + it("preserves disabled rune modifiers when rebuilding an item", function() + build.itemsTab:CreateDisplayItemFromRaw([[ + Test Wand + Runic Fork + Sockets: S + Rune: Perfect Storm Rune + LevelReq: 1 + Implicits: 1 + {enchant}{rune}Gain 12% of Damage as Extra Lightning Damage + 200% increased effect of Socketed Runes + ]]) + local item = build.itemsTab.displayItem + local runeModLine + for _, modLine in ipairs(item.runeModLines) do + if modLine.line == "Gain 12% of Damage as Extra Lightning Damage" then + runeModLine = modLine + break + end + end + assert.is_not_nil(runeModLine) + assert.are.equals(3, runeModLine.displayValueScalar) + + build.itemsTab:ToggleDisplayItemModLine(runeModLine) + + for _, modLine in ipairs(build.itemsTab.displayItem.runeModLines) do + if modLine.line == runeModLine.line then + assert.is_true(modLine.disabled) + return + end + end + assert(false, "Disabled rune modifier not found after rebuilding item") + end) + it("shows a fallback tooltip when an item's base is no longer supported", function() local item = new("Item"):Item([[ Rarity: Unique diff --git a/spec/System/TestItemParse_spec.lua b/spec/System/TestItemParse_spec.lua index 0cb526a9ad..37f90839c6 100644 --- a/spec/System/TestItemParse_spec.lua +++ b/spec/System/TestItemParse_spec.lua @@ -375,6 +375,11 @@ describe("TestItemParse", function() assert.are.equals("~price 1 chaos", item.note) end) + it("ignores disabled modifiers in item conditions", function() + local item = new("Item"):Item(raw("{disabled}+100 to maximum Life")) + assert.is_false(item:FindModifierSubstring("life", "body armour")) + end) + it("Rune level requirements", function() local item = new("Item"):Item([[ Test Wand @@ -1296,6 +1301,18 @@ describe("TestAdvancedItemParse #item", function() assert.are.equals(221, chaosDamageInc()) end) + it("does not apply disabled modifier magnitude", function() + local item = new("Item"):Item([[ + Rarity: UNIQUE + Magnitude Test + Arcane Raiment + Implicits: 1 + {range:0.5}+(10-20) to maximum Life + {disabled}100% increased Implicit Modifier magnitudes + ]]) + assert.are.equals(1, item.implicitModLines[1].valueScalar) + end) + it("scales properly using old Eyes of the Greatwolf line", function() build.itemsTab:CreateDisplayItemFromRaw([[ Rarity: UNIQUE diff --git a/src/Classes/Item.lua b/src/Classes/Item.lua index eb7c95794c..54808bb8a7 100644 --- a/src/Classes/Item.lua +++ b/src/Classes/Item.lua @@ -76,6 +76,7 @@ end local lineFlags = { ["crafted"] = true, ["custom"] = true, + ["disabled"] = true, ["enchant"] = true, ["fractured"] = true, ["implicit"] = true, @@ -278,7 +279,7 @@ function ItemClass:FindModifierSubstring(substring, itemSlotName) else currentVariant = true end - if currentVariant then + if not v.disabled and currentVariant then if v.line:lower():find(substring) and not v.line:lower():find(substring .. " modifier") then local excluded = false if data.itemTagSpecialExclusionPattern[substring] and data.itemTagSpecialExclusionPattern[substring][itemSlotName] then @@ -994,7 +995,7 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) end end - local lineLower = line:lower() + local lineLower = modLine.disabled and "" or line:lower() -- \d+% increased/reduced explicit/implicit/ *tags* modifier magnitudes local modMagnitudePattern = { "(%d+)%% ([ir][ne][cd][ru][ec][ae][sd]e?d?) ?([%a%s]*) modifier magnitudes", -- \d+% increased/reduced effect of suffixes/prefixes @@ -1126,17 +1127,15 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) if self.base then if self.base.weapon or self.base.armour or self.base.tags.wand or self.base.tags.staff or self.base.tags.sceptre or self.itemSocketCount > 0 then local shouldFixRunesOnItem = #self.runes == 0 + local canRebuildRunes if not shouldFixRunesOnItem and #self.runeModLines > 0 then - local canRebuildRunes = true + canRebuildRunes = true for _, rune in ipairs(self.runes) do if rune ~= "None" and not data.itemMods.Runes[rune] then canRebuildRunes = false break end end - if canRebuildRunes then - self:UpdateRunes() - end end local function getRuneLineParts(modLine) @@ -1151,6 +1150,24 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) return strippedModLine, values end + if canRebuildRunes then + local disabledRuneLines = { } + for _, modLine in ipairs(self.runeModLines) do + if modLine.disabled then + local strippedModLine = getRuneLineParts(modLine.line) + disabledRuneLines[strippedModLine] = (disabledRuneLines[strippedModLine] or 0) + 1 + end + end + self:UpdateRunes() + for _, modLine in ipairs(self.runeModLines) do + local strippedModLine = getRuneLineParts(modLine.line) + if (disabledRuneLines[strippedModLine] or 0) > 0 then + modLine.disabled = true + disabledRuneLines[strippedModLine] -= 1 + end + end + end + local function compareRuneValueSets(a, b) for i = 1, math.max(#a, #b) do local aVal = a[i] or 0 @@ -1639,6 +1656,9 @@ function ItemClass:BuildRaw() if modLine.mutated then line = "{mutated}" .. line end + if modLine.disabled then + line = "{disabled}" .. line + end if modLine.crafted then line = "{crafted}" .. line end @@ -2316,6 +2336,9 @@ function ItemClass:BuildModList() end end local function processModLine(modLine) + if modLine.disabled then + return + end local variantCount = self:GetModLineVariantCount(modLine) if variantCount > 0 then -- special section for variant over-ride of pre-modifier item parameters diff --git a/src/Classes/ItemsTab.lua b/src/Classes/ItemsTab.lua index 81b5fad9bd..ac20fda674 100644 --- a/src/Classes/ItemsTab.lua +++ b/src/Classes/ItemsTab.lua @@ -1396,6 +1396,27 @@ function ItemsTabClass:Draw(viewPort, inputEvents) if self.displayItem then local x, y = self.controls.displayItemTooltipAnchor:GetPos() self.displayItemTooltip:Draw(x, y, nil, nil, viewPort) + + -- Toggle mods + local cursorX, cursorY = GetCursorPos() + for _, line in ipairs(self.displayItemTooltip.lines) do + if line.modLine and line.bounds then + local b = line.bounds + if cursorX >= b.x and cursorX <= b.x + b.width and cursorY >= b.y and cursorY <= b.y + b.height then + SetDrawColor(1, 1, 1, 0.15) + DrawImage(nil, b.x, b.y, b.width, b.height) + SetDrawColor(1, 1, 1) + + for id, event in ipairs(inputEvents) do + if event.type == "KeyDown" and event.key:match("BUTTON") then + inputEvents[id] = nil + self:ToggleDisplayItemModLine(line.modLine) + break + end + end + end + end + end end self:UpdateSockets() @@ -1887,6 +1908,21 @@ function ItemsTabClass:UpdateDisplayItemTooltip() self.displayItemTooltip.center = true end +function ItemsTabClass:ToggleDisplayItemModLine(modLine) + if not self.displayItem or not modLine then + return + end + modLine.disabled = not modLine.disabled + self.displayItem:BuildAndParseRaw() + self:UpdateDisplayItemTooltip() + self:UpdateDisplayItemRangeLines() + self:UpdateCustomControls() + if self.displayItem.crafted then + self:UpdateAffixControls() + end + self.build.buildFlag = true +end + function ItemsTabClass:UpdateClusterJewelControls() local item = self.displayItem @@ -3672,7 +3708,7 @@ function ItemsTabClass:AddItemTooltip(tooltip, item, slot, dbMode, maxWidth) formattedModLine = itemLib.formatModLine(modLine, dbMode) end for _ = 1, variantCount do - tooltip:AddLine(fontSizeBig, formattedModLine, "FONTIN SC", bg) + tooltip:AddLine(fontSizeBig, formattedModLine, "FONTIN SC", bg, modLine) end -- Show mods from granted passives diff --git a/src/Classes/Tooltip.lua b/src/Classes/Tooltip.lua index 127b7f0af9..937b963782 100644 --- a/src/Classes/Tooltip.lua +++ b/src/Classes/Tooltip.lua @@ -116,7 +116,7 @@ function TooltipClass:CheckForUpdate(...) end end -function TooltipClass:AddLine(size, text, font, background) +function TooltipClass:AddLine(size, text, font, background, modLine) if text then local fontToUse if main.showFlavourText then @@ -142,10 +142,10 @@ function TooltipClass:AddLine(size, text, font, background) end end if activeColour then wrappedLine = wrappedLine .. "^7" end - t_insert(self.lines, { size = size, text = wrappedLine, block = #self.blocks, font = fontToUse, center = self.center, background = background }) + t_insert(self.lines, { size = size, text = wrappedLine, block = #self.blocks, font = fontToUse, center = self.center, background = background, modLine = modLine }) end else - t_insert(self.lines, { size = size, text = line, block = #self.blocks, font = fontToUse, center = self.center, background = background }) + t_insert(self.lines, { size = size, text = line, block = #self.blocks, font = fontToUse, center = self.center, background = background, modLine = modLine }) end end end @@ -426,7 +426,13 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) local lineX = lineCentered and (x + ttW / 2) or (x + (H_PAD / 2)) local lineAlign = lineCentered and "CENTER_X" or "LEFT" - t_insert(drawStack, {lineX, y, lineAlign, data.size, font, data.text, background = data.background}) + local stackEntry = {lineX, y, lineAlign, data.size, font, data.text, background = data.background} + if data.modLine then + stackEntry.tooltipLine = data + stackEntry.bounds = { x = x + (H_PAD / 2), y = y, width = ttW - H_PAD, height = data.size + 2 } + stackEntry.strikethrough = data.modLine.disabled + end + t_insert(drawStack, stackEntry) y = y + data.size + 2 -- track max width for extra columns @@ -476,6 +482,10 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort) -- "LEFT" aligned text and images (NOTE: "RIGHT" aligned does not seem to exist) line[xIdx] = origX - oldBaseX + newBaseX end + if line.bounds then + line.bounds.x = line.bounds.x - oldBaseX + newBaseX + line.bounds.width = extraColumnWidth - H_PAD + end -- Resize separators/dividers (technically unlikely to appear in extra columns, but just in case) if not isText then @@ -564,6 +574,9 @@ function TooltipClass:Draw(x, y, w, h, viewPort) -- Image, Separators, etc. have 5 entries and `x` at `[1]` line[1] = line[1] + offsetX end + if line.bounds then + line.bounds.x = line.bounds.x + offsetX + end end end @@ -717,6 +730,9 @@ function TooltipClass:Draw(x, y, w, h, viewPort) end end else + if line.tooltipLine then + line.tooltipLine.bounds = line.bounds + end -- Draw background if specified, used for gem mod lines and desecrated mods on items. local bg = line.background if bg then @@ -748,6 +764,14 @@ function TooltipClass:Draw(x, y, w, h, viewPort) -- Draw text line DrawString(unpack(line)) + if line.strikethrough then + local prevR, prevG, prevB, prevA = GetDrawColor() + local textW = DrawStringWidth(line[4], line[5], line[6]) + local strikeX = line[3] == "CENTER_X" and line[1] - textW / 2 or line[1] + SetDrawColor(0.75, 0.75, 0.75, 0.35) + DrawImage(nil, strikeX, line[2] + line[4] / 2, textW, 1) + SetDrawColor(prevR, prevG, prevB, prevA) + end end end diff --git a/src/Data/Global.lua b/src/Data/Global.lua index c97368fede..da43f115aa 100644 --- a/src/Data/Global.lua +++ b/src/Data/Global.lua @@ -19,6 +19,7 @@ colorCodes = { CUSTOM = "^x5CF0BB", SOURCE = "^x88FFFF", UNSUPPORTED = "^xF05050", + DISABLED = "^x7F7F7F", WARNING = "^xFF9922", TIP = "^x80A080", FIRE = "^xB97123", diff --git a/src/Modules/ItemTools.lua b/src/Modules/ItemTools.lua index 920982b547..9914a561b2 100644 --- a/src/Modules/ItemTools.lua +++ b/src/Modules/ItemTools.lua @@ -335,6 +335,9 @@ function itemLib.formatModLine(modLine, dbMode, skipUnsupported) if itemLib.isZeroValueLine(line) then -- Hack to hide 0-value modifiers return end + if modLine.disabled then + return colorCodes.DISABLED .. line + end local colorCode if modLine.extra and not skipUnsupported then colorCode = colorCodes.UNSUPPORTED @@ -378,4 +381,4 @@ itemLib.wiki = { return key == itemLib.wiki.key end, triggered = false -} \ No newline at end of file +}