Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a3be8e2
Initial Library and Spectre List
Blitz54 Jun 24, 2025
23a9b4d
Merge branch 'dev' into spectre-updates
Blitz54 Nov 21, 2025
17df987
run exporter again
Blitz54 Nov 21, 2025
008fe3f
Life still different than calcs, but closer
Blitz54 Nov 21, 2025
2559428
Merge branch 'dev' of https://github.com/Blitz54/PathOfBuilding into …
Blitz54 Nov 23, 2025
a3079d7
export
Blitz54 Nov 23, 2025
eb6c389
Merge branch 'dev' into spectre-updates
Blitz54 Jan 29, 2026
f8d2028
Merge branch 'dev' into spectre-updates
Blitz54 Apr 24, 2026
0a48c21
More fixes
Blitz54 Apr 24, 2026
8cb97ab
World area fixes, block chance in spectre library, and damage sorting…
Blitz54 Apr 25, 2026
4d12d11
Spec fixes from Schema
Blitz54 Apr 25, 2026
58cf40d
More spawn fixes
Blitz54 Apr 25, 2026
92f1ee8
Port over checkbox images from pob2, show icons for spectre type for …
Blitz54 Apr 25, 2026
6c8c3e8
Remove Labyrinth areas
Blitz54 Apr 25, 2026
3cd3507
Spec changes
Blitz54 Apr 25, 2026
c9612d8
World area flavour text, could be cleaner tho
Blitz54 Apr 25, 2026
284bd4f
More adjustments to world areas
Blitz54 Apr 25, 2026
d5d7d28
Used AI for this logic to combine world areas together. Probably doin…
Blitz54 Apr 26, 2026
341a3ee
Some Spectres
Blitz54 Apr 27, 2026
104ed52
More spectres
Blitz54 Apr 27, 2026
21ea25a
Moar spectre
Blitz54 Apr 28, 2026
82eecf7
Moar 2
Blitz54 Apr 28, 2026
2a12752
Moar 3
Blitz54 Apr 28, 2026
e8cca2f
Moar 4
Blitz54 Apr 28, 2026
47005b4
Remove Memory Void spawn location
Blitz54 Apr 28, 2026
0754ede
Moar 5
Blitz54 Apr 28, 2026
3037f2a
Moar 6
Blitz54 Apr 28, 2026
6d6428e
Moar 7
Blitz54 Apr 28, 2026
cbc1988
Additional Life Scaling
Blitz54 Apr 29, 2026
f02f30e
Moar Spectre 8
Blitz54 Apr 29, 2026
bc29dc1
ES Scaling
Blitz54 Apr 29, 2026
28a1e75
More spectre 9
Blitz54 Apr 29, 2026
489502a
Merge branch 'dev' into spectre-updates
Blitz54 Apr 29, 2026
e4e02ff
More spectres 10
Blitz54 May 1, 2026
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/monstercategory/categorybeasts.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/monstercategory/categoryconstruct.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/monstercategory/categorydemon.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/monstercategory/categoryeldritch.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/monstercategory/categoryhumanoid.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/monstercategory/categoryundead.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 30 additions & 7 deletions src/Classes/CheckBoxControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ local CheckBoxClass = newClass("CheckBoxControl", "Control", "TooltipHost", func
self.labelWidth = DrawStringWidth(self.width - 4, "VAR", label or "") + 5
self.changeFunc = changeFunc
self.state = initialState
self.checkImage = nil
end)

function CheckBoxClass:IsMouseOver()
Expand Down Expand Up @@ -42,6 +43,8 @@ function CheckBoxClass:Draw(viewPort, noTooltip)
elseif self.borderFunc then
local r, g, b = self.borderFunc()
SetDrawColor(r, g, b)
elseif self.checkImage and self.state then
SetDrawColor(0.75, 0.75, 0.75)
else
SetDrawColor(0.5, 0.5, 0.5)
end
Expand All @@ -56,15 +59,30 @@ function CheckBoxClass:Draw(viewPort, noTooltip)
SetDrawColor(0, 0, 0)
end
DrawImage(nil, x + 1, y + 1, size - 2, size - 2)
if self.state then
if not enabled then
SetDrawColor(0.33, 0.33, 0.33)
elseif mOver then
SetDrawColor(1, 1, 1)
if self.checkImage then
if self.state then
if not enabled then
SetDrawColor(0.33, 0.33, 0.33)
elseif mOver then
SetDrawColor(2, 2, 2)
else
SetDrawColor(1, 1, 1)
end
else
SetDrawColor(0.75, 0.75, 0.75)
SetDrawColor(0.5, 0.5, 0.5)
end
DrawImage(self.checkImage.handle, x + 1, y + 1, size - 2, size - 2, self.checkImage[1])
else
if self.state then
if not enabled then
SetDrawColor(0.33, 0.33, 0.33)
elseif mOver then
SetDrawColor(1, 1, 1)
else
SetDrawColor(0.75, 0.75, 0.75)
end
main:DrawCheckMark(x + size/2, y + size/2, size * 0.8)
end
main:DrawCheckMark(x + size/2, y + size/2, size * 0.8)
end
if enabled then
SetDrawColor(1, 1, 1)
Expand Down Expand Up @@ -106,3 +124,8 @@ function CheckBoxClass:OnKeyUp(key)
end
self.clicked = false
end

