diff --git a/Classes/Control.lua b/Classes/Control.lua index 7e095d14..39e0bcf0 100644 --- a/Classes/Control.lua +++ b/Classes/Control.lua @@ -3,6 +3,7 @@ -- Class: Control -- UI control base class -- +local launch, main = ... local t_insert = table.insert local m_floor = math.floor diff --git a/Classes/ImportTab.lua b/Classes/ImportTab.lua index daae9870..ee383dd4 100644 --- a/Classes/ImportTab.lua +++ b/Classes/ImportTab.lua @@ -130,13 +130,17 @@ You can get this from your web browser's cookies while logged into the Path of E end self.controls.generateCodePastebin = common.New("ButtonControl", {"LEFT",self.controls.generateCodeCopy,"RIGHT"}, 8, 0, 140, 20, "Share with Pastebin", function() local id = LaunchSubScript([[ - local code = ... + local code, proxyURL = ... local curl = require("lcurl.safe") local page = "" local easy = curl.easy() easy:setopt_url("https://pastebin.com/api/api_post.php") easy:setopt(curl.OPT_POST, true) easy:setopt(curl.OPT_POSTFIELDS, "api_dev_key=c4757f22e50e65e21c53892fd8e0a9ff&api_option=paste&api_paste_code="..code) + easy:setopt(curl.OPT_ACCEPT_ENCODING, "") + if proxyURL then + easy:setopt(curl.OPT_PROXY, proxyURL) + end easy:setopt_writefunction(function(data) page = page..data return true @@ -148,7 +152,7 @@ You can get this from your web browser's cookies while logged into the Path of E else return nil, page end - ]], "", "", self.controls.generateCodeOut.buf) + ]], "", "", self.controls.generateCodeOut.buf, launch.proxyURL) if id then self.controls.generateCodeOut:SetText("") self.controls.generateCodePastebin.label = "Creating paste..." diff --git a/Classes/ItemDBControl.lua b/Classes/ItemDBControl.lua index 54165b9e..c063c6d6 100644 --- a/Classes/ItemDBControl.lua +++ b/Classes/ItemDBControl.lua @@ -13,10 +13,7 @@ local ItemDBClass = common.NewClass("ItemDB", "ListControl", function(self, anch self.ListControl(anchor, x, y, width, height, 16, false) self.itemsTab = itemsTab self.db = db - self.dragTargetList = { itemsTab.controls.itemList } - for _, slot in pairs(itemsTab.slots) do - t_insert(self.dragTargetList, slot) - end + self.dragTargetList = { } self.sortControl = { NAME = { key = "name", order = 1, dir = "ASCEND", func = function(a,b) return a:gsub("^The ","") < b:gsub("^The ","") end } } @@ -163,8 +160,10 @@ function ItemDBClass:GetRowValue(column, index, item) end function ItemDBClass:AddValueTooltip(index, item) - self.itemsTab:AddItemTooltip(item, nil, true) - return data.colorCodes[item.rarity], true + if not main.popups[1] then + self.itemsTab:AddItemTooltip(item, nil, true) + return data.colorCodes[item.rarity], true + end end function ItemDBClass:GetDragValue(index, item) diff --git a/Classes/ItemListControl.lua b/Classes/ItemListControl.lua index d469126d..a11eb94f 100644 --- a/Classes/ItemListControl.lua +++ b/Classes/ItemListControl.lua @@ -13,9 +13,6 @@ local ItemListClass = common.NewClass("ItemList", "ListControl", function(self, self.itemsTab = itemsTab self.label = "^7All items:" self.dragTargetList = { } - for _, slot in pairs(itemsTab.slots) do - t_insert(self.dragTargetList, slot) - end self.controls.sort = common.New("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, -64, -2, 60, 18, "Sort", function() itemsTab:SortItemList() end) @@ -36,8 +33,10 @@ end function ItemListClass:AddValueTooltip(index, itemId) local item = self.itemsTab.list[itemId] - self.itemsTab:AddItemTooltip(item, nil, true) - return data.colorCodes[item.rarity], true + if not main.popups[1] then + self.itemsTab:AddItemTooltip(item, nil, true) + return data.colorCodes[item.rarity], true + end end function ItemListClass:GetDragValue(index, itemId) diff --git a/Classes/ItemSlotControl.lua b/Classes/ItemSlotControl.lua index 07210814..4267d0e0 100644 --- a/Classes/ItemSlotControl.lua +++ b/Classes/ItemSlotControl.lua @@ -104,6 +104,9 @@ function ItemSlotClass:Draw(viewPort) SetDrawColor(0, 1, 0, 0.25) DrawImage(nil, x, y, width, height) end + if main.popups[1] then + return + end if self.nodeId and (self.dropped or (self:IsMouseOver() and (self.otherDragSource or not self.itemsTab.selControl))) then SetDrawLayer(nil, 15) local viewerX = x + width + 5 @@ -124,7 +127,7 @@ function ItemSlotClass:Draw(viewPort) SetViewport() SetDrawLayer(nil, 0) end - if self:IsMouseOver() and not main.popups[1] then + if self:IsMouseOver() then local ttItem if self.dropped then if self.hoverSel then diff --git a/Classes/ItemsTab.lua b/Classes/ItemsTab.lua index 823c7ef6..ea47807f 100644 --- a/Classes/ItemsTab.lua +++ b/Classes/ItemsTab.lua @@ -168,12 +168,12 @@ local ItemsTabClass = common.NewClass("ItemsTab", "UndoHandler", "ControlHost", return not self.controls.selectDBLabel:IsShown() or self.controls.selectDB.sel == 2 end - -- Display item + -- Create/import item self.controls.craftDisplayItem = common.New("ButtonControl", {"TOPLEFT",self.controls.itemList,"TOPRIGHT"}, 20, 0, 120, 20, "Craft item...", function() self:CraftItem() end) self.controls.craftDisplayItem.shown = function() - return self.displayItem == nil + return self.displayItem == nil end self.controls.newDisplayItem = common.New("ButtonControl", {"TOPLEFT",self.controls.craftDisplayItem,"TOPRIGHT"}, 8, 0, 120, 20, "Create custom...", function() self:EditDisplayItemText() @@ -185,6 +185,9 @@ to view/edit the item and add it to your build. You can Control + Click an item to equip it, or drag it onto the slot. This will also add it to your build if it's from the unique/template list. If there's 2 slots an item can go in, holding Shift will put it in the second.]]) + self.controls.sharedItemList = common.New("SharedItemList", {"TOPLEFT",self.controls.craftDisplayItem, "BOTTOMLEFT"}, 0, 142, 360, 308, self) + + -- Display item self.anchorDisplayItem = common.New("Control", {"TOPLEFT",self.controls.itemList,"TOPRIGHT"}, 20, 0, 0, 0) self.anchorDisplayItem.shown = function() return self.displayItem ~= nil @@ -253,7 +256,21 @@ If there's 2 slots an item can go in, holding Shift will put it in the second.]] end) -- Scroll bar - self.controls.scrollBarH = common.New("ScrollBarControl", nil, 0, 0, 0, 18, 80, "HORIZONTAL", true) + self.controls.scrollBarH = common.New("ScrollBarControl", nil, 0, 0, 0, 18, 100, "HORIZONTAL", true) + + -- Initialise drag target lists + t_insert(self.controls.itemList.dragTargetList, self.controls.sharedItemList) + t_insert(self.controls.uniqueDB.dragTargetList, self.controls.itemList) + t_insert(self.controls.uniqueDB.dragTargetList, self.controls.sharedItemList) + t_insert(self.controls.rareDB.dragTargetList, self.controls.itemList) + t_insert(self.controls.rareDB.dragTargetList, self.controls.sharedItemList) + t_insert(self.controls.sharedItemList.dragTargetList, self.controls.itemList) + for _, slot in pairs(self.slots) do + t_insert(self.controls.itemList.dragTargetList, slot) + t_insert(self.controls.uniqueDB.dragTargetList, slot) + t_insert(self.controls.rareDB.dragTargetList, slot) + t_insert(self.controls.sharedItemList.dragTargetList, slot) + end end) function ItemsTabClass:Load(xml, dbFileName) @@ -352,6 +369,15 @@ function ItemsTabClass:Draw(viewPort, inputEvents) end end self:ProcessControlsInput(inputEvents, viewPort) + for id, event in ipairs(inputEvents) do + if event.type == "KeyUp" then + if event.key == "WHEELDOWN" then + self.controls.scrollBarH:Scroll(1) + elseif event.key == "WHEELUP" then + self.controls.scrollBarH:Scroll(-1) + end + end + end main:DrawBackground(viewPort) @@ -510,6 +536,7 @@ function ItemsTabClass:CreateDisplayItemFromRaw(itemRaw, normalise) if newItem then if normalise then itemLib.normaliseQuality(newItem) + itemLib.buildItemModList(newItem) end self:SetDisplayItem(newItem) end diff --git a/Classes/ListControl.lua b/Classes/ListControl.lua index ab36d970..ea4fb2e1 100644 --- a/Classes/ListControl.lua +++ b/Classes/ListControl.lua @@ -245,18 +245,18 @@ function ListClass:OnKeyDown(key, doubleClick) self.selValue = self.list[index] if self.selValue then self.selIndex = index - if self.isMutable or self.dragTargetList then - self.selCX = cursorX - self.selCY = cursorY - self.selDragging = true - self.selDragActive = false - end if self.OnSelect then self:OnSelect(self.selIndex, self.selValue) end if self.OnSelClick then self:OnSelClick(self.selIndex, self.selValue, doubleClick) end + if (self.isMutable or self.dragTargetList) and self:IsShown() then + self.selCX = cursorX + self.selCY = cursorY + self.selDragging = true + self.selDragActive = false + end end end elseif #self.list > 0 then diff --git a/Classes/PassiveTreeView.lua b/Classes/PassiveTreeView.lua index 4879c36b..df9197ea 100644 --- a/Classes/PassiveTreeView.lua +++ b/Classes/PassiveTreeView.lua @@ -26,6 +26,7 @@ local PassiveTreeViewClass = common.NewClass("PassiveTreeView", function(self) self.zoomY = 0 self.searchStr = "" + self.showStatDifferences = true end) function PassiveTreeViewClass:Load(xml, fileName) @@ -43,6 +44,9 @@ function PassiveTreeViewClass:Load(xml, fileName) if xml.attrib.showHeatMap then self.showHeatMap = xml.attrib.showHeatMap == "true" end + if xml.attrib.showStatDifferences then + self.showStatDifferences = xml.attrib.showStatDifferences == "true" + end end function PassiveTreeViewClass:Save(xml) @@ -52,6 +56,7 @@ function PassiveTreeViewClass:Save(xml) zoomY = tostring(self.zoomY), searchStr = self.searchStr, showHeatMap = tostring(self.showHeatMap), + showStatDifferences = tostring(self.showStatDifferences), } end @@ -74,6 +79,8 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) end elseif event.key == "p" then self.showHeatMap = not self.showHeatMap + elseif event.key == "d" and IsKeyDown("CTRL") then + self.showStatDifferences = not self.showStatDifferences end elseif event.type == "KeyUp" then if event.key == "LEFTBUTTON" then @@ -376,7 +383,14 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) local defence = m_max(node.power.defence or 0, 0) local dpsCol = (offence / build.calcsTab.powerMax.offence * 1.5) ^ 0.5 local defCol = (defence / build.calcsTab.powerMax.defence * 1.5) ^ 0.5 - SetDrawColor(dpsCol, (m_max(dpsCol - 0.5, 0) + m_max(defCol - 0.5, 0)) / 2, defCol) + local mixCol = (m_max(dpsCol - 0.5, 0) + m_max(defCol - 0.5, 0)) / 2 + if main.nodePowerTheme == "RED/BLUE" then + SetDrawColor(dpsCol, mixCol, defCol) + elseif main.nodePowerTheme == "RED/GREEN" then + SetDrawColor(dpsCol, defCol, mixCol) + elseif main.nodePowerTheme == "GREEN/BLUE" then + SetDrawColor(mixCol, dpsCol, defCol) + end else SetDrawColor(1, 1, 1) end @@ -427,7 +441,7 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) local size = 175 * scale / self.zoom ^ 0.4 DrawImage(self.highlightRing, scrX - size, scrY - size, size * 2, size * 2) end - if node == hoverNode and (node.type ~= "socket" or not IsKeyDown("SHIFT")) then + if node == hoverNode and (node.type ~= "socket" or not IsKeyDown("SHIFT")) and not main.popups[1] then -- Draw tooltip SetDrawLayer(nil, 100) local size = m_floor(hoverNode.size * scale) @@ -591,36 +605,42 @@ function PassiveTreeViewClass:AddNodeTooltip(node, build) end -- Mod differences - local calcFunc, calcBase = build.calcsTab:GetMiscCalculator(build) - if calcFunc then + if self.showStatDifferences then + local calcFunc, calcBase = build.calcsTab:GetMiscCalculator(build) + if calcFunc then + main:AddTooltipSeparator(14) + local path = (node.alloc and node.depends) or self.tracePath or node.path or { } + local pathLength = #path + local pathNodes = { } + for _, node in pairs(path) do + pathNodes[node] = true + end + local nodeOutput, pathOutput + if node.alloc then + -- Calculate the differences caused by deallocating this node and its dependants + nodeOutput = calcFunc({ removeNodes = { [node] = true } }) + if pathLength > 1 then + pathOutput = calcFunc({ removeNodes = pathNodes }) + end + else + -- Calculated the differences caused by allocating this node and all nodes along the path to it + nodeOutput = calcFunc({ addNodes = { [node] = true } }) + if pathLength > 1 then + pathOutput = calcFunc({ addNodes = pathNodes }) + end + end + local count = build:AddStatComparesToTooltip(calcBase, nodeOutput, node.alloc and "^7Unallocating this node will give you:" or "^7Allocating this node will give you:") + if pathLength > 1 then + count = count + build:AddStatComparesToTooltip(calcBase, pathOutput, node.alloc and "^7Unallocating this node and all nodes depending on it will give you:" or "^7Allocating this node and all nodes leading to it will give you:", pathLength) + end + if count == 0 then + main:AddTooltipLine(14, string.format("^7No changes from %s this node%s.", node.alloc and "unallocating" or "allocating", pathLength > 1 and " or the nodes leading to it" or "")) + end + main:AddTooltipLine(14, "^x80A080Tip: Press Ctrl+D to disable the display of stat differences.") + end + else main:AddTooltipSeparator(14) - local path = (node.alloc and node.depends) or self.tracePath or node.path or { } - local pathLength = #path - local pathNodes = { } - for _, node in pairs(path) do - pathNodes[node] = true - end - local nodeOutput, pathOutput - if node.alloc then - -- Calculate the differences caused by deallocating this node and its dependants - nodeOutput = calcFunc({ removeNodes = { [node] = true } }) - if pathLength > 1 then - pathOutput = calcFunc({ removeNodes = pathNodes }) - end - else - -- Calculated the differences caused by allocating this node and all nodes along the path to it - nodeOutput = calcFunc({ addNodes = { [node] = true } }) - if pathLength > 1 then - pathOutput = calcFunc({ addNodes = pathNodes }) - end - end - local count = build:AddStatComparesToTooltip(calcBase, nodeOutput, node.alloc and "^7Unallocating this node will give you:" or "^7Allocating this node will give you:") - if pathLength > 1 then - count = count + build:AddStatComparesToTooltip(calcBase, pathOutput, node.alloc and "^7Unallocating this node and all nodes depending on it will give you:" or "^7Allocating this node and all nodes leading to it will give you:", pathLength) - end - if count == 0 then - main:AddTooltipLine(14, string.format("^7No changes from %s this node%s.", node.alloc and "unallocating" or "allocating", pathLength > 1 and " or the nodes leading to it" or "")) - end + main:AddTooltipLine(14, "^x80A080Tip: Press Ctrl+D to enable the display of stat differences.") end -- Pathing distance diff --git a/Classes/SharedItemListControl.lua b/Classes/SharedItemListControl.lua new file mode 100644 index 00000000..d4948796 --- /dev/null +++ b/Classes/SharedItemListControl.lua @@ -0,0 +1,68 @@ +-- Path of Building +-- +-- Class: Item list +-- Shared item list control. +-- +local launch, main = ... + +local pairs = pairs +local t_insert = table.insert +local t_remove = table.remove + +local SharedItemListClass = common.NewClass("SharedItemList", "ListControl", function(self, anchor, x, y, width, height, itemsTab) + self.ListControl(anchor, x, y, width, height, 16, true, main.sharedItems) + self.itemsTab = itemsTab + self.label = "^7Shared items:" + self.dragTargetList = { } + self.controls.delete = common.New("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, 0, -2, 60, 18, "Delete", function() + self:OnSelDelete(self.selIndex, self.selValue) + end) + self.controls.delete.enabled = function() + return self.selValue ~= nil + end +end) + +function SharedItemListClass:GetRowValue(column, index, item) + if column == 1 then + return data.colorCodes[item.rarity] .. item.name + end +end + +function SharedItemListClass:AddValueTooltip(index, item) + if not main.popups[1] then + self.itemsTab:AddItemTooltip(item, nil, true) + return data.colorCodes[item.rarity], true + end +end + +function SharedItemListClass:GetDragValue(index, item) + return "Item", item +end + +function SharedItemListClass:ReceiveDrag(type, value, source) + if type == "Item" then + local newItem = itemLib.makeItemFromRaw(value.raw) + if not value.id then + itemLib.normaliseQuality(newItem) + end + t_insert(self.list, self.selDragIndex or #self.list, newItem) + end +end + +function SharedItemListClass:OnSelClick(index, item, doubleClick) + if doubleClick then + self.itemsTab:CreateDisplayItemFromRaw(item.raw, true) + end +end + +function SharedItemListClass:OnSelCopy(index, item) + Copy(itemLib.createItemRaw(item):gsub("\n","\r\n")) +end + +function SharedItemListClass:OnSelDelete(index, item) + main:OpenConfirmPopup("Delete Item", "Are you sure you want to remove '"..item.name.."' from the shared item list?", "Delete", function() + t_remove(self.list, index) + self.selIndex = nil + self.selValue = nil + end) +end diff --git a/Classes/SkillsTab.lua b/Classes/SkillsTab.lua index 678d1232..de99765a 100644 --- a/Classes/SkillsTab.lua +++ b/Classes/SkillsTab.lua @@ -488,6 +488,7 @@ function SkillsTabClass:CreateUndoState() state.socketGroupList = { } for _, socketGroup in ipairs(self.socketGroupList) do local newGroup = copyTable(socketGroup, true) + newGroup.gemList = { } for index, gem in pairs(socketGroup.gemList) do newGroup.gemList[index] = copyTable(gem, true) end diff --git a/Classes/TreeTab.lua b/Classes/TreeTab.lua index 53d53618..d621fc2f 100644 --- a/Classes/TreeTab.lua +++ b/Classes/TreeTab.lua @@ -81,10 +81,13 @@ local TreeTabClass = common.NewClass("TreeTab", "ControlHost", function(self, bu self.controls.treeSearch = common.New("EditControl", {"LEFT",self.controls.export,"RIGHT"}, 8, 0, 300, 20, "", "Search", "%c%(%)", 100, function(buf) self.viewer.searchStr = buf end) - self.controls.treeHeatMap = common.New("CheckBoxControl", {"LEFT",self.controls.treeSearch,"RIGHT"}, 130, 0, 20, "Show node power:", function(state) + self.controls.treeHeatMap = common.New("CheckBoxControl", {"LEFT",self.controls.treeSearch,"RIGHT"}, 130, 0, 20, "Show Node Power:", function(state) self.viewer.showHeatMap = state end) - self.controls.treeHeatMap.tooltip = "When enabled, an estimate of the offensive and defensive strength of\neach unallocated passive is calculated and displayed visually.\nOffensive power shows as red, defensive power as blue." + self.controls.treeHeatMap.tooltip = function() + local offCol, defCol = main.nodePowerTheme:match("(%a+)/(%a+)") + return "When enabled, an estimate of the offensive and defensive strength of\neach unallocated passive is calculated and displayed visually.\nOffensive power shows as "..offCol:lower()..", defensive power as "..defCol:lower().."." + end end) function TreeTabClass:Draw(viewPort, inputEvents) diff --git a/Launch.lua b/Launch.lua index 63906924..f510a41b 100644 --- a/Launch.lua +++ b/Launch.lua @@ -19,22 +19,21 @@ function launch:OnInit() self.versionPlatform = "?" self.lastUpdateCheck = GetTime() self.subScripts = { } - ConPrintf("Loading main script...") - local changeLogFile = io.open("changelog.txt") - if changeLogFile then - changeLogFile:close() - else - -- Changelog isn't present, this must be a fresh installation + local firstRunFile = io.open("first.run", "r") + if firstRunFile then + firstRunFile:close() + os.remove("first.run") + -- This is a fresh installation -- Perform an immediate update to download the latest version ConClear() ConPrintf("Please wait while we complete installation...\n") - local updateMode = LoadModule("UpdateCheck") - if not updateMode or updateMode == "none" then - Exit("Failed to install.") - else + local updateMode, errMsg = LoadModule("UpdateCheck") + if not updateMode then + self.updateErrMsg = errMsg + elseif updateMode ~= "none" then self:ApplyUpdate(updateMode) + return end - return end local xml = require("xml") local localManXML = xml.LoadXMLFile("manifest.xml") @@ -54,6 +53,7 @@ function launch:OnInit() -- Enable dev mode to disable updates and set user path to be the script path self.devMode = true end + ConPrintf("Loading main script...") local errMsg errMsg, self.main = PLoadModule("Modules/Main", self) if errMsg then @@ -106,8 +106,6 @@ function launch:OnFrame() if self.promptMsg then local r, g, b = unpack(self.promptCol) self:DrawPopup(r, g, b, "^0%s", self.promptMsg) - elseif self.updateChecking then - self:DrawPopup(0, 0.5, 0, "^0%s", self.updateMsg) end if self.doRestart then local screenW, screenH = GetScreenSize() @@ -132,7 +130,7 @@ function launch:OnKeyDown(key, doubleClick) end elseif self.promptMsg then self:RunPromptFunc(key) - elseif not self.updateChecking then + else if self.main and self.main.OnKeyDown then local errMsg = PCall(self.main.OnKeyDown, self.main, key, doubleClick) if errMsg then @@ -143,7 +141,7 @@ function launch:OnKeyDown(key, doubleClick) end function launch:OnKeyUp(key) - if not self.promptMsg and not self.updateChecking then + if not self.promptMsg then if self.main and self.main.OnKeyUp then local errMsg = PCall(self.main.OnKeyUp, self.main, key) if errMsg then @@ -156,7 +154,7 @@ end function launch:OnChar(key) if self.promptMsg then self:RunPromptFunc(key) - elseif not self.updateChecking then + else if self.main and self.main.OnChar then local errMsg = PCall(self.main.OnChar, self.main, key) if errMsg then @@ -167,9 +165,7 @@ function launch:OnChar(key) end function launch:OnSubCall(func, ...) - if func == "ConPrintf" and self.updateChecking then - self.updateMsg = string.format(...) - elseif func == "UpdateProgress" then + if func == "UpdateProgress" then self.updateProgress = string.format(...) end if _G[func] then @@ -192,18 +188,7 @@ end function launch:OnSubFinished(id, ...) if self.subScripts[id].type == "UPDATE" then - local ret = (...) - self.updateAvailable = ret - if self.updateChecking then - if not ret then - self:ShowPrompt(1, 0, 0, self.updateMsg .. "\n\nPress Enter/Escape to dismiss") - elseif ret == "none" then - self:ShowPrompt(0, 0, 0, "No update available.", function(key) return true end) - else - self:ShowPrompt(0.2, 0.8, 0.2, "An update has been downloaded.\n\nClick 'Update Ready' at bottom left when you are ready to update.", function(key) return true end) - end - self.updateChecking = false - end + self.updateAvailable, self.updateErrMsg = ... self.updateCheckRunning = false elseif self.subScripts[id].type == "DOWNLOAD" then local errMsg = PCall(self.subScripts[id].callback, ...) @@ -234,7 +219,7 @@ function launch:DownloadPage(url, callback, cookies) -- Download the given page in the background, and calls the provided callback function when done: -- callback(pageText, errMsg) local id = LaunchSubScript([[ - local url, cookies = ... + local url, cookies, proxyURL = ... ConPrintf("Downloading page at: %s", url) local curl = require("lcurl.safe") local page = "" @@ -244,6 +229,9 @@ function launch:DownloadPage(url, callback, cookies) if cookies then easy:setopt(curl.OPT_COOKIE, cookies) end + if proxyURL then + easy:setopt(curl.OPT_PROXY, proxyURL) + end easy:setopt_writefunction(function(data) page = page..data return true @@ -265,7 +253,7 @@ function launch:DownloadPage(url, callback, cookies) else return page end - ]], "", "ConPrintf", url, cookies) + ]], "", "ConPrintf", url, cookies, self.proxyURL) if id then self.subScripts[id] = { type = "DOWNLOAD", @@ -292,12 +280,12 @@ function launch:CheckForUpdate(inBackground) if self.updateCheckRunning then return end - self.updateChecking = not inBackground + self.updateCheckBackground = inBackground self.updateMsg = "Initialising..." self.updateProgress = "Checking..." self.lastUpdateCheck = GetTime() local update = io.open("UpdateCheck.lua", "r") - local id = LaunchSubScript(update:read("*a"), "GetScriptPath,GetRuntimePath,GetWorkDir,MakeDir", "ConPrintf,UpdateProgress") + local id = LaunchSubScript(update:read("*a"), "GetScriptPath,GetRuntimePath,GetWorkDir,MakeDir", "ConPrintf,UpdateProgress", self.proxyURL) if id then self.subScripts[id] = { type = "UPDATE" diff --git a/Modules/Build.lua b/Modules/Build.lua index 94db2d3a..c9b4b843 100644 --- a/Modules/Build.lua +++ b/Modules/Build.lua @@ -250,7 +250,7 @@ function buildMode:Init(dbFileName, buildName) self.controls.statBox = common.New("TextListControl", {"TOPLEFT",self.controls.mainSocketGroup,"BOTTOMLEFT"}, 0, 62, 300, 0, {{x=170,align="RIGHT_X"},{x=174,align="LEFT"}}) self.controls.statBox.height = function(control) local x, y = control:GetPos() - return main.screenH - 30 - y + return main.screenH - main.mainBarHeight - 4 - y end -- Initialise class dropdown @@ -623,11 +623,11 @@ function buildMode:OpenSaveAsPopup() popup.controls.save.enabled = true end), save = common.New("ButtonControl", nil, -45, 70, 80, 20, "Save", function() + main:ClosePopup() self.dbFileName = newFileName self.buildName = newBuildName main.modeArgs = { newFileName, newBuildName } self:SaveDBFile() - main:ClosePopup() end), common.New("ButtonControl", nil, 45, 70, 80, 20, "Cancel", function() main:ClosePopup() diff --git a/Modules/CalcOffence.lua b/Modules/CalcOffence.lua index 0cc09a03..d4601e66 100644 --- a/Modules/CalcOffence.lua +++ b/Modules/CalcOffence.lua @@ -630,16 +630,17 @@ function calcs.offence(env, actor) local base = modDB:Sum("BASE", cfg, "CritChance") local inc = modDB:Sum("INC", cfg, "CritChance") local more = modDB:Sum("MORE", cfg, "CritChance") + local enemyExtra = env.mode_effective and enemyDB:Sum("BASE", nil, "SelfExtraCritChance") or 0 output.CritChance = (baseCrit + base) * (1 + inc / 100) * more - if env.mode_effective then - output.CritChance = output.CritChance + enemyDB:Sum("BASE", nil, "SelfExtraCritChance") - end local preCapCritChance = output.CritChance output.CritChance = m_min(output.CritChance, 95) if (baseCrit + base) > 0 then output.CritChance = m_max(output.CritChance, 5) end output.PreEffectiveCritChance = output.CritChance + if enemyExtra ~= 0 then + output.CritChance = m_min(output.CritChance + enemyExtra, 100) + end local preLuckyCritChance = output.CritChance if env.mode_effective and modDB:Sum("FLAG", cfg, "CritChanceLucky") then output.CritChance = (1 - (1 - output.CritChance / 100) ^ 2) * 100 @@ -649,7 +650,6 @@ function calcs.offence(env, actor) output.CritChance = output.CritChance * output.HitChance / 100 end if breakdown and output.CritChance ~= baseCrit then - local enemyExtra = enemyDB:Sum("BASE", nil, "SelfExtraCritChance") breakdown.CritChance = { } if base ~= 0 then t_insert(breakdown.CritChance, s_format("(%g + %g) ^8(base)", baseCrit, base)) @@ -662,24 +662,25 @@ function calcs.offence(env, actor) if more ~= 1 then t_insert(breakdown.CritChance, s_format("x %.2f", more).." ^8(more/less)") end - if env.mode_effective and enemyExtra ~= 0 then - t_insert(breakdown.CritChance, s_format("+ %g ^8(extra chance for enemy to be crit)", enemyExtra)) - end - t_insert(breakdown.CritChance, s_format("= %g", preLuckyCritChance)) + t_insert(breakdown.CritChance, s_format("= %.2f%% ^8(crit chance)", output.PreEffectiveCritChance)) if preCapCritChance > 95 then local overCap = preCapCritChance - 95 t_insert(breakdown.CritChance, s_format("Crit is overcapped by %.2f%% (%d%% increased Critical Strike Chance)", overCap, overCap / more / (baseCrit + base) * 100)) end + if enemyExtra ~= 0 then + t_insert(breakdown.CritChance, s_format("+ %g ^8(extra chance for enemy to be crit)", enemyExtra)) + t_insert(breakdown.CritChance, s_format("= %.2f%% ^8(chance to crit against enemy)", preLuckyCritChance)) + end if env.mode_effective and modDB:Sum("FLAG", cfg, "CritChanceLucky") then t_insert(breakdown.CritChance, "Crit Chance is Lucky:") t_insert(breakdown.CritChance, s_format("1 - (1 - %.4f) x (1 - %.4f)", preLuckyCritChance / 100, preLuckyCritChance / 100)) - t_insert(breakdown.CritChance, s_format("= %.2f", preHitCheckCritChance)) + t_insert(breakdown.CritChance, s_format("= %.2f%%", preHitCheckCritChance)) end if env.mode_effective and output.HitChance < 100 then t_insert(breakdown.CritChance, "Crit confirmation roll:") - t_insert(breakdown.CritChance, s_format("%.2f", preHitCheckCritChance)) + t_insert(breakdown.CritChance, s_format("%.2f%%", preHitCheckCritChance)) t_insert(breakdown.CritChance, s_format("x %.2f ^8(chance to hit)", output.HitChance / 100)) - t_insert(breakdown.CritChance, s_format("= %.2f", output.CritChance)) + t_insert(breakdown.CritChance, s_format("= %.2f%%", output.CritChance)) end end end @@ -865,6 +866,15 @@ function calcs.offence(env, actor) enemyDB.conditions.HitByLightningDamage = output.LightningHitAverage > 0 end + if breakdown then + -- For each damage type, calculate percentage of total damage + for _, damageType in ipairs(dmgTypeList) do + if output[damageType.."HitAverage"] > 0 then + t_insert(breakdown[damageType], s_format("Portion of total damage: %d%%", output[damageType.."HitAverage"] / (totalHitMin + totalHitMax) * 200)) + end + end + end + local hitRate = output.HitChance / 100 * (globalOutput.HitSpeed or globalOutput.Speed) * (skillData.dpsMultiplier or 1) -- Calculate leech diff --git a/Modules/CalcPerform.lua b/Modules/CalcPerform.lua index 88ded16a..259ab118 100644 --- a/Modules/CalcPerform.lua +++ b/Modules/CalcPerform.lua @@ -8,6 +8,7 @@ local calcs = ... local pairs = pairs local ipairs = ipairs local t_insert = table.insert +local m_min = math.min local m_ceil = math.ceil local m_floor = math.floor local s_format = string.format @@ -178,7 +179,7 @@ local function doActorAttribsPoolsConditions(env, actor) end for _, value in ipairs(modDB:Sum("LIST", nil, "GrantReserved"..pool.."AsAura")) do local auraMod = copyTable(value.mod) - auraMod.value = m_floor(auraMod.value * reserved) + auraMod.value = m_floor(auraMod.value * m_min(reserved, max)) modDB:NewMod("ExtraAura", "LIST", { mod = auraMod }) end end @@ -255,7 +256,16 @@ local function doActorMisc(env, actor) end end --- Finalise environment and perform the calculations +-- Finalises the environment and performs the stat calculations: +-- 1. Merges keystone modifiers +-- 2. Initialises minion skills +-- 3. Initialises the main skill's minion, if present +-- 4. Merges flask effects +-- 5. Calculates reservations +-- 6. Sets conditions and calculates attributes and life/mana pools (doActorAttribsPoolsConditions) +-- 7. Processes buffs and debuffs +-- 8. Processes charges and misc buffs (doActorMisc) +-- 9. Calculates defence and offence stats (calcs.defence, calcs.offence) function calcs.perform(env) local modDB = env.modDB local enemyDB = env.enemyDB diff --git a/Modules/CalcSetup.lua b/Modules/CalcSetup.lua index 8f857a45..d032da96 100644 --- a/Modules/CalcSetup.lua +++ b/Modules/CalcSetup.lua @@ -81,12 +81,12 @@ function calcs.buildNodeModList(env, nodeList, finishJewels) end -- Initialise environment: --- 1. Initialises the modifier databases +-- 1. Initialises the player and enemy modifier databases -- 2. Merges modifiers for all items -- 3. Builds a list of jewels with radius functions -- 4. Merges modifiers for all allocated passive nodes --- 5. Builds a list of active skills and their supports --- 6. Builds modifier lists for all active skills +-- 5. Builds a list of active skills and their supports (calcs.createActiveSkill) +-- 6. Builds modifier lists for all active skills (calcs.buildActiveSkillModList) function calcs.initEnv(build, mode, override) override = override or { } diff --git a/Modules/Main.lua b/Modules/Main.lua index b7aa8de2..16c914ec 100644 --- a/Modules/Main.lua +++ b/Modules/Main.lua @@ -62,6 +62,7 @@ local classList = { "ItemSlotControl", "ItemListControl", "ItemDBControl", + "SharedItemListControl", "CalcsTab", "CalcSectionControl", "CalcBreakdownControl", @@ -85,7 +86,8 @@ function main:Init() self.userPath = GetUserPath().."/Path of Building/" MakeDir(self.userPath) end - self.buildPath = self.userPath.."Builds/" + self.defaultBuildPath = self.userPath.."Builds/" + self.buildPath = self.defaultBuildPath MakeDir(self.buildPath) self.tree = common.New("PassiveTree") @@ -114,17 +116,25 @@ function main:Init() end end + self.sharedItems = { } + self.anchorUpdate = common.New("Control", nil, 2, 0, 0, 0) self.anchorUpdate.y = function() return self.screenH - 4 end - self.controls.applyUpdate = common.New("ButtonControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 0, 0, 110, 20, "^x50E050Update Ready", function() + self.controls.options = common.New("ButtonControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 0, 0, 70, 20, "Options", function() + self:OpenOptionsPopup() + end) + self.controls.about = common.New("ButtonControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 230, 0, 70, 20, "About", function() + self:OpenAboutPopup() + end) + self.controls.applyUpdate = common.New("ButtonControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 0, -28, 110, 20, "^x50E050Update Ready", function() self:OpenUpdatePopup() end) self.controls.applyUpdate.shown = function() return launch.updateAvailable and launch.updateAvailable ~= "none" end - self.controls.checkUpdate = common.New("ButtonControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 0, 0, 120, 18, "", function() + self.controls.checkUpdate = common.New("ButtonControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 0, -28, 120, 18, "", function() launch:CheckForUpdate() end) self.controls.checkUpdate.shown = function() @@ -136,17 +146,36 @@ function main:Init() self.controls.checkUpdate.enabled = function() return not launch.updateCheckRunning end - self.controls.versionLabel = common.New("LabelControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 124, 0, 0, 14, "") + self.controls.versionLabel = common.New("LabelControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 124, -28, 0, 14, "") self.controls.versionLabel.label = function() return "^8Version: "..launch.versionNumber..(launch.versionBranch == "dev" and " (Dev)" or "") end - self.controls.about = common.New("ButtonControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 250, 0, 50, 20, "About", function() - self:OpenAboutPopup() - end) - self.controls.devMode = common.New("LabelControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 0, 0, 0, 18, "^1Dev Mode") + self.controls.devMode = common.New("LabelControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 0, -28, 0, 18, "^1Dev Mode") self.controls.devMode.shown = function() return launch.devMode end + self.controls.dismissToast = common.New("ButtonControl", {"BOTTOMLEFT",self.anchorUpdate,"BOTTOMLEFT"}, 0, function() return -self.mainBarHeight + self.toastHeight end, 80, 20, "Dismiss", function() + self.toastMode = "HIDING" + self.toastStart = GetTime() + end) + self.controls.dismissToast.shown = function() + return self.toastMode == "SHOWN" + end + + self.mainBarHeight = 58 + self.toastMessages = { } + + if launch.devMode and GetTime() < 15000 then + t_insert(self.toastMessages, [[ +^xFF7700Warning: ^7Developer Mode active! +The program is currently running in developer +mode, which is not intended for normal use. +If you are not expecting this, then you may have +set up the program from the source .zip instead +of using one of the installers. If that is the case, +please reinstall using one of the installers from +the "Releases" section of the GitHub page.]]) + end self.inputEvents = { } self.popups = { } @@ -155,6 +184,7 @@ function main:Init() self.accountSessionIDs = { } self.buildSortMode = "NAME" + self.nodePowerTheme = "RED/BLUE" self:SetMode("BUILD", false, "Unnamed build") @@ -200,6 +230,58 @@ function main:OnFrame() self:CallMode("OnFrame", self.inputEvents, self.viewPort) + if launch.updateErrMsg then + t_insert(self.toastMessages, string.format("Update check failed!\n%s", launch.updateErrMsg)) + launch.updateErrMsg = nil + end + if launch.updateAvailable and launch.updateAvailable ~= "none" and not self.updateAvailableShown then + t_insert(self.toastMessages, "Update Available\nAn update has been downloaded and is ready\nto be applied.") + self.updateAvailableShown = true + end + + -- Run toasts + if self.toastMessages[1] then + if not self.toastMode then + self.toastMode = "SHOWING" + self.toastStart = GetTime() + self.toastHeight = #self.toastMessages[1]:gsub("[^\n]","") * 16 + 20 + 40 + end + if self.toastMode == "SHOWING" then + local now = GetTime() + if now >= self.toastStart + 250 then + self.toastMode = "SHOWN" + else + self.mainBarHeight = 58 + self.toastHeight * (now - self.toastStart) / 250 + end + end + if self.toastMode == "SHOWN" then + self.mainBarHeight = 58 + self.toastHeight + elseif self.toastMode == "HIDING" then + local now = GetTime() + if now >= self.toastStart + 75 then + self.toastMode = nil + self.mainBarHeight = 58 + t_remove(self.toastMessages, 1) + else + self.mainBarHeight = 58 + self.toastHeight * (1 - (now - self.toastStart) / 75) + end + end + if self.toastMode then + SetDrawColor(0.85, 0.85, 0.85) + DrawImage(nil, 0, self.screenH - self.mainBarHeight, 312, self.mainBarHeight) + SetDrawColor(0.1, 0.1, 0.1) + DrawImage(nil, 0, self.screenH - self.mainBarHeight + 4, 308, self.mainBarHeight - 4) + SetDrawColor(1, 1, 1) + DrawString(4, self.screenH - self.mainBarHeight + 8, "LEFT", 20, "VAR", self.toastMessages[1]:gsub("\n.*","")) + DrawString(4, self.screenH - self.mainBarHeight + 28, "LEFT", 16, "VAR", self.toastMessages[1]:gsub("^[^\n]*\n?","")) + end + end + + -- Draw main controls + SetDrawColor(0.85, 0.85, 0.85) + DrawImage(nil, 0, self.screenH - 58, 312, 58) + SetDrawColor(0.1, 0.1, 0.1) + DrawImage(nil, 0, self.screenH - 54, 308, 54) self:DrawControls(self.viewPort) if self.popups[1] then @@ -274,10 +356,32 @@ function main:LoadSettings() self.accountSessionIDs[child.attrib.accountName] = child.attrib.sessionID end end + elseif node.elem == "SharedItems" then + for _, child in ipairs(node) do + if child.elem == "Item" then + local item = { raw = "" } + itemLib.parseItemRaw(item) + for _, subChild in ipairs(child) do + if type(subChild) == "string" then + item.raw = subChild + itemLib.parseItemRaw(item) + end + end + itemLib.buildItemModList(item) + t_insert(self.sharedItems, item) + end + end elseif node.elem == "Misc" then if node.attrib.buildSortMode then self.buildSortMode = node.attrib.buildSortMode end + launch.proxyURL = node.attrib.proxyURL + if node.attrib.buildPath then + self.buildPath = node.attrib.buildPath + end + if node.attrib.nodePowerTheme then + self.nodePowerTheme = node.attrib.nodePowerTheme + end end end end @@ -303,7 +407,17 @@ function main:SaveSettings() t_insert(accounts, { elem = "Account", attrib = { accountName = accountName, sessionID = sessionID } }) end t_insert(setXML, accounts) - t_insert(setXML, { elem = "Misc", attrib = { buildSortMode = self.buildSortMode } }) + local sharedItems = { elem = "SharedItems" } + for _, item in ipairs(self.sharedItems) do + t_insert(sharedItems, { elem = "Item", [1] = item.raw }) + end + t_insert(setXML, sharedItems) + t_insert(setXML, { elem = "Misc", attrib = { + buildSortMode = self.buildSortMode, + proxyURL = launch.proxyURL, + buildPath = (self.buildPath ~= self.defaultBuildPath and self.buildPath or nil), + nodePowerTheme = self.nodePowerTheme, + } }) local res, errMsg = common.xml.SaveXMLFile(setXML, self.userPath.."Settings.xml") if not res then launch:ShowErrMsg("Error saving 'Settings.xml': %s", errMsg) @@ -311,6 +425,55 @@ function main:SaveSettings() end end +function main:OpenOptionsPopup() + local controls = { } + controls.proxyType = common.New("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, 150, 20, 80, 18, {{val="http",label="HTTP"},{val="socks5",label="SOCKS"}}) + controls.proxyLabel = common.New("LabelControl", {"RIGHT",controls.proxyType,"LEFT"}, -4, 0, 0, 16, "^7Proxy server:") + controls.proxyURL = common.New("EditControl", {"LEFT",controls.proxyType,"RIGHT"}, 4, 0, 206, 18) + if launch.proxyURL then + local scheme, url = launch.proxyURL:match("(%w+)://(.+)") + controls.proxyType:SelByValue(scheme) + controls.proxyURL:SetText(url) + end + controls.buildPath = common.New("EditControl", {"TOPLEFT",nil,"TOPLEFT"}, 150, 44, 290, 18) + controls.buildPathLabel = common.New("LabelControl", {"RIGHT",controls.buildPath,"LEFT"}, -4, 0, 0, 16, "^7Build save path:") + if self.buildPath ~= self.defaultBuildPath then + controls.buildPath:SetText(self.buildPath) + end + controls.buildPath.tooltip = "Overrides the default save location for builds.\nThe default location is: '"..self.defaultBuildPath.."'" + controls.nodePowerTheme = common.New("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, 150, 68, 100, 18, {{val="RED/BLUE",label="Red & Blue"},{val="RED/GREEN",label="Red & Green"},{val="GREEN/BLUE",label="Green & Blue"}}, function(sel, value) + self.nodePowerTheme = value.val + end) + controls.nodePowerThemeLabel = common.New("LabelControl", {"RIGHT",controls.nodePowerTheme,"LEFT"}, -4, 0, 0, 16, "^7Node Power colours:") + controls.nodePowerTheme.tooltip = "Changes the colour scheme used for the node power display on the passive tree." + controls.nodePowerTheme:SelByValue(self.nodePowerTheme) + local initialNodePowerTheme = self.nodePowerTheme + controls.save = common.New("ButtonControl", nil, -45, 120, 80, 20, "Save", function() + if controls.proxyURL.buf:match("%w") then + launch.proxyURL = controls.proxyType.list[controls.proxyType.sel].val .. "://" .. controls.proxyURL.buf + else + launch.proxyURL = nil + end + if controls.buildPath.buf:match("%S") then + self.buildPath = controls.buildPath.buf + if not self.buildPath:match("[\\/]$") then + self.buildPath = self.buildPath .. "/" + end + else + self.buildPath = self.defaultBuildPath + end + if self.mode == "LIST" then + self.modes.LIST:BuildList() + end + main:ClosePopup() + end) + controls.cancel = common.New("ButtonControl", nil, 45, 120, 80, 20, "Cancel", function() + self.nodePowerTheme = initialNodePowerTheme + main:ClosePopup() + end) + self:OpenPopup(450, 150, "Options", controls, "save", nil, "cancel") +end + function main:OpenUpdatePopup() local changeList = { } for line in io.lines("changelog.txt") do diff --git a/PathOfBuilding.sln b/PathOfBuilding.sln index 7e5a0729..68075a6f 100644 --- a/PathOfBuilding.sln +++ b/PathOfBuilding.sln @@ -88,6 +88,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Classes", "Classes", "{7EE4 Classes\PopupDialog.lua = Classes\PopupDialog.lua Classes\ScrollBarControl.lua = Classes\ScrollBarControl.lua Classes\SectionControl.lua = Classes\SectionControl.lua + Classes\SharedItemListControl.lua = Classes\SharedItemListControl.lua Classes\SkillListControl.lua = Classes\SkillListControl.lua Classes\SkillsTab.lua = Classes\SkillsTab.lua Classes\SliderControl.lua = Classes\SliderControl.lua diff --git a/README.md b/README.md index fc93cbf0..c771b3b6 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,17 @@ If you'd like to help support the development of Path of Building, I have a [Pat ![ss3](https://cloud.githubusercontent.com/assets/19189971/18089780/f0ff234a-6f04-11e6-8c88-6193fe59a5c4.png) ## Changelog +### 1.4.12 - 2017/05/19 + * The Items tab now has a "Shared items" list which is shared between all of your builds + * Added an Options screen, accessed via a new button at the bottom left corner. The following options have been added: + * Proxy server: specifies the proxy that the program should use when updating or importing characters + * Build save path: overrides the default save location for builds + * Node Power colours: changes the colour scheme used for the node power display + * The breakdowns for hit damage types now show the percentage of total hit damage that is being dealt as that type + * Some friendly toasts have set up camp in the bottom left corner, and may appear occasionally to convey various messages + * With the new installer versions, the program will always update itself when started for the first time, but will still + start even if the update check fails + ### 1.4.11 - 2017/05/16 * Fixed a stack overflow error that could occur when trying to view breakdowns in the Calcs tab * Fixed interaction between weapon swap and skills granted by items diff --git a/UpdateCheck.lua b/UpdateCheck.lua index 9909f7d2..fc0bc9a8 100644 --- a/UpdateCheck.lua +++ b/UpdateCheck.lua @@ -4,6 +4,7 @@ -- Module: Update Check -- Checks for updates -- +local proxyURL = ... local xml = require("xml") local sha1 = require("sha1") @@ -19,6 +20,10 @@ local function downloadFileText(url) local text = "" local easy = curl.easy() easy:setopt_url(url) + easy:setopt(curl.OPT_ACCEPT_ENCODING, "") + if proxyURL then + easy:setopt(curl.OPT_PROXY, proxyURL) + end easy:setopt_writefunction(function(data) text = text..data return true @@ -29,8 +34,8 @@ local function downloadFileText(url) return text end ConPrintf("Download failed (%s)", error:msg()) - if globalRetryLimit == 0 then - break + if globalRetryLimit == 0 or i == 5 then + return nil, error:msg() end globalRetryLimit = globalRetryLimit - 1 end @@ -86,7 +91,7 @@ if localManXML and localManXML[1].elem == "PoBVersion" then end if not localVer or not localSource or not localBranch or not next(localFiles) then ConPrintf("Update check failed: invalid local manifest") - return + return nil, "Invalid local manifest" end localSource = localSource:gsub("{branch}", localBranch) @@ -94,10 +99,10 @@ localSource = localSource:gsub("{branch}", localBranch) local remoteVer local remoteFiles = { } local remoteSources = { } -local remoteManText = downloadFileText(localSource.."manifest.xml") +local remoteManText, errMsg = downloadFileText(localSource.."manifest.xml") if not remoteManText then ConPrintf("Update check failed: couldn't download version manifest") - return + return nil, "Couldn't download version manifest.\nReason: "..errMsg.."\nCheck your internet connectivity.\nIf you are using a proxy, specify it in Options." end local remoteManXML = xml.ParseXML(remoteManText) if remoteManXML and remoteManXML[1].elem == "PoBVersion" then @@ -126,7 +131,7 @@ if remoteManXML and remoteManXML[1].elem == "PoBVersion" then end if not remoteVer or not next(remoteSources) or not next(remoteFiles) then ConPrintf("Update check failed: invalid remote manifest") - return + return nil, "Invalid remote manifest" end -- Build lists of files to be updated or deleted @@ -225,7 +230,7 @@ for name, zip in pairs(zipFiles) do end if failedFile then ConPrintf("Update failed: one or more files couldn't be downloaded") - return + return nil, "One or more files couldn't be downloaded.\nCheck your internet connectivity,\nor try again later." end -- Create new manifest diff --git a/changelog.txt b/changelog.txt index 2bc85cd2..d738748a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,13 @@ +VERSION[1.4.12][2017/05/19] + * The Items tab now has a "Shared items" list which is shared between all of your builds + * Added an Options screen, accessed via a new button at the bottom left corner. The following options have been added: + * Proxy server: specifies the proxy that the program should use when updating or importing characters + * Build save path: overrides the default save location for builds + * Node Power colours: changes the colour scheme used for the node power display + * The breakdowns for hit damage types now show the percentage of total hit damage that is being dealt as that type + * Some friendly toasts have set up camp in the bottom left corner, and may appear occasionally to convey various messages + * With the new installer versions, the program will always update itself when started for the first time, but will still + start even if the update check fails VERSION[1.4.11][2017/05/16] * Fixed a stack overflow error that could occur when trying to view breakdowns in the Calcs tab * Fixed interaction between weapon swap and skills granted by items diff --git a/manifest.xml b/manifest.xml index 168f976e..816530f0 100644 --- a/manifest.xml +++ b/manifest.xml @@ -1,13 +1,13 @@ - + - - + + - + @@ -15,18 +15,18 @@ - + - - - - - + + + + + - + @@ -34,31 +34,32 @@ - + + - + - + - + - - + + - + - + @@ -123,9 +124,9 @@ - - - + + + diff --git a/runtime-win32.zip b/runtime-win32.zip index d052dadb..f90b748a 100644 Binary files a/runtime-win32.zip and b/runtime-win32.zip differ