Skip to content
Open
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
141 changes: 109 additions & 32 deletions src/Classes/GemSelectControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ local GemSelectClass = newClass("GemSelectControl", "EditControl", function(self
lifeReservationPercent = "LifePercent",
}
self.imbuedSelect = imbued
self.dpsBuildFlag = false
end)

function GemSelectClass:CalcOutputWithThisGem(calcFunc, gemData, useFullDPS)
Expand Down Expand Up @@ -168,11 +169,12 @@ function GemSelectClass:BuildList(buf)
t_remove(tagsList, 1)

-- Search for gem name using increasingly broad search patterns
local lowerSearch = searchTerm:lower()
local patternList = {
"^ " .. searchTerm:lower().."$", -- Exact match
"^" .. searchTerm:lower():gsub("%a", " %0%%l+") .. "$", -- Simple abbreviation ("CtF" -> "Cold to Fire")
"^ " .. searchTerm:lower(), -- Starts with
searchTerm:lower(), -- Contains
"^ " .. lowerSearch.."$", -- Exact match
"^" .. lowerSearch:gsub("%a", " %0%%l+") .. "$", -- Simple abbreviation ("CtF" -> "Cold to Fire")
"^ " .. lowerSearch, -- Starts with
lowerSearch, -- Contains
}
for i, pattern in ipairs(patternList) do
local matchList = { }
Expand Down Expand Up @@ -340,44 +342,87 @@ function GemSelectClass:UpdateSortCache()
-- Check for nil because some fields may not be populated, default to 0
local baseDPS = (dpsField == "FullDPS" and calcBase[dpsField] ~= nil and calcBase[dpsField]) or (calcBase.Minion and calcBase.Minion.CombinedDPS) or (calcBase[dpsField] ~= nil and calcBase[dpsField]) or 0

sortCache.calcFunc = calcFunc
sortCache.useFullDPS = useFullDPS
sortCache.baseDPS = baseDPS
sortCache.dpsField = dpsField
sortCache.pendingGems = { }

