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
41 changes: 41 additions & 0 deletions .emmyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"runtime": {
"version": "LuaJIT",
"requirePattern": [
"?.lua",
"?/init.lua"
],
"requireLikeFunction": [
"LoadModule",
"PLoadModule"
],
"nonstandardSymbol": [
"+="
]
},
"diagnostics": {
"severity": {
"global-in-non-module": "hint",
"inject-field": "hint",
"unnecessary-assert": "hint",
"unnecessary-if": "hint"
}
},
"workspace": {
"workspaceRoots": [
"./src",
"./spec"
],
"library": [
"./runtime/lua",
"./types"
],
"ignoreGlobs": [
"**/TreeData/**",
"**/Data/ModCache.lua",
"**/Data/Skills/**",
"**/Data/StatDescriptions/stat_descriptions.lua",
"**/Export/**"
]
}
}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,4 @@ runtime/SimpleGraphic/SimpleGraphic.log
src/poe_api_response.json
runtime/SimpleGraphic/Screenshots

.emmyrc.json
.luarc.json
5 changes: 5 additions & 0 deletions spec/GenerateBuilds.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
local lfs = require("lfs")

local function fetchBuilds(path, buildList)
buildList = buildList or {}
for file in lfs.dir(path) do
Expand Down Expand Up @@ -45,6 +47,9 @@ local buildList = fetchBuilds("../spec/TestBuilds")
for filename, testBuild in pairs(buildList) do
loadBuildFromXML(testBuild)
local fileHnd, errMsg = io.open(filename:gsub("^(.+)%..+$", "%1.lua"), "w+")
if not fileHnd then
error(errMsg)
end
fileHnd:write("return {\n xml = [[")
fileHnd:write(testBuild)
fileHnd:write("]],\n ")
Expand Down
2 changes: 2 additions & 0 deletions spec/System/TestBuilds_spec.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
local lfs = require("lfs")

