Skip to content

Add option for Item Flavour Text with Styled Tooltips and Passive Tree Headers #1151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
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
Binary file added src/Assets/itemsheaderfoilleft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderfoilmiddle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderfoilright.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheadergemleft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheadergemmiddle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheadergemright.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheadermagicleft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheadermagicmiddle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheadermagicright.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderrareleft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderraremiddle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderrareright.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderuniqueleft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderuniquemiddle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderuniqueright.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderwhiteleft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderwhitemiddle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsheaderwhiteright.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsseparatorfoil.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsseparatorgem.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsseparatormagic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsseparatorrare.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsseparatorunique.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/itemsseparatorwhite.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/jewelpassiveheaderleft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Assets/jewelpassiveheadermiddle.png
Binary file added src/Assets/jewelpassiveheaderright.png
Binary file added src/Assets/keystonepassiveheaderleft.png
Binary file added src/Assets/keystonepassiveheadermiddle.png
Binary file added src/Assets/keystonepassiveheaderright.png
Binary file added src/Assets/normalpassiveheaderleft.png
Binary file added src/Assets/normalpassiveheadermiddle.png
Binary file added src/Assets/normalpassiveheaderright.png
Binary file added src/Assets/notablepassiveheaderleft.png
Binary file added src/Assets/notablepassiveheadermiddle.png
Binary file added src/Assets/notablepassiveheaderright.png
3 changes: 2 additions & 1 deletion src/Classes/GemSelectControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ function GemSelectClass:Draw(viewPort, noTooltip)
if gemInstance and gemInstance.gemData then
self:AddGemTooltip(gemInstance)
else
self.tooltip.itemTooltip = false
self.tooltip:AddLine(16, toolTipText)
end

Expand Down Expand Up @@ -528,7 +529,7 @@ function GemSelectClass:AddGemTooltip(gemInstance)
self.tooltip.color = colorCodes.GEM
local grantedEffect = gemInstance.gemData.grantedEffect
local additionalEffects = gemInstance.gemData.additionalGrantedEffects

self.tooltip.itemTooltip = "GEM"
self.tooltip:AddLine(20, colorCodes.GEM .. grantedEffect.name)
self.tooltip:AddSeparator(10)
self.tooltip:AddLine(18, colorCodes.NORMAL .. gemInstance.gemData.gemType)
Expand Down
69 changes: 68 additions & 1 deletion src/Classes/ItemsTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ local catalystQualityFormat = {
"^x7F7F7FQuality (Attribute Modifiers): "..colorCodes.MAGIC.."+%d%% (augmented)",
}

local flavourLookup = {}

for _, entry in pairs(data.flavourText) do
if entry.name and entry.id and entry.text then
flavourLookup[entry.name] = flavourLookup[entry.name] or {}
flavourLookup[entry.name][entry.id] = entry.text
end
end


local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Control", function(self, build)
self.UndoHandler()
self.ControlHost()
Expand Down Expand Up @@ -2565,6 +2575,8 @@ end
function ItemsTabClass:AddItemTooltip(tooltip, item, slot, dbMode)
-- Item name
local rarityCode = colorCodes[item.rarity]
tooltip.maxWidth = 600 -- Should instead get the longest mod and set the width to that. Some flavour text is way too long so we need a cap of sorts.
tooltip.itemTooltip = item.rarity
tooltip.center = true
tooltip.color = rarityCode
if item.title then
Expand Down Expand Up @@ -2869,8 +2881,63 @@ function ItemsTabClass:AddItemTooltip(tooltip, item, slot, dbMode)
if item.corrupted then
tooltip:AddLine(16, colorCodes.NEGATIVE.."Corrupted")
end
tooltip:AddSeparator(14)
end

-- Show flavour text:
if item.rarity == "UNIQUE" and main.showFlavourText == true then
local flavourTable = flavourLookup[item.title]
if flavourTable then
local flavour = nil

if item.title == "Sekhema's Resolve" then
local selectedFlavourId = nil
for _, lineEntry in ipairs(tooltip.lines or {}) do
local lineText = lineEntry.text or ""
if lineText:find("Emerald") then
selectedFlavourId = "FourUniqueSanctum4a"
break
elseif lineText:find("Sapphire") then
selectedFlavourId = "FourUniqueSanctum4b"
break
elseif lineText:find("Ruby") then
selectedFlavourId = "FourUniqueSanctum4c"
break
end
end
if selectedFlavourId then
flavour = flavourTable[selectedFlavourId]
end

elseif item.title == "Grand Spectrum" then
local selectedFlavourId = nil
local baseName = item.baseName
if baseName == "Ruby" then
selectedFlavourId = "FourUniqueJewel1"
elseif baseName == "Emerald" then
selectedFlavourId = "FourUniqueJewel2"
elseif baseName == "Sapphire" then
selectedFlavourId = "FourUniqueJewel3"
end
if selectedFlavourId then
flavour = flavourTable[selectedFlavourId]
end