for gemId, gemData in pairs(self.gems) do
sortCache.dps[gemId] = baseDPS
-- Ignore gems that don't support the active skill
-- Gems that support the active skill or have global effects need DPS calc
if sortCache.canSupport[gemId] or (gemData.grantedEffect.hasGlobalEffect and not gemData.grantedEffect.support) then
local output = self:CalcOutputWithThisGem(calcFunc, gemData, useFullDPS)
-- Check for nil because some fields may not be populated, default to 0
sortCache.dps[gemId] = (dpsField == "FullDPS" and output[dpsField] ~= nil and output[dpsField]) or (output.Minion and output.Minion.CombinedDPS) or (output[dpsField] ~= nil and output[dpsField]) or 0
end
-- Color based on the DPS
if sortCache.dps[gemId] > baseDPS then
sortCache.dpsColor[gemId] = "^x228866"
elseif sortCache.dps[gemId] < baseDPS then
sortCache.dpsColor[gemId] = "^xFF4422"
else
sortCache.dpsColor[gemId] = "^xFFFF66"
sortCache.pendingGems[#sortCache.pendingGems + 1] = gemId
end
-- Neutral color until DPS is computed
sortCache.dpsColor[gemId] = ""
end

--ConPrintf("Gem Selector time: %d ms", GetTime() - start)
self.dpsBuildFlag = true
end

function GemSelectClass:SortGemList(gemList)
local sortCache = self.sortCache
local gems = self.gems
-- cache names to avoid repeated table lookups in comparator
local names = {}
for _, gemId in ipairs(gemList) do
local gem = gems[gemId]
names[gemId] = gem and gem.name or gemId
end
t_sort(gemList, function(a, b)
if sortCache.canSupport[a] == sortCache.canSupport[b] then
if self.skillsTab.sortGemsByDPS and sortCache.dps[a] ~= sortCache.dps[b] then
return sortCache.dps[a] > sortCache.dps[b]
else
local nameA = (self.gems[a] and self.gems[a].name) or a
local nameB = (self.gems[b] and self.gems[b].name) or b
return nameA < nameB
return names[a] < names[b]
end
else
return sortCache.canSupport[a]
end
end)
end

function GemSelectClass:DPSBuilder()
local sortCache = self.sortCache
if not sortCache or not sortCache.pendingGems then return end

local pending = sortCache.pendingGems
local calcFunc = sortCache.calcFunc
local useFullDPS = sortCache.useFullDPS
local baseDPS = sortCache.baseDPS
local dpsField = sortCache.dpsField
local start = GetTime()

for index, gemId in ipairs(pending) do
local gemData = self.gems[gemId]
if gemData then
local output = self:CalcOutputWithThisGem(calcFunc, gemData, useFullDPS)
sortCache.dps[gemId] = (dpsField == "FullDPS" and output[dpsField] ~= nil and output[dpsField]) or (output.Minion and output.Minion.CombinedDPS) or (output[dpsField] ~= nil and output[dpsField]) or 0
if sortCache.dps[gemId] > baseDPS then
sortCache.dpsColor[gemId] = "^x228866"
elseif sortCache.dps[gemId] < baseDPS then
sortCache.dpsColor[gemId] = "^xFF4422"
else
sortCache.dpsColor[gemId] = "^xFFFF66"
end
end
local now = GetTime()
if now - start > 50 then
if #self.searchStr == 0 then
self:SortGemList(self.list)
end
coroutine.yield()
start = now
end
end

if #self.searchStr == 0 then
self:SortGemList(self.list)
end
sortCache.pendingGems = nil
end

function GemSelectClass:UpdateGem(setText, addUndo, focusLost)
local gemId = self.list[m_max(self.selIndex, 1)]
-- don't process unless the buffer equals an actual gem, whether typed, clicked, or navigated with arrows
Expand Down Expand Up @@ -428,6 +473,20 @@ function GemSelectClass:IsMouseOver()
end

function GemSelectClass:Draw(viewPort, noTooltip)
if self.dpsBuildFlag then
self.dpsBuildFlag = false
self.dpsBuilder = coroutine.create(self.DPSBuilder)
end
if self.dpsBuilder then
local res, errMsg = coroutine.resume(self.dpsBuilder, self)
if launch.devMode and not res then
error(errMsg)
end
if coroutine.status(self.dpsBuilder) == "dead" then
self.dpsBuilder = nil
end
end

self.EditControl:Draw(viewPort, noTooltip and not self.forceTooltip)
local x, y = self:GetPos()
local width, height = self:GetSize()
Expand All @@ -446,6 +505,11 @@ function GemSelectClass:Draw(viewPort, noTooltip)
end
if self.dropped then
SetDrawLayer(nil, 5)
if self.dpsBuilder then
local dots = ("."):rep((math.floor(GetTime() / 500) % 3) + 1)
SetDrawColor(0.75, 0.75, 0.75)
DrawString(x + width - 80, y, "LEFT", height - 2, "VAR", "Sorting" .. dots)
end
local cursorX, cursorY = GetCursorPos()
self.hoverSel = mOverComp == "DROP" and math.floor((cursorY - y - height + scrollBar.offset) / (height - 4)) + 1
if self.hoverSel and not self.gems[self.list[self.hoverSel]] then
Expand Down Expand Up @@ -475,10 +539,10 @@ function GemSelectClass:Draw(viewPort, noTooltip)
local gemText = gemData and gemData.name or "<No matches>"
DrawString(0, y, "LEFT", height - 4, "VAR", gemText)
if gemData then
if gemData.grantedEffect.support and self.sortCache.canSupport[gemId] then
if gemData.grantedEffect.support and self.sortCache.canSupport[gemId] and self.sortCache.dpsColor[gemId] ~= "" then
SetDrawColor(self.sortCache.dpsColor[gemId])
main:DrawCheckMark(width - 4 - height / 2 - (scrollBar.enabled and 18 or 0), y + (height - 4) / 2, (height - 4) * 0.8)
elseif gemData.grantedEffect.hasGlobalEffect then
elseif gemData.grantedEffect.hasGlobalEffect and self.sortCache.dpsColor[gemId] ~= "" then
SetDrawColor(self.sortCache.dpsColor[gemId])
DrawString(width - 4 - height / 2 - (scrollBar.enabled and 18 or 0), y - 2, "CENTER_X", height, "VAR", "+")
end
Expand All @@ -487,14 +551,23 @@ function GemSelectClass:Draw(viewPort, noTooltip)
SetViewport()
self:DrawControls(viewPort, (noTooltip and not self.forceTooltip) and self)
if self.hoverSel then
local calcFunc, calcBase = self.skillsTab.build.calcsTab:GetMiscCalculator(self.build)
if calcFunc then
self.tooltip:Clear()
local gemData = self.gems[self.list[self.hoverSel]]
local output= self:CalcOutputWithThisGem(calcFunc, gemData, self.skillsTab.sortGemsByDPSField == "FullDPS")
local gemInstance = {
-- Debounce hover
if self.hoverSel == self.lastHoverSel then
self.hoverFrameCount = (self.hoverFrameCount or 0) + 1
else
self.lastHoverSel = self.hoverSel
self.hoverFrameCount = 0
end
if self.hoverFrameCount >= 2 then
local calcFunc, calcBase = self.skillsTab.build.calcsTab:GetMiscCalculator(self.build)
if calcFunc then
self.tooltip:Clear()
local gemData = self.gems[self.list[self.hoverSel]]
local output= self:CalcOutputWithThisGem(calcFunc, gemData, self.skillsTab.sortGemsByDPSField == "FullDPS")
local gemInstance = {
level = self.skillsTab:ProcessGemLevel(gemData, self.imbuedSelect),
quality = self.skillsTab.defaultGemQuality or 0,
qualityId = "Default",
count = 1,
enabled = true,
enableGlobal1 = true,
Expand All @@ -505,11 +578,15 @@ function GemSelectClass:Draw(viewPort, noTooltip)
displayEffect = nil,
gemData = gemData
}
self:AddGemTooltip(gemInstance)
self.tooltip:AddSeparator(10)
self.skillsTab.build:AddStatComparesToTooltip(self.tooltip, calcBase, output, "^7Selecting this gem will give you:")
self.tooltip:Draw(x, y + height + 2 + (self.hoverSel - 1) * (height - 4) - scrollBar.offset, width, height - 4, viewPort)
self:AddGemTooltip(gemInstance)
self.tooltip:AddSeparator(10)
self.skillsTab.build:AddStatComparesToTooltip(self.tooltip, calcBase, output, "^7Selecting this gem will give you:")
self.tooltip:Draw(x, y + height + 2 + (self.hoverSel - 1) * (height - 4) - scrollBar.offset, width, height - 4, viewPort)
end
end
else
self.lastHoverSel = nil
self.hoverFrameCount = 0
end
SetDrawLayer(nil, 0)
else
Expand Down
Loading