local function fetchBuilds(path, buildList)
buildList = buildList or {}
for file in lfs.dir(path) do
Expand Down
10 changes: 8 additions & 2 deletions spec/System/TestImport_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ describe("TestImport", function()
local dkjson = require "dkjson"

local sampleJson, err = io.open("../spec/System/SampleCharacter.json", "r")
if err then
ConPrintf("Failed to read sample character response: %s", err)
if not sampleJson then
local errMsg = err or "unknown error"
ConPrintf("Failed to read sample character response: %s", errMsg)
error(errMsg)
end
---@cast sampleJson -?
local sampleData = dkjson.decode(sampleJson:read("*a")).character
sampleJson:close()

Expand Down Expand Up @@ -131,6 +134,9 @@ describe("TestImport", function()

local itemId = build.itemsTab.slots.Gloves.selItemId
local item = build.itemsTab.items[itemId]
if not item then
error("Failed to import test item")
end
local explicitMods = { }
for _, modLine in ipairs(item.explicitModLines) do
explicitMods[modLine.line] = modLine
Expand Down
2 changes: 1 addition & 1 deletion spec/TestBuilds/3.13/Dual Savior.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,7 @@ Triggers Level 20 Reflection when Equipped
["ManaLeechDuration"] = 0,
["EnergyShieldRecoveryRateMod"] = 1,
["ChaosResistOver75"] = 0,
["EnergyShieldRegenPercent"] = nan,
["EnergyShieldRegenPercent"] = 0 / 0,
["CurrentScorch"] = 0,
["SelfChillDuration"] = 100,
["BlockChance"] = 15,
Expand Down
48 changes: 31 additions & 17 deletions src/Classes/CalcBreakdownControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ function CalcBreakdownClass:CalcBreakdownControl(calcsTab)
self.borderThickness = 2
self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({ "RIGHT", self, "RIGHT" }, { -2, 0, 18, 0 }, 80,
"VERTICAL", true)
self.controls.scrollBar.x = function()
return -self.borderThickness
end
self.controls.scrollBar.x = -self.borderThickness
self.pinnedColour = { 0.25, 1, 0.25 }
self.borderColour = { 0.33, 0.66, 0.33 }
return self
Expand Down Expand Up @@ -435,13 +433,22 @@ function CalcBreakdownClass:AddModSection(sectionData, modList)
-- Modifier is from a passive node, add node name, and add node ID (used to show node location)
local nodeId = row.mod.source:match("Tree:(%d+)")
local tattooNodeId = row.mod.source:match("Tree:(%w+)")
local tree = build.spec.tree
if nodeId then
local nodeIdNumber = tonumber(nodeId)
local node = build.spec.nodes[nodeIdNumber] or build.spec.tree.nodes[nodeIdNumber] or build.latestTree.nodes[nodeIdNumber]
row.sourceName = node.dn
row.sourceNameNode = node
elseif tattooNodeId then
row.sourceName = build.spec.tree.tattoo.idMap[tattooNodeId]
---@type table<integer, any>
local specNodes = build.spec.nodes
---@type table<integer, any>?
local treeNodes = tree and tree.nodes
---@type table<integer, any>?
local latestTreeNodes = build.latestTree and build.latestTree.nodes
local node = specNodes[nodeIdNumber] or (treeNodes and treeNodes[nodeIdNumber]) or (latestTreeNodes and latestTreeNodes[nodeIdNumber])
if node then
row.sourceName = node.dn
row.sourceNameNode = node
end
elseif tattooNodeId and tree and tree.tattoo then
row.sourceName = tree.tattoo.idMap[tattooNodeId]
end
elseif sourceType == "Skill" then
-- Extract skill name
Expand Down Expand Up @@ -629,16 +636,22 @@ function CalcBreakdownClass:DrawBreakdownTable(viewPort, x, y, section)
SetDrawColor(1, 1, 1)
DrawImage(nil, viewerX, viewerY, 304, 304)
local viewer = self.nodeViewer
---@cast viewer PassiveTreeView
viewer.zoom = 5
local scale = self.calcsTab.build.spec.tree.size / 1500
viewer.zoomX = -ttNode.x / scale
viewer.zoomY = -ttNode.y / scale
SetViewport(viewerX + 2, viewerY + 2, 300, 300)
viewer:Draw(self.calcsTab.build, { x = 0, y = 0, width = 300, height = 300 }, { })
SetDrawLayer(nil, 30)
SetDrawColor(1, 0, 0)
DrawImage(viewer.highlightRing, 135, 135, 30, 30)
SetViewport()
local tree = self.calcsTab.build.spec.tree
if tree then
local scale = tree.size / 1500
---@type number
viewer.zoomX = -ttNode.x / scale
---@type number
viewer.zoomY = -ttNode.y / scale
SetViewport(viewerX + 2, viewerY + 2, 300, 300)
viewer:Draw(self.calcsTab.build, { x = 0, y = 0, width = 300, height = 300 }, { })
SetDrawLayer(nil, 30)
SetDrawColor(1, 0, 0)
DrawImage(viewer.highlightRing, 135, 135, 30, 30)
SetViewport()
end
end
SetDrawLayer(nil, 10)
end
Expand Down Expand Up @@ -697,6 +710,7 @@ function CalcBreakdownClass:Draw(viewPort)
-- Content won't fit the screen height, so set the scrollbar
width = self.contentWidth + scrollBar.width
height = viewPort.height
---@cast scrollBar any
scrollBar.height = height - borderThickness * 2
scrollBar:SetContentDimension(self.contentHeight - borderThickness * 2, viewPort.height - borderThickness * 2)
else
Expand Down
1 change: 0 additions & 1 deletion src/Classes/Control.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ function ControlClass:Control(anchor, rect)
return self
end

---@generic T
---@alias Prop<T> (fun(self: self): T) | T

---@param name string
Expand Down
2 changes: 1 addition & 1 deletion src/Classes/ControlHost.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function ControlHostClass:ProcessControlsInput(inputEvents, viewPort)
inputEvents[id] = nil
end

local mOverControl = self:GetMouseOverControl(viewPort)
local mOverControl = self:GetMouseOverControl()

-- Avoid calculating isMouseInRegion as much as possible as it's expensive
if mOverControl and (not selControl or mOverControl.OnHoverKeyUp) then
Expand Down
3 changes: 1 addition & 2 deletions src/Classes/ImportTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ function ImportTabClass:DownloadItems(realm)
end)
end
function ImportTabClass:DownloadSiteCharacterList(realm)
function FindMatchingStandardLeague(league)
local function FindMatchingStandardLeague(league)
-- Find a Standard league name for a given league name
-- Reference https://api.pathofexile.com/league?realm=pc
if string.find(league, "Hardcore") then
Expand Down Expand Up @@ -970,7 +970,6 @@ function ImportTabClass:DownloadSiteCharacterList(realm)
self.lastAccountHash = common.sha1(accountName)
main.lastAccountName = accountName
main.gameAccounts[accountName] = main.gameAccounts[accountName] or {}
main.gameAccounts[accountName].sessionID = sessionID
local leagueList = {}
for i, char in ipairs(charList) do
if not isValueInArray(leagueList, char.league) then
Expand Down
3 changes: 3 additions & 0 deletions src/Classes/ItemDBControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ local ItemDBClass = newClass("ItemDBControl", "ListControl")
---@field byTitle? table<string, Item>
---@field loading boolean?

---@class UniqueItemDBData: ItemDBData
---@field byTitle table<string, Item>

---@param anchor Anchor?
---@param rect Rect?
---@param itemsTab ItemsTab
Expand Down
1 change: 1 addition & 0 deletions src/Classes/ItemsTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ end

---@class ItemsTab: UndoHandler, ControlHost, Control
---@field displayItem Item?
---@field items table<integer, Item>
local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Control")

---@param build Build
Expand Down
2 changes: 1 addition & 1 deletion src/Classes/ModDB.lua
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ function ModDBClass:ListInternal(context, result, cfg, flags, keywordFlags, sour
if mod.type == "LIST" and band(flags, mod.flags) == mod.flags and MatchKeywordFlags(keywordFlags, mod.keywordFlags) and (not source or mod.source:match("[^:]+") == source) then
local value
if mod[1] then
local value = context:EvalMod(mod, cfg) or nullValue
local value = context:EvalMod(mod, cfg)
if value then
t_insert(result, value)
end
Expand Down
2 changes: 1 addition & 1 deletion src/Classes/ModList.lua
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ function ModListClass:ListInternal(context, result, cfg, flags, keywordFlags, so
if mod.name == modName and mod.type == "LIST" and band(flags, mod.flags) == mod.flags and MatchKeywordFlags(keywordFlags, mod.keywordFlags) and (not source or mod.source:match("[^:]+") == source) then
local value
if mod[1] then
local value = context:EvalMod(mod, cfg) or nullValue
local value = context:EvalMod(mod, cfg)
if value then
t_insert(result, value)
end
Expand Down
31 changes: 28 additions & 3 deletions src/Classes/ModStore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,37 @@ local conditionName = setmetatable({ }, { __index = function(t, var)
return t[var]
end })

-- TODO: very incomplete
---@class ModCfg
---@field flags number? bit mask
---@field keywordFlags number?
---@field flags integer? bit mask
---@field keywordFlags integer?
---@field skillName string?
---@field summonSkillName string?
---@field skillGem any?
---@field skillGrantedEffect any?
---@field skillPart integer?
---@field skillTypes table?
---@field skillCond table<string, boolean>?
---@field skillDist number?
---@field slotName string?
---@field socketColor any?
---@field socketNum integer?
---@field source string?
---@field actor string?
---@field skillStats table<string, number>?
---@field baseFlags table?
---@field dexterityGems integer?
---@field intelligenceGems integer?
---@field strengthGems integer?
---@field item Item?

---@class SkillCfg: ModCfg
---@field flags integer
---@field keywordFlags integer
---@field skillName string
---@field skillGrantedEffect any
---@field skillPart integer
---@field skillTypes table
---@field skillCond table<string, boolean>

---@class ModStore
local ModStoreClass = newClass("ModStore")
Expand Down
4 changes: 2 additions & 2 deletions src/Classes/NotableDBControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ local function IsAnointableNode(node)
return node.recipe and #node.recipe >= 1
end

---@class NotableDBControl : ListControl
---@class NotableDBControl : ListControl<table>
local NotableDBClass = newClass("NotableDBControl", "ListControl")

---@param itemsTab ItemsTab
Expand Down Expand Up @@ -290,5 +290,5 @@ end
---@param index number
---@param node table
function NotableDBClass:OnSelCopy(index, node)
Copy(item.dn)
Copy(node.dn)
end
8 changes: 4 additions & 4 deletions src/Classes/PartyTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,10 @@ function PartyTabClass:PartyTab(build)
-- Parse the XML
local dbXML, errMsg = common.xml.ParseXML(self.importCodeXML)
if not dbXML then
launch:ShowErrMsg("^1Error loading '%s': %s", fileName, errMsg)
launch:ShowErrMsg("^1Error loading import code: %s", errMsg)
return
elseif dbXML[1].elem ~= "PathOfBuilding" then
launch:ShowErrMsg("^1Error parsing '%s': 'PathOfBuilding' root element missing", fileName)
launch:ShowErrMsg("^1Error parsing import code: 'PathOfBuilding' root element missing")
return
end

Expand Down Expand Up @@ -916,8 +916,8 @@ function PartyTabClass:ParseBuffs(list, buf, buffType, label)
end
end
if list["AuraDebuff"] and list["AuraDebuff"]["Vaal"] then
if not list["Aura"] or not list["Aura"]["Vaal"] or not list["Aura"]["Vaal"][aura] then
for aura, auraMod in pairs(list["AuraDebuff"]["Vaal"]) do
for aura, auraMod in pairs(list["AuraDebuff"]["Vaal"]) do
if not list["Aura"] or not list["Aura"]["Vaal"] or not list["Aura"]["Vaal"][aura] then
t_insert(labelList, aura..": "..auraMod.effectMult.."%\n")
end
end
Expand Down
2 changes: 2 additions & 0 deletions src/Classes/PassiveSpec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ local bor = bit.bor
---@class PassiveSpec: UndoHandler
---@field nodes table<integer, Node>
---@field allocNodes table<integer, Node>
---@field jewel_data table<integer, table>
local PassiveSpecClass = newClass("PassiveSpec", "UndoHandler")

---@param build Build
Expand Down Expand Up @@ -82,6 +83,7 @@ function PassiveSpecClass:Init(treeVersion, convert)
-- Table of jewels equipped in this tree
-- Keys are node IDs, values are items
self.jewels = { }
self.jewel_data = { }

-- Tree graphs dynamically generated from cluster jewels
-- Keys are subgraph IDs, values are graphs
Expand Down
4 changes: 4 additions & 0 deletions src/Classes/PassiveTreeView.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ local function isAbyssConquered(node)
end

---@class PassiveTreeView
---@field zoomX number
---@field zoomY number
local PassiveTreeViewClass = newClass("PassiveTreeView")

function PassiveTreeViewClass:PassiveTreeView()
Expand Down Expand Up @@ -72,7 +74,9 @@ function PassiveTreeViewClass:PassiveTreeView()

self.zoomLevel = 3
self.zoom = 1.2 ^ self.zoomLevel
---@type number
self.zoomX = 0
---@type number
self.zoomY = 0

self.searchStr = ""
Expand Down
2 changes: 1 addition & 1 deletion src/Classes/PathControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
local ipairs = ipairs
local t_insert = table.insert

---@class PathControl
---@class PathControl: Control, ControlHost, UndoHandler
local PathClass = newClass("PathControl", "Control", "ControlHost", "UndoHandler")

function PathClass:PathControl(anchor, rect, basePath, subPath, onChange)
Expand Down
2 changes: 1 addition & 1 deletion src/Classes/SharedItemListControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ local pairs = pairs
local t_insert = table.insert
local t_remove = table.remove

---@class SharedItemListControl: ListControl
---@class SharedItemListControl: ListControl<Item>
local SharedItemListClass = newClass("SharedItemListControl", "ListControl")

---@param anchor Anchor?
Expand Down
4 changes: 4 additions & 0 deletions src/Classes/TooltipHost.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
-- Tooltip host
--
---@class TooltipHost
---@field tooltip Tooltip
---@field tooltipText string?
---@field tooltipFunc? fun(tooltip: Tooltip, ...: any)
---@field Object Control
local TooltipHostClass = newClass("TooltipHost")

function TooltipHostClass:TooltipHost(tooltipText)
Expand Down
Loading