else
for _, text in pairs(flavourTable) do
flavour = text
break
end
end

if flavour then
for _, line in ipairs(flavour) do
tooltip:AddLine(16, colorCodes.UNIQUE .. line)
end
tooltip:AddSeparator(14)
end
end
end
tooltip:AddSeparator(14)

-- Stat differences
if not self.showStatDifferences then
Expand Down
9 changes: 9 additions & 0 deletions src/Classes/PassiveTreeView.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,15 @@ end

function PassiveTreeViewClass:AddNodeName(tooltip, node, build)
tooltip:SetRecipe(node.infoRecipe)
if node.type == "Normal" then
tooltip.itemTooltip = "PASSIVE"
elseif node.type == "Notable" then
tooltip.itemTooltip = "NOTABLE"
elseif node.type == "Socket" then
tooltip.itemTooltip = "JEWEL"
elseif node.type == "Keystone" then -- keystone runs but still prints default header
tooltip.itemTooltip = "KEYSTONE"
end
tooltip:AddLine(24, "^7"..node.dn..(launch.devModeAlt and " ["..node.id.."]" or ""))
if launch.devModeAlt and node.id > 65535 then
-- Decompose cluster node Id
Expand Down
188 changes: 158 additions & 30 deletions src/Classes/Tooltip.lua
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,46 @@ function TooltipClass:SetRecipe(recipe)
end

function TooltipClass:AddSeparator(size)
t_insert(self.lines, { size = size })
size = size or 10

local lastLine = self.lines[#self.lines]
if lastLine and lastLine.separatorImage then
-- Prevent back-to-back separator lines
return
end

local separatorImage = nil

if self.itemTooltip then
local rarity = tostring(self.itemTooltip):upper()
local separatorConfigs = {
RELIC = "Assets/ItemsSeparatorFoil.png",
UNIQUE = "Assets/ItemsSeparatorUnique.png",
RARE = "Assets/ItemsSeparatorRare.png",
MAGIC = "Assets/ItemsSeparatorMagic.png",
NORMAL = "Assets/ItemsSeparatorWhite.png",
GEM = "Assets/ItemsSeparatorGem.png",
}
local separatorPath = separatorConfigs[rarity] or separatorConfigs.NORMAL

if not self.separatorImage or self.separatorImagePath ~= separatorPath then
self.separatorImage = NewImageHandle()
self.separatorImage:Load(separatorPath)
self.separatorImagePath = separatorPath
end

separatorImage = self.separatorImage
end

local lastBlock = lastLine and lastLine.block or 1
t_insert(self.lines, {
separatorImage = separatorImage,
size = size,
block = lastBlock,
})
end


function TooltipClass:GetSize()
local ttW, ttH = 0, 0
for i, data in ipairs(self.lines) do
Expand Down Expand Up @@ -128,6 +165,7 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort)
local drawStack = {}

