Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 118 additions & 1 deletion src/Classes/PassiveTreeView.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,97 @@ local JEWEL_RADIUS_TINT_NEUTRAL = { 1, 1, 1, 0.7 }
local JEWEL_RADIUS_TINT_PRIMARY_ONLY = { 1, 0, 0, 0.7 }
local JEWEL_RADIUS_TINT_COMPARE_ONLY = { 0, 1, 0, 0.7 }

-- GGG tags keyword references inside popup text as [Id] or [Id|Display], and wraps
-- emphasis as <tag>{text}. Strip both down to the plain words.
local keywordBodyColour = "^xA0A080"
local function stripKeywordText(text)
-- unwrap innermost first, since these nest: <font>{<italic>{<rgb>{text}}}
local prev
repeat
prev = text
text = text:gsub("<[^<>]+>{([^{}]*)}", "%1")
until text == prev
-- then drop any tag left without braces, including the <> from <<Name>>
repeat
prev = text
text = text:gsub("<[^<>]*>", "")
until text == prev
return (text:gsub("%[([^|%]]+)|([^%]]+)%]", "%2"):gsub("%[([^|%]]+)%]", "%1"))
end

local function keywordTags(node, index)
local tags
for entry in (node.keywordPopups and node.keywordPopups[index] or ""):gmatch("[^;]+") do
local id, display = entry:match("^([^|]+)|(.+)$")
tags = tags or { }
t_insert(tags, { id = id or entry, text = display or entry })
end
return tags
end

-- Keywords not worth explaining on a passive node due them being self-explanatory.
local deniedKeywords = { }
for _, id in ipairs({
"Recently", -- past 4 seconds
"MaximumTotal", -- explains modifier ranges
"Equipment", -- "Equipment are items that can be Equipped"
"Equipped", -- restates weapons/armour is worn
"Rune", -- "Runes are Augments of Kalguuran origin and make."
"Power", -- monster difficulty rating
"BuffMagnitude", -- Buff/Debuff Scaling
"Hit",
"Attack",
"Spell",
"Energy Shield",
"Melee",
"Projectile",
"Flasks",
"Resistances",
"Jewels",
"Minions",
"Totems",
"ItemRarity",
-- weapon and off-hand types, where the popup just restates the base item
"Axe", "Mace", "Sword", "Bow", "Crossbow", "Spear", "Dagger", "Claw", "Flail",
"Wand", "Staff", "Sceptre", "Quarterstaff", "Buckler", "Shield", "Focus", "Two-Handed",
-- Stats
"Strength", "Dexterity", "Intelligence",
-- Damage Types
"Physical", "Fire", "Cold", "Lightning", "Chaos", "ElementalDamage"
}) do
deniedKeywords[id] = true
end

local function findKeywords(node)
local granted, mentioned, seen = { }, { }, { }
for index, line in ipairs(node.sd or { }) do
for _, tag in ipairs(keywordTags(node, index) or { }) do
local popup = data.keywordPopups[tag.id]
if popup and popup.description and popup.description ~= "" and not seen[tag.id] then
seen[tag.id] = true
if line == tag.text or line == "Grants " .. tag.text then
t_insert(granted, popup)
elseif main.showKeywordTooltips and not deniedKeywords[tag.id] then
t_insert(mentioned, popup)
end
end
end
end
return granted, mentioned
end

local function keywordWords(node, index)
local words
for _, tag in ipairs(keywordTags(node, index) or { }) do
local popup = data.keywordPopups[tag.id]
if popup and popup.description and popup.description ~= "" and not deniedKeywords[tag.id] then
words = words or { }
words[tag.text] = true
end
end
return words
end

---@class PassiveTreeView
local PassiveTreeViewClass = newClass("PassiveTreeView")