---@param image table @The image to display instead of a check. Expects a `handle` field with an image handle, and the sprite position at index `1`. All other fields are ignored. Set to `nil` to draw a normal check.
function CheckBoxClass:SetCheckImage(image)
self.checkImage = image
end
66 changes: 63 additions & 3 deletions src/Classes/MinionListControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ end
function MinionListClass:AddValueTooltip(tooltip, index, minionId)
if tooltip:CheckForUpdate(minionId) then
local minion = self.data.minions[minionId]
tooltip:AddLine(18, "^7"..minion.name)
tooltip.center = true
tooltip:AddLine(20, "^7"..minion.name, "FONTIN SC")
tooltip.center = false
tooltip:AddSeparator(10)
tooltip:AddLine(14, s_format("^7Life Multiplier: x%.2f", minion.life))
if minion.energyShield then
tooltip:AddLine(14, s_format("^7Energy Shield: %d%% of base Life", minion.energyShield * 100))
Expand All @@ -59,20 +62,35 @@ function MinionListClass:AddValueTooltip(tooltip, index, minionId)
if minion.evasion then
tooltip:AddLine(14, s_format("^7Evasion Multiplier: x%.2f", 1 + minion.evasion))
end
tooltip:AddLine(14, s_format("^7Resistances: %s%d^7/%s%d^7/%s%d^7/%s%d",
tooltip:AddLine(14, s_format("^7Resistances: %s%d ^7/ %s%d ^7/ %s%d ^7/ %s%d",
colorCodes.FIRE, minion.fireResist,
colorCodes.COLD, minion.coldResist,
colorCodes.LIGHTNING, minion.lightningResist,
colorCodes.CHAOS, minion.chaosResist
))
tooltip:AddLine(14, s_format("^7Base Damage: x%.2f", minion.damage))
tooltip:AddLine(14, s_format("^7Base Attack Speed: %.2f", 1 / minion.attackTime))

tooltip:AddLine(14, s_format("^7Base Movement Speed: %.2f", minion.baseMovementSpeed / 10))
for _, skillId in ipairs(minion.skillList) do
if self.data.skills[skillId] then
tooltip:AddLine(14, "^7Skill: "..self.data.skills[skillId].name)
end
end
tooltip:AddSeparator(10)
if #minion.spawnLocation > 0 then
local coloredLocations = {}
for _, location in ipairs(minion.spawnLocation) do -- Print (Map) or (Act 7) in white, and map name in green.
local mainText, bracket = location:match("^(.-)%s*(%b())%s*$")
table.insert(coloredLocations, bracket and (colorCodes.RELIC .. mainText .. " " .. "^7" .. bracket) or (colorCodes.RELIC .. location))
end
for i, spawn in ipairs(coloredLocations) do
if i == 1 then
tooltip:AddLine(14, s_format("^7Spawn: %s", spawn))
else
tooltip:AddLine(14, s_format("^7%s%s", " ", spawn)) -- Indented so all locations line up vertically in tooltip
end
end
end
end
end

Expand Down Expand Up @@ -101,3 +119,45 @@ function MinionListClass:OnSelDelete(index, minionId)
self.selValue = nil
end
end

local SpawnListClass = newClass("SpawnListControl", "ListControl", function(self, anchor, rect, data, list, label)
self.ListControl(anchor, rect, 16, "VERTICAL", false)
self.data = data
self.label = label or "^7Available Items:"
end)

function SpawnListClass:GetRowValue(column, index, spawnLocation)
return spawnLocation
end

function SpawnListClass:AddValueTooltip(tooltip, index, value)
if tooltip:CheckForUpdate(value) then
local foundArea = nil
for _, area in pairs(data.worldAreas) do
if area.name == value then
foundArea = area
break
end
end
if foundArea then
tooltip:AddLine(18, foundArea.name)
if foundArea.description then
ConPrintf("YES")
for _, line in ipairs(foundArea.description) do
tooltip:AddLine(14, colorCodes.CURRENCY .. '"' .. line .. '"')
end
end
if foundArea.bossVarieties and #foundArea.bossVarieties > 0 then
tooltip:AddLine(14, colorCodes.UNIQUE.. "Bosses: ^7" .. table.concat(foundArea.bossVarieties, ", "))
end
tooltip:AddLine(14, "^7Area Level: "..foundArea.level)
tooltip:AddSeparator(10)
tooltip:AddLine(14, "^7Spectres:")
for _, monsterName in ipairs(foundArea.monsterVarieties) do
tooltip:AddLine(14, " - " .. monsterName)
end
else
tooltip:AddLine(14, "^7World area not found: " .. tostring(value))
end
end
end
78 changes: 73 additions & 5 deletions src/Classes/MinionSearchListControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,95 @@ local t_remove = table.remove
local s_format = string.format

local MinionSearchListClass = newClass("MinionSearchListControl", "MinionListControl", function(self, anchor, rect, data, list, dest)
self.MinionListControl(anchor, rect, data, list, dest)
self.MinionListControl(anchor, rect, data, list, dest)
self:sortSourceList()
self.unfilteredList = copyTable(list)
self.isMutable = false

self.controls.searchText = new("EditControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 203, 18}, "", "Search", "%c", 100, function(buf)
self.controls.searchText = new("EditControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 148, 18}, "", "Search", "%c", 100, function(buf)
self:ListFilterChanged(buf, self.controls.searchModeDropDown.selIndex)
self:sortSourceList()
end, nil, nil, true)

self.controls.searchModeDropDown = new("DropDownControl", {"LEFT",self.controls.searchText,"RIGHT"}, {2, 0, 60, 18}, { "Names", "Skills", "Both"}, function(index, value)
self:ListFilterChanged(self.controls.searchText.buf, index)
self:sortSourceList()
end)
self.controls.sortModeDropDown = new("DropDownControl", {"BOTTOMRIGHT", self.controls.searchModeDropDown, "TOPRIGHT"}, {0, -2, self.width, 18}, {
"Sort by Names",
"Sort by Life + ES",
"Sort by Life",
"Sort by Energy Shield",
"Sort by Attack Speed",
"Sort by Base Damage",
"Sort by Fire Resistance",
"Sort by Cold Resistance",
"Sort by Lightning Resistance",
"Sort by Chaos Resistance",
"Sort by Total Resistance",
"Sort by Movement Speed",
}, function(index, value)
self:sortSourceList()
end)

self.labelPositionOffset = {0, -20}
self.labelPositionOffset = {0, -40}
if dest then
self.controls.add.y = self.controls.add.y - 20
self.controls.add.y = self.controls.add.y - 40
else
self.controls.delete.y = self.controls.add.y - 20
self.controls.delete.y = self.controls.add.y - 40
end

end)

function MinionSearchListClass:sortSourceList()
local sortFields = {
[1] = { field = "name", asc = true },
[2] = { field = "totalHitPoints", asc = false },
[3] = { field = "life", asc = false },
[4] = { field = "energyShield", asc = false },
[5] = { field = "attackTime", asc = true },
[6] = { field = "damage", asc = false },
[7] = { field = "fireResist", asc = false },
[8] = { field = "coldResist", asc = false },
[9] = { field = "lightningResist", asc = false },
[10] = { field = "chaosResist", asc = false },
[11] = { field = "totalResist", asc = false },
[12] = { field = "baseMovementSpeed", asc = false },
}
local sortModeIndex = self.controls.sortModeDropDown and self.controls.sortModeDropDown.selIndex or 1
local sortOption = sortFields[sortModeIndex]
if sortOption then
table.sort(self.list, function(a, b)
local minionA = self.data.minions[a]
local minionB = self.data.minions[b]
local valueA = minionA[sortOption.field]
local valueB = minionB[sortOption.field]
if sortOption.field == "life" then
valueA = minionA.life * (1 - (minionA.energyShield or 0))
valueB = minionB.life * (1 - (minionB.energyShield or 0))
elseif sortOption.field == "totalHitPoints" then
valueA = minionA.life
valueB = minionB.life
elseif sortOption.field == "energyShield" then
valueA = (minionA.energyShield or 0) * minionA.life
valueB = (minionB.energyShield or 0) * minionB.life
elseif sortOption.field == "totalResist" then
valueA = (minionA.fireResist or 0) + (minionA.coldResist or 0) + (minionA.lightningResist or 0) + (minionA.chaosResist or 0)
valueB = (minionB.fireResist or 0) + (minionB.coldResist or 0) + (minionB.lightningResist or 0) + (minionB.chaosResist or 0)
end
if valueA == valueB then
return minionA.name < minionB.name
else
if sortOption.asc then
return valueA < valueB
else
return valueA > valueB
end
end
end)
end
end

function MinionSearchListClass:DoesEntryMatchFilters(searchStr, minionId, filterMode)
if filterMode == 1 or filterMode == 3 then
local err, match = PCall(string.matchOrPattern, self.data.minions[minionId].name:lower(), searchStr)
Expand Down
1 change: 1 addition & 0 deletions src/Classes/Tooltip.lua
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ function TooltipClass:Draw(x, y, w, h, viewPort)
end
DrawImage(nil, ttX, ttY, ttW * columns, BORDER_WIDTH) -- top border
DrawImage(nil, ttX, ttY + maxColumnHeight - BORDER_WIDTH, ttW * columns, BORDER_WIDTH) -- bottom border
SetDrawColor(1, 1, 1) -- Reset draw color to white as it messes with Spectre Library

return ttW, ttH
end
Loading
Loading