for i, data in ipairs(self.lines) do
-- Draw recipe oils on first line
if self.recipe and i == 1 then
local title = self.lines[1]
local imageX = DrawStringWidth(title.size, "VAR", title.text) + title.size
Expand All @@ -140,31 +178,55 @@ function TooltipClass:CalculateColumns(ttY, ttX, ttH, ttW, viewPort)
recipeNameShort = recipeNameShort:sub(1, #recipeNameShort - 3)
end
-- Draw the name of the recipe component (oil)
t_insert(drawStack, {ttX + imageX, y + (title.size - recipeTextSize)/2, "LEFT", recipeTextSize, "VAR", recipeNameShort})
t_insert(drawStack, {ttX + imageX, y + (title.size - recipeTextSize) / 2, "LEFT", recipeTextSize, "VAR", recipeNameShort})
imageX = imageX + DrawStringWidth(recipeTextSize, "VAR", recipeNameShort)
-- Draw the image of the recipe component (oil)
t_insert(drawStack, {recipeInfo.sprite, ttX + imageX, y, title.size, title.size})
imageX = imageX + title.size * 1.25
end
end

local margin = 80
local maxHeight = math.min(ttH, viewPort.height - margin)

-- Wrapping logic for text lines
if data.text then
-- if data + borders is going to go outside of the viewPort
if currentBlock ~= data.block and self.blocks[data.block].height + y > ttY + math.min(ttH, viewPort.height) then
if currentBlock ~= data.block and (y + data.size > ttY + maxHeight) then
y = ttY + 2 * BORDER_WIDTH
x = ttX + ttW * columns
columns = columns + 1
end
currentBlock = data.block

local yOffset = (i == 1 and self.titleYOffset) or 0
local drawY = y + yOffset

if self.center then
t_insert(drawStack, {x + ttW/2, y, "CENTER_X", data.size, "VAR", data.text})
t_insert(drawStack, {x + ttW / 2, drawY, "CENTER_X", data.size, "VAR", data.text})
else
t_insert(drawStack, {x + 6, y, "LEFT", data.size, "VAR", data.text})
t_insert(drawStack, {x + 6, drawY, "LEFT", data.size, "VAR", data.text})
end
y = y + data.size + 2

-- Wrapping logic for separator images (counts as a "text" line for wrap height)
elseif data.separatorImage and main.showFlavourText then
local sepSize = data.size or 10
if currentBlock ~= data.block and (y + sepSize > ttY + maxHeight) then
y = ttY + 2 * BORDER_WIDTH
x = ttX + ttW * columns
columns = columns + 1
end
currentBlock = data.block

t_insert(drawStack, {{ handle = data.separatorImage, isSeparator = true },x + 6, y, ttW - 12, sepSize})
y = y + sepSize + 2

-- Horizontal line, if surrounded by text lines
elseif self.lines[i + 1] and self.lines[i - 1] and self.lines[i + 1].text then
t_insert(drawStack, {nil, x, y - 1 + data.size / 2, ttW - BORDER_WIDTH, 2})
y = y + data.size + 2
end

maxColumnHeight = m_max(y - ttY + 2 * BORDER_WIDTH, maxColumnHeight)
end

Expand All @@ -190,9 +252,9 @@ function TooltipClass:Draw(x, y, w, h, viewPort)
ttY = m_max(viewPort.y, y + h - ttH)
end
elseif self.center then
ttX = m_floor(x - ttW/2)
ttX = m_floor(x - ttW / 2)
end

SetDrawColor(1, 1, 1)

local columns, maxColumnHeight, drawStack = self:CalculateColumns(ttY, ttX, ttH, ttW, viewPort)
Expand All @@ -203,44 +265,110 @@ function TooltipClass:Draw(x, y, w, h, viewPort)
DrawImage(nil, ttX, ttY + BORDER_WIDTH, ttW * columns - BORDER_WIDTH, maxColumnHeight - 2 * BORDER_WIDTH)
--SetDrawLayer(nil, GetDrawLayer())
SetDrawColor(1, 1, 1)
for i, lines in ipairs(drawStack) do
if #lines < 6 then
if(type(self.color) == "string") then

-- Item header (drawn within borders)
if self.itemTooltip and main.showFlavourText and self.lines[1] and self.lines[1].text then
local rarity = tostring(self.itemTooltip):upper()
local headerConfigs = {
RELIC = {left="Assets/ItemsHeaderFoilLeft.png",middle="Assets/ItemsHeaderFoilMiddle.png",right="Assets/ItemsHeaderFoilRight.png",height=53,sideWidth=43,middleWidth=43,textYOffset=2},
UNIQUE = {left="Assets/ItemsHeaderUniqueLeft.png",middle="Assets/ItemsHeaderUniqueMiddle.png",right="Assets/ItemsHeaderUniqueRight.png",height=53,sideWidth=43,middleWidth=43,textYOffset=2},
RARE = {left="Assets/ItemsHeaderRareLeft.png",middle="Assets/ItemsHeaderRareMiddle.png",right="Assets/ItemsHeaderRareRight.png",height=53,sideWidth=43,middleWidth=43,textYOffset=2},
MAGIC = {left="Assets/ItemsHeaderMagicLeft.png",middle="Assets/ItemsHeaderMagicMiddle.png",right="Assets/ItemsHeaderMagicRight.png",height=38,sideWidth=32,middleWidth=32,textYOffset=4},
NORMAL = {left="Assets/ItemsHeaderWhiteLeft.png",middle="Assets/ItemsHeaderWhiteMiddle.png",right="Assets/ItemsHeaderWhiteRight.png",height=38,sideWidth=32,middleWidth=32,textYOffset=4},
GEM = {left="Assets/ItemsHeaderGemLeft.png",middle="Assets/ItemsHeaderGemMiddle.png",right="Assets/ItemsHeaderGemRight.png",height=38,sideWidth=32,middleWidth=32,textYOffset=4},
JEWEL = {left="Assets/JewelPassiveHeaderLeft.png",middle="Assets/JewelPassiveHeaderMiddle.png",right="Assets/JewelPassiveHeaderRight.png",height=38,sideWidth=32,middleWidth=32,textYOffset=2},
NOTABLE = {left="Assets/NotablePassiveHeaderLeft.png",middle="Assets/NotablePassiveHeaderMiddle.png",right="Assets/NotablePassiveHeaderRight.png",height=38,sideWidth=38,middleWidth=32,textYOffset=2},
PASSIVE = {left="Assets/NormalPassiveHeaderLeft.png",middle="Assets/NormalPassiveHeaderMiddle.png",right="Assets/NormalPassiveHeaderRight.png",height=38,sideWidth=32,middleWidth=32,textYOffset=2},
KEYSTONE = {left="Assets/KeystonePassiveHeaderLeft.png",middle="Assets/KeystonePassiveHeaderMiddle.png",right="Assets/KeystonePassiveHeaderRight.png",height=38,sideWidth=32,middleWidth=32,textYOffset=2},
}
local config = headerConfigs[rarity] or headerConfigs.NORMAL

self.titleYOffset = config.textYOffset or 0

if not self.headerLeft or self.headerLeftPath ~= config.left then
self.headerLeft = NewImageHandle()
self.headerLeft:Load(config.left)
self.headerLeftPath = config.left
end
if not self.headerMiddle or self.headerMiddlePath ~= config.middle then
self.headerMiddle = NewImageHandle()
self.headerMiddle:Load(config.middle)
self.headerMiddlePath = config.middle
end
if not self.headerRight or self.headerRightPath ~= config.right then
self.headerRight = NewImageHandle()
self.headerRight:Load(config.right)
self.headerRightPath = config.right
end

local headerHeight = config.height
local headerSideWidth = config.sideWidth
local headerMiddleWidth = config.middleWidth

local headerX = ttX + BORDER_WIDTH
local headerY = ttY + BORDER_WIDTH
local headerTotalWidth = ttW - 2 * BORDER_WIDTH
local headerMiddleAreaWidth = m_max(0, headerTotalWidth - 2 * headerSideWidth)

-- Draw left cap
DrawImage(self.headerLeft, headerX, headerY, headerSideWidth, headerHeight)

-- Draw middle fill
if headerMiddleAreaWidth > 0 then
local drawX = headerX + headerSideWidth
local endX = headerX + headerTotalWidth - headerSideWidth
while drawX + headerMiddleWidth <= endX do
DrawImage(self.headerMiddle, drawX, headerY, headerMiddleWidth, headerHeight)
drawX = drawX + headerMiddleWidth
end
local remainingWidth = endX - drawX
if remainingWidth > 0 then
DrawImage(self.headerMiddle, drawX, headerY, remainingWidth, headerHeight)
end
end

-- Draw right cap
DrawImage(self.headerRight, headerX + headerTotalWidth - headerSideWidth, headerY, headerSideWidth, headerHeight)
end

-- Draw lines and images
for _, line in ipairs(drawStack) do
if #line < 6 then
if line[1] and type(line[1]) == "table" and line[1].isSeparator then
SetDrawColor(1, 1, 1)
elseif type(self.color) == "string" then
SetDrawColor(self.color)
elseif lines[1] then -- Don't color images
SetDrawColor(1,1,1)
else
SetDrawColor(unpack(self.color))
end
if lines[1] and lines[1].handle then
local arguments = {
lines[1].handle,
lines[2],
lines[3],
lines[4],
lines[5]
if line[1] and line[1].handle then
local args = {
line[1].handle, line[2], line[3], line[4], line[5]
}
for _, v in ipairs(lines[1]) do
t_insert(arguments, v)
for _, v in ipairs(line[1]) do
t_insert(args, v)
end
DrawImage(unpack(arguments))
SetDrawColor(1,1,1)
DrawImage(unpack(args))
else
DrawImage(unpack(lines))
DrawImage(unpack(line))
end
else
DrawString(unpack(lines))
DrawString(unpack(line))
end
end

-- Draw borders
if type(self.color) == "string" then
SetDrawColor(self.color)
else
SetDrawColor(unpack(self.color))
end
for i=0,columns do
DrawImage(nil, ttX + ttW * i - BORDER_WIDTH * math.ceil(i^2 / (i^2 + 1)), ttY, BORDER_WIDTH, maxColumnHeight) -- borders
for i = 0, columns do
DrawImage(nil, ttX + ttW * i - BORDER_WIDTH * math.ceil(i^2 / (i^2 + 1)), ttY, BORDER_WIDTH, maxColumnHeight)
end
DrawImage(nil, ttX, ttY, ttW * columns, BORDER_WIDTH) -- top border
DrawImage(nil, ttX, ttY + maxColumnHeight - BORDER_WIDTH, ttW * columns, BORDER_WIDTH) -- bottom border
DrawImage(nil, ttX, ttY, ttW * columns, BORDER_WIDTH) -- top
DrawImage(nil, ttX, ttY + maxColumnHeight - BORDER_WIDTH, ttW * columns, BORDER_WIDTH) -- bottom

return ttW, ttH
end
end
Loading