Expand Down Expand Up @@ -1217,7 +1308,7 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
-- Draw tooltip
SetDrawLayer(nil, 100)
local size = m_floor(node.size * scale)
if self.tooltip:CheckForUpdate(node, self.showStatDifferences, self.tracePath, launch.devModeAlt, build.outputRevision, build.spec.allocMode) then
if self.tooltip:CheckForUpdate(node, self.showStatDifferences, self.tracePath, launch.devModeAlt, build.outputRevision, build.spec.allocMode, IsKeyDown("ALT"), main.showKeywordTooltips) then
self:AddNodeTooltip(self.tooltip, node, build, incSmallPassiveSkillEffect)
end
self.tooltip.center = true
Expand Down Expand Up @@ -1890,9 +1981,24 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
if not (mNode.isAttribute and not mNode.conqueredBy) and (mNode.type == "Normal" or mNode.type == "Notable") and isNodeInARadius(node) then
localIncEffect = processTimeLostModsAndGetLocalEffect(mNode, build)
end
local granted, mentioned = findKeywords(mNode)
for i, line in ipairs(mNode.sd) do
-- only the words GGG tagged on this particular line
tooltip.underlineWords = keywordWords(mNode, i)
addModInfoToTooltip(mNode, i, line, localIncEffect)
end
tooltip.underlineWords = nil
-- A node whose stat line is nothing but a keyword is explained inline: there is only
-- ever one, and it is the whole point of the node
for _, popup in ipairs(granted) do
tooltip:AddSeparator(10)
tooltip:AddLine(14, colorCodes.MAGIC .. popup.name)
tooltip:AddLine(14, keywordBodyColour .. stripKeywordText(popup.description:gsub("\r", "")))
end
if mentioned[1] and not IsKeyDown("ALT") then
tooltip:AddSeparator(10)
tooltip:AddLine(14, colorCodes.TIP .. "Tip: Hold Alt to explain the keywords in this node")
end
-- add child tooltip for skills
self.skillTooltip:Clear()
self.skillTooltip.maxWidth = 600
Expand All @@ -1911,6 +2017,17 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
end
end
end
-- Keywords the node merely mentions go in the side tooltip, since there can be
-- several long ones and they would otherwise move the stat and allocation numbers
if IsKeyDown("ALT") then
for _, popup in ipairs(mentioned) do
if #self.skillTooltip.lines > 0 then
self.skillTooltip:AddSeparator(10)
end
self.skillTooltip:AddLine(14, colorCodes.MAGIC .. popup.name)
self.skillTooltip:AddLine(14, keywordBodyColour .. stripKeywordText(popup.description:gsub("\r", "")))
end
end
end

if node.containJewelSocket and node.alloc then
Expand Down
39 changes: 37 additions & 2 deletions src/Classes/Tooltip.lua
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,28 @@ function TooltipClass:CheckForUpdate(...)
end
end

function TooltipClass:GetUnderlineSpans(text)
if not self.underlineWords then
return nil
end
local plain = StripEscapes(text)
local spans
for word in pairs(self.underlineWords) do
local init = 1
while true do
local s, e = plain:find(word, init, true)
if not s then break end
if (s == 1 or not plain:sub(s - 1, s - 1):match("%w"))
and (e == #plain or not plain:sub(e + 1, e + 1):match("%w")) then
spans = spans or { }
t_insert(spans, { prefix = plain:sub(1, s - 1), text = word })
end
init = e + 1
end
end
return spans
end

function TooltipClass:AddLine(size, text, font, background, modLine)
if text then
local fontToUse
Expand All @@ -191,10 +213,10 @@ function TooltipClass:AddLine(size, text, font, background, modLine)
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, modLine = modLine })
t_insert(self.lines, { size = size, text = wrappedLine, block = #self.blocks, font = fontToUse, center = self.center, background = background, modLine = modLine, underline = self:GetUnderlineSpans(wrappedLine) })
end
else
t_insert(self.lines, { size = size, text = line, block = #self.blocks, font = fontToUse, center = self.center, background = background, modLine = modLine })
t_insert(self.lines, { size = size, text = line, block = #self.blocks, font = fontToUse, center = self.center, background = background, modLine = modLine, underline = self:GetUnderlineSpans(line) })
end
end
end
Expand Down Expand Up @@ -463,6 +485,7 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort)
stackEntry.bounds = { x = x + (H_PAD / 2), y = y, width = ttW - H_PAD, height = data.size + 2 }
stackEntry.strikethrough = data.modLine.disabled
end
stackEntry.underline = data.underline
t_insert(drawStack, stackEntry)
y = y + data.size + 2

Expand Down Expand Up @@ -776,6 +799,18 @@ function TooltipClass:Draw(x, y, w, h, viewPort)
DrawImage(nil, strikeX, line[2] + line[4] / 2, textW, 1)
SetDrawColor(prevR, prevG, prevB, prevA)
end
if line.underline then
local prevR, prevG, prevB, prevA = GetDrawColor()
local textW = DrawStringWidth(line[4], line[5], line[6])
local baseX = line[3] == "CENTER_X" and line[1] - textW / 2 or line[1]
SetDrawColor(0.65, 0.65, 0.65, 0.8)
for _, span in ipairs(line.underline) do
local preW = DrawStringWidth(line[4], line[5], span.prefix)
local wordW = DrawStringWidth(line[4], line[5], span.text)
DrawImage(nil, baseX + preW, line[2] + line[4], wordW, 1)
end
SetDrawColor(prevR, prevG, prevB, prevA)
end
end
end

Expand Down
Loading
Loading