Release 1.4.11
- Fixed stack overflow in copyTable() - Fixed interaction between weapon swap and skilsl granted by items - Consolidated list controls using a new base class
This commit is contained in:
@@ -5,181 +5,124 @@
|
||||
--
|
||||
local launch, main = ...
|
||||
|
||||
local t_insert = table.insert
|
||||
local t_remove = table.remove
|
||||
local m_min = math.min
|
||||
local m_max = math.max
|
||||
local m_floor = math.floor
|
||||
local s_format = string.format
|
||||
|
||||
local BuildListClass = common.NewClass("BuildList", "Control", "ControlHost", function(self, anchor, x, y, width, height, listMode)
|
||||
self.Control(anchor, x, y, width, height)
|
||||
self.ControlHost()
|
||||
local BuildListClass = common.NewClass("BuildList", "ListControl", function(self, anchor, x, y, width, height, listMode)
|
||||
self.ListControl(anchor, x, y, width, height, 20, false, listMode.list)
|
||||
self.listMode = listMode
|
||||
self.controls.scrollBar = common.New("ScrollBarControl", {"RIGHT",self,"RIGHT"}, -1, 0, 18, 0, 40)
|
||||
self.controls.scrollBar.height = function()
|
||||
local width, height = self:GetSize()
|
||||
return height - 2
|
||||
end
|
||||
self.controls.scrollBar.locked = function()
|
||||
return self.listMode.edit
|
||||
end
|
||||
self.controls.nameEdit = common.New("EditControl", {"TOPLEFT",self,"TOPLEFT"}, 0, 0, 0, 20, nil, nil, "\\/:%*%?\"<>|%c", 100)
|
||||
self.controls.nameEdit.shown = function()
|
||||
return self.listMode.edit
|
||||
end
|
||||
self.controls.nameEdit.width = function()
|
||||
local width, height = self:GetSize()
|
||||
return width - 20
|
||||
end
|
||||
self.showRowSeparators = true
|
||||
end)
|
||||
|
||||
function BuildListClass:ScrollSelIntoView()
|
||||
if self.listMode.sel then
|
||||
local width, height = self:GetSize()
|
||||
self.controls.scrollBar:SetContentDimension(#self.listMode.list * 20, height - 4)
|
||||
self.controls.scrollBar:ScrollIntoView((self.listMode.sel - 2) * 20, 60)
|
||||
function BuildListClass:SelByFileName(selFileName)
|
||||
for index, build in ipairs(self.list) do
|
||||
if build.fileName == selFileName then
|
||||
self:SelectIndex(index)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function BuildListClass:SelectIndex(index)
|
||||
if self.listMode.list[index] then
|
||||
self.listMode.sel = index
|
||||
self:ScrollSelIntoView()
|
||||
end
|
||||
function BuildListClass:LoadBuild(build)
|
||||
main:SetMode("BUILD", main.buildPath..build.fileName, build.buildName)
|
||||
end
|
||||
|
||||
function BuildListClass:IsMouseOver()
|
||||
if not self:IsShown() then
|
||||
return
|
||||
end
|
||||
return self:IsMouseInBounds() or self:GetMouseOverControl()
|
||||
end
|
||||
|
||||
function BuildListClass:Draw(viewPort)
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local list = self.listMode.list
|
||||
local scrollBar = self.controls.scrollBar
|
||||
scrollBar:SetContentDimension(#list * 20, height - 4)
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, x, y, width, height)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, x + 1, y + 1, width - 2, height - 2)
|
||||
SetViewport(x + 2, y + 2, width - 22, height - 4)
|
||||
local selBuildIndex = self.listMode.sel
|
||||
local minIndex = m_floor(scrollBar.offset / 20 + 1)
|
||||
local maxIndex = m_min(m_floor((scrollBar.offset + height) / 20 + 1), #list)
|
||||
for index = minIndex, maxIndex do
|
||||
local build = list[index]
|
||||
local lineY = 20 * (index - 1) - scrollBar.offset
|
||||
if index == selBuildIndex then
|
||||
self.controls.nameEdit.y = lineY + 2
|
||||
end
|
||||
local mOverLine
|
||||
if not scrollBar.dragging then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
local relX = cursorX - (x + 2)
|
||||
local relY = cursorY - (y + 2)
|
||||
if relX >= 0 and relX < width - 19 and relY >= 0 and relY >= lineY and relY < height - 2 and relY < lineY + 20 then
|
||||
mOverLine = true
|
||||
end
|
||||
end
|
||||
if index == selBuildIndex then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, 0, lineY, width - 22, 20)
|
||||
if mOverLine or index == selBuildIndex then
|
||||
SetDrawColor(0.33, 0.33, 0.33)
|
||||
elseif index % 2 == 0 then
|
||||
SetDrawColor(0.05, 0.05, 0.05)
|
||||
else
|
||||
SetDrawColor(0, 0, 0)
|
||||
end
|
||||
DrawImage(nil, 0, lineY + 1, width - 22, 18)
|
||||
if self.listMode.edit ~= index then
|
||||
DrawString(0, lineY + 2, "LEFT", 16, "VAR", "^7"..(build.buildName or "?"))
|
||||
if mOverLine or index == selBuildIndex then
|
||||
SetDrawColor(0.33, 0.33, 0.33)
|
||||
elseif index % 2 == 0 then
|
||||
SetDrawColor(0.05, 0.05, 0.05)
|
||||
function BuildListClass:RenameBuild(build, copyOnName)
|
||||
local controls = { }
|
||||
controls.label = common.New("LabelControl", nil, 0, 20, 0, 16, "^7Enter the new name for this build:")
|
||||
controls.edit = common.New("EditControl", nil, 0, 40, 350, 20, build.buildName, nil, "\\/:%*%?\"<>|%c", 100, function(buf)
|
||||
controls.save.enabled = false
|
||||
if buf:match("%S") and buf:lower() ~= build.buildName:lower() then
|
||||
local newName = buf..".xml"
|
||||
local newFile = io.open(main.buildPath..newName, "r")
|
||||
if newFile then
|
||||
newFile:close()
|
||||
else
|
||||
SetDrawColor(0, 0, 0)
|
||||
end
|
||||
DrawImage(nil, width - 162, lineY + 2, 162, 16)
|
||||
SetDrawColor(build.className and data.colorCodes[build.className:upper()] or "^7")
|
||||
DrawString(width - 160, lineY + 2, "LEFT", 16, "VAR", string.format("Level %d %s", build.level or 1, (build.ascendClassName ~= "None" and build.ascendClassName) or build.className or "?"))
|
||||
end
|
||||
end
|
||||
SetViewport()
|
||||
if self.listMode.edit then
|
||||
self.listMode:SelectControl(self.controls.nameEdit)
|
||||
end
|
||||
self:DrawControls(viewPort)
|
||||
end
|
||||
|
||||
function BuildListClass:OnKeyDown(key, doubleClick)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
local mOverControl = self:GetMouseOverControl()
|
||||
if mOverControl and mOverControl.OnKeyDown then
|
||||
return mOverControl:OnKeyDown(key)
|
||||
end
|
||||
if not self:IsMouseOver() and key:match("BUTTON") then
|
||||
return
|
||||
end
|
||||
if self.listMode.edit then
|
||||
return self
|
||||
end
|
||||
if key == "LEFTBUTTON" then
|
||||
self.listMode.sel = nil
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 20 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + self.controls.scrollBar.offset) / 20) + 1
|
||||
local selBuild = self.listMode.list[index]
|
||||
if selBuild then
|
||||
self.listMode.sel = index
|
||||
if doubleClick then
|
||||
self.listMode:LoadSel()
|
||||
end
|
||||
controls.save.enabled = true
|
||||
end
|
||||
end
|
||||
elseif key == "UP" then
|
||||
self:SelectIndex(((self.listMode.sel or 1) - 2) % #self.listMode.list + 1)
|
||||
elseif key == "DOWN" then
|
||||
self:SelectIndex((self.listMode.sel or #self.listMode.list) % #self.listMode.list + 1)
|
||||
elseif key == "HOME" then
|
||||
self:SelectIndex(1)
|
||||
elseif key == "END" then
|
||||
self:SelectIndex(#self.listMode.list)
|
||||
elseif self.listMode.sel then
|
||||
if key == "BACK" or key == "DELETE" then
|
||||
self.listMode:DeleteSel()
|
||||
elseif key == "F2" then
|
||||
self.listMode:RenameSel()
|
||||
elseif key == "RETURN" then
|
||||
self.listMode:LoadSel()
|
||||
end)
|
||||
controls.save = common.New("ButtonControl", nil, -45, 70, 80, 20, "Save", function()
|
||||
local newBuildName = controls.edit.buf
|
||||
local newFileName = newBuildName..".xml"
|
||||
if copyOnName then
|
||||
local inFile, msg = io.open(main.buildPath..build.fileName, "r")
|
||||
if not inFile then
|
||||
main:OpenMessagePopup("Error", "Couldn't open '"..build.fileName.."': "..msg)
|
||||
return
|
||||
end
|
||||
local outFile, msg = io.open(main.buildPath..newFileName, "w")
|
||||
if not outFile then
|
||||
main:OpenMessagePopup("Error", "Couldn't create '"..newFileName.."': "..msg)
|
||||
return
|
||||
end
|
||||
outFile:write(inFile:read("*a"))
|
||||
inFile:close()
|
||||
outFile:close()
|
||||
else
|
||||
local res, msg = os.rename(main.buildPath..build.fileName, main.buildPath..newFileName)
|
||||
if not res then
|
||||
main:OpenMessagePopup("Error", "Couldn't rename '"..build.fileName.."' to '"..newFileName.."': "..msg)
|
||||
return
|
||||
end
|
||||
build.buildName = newBuildName
|
||||
build.fileName = newFileName
|
||||
end
|
||||
end
|
||||
return self
|
||||
self.listMode:BuildList()
|
||||
self:SelByFileName(newFileName)
|
||||
main:ClosePopup()
|
||||
self.listMode:SelectControl(self)
|
||||
end)
|
||||
controls.save.enabled = false
|
||||
controls.cancel = common.New("ButtonControl", nil, 45, 70, 80, 20, "Cancel", function()
|
||||
main:ClosePopup()
|
||||
self.listMode:SelectControl(self)
|
||||
end)
|
||||
main:OpenPopup(370, 100, copyOnName and "Copy Build" or "Rename Build", controls, "save", "edit")
|
||||
end
|
||||
|
||||
function BuildListClass:OnKeyUp(key)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
function BuildListClass:DeleteBuild(build)
|
||||
main:OpenConfirmPopup("Confirm Delete", "Are you sure you want to delete build:\n"..build.buildName.."\nThis cannot be undone.", "Delete", function()
|
||||
os.remove(main.buildPath..build.fileName)
|
||||
self.listMode:BuildList()
|
||||
self.selIndex = nil
|
||||
self.selValue = nil
|
||||
end)
|
||||
end
|
||||
|
||||
function BuildListClass:GetColumnOffset(column)
|
||||
if column == 1 then
|
||||
return 0
|
||||
elseif column == 2 then
|
||||
return self:GetProperty("width") - 164
|
||||
end
|
||||
if key == "WHEELDOWN" then
|
||||
self.controls.scrollBar:Scroll(1)
|
||||
elseif key == "WHEELUP" then
|
||||
self.controls.scrollBar:Scroll(-1)
|
||||
end
|
||||
|
||||
function BuildListClass:GetRowValue(column, index, build)
|
||||
if column == 1 then
|
||||
return build.buildName or "?"
|
||||
elseif column == 2 then
|
||||
return s_format("%sLevel %d %s",
|
||||
build.className and data.colorCodes[build.className:upper()] or "^7",
|
||||
build.level or 1,
|
||||
(build.ascendClassName ~= "None" and build.ascendClassName) or build.className or "?"
|
||||
)
|
||||
end
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
function BuildListClass:OnSelClick(index, build, doubleClick)
|
||||
if doubleClick then
|
||||
self:LoadBuild(build)
|
||||
end
|
||||
end
|
||||
|
||||
function BuildListClass:OnSelDelete(index, build)
|
||||
self:DeleteBuild(build)
|
||||
end
|
||||
|
||||
function BuildListClass:OnSelKeyDown(index, build, key)
|
||||
if key == "RETURN" then
|
||||
self:LoadBuild(build)
|
||||
elseif key == "F2" then
|
||||
self:RenameBuild(build)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -405,8 +405,8 @@ function CalcsTabClass:PowerBuilder()
|
||||
local calcFunc, calcBase = self:GetNodeCalculator()
|
||||
local cache = { }
|
||||
local newPowerMax = {
|
||||
dps = 0,
|
||||
def = 0
|
||||
offence = 0,
|
||||
defence = 0
|
||||
}
|
||||
if not self.powerMax then
|
||||
self.powerMax = newPowerMax
|
||||
@@ -423,19 +423,19 @@ function CalcsTabClass:PowerBuilder()
|
||||
end
|
||||
local output = cache[node.modKey]
|
||||
if calcBase.Minion then
|
||||
node.power.dps = (output.Minion.CombinedDPS - calcBase.Minion.CombinedDPS) / calcBase.Minion.CombinedDPS
|
||||
node.power.offence = (output.Minion.CombinedDPS - calcBase.Minion.CombinedDPS) / calcBase.Minion.CombinedDPS
|
||||
else
|
||||
node.power.dps = (output.CombinedDPS - calcBase.CombinedDPS) / calcBase.CombinedDPS
|
||||
node.power.offence = (output.CombinedDPS - calcBase.CombinedDPS) / calcBase.CombinedDPS
|
||||
end
|
||||
node.power.def = (output.LifeUnreserved - calcBase.LifeUnreserved) / m_max(3000, calcBase.Life) +
|
||||
node.power.defence = (output.LifeUnreserved - calcBase.LifeUnreserved) / m_max(3000, calcBase.Life) +
|
||||
(output.Armour - calcBase.Armour) / m_max(10000, calcBase.Armour) +
|
||||
(output.EnergyShield - calcBase.EnergyShield) / m_max(3000, calcBase.EnergyShield) +
|
||||
(output.Evasion - calcBase.Evasion) / m_max(10000, calcBase.Evasion) +
|
||||
(output.LifeRegen - calcBase.LifeRegen) / 500 +
|
||||
(output.EnergyShieldRegen - calcBase.EnergyShieldRegen) / 1000
|
||||
if node.path then
|
||||
newPowerMax.dps = m_max(newPowerMax.dps, node.power.dps)
|
||||
newPowerMax.def = m_max(newPowerMax.def, node.power.def)
|
||||
newPowerMax.offence = m_max(newPowerMax.offence, node.power.offence)
|
||||
newPowerMax.defence = m_max(newPowerMax.defence, node.power.defence)
|
||||
end
|
||||
end
|
||||
if coroutine.running() and GetTime() - start > 100 then
|
||||
|
||||
@@ -574,15 +574,17 @@ end
|
||||
|
||||
function ConfigTabClass:Save(xml)
|
||||
for k, v in pairs(self.input) do
|
||||
local child = { elem = "Input", attrib = {name = k} }
|
||||
if type(v) == "number" then
|
||||
child.attrib.number = tostring(v)
|
||||
elseif type(v) == "boolean" then
|
||||
child.attrib.boolean = tostring(v)
|
||||
else
|
||||
child.attrib.string = tostring(v)
|
||||
if v then
|
||||
local child = { elem = "Input", attrib = {name = k} }
|
||||
if type(v) == "number" then
|
||||
child.attrib.number = tostring(v)
|
||||
elseif type(v) == "boolean" then
|
||||
child.attrib.boolean = tostring(v)
|
||||
else
|
||||
child.attrib.string = tostring(v)
|
||||
end
|
||||
t_insert(xml, child)
|
||||
end
|
||||
t_insert(xml, child)
|
||||
end
|
||||
self.modFlag = false
|
||||
end
|
||||
|
||||
@@ -5,25 +5,21 @@
|
||||
--
|
||||
local launch, main = ...
|
||||
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local t_insert = table.insert
|
||||
local t_remove = table.remove
|
||||
local m_min = math.min
|
||||
local m_max = math.max
|
||||
local m_floor = math.floor
|
||||
|
||||
local ItemDBClass = common.NewClass("ItemDB", "Control", "ControlHost", function(self, anchor, x, y, width, height, itemsTab, db)
|
||||
self.Control(anchor, x, y, width, height)
|
||||
self.ControlHost()
|
||||
local ItemDBClass = common.NewClass("ItemDB", "ListControl", function(self, anchor, x, y, width, height, itemsTab, db)
|
||||
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.sortControl = {
|
||||
NAME = { key = "name", order = 1, dir = "ASCEND", func = function(a,b) return a:gsub("^The ","") < b:gsub("^The ","") end }
|
||||
}
|
||||
self.controls.scrollBar = common.New("ScrollBarControl", {"RIGHT",self,"RIGHT"}, -1, 0, 16, 0, 32)
|
||||
self.controls.scrollBar.height = function()
|
||||
local width, height = self:GetSize()
|
||||
return height - 2
|
||||
end
|
||||
local leagueFlag = { }
|
||||
local typeFlag = { }
|
||||
for _, item in pairs(db.list) do
|
||||
@@ -49,25 +45,25 @@ local ItemDBClass = common.NewClass("ItemDB", "Control", "ControlHost", function
|
||||
t_insert(self.typeList, 1, "Any type")
|
||||
self.slotList = { "Any slot", "Weapon 1", "Weapon 2", "Helmet", "Body Armour", "Gloves", "Boots", "Amulet", "Ring", "Belt", "Jewel" }
|
||||
self.controls.slot = common.New("DropDownControl", {"BOTTOMLEFT",self,"TOPLEFT"}, 0, -22, 95, 18, self.slotList, function()
|
||||
self:BuildOrderList()
|
||||
self:BuildList()
|
||||
end)
|
||||
self.controls.type = common.New("DropDownControl", {"LEFT",self.controls.slot,"RIGHT"}, 2, 0, 135, 18, self.typeList, function()
|
||||
self:BuildOrderList()
|
||||
self:BuildList()
|
||||
end)
|
||||
self.controls.league = common.New("DropDownControl", {"LEFT",self.controls.type,"RIGHT"}, 2, 0, 126, 18, self.leagueList, function()
|
||||
self:BuildOrderList()
|
||||
self:BuildList()
|
||||
end)
|
||||
self.controls.league.shown = function()
|
||||
return #self.leagueList > 2
|
||||
end
|
||||
self.controls.search = common.New("EditControl", {"BOTTOMLEFT",self,"TOPLEFT"}, 0, -2, 258, 18, "", "Search", "%c", 100, function()
|
||||
self:BuildOrderList()
|
||||
self:BuildList()
|
||||
end)
|
||||
self.controls.searchMode = common.New("DropDownControl", {"LEFT",self.controls.search,"RIGHT"}, 2, 0, 100, 18, { "Anywhere", "Names", "Modifiers" }, function()
|
||||
self:BuildOrderList()
|
||||
self:BuildList()
|
||||
end)
|
||||
self:BuildSortOrder()
|
||||
self:BuildOrderList()
|
||||
self:BuildList()
|
||||
end)
|
||||
|
||||
function ItemDBClass:DoesItemMatchFilters(item)
|
||||
@@ -105,7 +101,7 @@ function ItemDBClass:DoesItemMatchFilters(item)
|
||||
end
|
||||
if not found then
|
||||
searchStr = searchStr:gsub(" ","")
|
||||
for i, mod in pairs(item.baseModList) do
|
||||
for i, mod in ipairs(item.baseModList) do
|
||||
if mod.name:lower():find(searchStr, 1, true) then
|
||||
found = true
|
||||
break
|
||||
@@ -130,14 +126,14 @@ function ItemDBClass:BuildSortOrder()
|
||||
end)
|
||||
end
|
||||
|
||||
function ItemDBClass:BuildOrderList()
|
||||
self.orderList = wipeTable(self.orderList)
|
||||
function ItemDBClass:BuildList()
|
||||
wipeTable(self.list)
|
||||
for id, item in pairs(self.db.list) do
|
||||
if self:DoesItemMatchFilters(item) then
|
||||
t_insert(self.orderList, item)
|
||||
t_insert(self.list, item)
|
||||
end
|
||||
end
|
||||
table.sort(self.orderList, function(a, b)
|
||||
table.sort(self.list, function(a, b)
|
||||
for _, data in ipairs(self.sortOrder) do
|
||||
local aVal = a[data.key]
|
||||
local bVal = b[data.key]
|
||||
@@ -160,195 +156,53 @@ function ItemDBClass:BuildOrderList()
|
||||
end)
|
||||
end
|
||||
|
||||
function ItemDBClass:SelectIndex(index)
|
||||
self.selItem = self.orderList[index]
|
||||
if self.selItem then
|
||||
self.selIndex = index
|
||||
self.controls.scrollBar:ScrollIntoView((index - 2) * 16, 48)
|
||||
function ItemDBClass:GetRowValue(column, index, item)
|
||||
if column == 1 then
|
||||
return data.colorCodes[item.rarity] .. item.name
|
||||
end
|
||||
end
|
||||
|
||||
function ItemDBClass:IsMouseOver()
|
||||
if not self:IsShown() then
|
||||
return
|
||||
end
|
||||
return self:IsMouseInBounds() or self:GetMouseOverControl()
|
||||
function ItemDBClass:AddValueTooltip(index, item)
|
||||
self.itemsTab:AddItemTooltip(item, nil, true)
|
||||
return data.colorCodes[item.rarity], true
|
||||
end
|
||||
|
||||
function ItemDBClass:Draw(viewPort)
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local list = self.db.list
|
||||
local orderList = self.orderList
|
||||
local scrollBar = self.controls.scrollBar
|
||||
scrollBar:SetContentDimension(#orderList * 16, height - 4)
|
||||
if self.selItem and self.selDragging then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if not self.selDragActive and (cursorX-self.selCX)*(cursorX-self.selCX)+(cursorY-self.selCY)*(cursorY-self.selCY) > 100 then
|
||||
self.selDragActive = true
|
||||
end
|
||||
end
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, x, y, width, height)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, x + 1, y + 1, width - 2, height - 2)
|
||||
self:DrawControls(viewPort)
|
||||
SetViewport(x + 2, y + 2, width - 20, height - 4)
|
||||
local ttItem, ttY, ttWidth
|
||||
local minIndex = m_floor(scrollBar.offset / 16 + 1)
|
||||
local maxIndex = m_min(m_floor((scrollBar.offset + height) / 16 + 1), #orderList)
|
||||
for index = minIndex, maxIndex do
|
||||
local item = orderList[index]
|
||||
local itemY = 16 * (index - 1) - scrollBar.offset
|
||||
local nameWidth = DrawStringWidth(16, "VAR", item.name)
|
||||
if not scrollBar.dragging and (not self.itemsTab.selControl or self.hasFocus or self.controls.search.hasFocus) and not main.popups[1] then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
local relX = cursorX - (x + 2)
|
||||
local relY = cursorY - (y + 2)
|
||||
if relX >= 0 and relX < width - 17 and relY >= 0 and relY >= itemY and relY < height - 2 and relY < itemY + 16 then
|
||||
ttItem = item
|
||||
ttWidth = m_max(nameWidth + 8, relX)
|
||||
ttY = itemY + y + 2
|
||||
function ItemDBClass:GetDragValue(index, item)
|
||||
return "Item", item
|
||||
end
|
||||
|
||||
function ItemDBClass:OnSelClick(index, item, doubleClick)
|
||||
if IsKeyDown("CTRL") then
|
||||
-- Add item
|
||||
local newItem = itemLib.makeItemFromRaw(item.raw)
|
||||
itemLib.normaliseQuality(newItem)
|
||||
self.itemsTab:AddItem(newItem, true)
|
||||
|
||||
-- Equip item if able
|
||||
local slotName = itemLib.getPrimarySlotForItem(newItem)
|
||||
if slotName and self.itemsTab.slots[slotName] then
|
||||
if self.itemsTab.slots[slotName].weaponSet == 1 and self.itemsTab.useSecondWeaponSet then
|
||||
-- Redirect to second weapon set
|
||||
slotName = slotName .. " Swap"
|
||||
end
|
||||
end
|
||||
if item == ttItem or item == self.selItem then
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, 0, itemY, width - 20, 16)
|
||||
SetDrawColor(0.15, 0.15, 0.15)
|
||||
DrawImage(nil, 0, itemY + 1, width - 20, 14)
|
||||
end
|
||||
SetDrawColor(data.colorCodes[item.rarity])
|
||||
DrawString(0, itemY, "LEFT", 16, "VAR", item.name)
|
||||
end
|
||||
SetViewport()
|
||||
if ttItem then
|
||||
self.itemsTab:AddItemTooltip(ttItem, nil, true)
|
||||
SetDrawLayer(nil, 100)
|
||||
main:DrawTooltip(x + 2, ttY, ttWidth, 16, viewPort, data.colorCodes[ttItem.rarity], true)
|
||||
SetDrawLayer(nil, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function ItemDBClass:OnKeyDown(key, doubleClick)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
local mOverControl = self:GetMouseOverControl()
|
||||
if mOverControl and mOverControl.OnKeyDown then
|
||||
return mOverControl:OnKeyDown(key)
|
||||
end
|
||||
if not self:IsMouseOver() and key:match("BUTTON") then
|
||||
return
|
||||
end
|
||||
if key == "LEFTBUTTON" then
|
||||
self.selItem = nil
|
||||
self.selIndex = nil
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = m_floor((cursorY - y - 2 + self.controls.scrollBar.offset) / 16) + 1
|
||||
local selItem = self.orderList[index]
|
||||
if selItem then
|
||||
self.selItem = selItem
|
||||
self.selIndex = index
|
||||
if IsKeyDown("CTRL") then
|
||||
-- Immediately add and equip it
|
||||
self.itemsTab:CreateDisplayItemFromRaw(selItem.raw, true)
|
||||
local newItem = self.itemsTab.displayItem
|
||||
self.itemsTab:AddDisplayItem(true)
|
||||
itemLib.buildItemModList(newItem)
|
||||
local slotName = itemLib.getPrimarySlotForItem(newItem)
|
||||
if slotName and self.itemsTab.slots[slotName] then
|
||||
if IsKeyDown("SHIFT") then
|
||||
local altSlot = slotName:gsub("1","2")
|
||||
if self.itemsTab:IsItemValidForSlot(newItem, altSlot) then
|
||||
slotName = altSlot
|
||||
end
|
||||
end
|
||||
if self.itemsTab.slots[slotName].selItemId ~= newItem.id then
|
||||
self.itemsTab.slots[slotName]:SetSelItemId(newItem.id)
|
||||
self.itemsTab:PopulateSlots()
|
||||
self.itemsTab:AddUndoState()
|
||||
self.itemsTab.build.buildFlag = true
|
||||
end
|
||||
end
|
||||
elseif doubleClick then
|
||||
self.itemsTab:CreateDisplayItemFromRaw(selItem.raw, true)
|
||||
if IsKeyDown("SHIFT") then
|
||||
-- Redirect to second slot if possible
|
||||
local altSlot = slotName:gsub("1","2")
|
||||
if self.itemsTab:IsItemValidForSlot(newItem, altSlot) then
|
||||
slotName = altSlot
|
||||
end
|
||||
end
|
||||
self.itemsTab.slots[slotName]:SetSelItemId(newItem.id)
|
||||
end
|
||||
if self.selItem then
|
||||
self.selCX = cursorX
|
||||
self.selCY = cursorY
|
||||
self.selDragging = true
|
||||
self.selDragActive = false
|
||||
end
|
||||
elseif key == "UP" then
|
||||
self:SelectIndex(((self.selIndex or 1) - 2) % #self.orderList + 1)
|
||||
elseif key == "DOWN" then
|
||||
self:SelectIndex((self.selIndex or #self.orderList) % #self.orderList + 1)
|
||||
elseif key == "HOME" then
|
||||
self:SelectIndex(1)
|
||||
elseif key == "END" then
|
||||
self:SelectIndex(#self.orderList)
|
||||
elseif key == "c" and IsKeyDown("CTRL") then
|
||||
if self.selItem then
|
||||
Copy(self.selItem.raw:gsub("\n","\r\n"))
|
||||
end
|
||||
|
||||
self.itemsTab:PopulateSlots()
|
||||
self.itemsTab:AddUndoState()
|
||||
self.itemsTab.build.buildFlag = true
|
||||
elseif doubleClick then
|
||||
self.itemsTab:CreateDisplayItemFromRaw(item.raw, true)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function ItemDBClass:OnKeyUp(key)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
if key == "WHEELDOWN" then
|
||||
self.controls.scrollBar:Scroll(1)
|
||||
elseif key == "WHEELUP" then
|
||||
self.controls.scrollBar:Scroll(-1)
|
||||
elseif self.selItem then
|
||||
if key == "LEFTBUTTON" then
|
||||
self.selDragging = false
|
||||
if self.selDragActive then
|
||||
self.selDragActive = false
|
||||
if self.itemsTab.controls.itemList:IsMouseOver() and self.itemsTab.controls.itemList.selDragIndex then
|
||||
self.itemsTab:CreateDisplayItemFromRaw(self.selItem.raw, true)
|
||||
local newItem = self.itemsTab.displayItem
|
||||
self.itemsTab:AddDisplayItem()
|
||||
itemLib.buildItemModList(newItem)
|
||||
t_remove(self.itemsTab.orderList, #self.itemsTab.orderList)
|
||||
t_insert(self.itemsTab.orderList, self.itemsTab.controls.itemList.selDragIndex, newItem.id)
|
||||
else
|
||||
for slotName, slot in pairs(self.itemsTab.slots) do
|
||||
if not slot.inactive and slot:IsMouseOver() then
|
||||
if self.itemsTab:IsItemValidForSlot(self.selItem, slotName) then
|
||||
self.itemsTab:CreateDisplayItemFromRaw(self.selItem.raw, true)
|
||||
local newItem = self.itemsTab.displayItem
|
||||
self.itemsTab:AddDisplayItem(true)
|
||||
itemLib.buildItemModList(newItem)
|
||||
slot:SetSelItemId(newItem.id)
|
||||
self.itemsTab:PopulateSlots()
|
||||
self.itemsTab:AddUndoState()
|
||||
self.itemsTab.build.buildFlag = true
|
||||
end
|
||||
self.selItem = nil
|
||||
self.selIndex = nil
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
function ItemDBClass:OnSelCopy(index, item)
|
||||
Copy(item.raw:gsub("\n","\r\n"))
|
||||
end
|
||||
@@ -5,281 +5,107 @@
|
||||
--
|
||||
local launch, main = ...
|
||||
|
||||
local pairs = pairs
|
||||
local t_insert = table.insert
|
||||
local t_remove = table.remove
|
||||
local m_min = math.min
|
||||
local m_max = math.max
|
||||
local m_floor = math.floor
|
||||
|
||||
local ItemListClass = common.NewClass("ItemList", "Control", "ControlHost", function(self, anchor, x, y, width, height, itemsTab)
|
||||
self.Control(anchor, x, y, width, height)
|
||||
self.ControlHost()
|
||||
local ItemListClass = common.NewClass("ItemList", "ListControl", function(self, anchor, x, y, width, height, itemsTab)
|
||||
self.ListControl(anchor, x, y, width, height, 16, true, itemsTab.orderList)
|
||||
self.itemsTab = itemsTab
|
||||
self.controls.scrollBar = common.New("ScrollBarControl", {"RIGHT",self,"RIGHT"}, -1, 0, 16, 0, 32)
|
||||
self.controls.scrollBar.height = function()
|
||||
local width, height = self:GetSize()
|
||||
return height - 2
|
||||
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()
|
||||
table.sort(itemsTab.orderList, function(a, b)
|
||||
local itemA = itemsTab.list[a]
|
||||
local itemB = itemsTab.list[b]
|
||||
local primSlotA = itemLib.getPrimarySlotForItem(itemA)
|
||||
local primSlotB = itemLib.getPrimarySlotForItem(itemB)
|
||||
if primSlotA ~= primSlotB then
|
||||
if not itemsTab.slotOrder[primSlotA] then
|
||||
return false
|
||||
elseif not itemsTab.slotOrder[primSlotB] then
|
||||
return true
|
||||
end
|
||||
return itemsTab.slotOrder[primSlotA] < itemsTab.slotOrder[primSlotB]
|
||||
end
|
||||
local equipSlotA = itemsTab:GetEquippedSlotForItem(itemA)
|
||||
local equipSlotB = itemsTab:GetEquippedSlotForItem(itemB)
|
||||
if equipSlotA and equipSlotB then
|
||||
return itemsTab.slotOrder[equipSlotA.slotName] < itemsTab.slotOrder[equipSlotB.slotName]
|
||||
elseif not equipSlotA then
|
||||
return false
|
||||
elseif not equipSlotB then
|
||||
return true
|
||||
end
|
||||
return itemA.name < itemB.name
|
||||
end)
|
||||
itemsTab:AddUndoState()
|
||||
itemsTab:SortItemList()
|
||||
end)
|
||||
self.controls.delete = common.New("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, 0, -2, 60, 18, "Delete", function()
|
||||
self:OnKeyUp("DELETE")
|
||||
self:OnSelDelete(self.selIndex, self.selValue)
|
||||
end)
|
||||
self.controls.delete.enabled = function()
|
||||
return self.selItem ~= nil
|
||||
return self.selValue ~= nil
|
||||
end
|
||||
end)
|
||||
|
||||
function ItemListClass:SelectIndex(index)
|
||||
local selItemId = self.itemsTab.orderList[index]
|
||||
if selItemId then
|
||||
self.selItem = self.itemsTab.list[selItemId]
|
||||
self.selIndex = index
|
||||
self.controls.scrollBar:ScrollIntoView((index - 2) * 16, 48)
|
||||
function ItemListClass:GetRowValue(column, index, itemId)
|
||||
local item = self.itemsTab.list[itemId]
|
||||
if column == 1 then
|
||||
return data.colorCodes[item.rarity] .. item.name .. (not self.itemsTab:GetEquippedSlotForItem(item) and " ^9(Unused)" or "")
|
||||
end
|
||||
end
|
||||
|
||||
function ItemListClass:IsMouseOver()
|
||||
if not self:IsShown() then
|
||||
return
|
||||
end
|
||||
return self:IsMouseInBounds() or self:GetMouseOverControl()
|
||||
function ItemListClass:AddValueTooltip(index, itemId)
|
||||
local item = self.itemsTab.list[itemId]
|
||||
self.itemsTab:AddItemTooltip(item, nil, true)
|
||||
return data.colorCodes[item.rarity], true
|
||||
end
|
||||
|
||||
function ItemListClass:Draw(viewPort)
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local list = self.itemsTab.list
|
||||
local orderList = self.itemsTab.orderList
|
||||
local scrollBar = self.controls.scrollBar
|
||||
scrollBar:SetContentDimension(#orderList * 16, height - 4)
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
self.selDragIndex = nil
|
||||
if self.selItem and self.selDragging then
|
||||
if not self.selDragActive and (cursorX-self.selCX)*(cursorX-self.selCX)+(cursorY-self.selCY)*(cursorY-self.selCY) > 100 then
|
||||
self.selDragActive = true
|
||||
end
|
||||
elseif (self.itemsTab.controls.uniqueDB:IsShown() and self.itemsTab.controls.uniqueDB.selDragActive) or (self.itemsTab.controls.rareDB:IsShown() and self.itemsTab.controls.rareDB.selDragActive) then
|
||||
self.selDragActive = true
|
||||
else
|
||||
self.selDragActive = false
|
||||
function ItemListClass:GetDragValue(index, itemId)
|
||||
return "Item", self.itemsTab.list[itemId]
|
||||
end
|
||||
|
||||
function ItemListClass:ReceiveDrag(type, value, source)
|
||||
if type == "Item" then
|
||||
local newItem = itemLib.makeItemFromRaw(value.raw)
|
||||
itemLib.normaliseQuality(newItem)
|
||||
self.itemsTab:AddItem(newItem, true, self.selDragIndex)
|
||||
self.itemsTab:PopulateSlots()
|
||||
self.itemsTab:AddUndoState()
|
||||
self.itemsTab.build.buildFlag = true
|
||||
end
|
||||
if self.selDragActive then
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + scrollBar.offset) / 16 + 0.5) + 1
|
||||
if not self.selDragging or index < self.selIndex or index > self.selIndex + 1 then
|
||||
self.selDragIndex = m_min(index, #orderList + 1)
|
||||
end
|
||||
|
||||
function ItemListClass:OnOrderChange()
|
||||
self.itemsTab:AddUndoState()
|
||||
end
|
||||
|
||||
function ItemListClass:OnSelClick(index, itemId, doubleClick)
|
||||
local item = self.itemsTab.list[itemId]
|
||||
if IsKeyDown("CTRL") then
|
||||
local slotName = itemLib.getPrimarySlotForItem(item)
|
||||
if slotName and self.itemsTab.slots[slotName] then
|
||||
if self.itemsTab.slots[slotName].weaponSet == 1 and self.itemsTab.useSecondWeaponSet then
|
||||
-- Redirect to second weapon set
|
||||
slotName = slotName .. " Swap"
|
||||
end
|
||||
end
|
||||
end
|
||||
DrawString(x, y - 20, "LEFT", 16, "VAR", "^7All items:")
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, x, y, width, height)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, x + 1, y + 1, width - 2, height - 2)
|
||||
self:DrawControls(viewPort)
|
||||
SetViewport(x + 2, y + 2, width - 20, height - 4)
|
||||
local ttItem, ttY, ttWidth
|
||||
local minIndex = m_floor(scrollBar.offset / 16 + 1)
|
||||
local maxIndex = m_min(m_floor((scrollBar.offset + height) / 16 + 1), #orderList)
|
||||
for index = minIndex, maxIndex do
|
||||
local item = list[orderList[index]]
|
||||
local itemY = 16 * (index - 1) - scrollBar.offset
|
||||
local nameWidth = DrawStringWidth(16, "VAR", item.name)
|
||||
if not scrollBar.dragging and not self.selDragActive and (not self.itemsTab.selControl or self.hasFocus) and not main.popups[1] then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
local relX = cursorX - (x + 2)
|
||||
local relY = cursorY - (y + 2)
|
||||
if relX >= 0 and relX < width - 17 and relY >= 0 and relY >= itemY and relY < height - 2 and relY < itemY + 16 then
|
||||
ttItem = item
|
||||
ttWidth = m_max(nameWidth + 8, relX)
|
||||
ttY = itemY + y + 2
|
||||
if IsKeyDown("SHIFT") then
|
||||
-- Redirect to second slot if possible
|
||||
local altSlot = slotName:gsub("1","2")
|
||||
if self.itemsTab:IsItemValidForSlot(item, altSlot) then
|
||||
slotName = altSlot
|
||||
end
|
||||
end
|
||||
end
|
||||
if item == ttItem or item == self.selItem then
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
if self.itemsTab.slots[slotName].selItemId == item.id then
|
||||
self.itemsTab.slots[slotName]:SetSelItemId(0)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
self.itemsTab.slots[slotName]:SetSelItemId(item.id)
|
||||
end
|
||||
DrawImage(nil, 0, itemY, width - 20, 16)
|
||||
SetDrawColor(0.15, 0.15, 0.15)
|
||||
DrawImage(nil, 0, itemY + 1, width - 20, 14)
|
||||
self.itemsTab:PopulateSlots()
|
||||
self.itemsTab:AddUndoState()
|
||||
self.itemsTab.build.buildFlag = true
|
||||
end
|
||||
SetDrawColor(data.colorCodes[item.rarity])
|
||||
DrawString(0, itemY, "LEFT", 16, "VAR", item.name)
|
||||
if not self.itemsTab:GetEquippedSlotForItem(item) then
|
||||
DrawString(nameWidth + 8, itemY, "LEFT", 16, "VAR", "^9(Unused)")
|
||||
end
|
||||
end
|
||||
if self.selDragIndex then
|
||||
local itemY = 16 * (self.selDragIndex - 1) - scrollBar.offset
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawImage(nil, 0, itemY - 1, width - 20, 3)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, 0, itemY, width - 20, 1)
|
||||
end
|
||||
SetViewport()
|
||||
if ttItem then
|
||||
self.itemsTab:AddItemTooltip(ttItem)
|
||||
SetDrawLayer(nil, 100)
|
||||
main:DrawTooltip(x + 2, ttY, ttWidth, 16, viewPort, data.colorCodes[ttItem.rarity], true)
|
||||
SetDrawLayer(nil, 0)
|
||||
elseif doubleClick then
|
||||
self.itemsTab:SetDisplayItem(copyTable(item))
|
||||
end
|
||||
end
|
||||
|
||||
function ItemListClass:OnKeyDown(key, doubleClick)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
local mOverControl = self:GetMouseOverControl()
|
||||
if mOverControl and mOverControl.OnKeyDown then
|
||||
return mOverControl:OnKeyDown(key)
|
||||
end
|
||||
if not self:IsMouseOver() and key:match("BUTTON") then
|
||||
return
|
||||
end
|
||||
if key == "LEFTBUTTON" then
|
||||
self.selItem = nil
|
||||
function ItemListClass:OnSelCopy(index, itemId)
|
||||
local item = self.itemsTab.list[itemId]
|
||||
Copy(itemLib.createItemRaw(item):gsub("\n","\r\n"))
|
||||
end
|
||||
|
||||
function ItemListClass:OnSelDelete(index, itemId)
|
||||
local item = self.itemsTab.list[itemId]
|
||||
local equipSlot = self.itemsTab:GetEquippedSlotForItem(item)
|
||||
if equipSlot then
|
||||
main:OpenConfirmPopup("Delete Item", item.name.." is currently equipped in "..equipSlot.label..".\nAre you sure you want to delete it?", "Delete", function()
|
||||
self.itemsTab:DeleteItem(item)
|
||||
self.selIndex = nil
|
||||
self.selValue = nil
|
||||
end)
|
||||
else
|
||||
self.itemsTab:DeleteItem(item)
|
||||
self.selIndex = nil
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + self.controls.scrollBar.offset) / 16) + 1
|
||||
local selItemId = self.itemsTab.orderList[index]
|
||||
if selItemId then
|
||||
self.selItem = self.itemsTab.list[selItemId]
|
||||
self.selIndex = index
|
||||
if IsKeyDown("CTRL") then
|
||||
-- Equip it
|
||||
local slotName = itemLib.getPrimarySlotForItem(self.selItem)
|
||||
if slotName and self.itemsTab.slots[slotName] then
|
||||
if IsKeyDown("SHIFT") then
|
||||
local altSlot = slotName:gsub("1","2")
|
||||
if self.itemsTab:IsItemValidForSlot(self.selItem, altSlot) then
|
||||
slotName = altSlot
|
||||
end
|
||||
end
|
||||
if self.itemsTab.slots[slotName].selItemId == selItemId then
|
||||
self.itemsTab.slots[slotName]:SetSelItemId(0)
|
||||
else
|
||||
self.itemsTab.slots[slotName]:SetSelItemId(selItemId)
|
||||
end
|
||||
self.itemsTab:PopulateSlots()
|
||||
self.itemsTab:AddUndoState()
|
||||
self.itemsTab.build.buildFlag = true
|
||||
end
|
||||
elseif doubleClick then
|
||||
self.itemsTab:SetDisplayItem(copyTable(self.selItem))
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.selItem then
|
||||
self.selCX = cursorX
|
||||
self.selCY = cursorY
|
||||
self.selDragging = true
|
||||
self.selDragActive = false
|
||||
end
|
||||
elseif key == "UP" then
|
||||
self:SelectIndex(((self.selIndex or 1) - 2) % #self.itemsTab.orderList + 1)
|
||||
elseif key == "DOWN" then
|
||||
self:SelectIndex((self.selIndex or #self.itemsTab.orderList) % #self.itemsTab.orderList + 1)
|
||||
elseif key == "HOME" then
|
||||
self:SelectIndex(1)
|
||||
elseif key == "END" then
|
||||
self:SelectIndex(#self.itemsTab.orderList)
|
||||
elseif key == "c" and IsKeyDown("CTRL") then
|
||||
if self.selItem then
|
||||
Copy(itemLib.createItemRaw(self.selItem):gsub("\n","\r\n"))
|
||||
end
|
||||
self.selValue = nil
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function ItemListClass:OnKeyUp(key)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
if key == "WHEELDOWN" then
|
||||
self.controls.scrollBar:Scroll(1)
|
||||
elseif key == "WHEELUP" then
|
||||
self.controls.scrollBar:Scroll(-1)
|
||||
elseif self.selItem then
|
||||
if key == "BACK" or key == "DELETE" then
|
||||
local equipSlot = self.itemsTab:GetEquippedSlotForItem(self.selItem)
|
||||
if equipSlot then
|
||||
main:OpenConfirmPopup("Delete Item", self.selItem.name.." is currently equipped in "..equipSlot.label..".\nAre you sure you want to delete it?", "Delete", function()
|
||||
self.itemsTab:DeleteItem(self.selItem)
|
||||
self.selItem = nil
|
||||
self.selIndex = nil
|
||||
end)
|
||||
else
|
||||
self.itemsTab:DeleteItem(self.selItem)
|
||||
self.selItem = nil
|
||||
self.selIndex = nil
|
||||
end
|
||||
elseif key == "LEFTBUTTON" then
|
||||
self.selDragging = false
|
||||
if self.selDragActive then
|
||||
self.selDragActive = false
|
||||
if self.selDragIndex then
|
||||
if self.selDragIndex ~= self.selIndex then
|
||||
t_remove(self.itemsTab.orderList, self.selIndex)
|
||||
if self.selDragIndex > self.selIndex then
|
||||
self.selDragIndex = self.selDragIndex - 1
|
||||
end
|
||||
t_insert(self.itemsTab.orderList, self.selDragIndex, self.selItem.id)
|
||||
self.itemsTab:AddUndoState()
|
||||
self.selItem = nil
|
||||
self.selIndex = nil
|
||||
end
|
||||
else
|
||||
for slotName, slot in pairs(self.itemsTab.slots) do
|
||||
if not slot.inactive and slot:IsMouseOver() then
|
||||
if self.itemsTab:IsItemValidForSlot(self.selItem, slotName) and slot.selItemId ~= self.selItem.id then
|
||||
slot:SetSelItemId(self.selItem.id)
|
||||
self.itemsTab:PopulateSlots()
|
||||
self.itemsTab:AddUndoState()
|
||||
self.itemsTab.build.buildFlag = true
|
||||
end
|
||||
self.selItem = nil
|
||||
self.selIndex = nil
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -5,7 +5,7 @@
|
||||
--
|
||||
local launch, main = ...
|
||||
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local t_insert = table.insert
|
||||
local m_min = math.min
|
||||
|
||||
@@ -76,22 +76,35 @@ function ItemSlotClass:Populate()
|
||||
end
|
||||
end
|
||||
|
||||
function ItemSlotClass:CanReceiveDrag(type, value)
|
||||
return type == "Item" and self.itemsTab:IsItemValidForSlot(value, self.slotName)
|
||||
end
|
||||
|
||||
function ItemSlotClass:ReceiveDrag(type, value, source)
|
||||
if value.id and self.itemsTab.list[value.id] then
|
||||
self:SetSelItemId(value.id)
|
||||
else
|
||||
local newItem = itemLib.makeItemFromRaw(value.raw)
|
||||
itemLib.normaliseQuality(newItem)
|
||||
self.itemsTab:AddItem(newItem, true)
|
||||
self:SetSelItemId(newItem.id)
|
||||
end
|
||||
self.itemsTab:PopulateSlots()
|
||||
self.itemsTab:AddUndoState()
|
||||
self.itemsTab.build.buildFlag = true
|
||||
end
|
||||
|
||||
function ItemSlotClass:Draw(viewPort)
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
DrawString(x + self.labelOffset, y + 2, "RIGHT_X", height - 4, "VAR", "^7"..self.label..":")
|
||||
self.DropDownControl:Draw(viewPort)
|
||||
self:DrawControls(viewPort)
|
||||
local highlight = false
|
||||
for _, control in pairs({self.itemsTab.controls.itemList, self.itemsTab.controls.uniqueDB, self.itemsTab.controls.rareDB}) do
|
||||
if control:IsShown() and control.selDragging and control.selDragActive and control.selItem and self.itemsTab:IsItemValidForSlot(control.selItem, self.slotName) then
|
||||
highlight = true
|
||||
SetDrawColor(0, 1, 0, 0.25)
|
||||
DrawImage(nil, x, y, width, height)
|
||||
break
|
||||
end
|
||||
if self.otherDragSource then
|
||||
SetDrawColor(0, 1, 0, 0.25)
|
||||
DrawImage(nil, x, y, width, height)
|
||||
end
|
||||
if self.nodeId and (self.dropped or (self:IsMouseOver() and (highlight or not self.itemsTab.selControl))) then
|
||||
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
|
||||
local viewerY = m_min(y, viewPort.y + viewPort.height - 304)
|
||||
|
||||
@@ -406,6 +406,213 @@ function ItemsTabClass:GetSocketAndJewelForNodeID(nodeId)
|
||||
return self.sockets[nodeId], self.list[self.sockets[nodeId].selItemId]
|
||||
end
|
||||
|
||||
-- Adds the given item to the build's item list
|
||||
function ItemsTabClass:AddItem(item, noAutoEquip, index)
|
||||
if not item.id then
|
||||
-- Find an unused item ID
|
||||
item.id = 1
|
||||
while self.list[item.id] do
|
||||
item.id = item.id + 1
|
||||
end
|
||||
|
||||
if index then
|
||||
t_insert(self.orderList, index, item.id)
|
||||
else
|
||||
-- Add it to the end of the display order list
|
||||
t_insert(self.orderList, item.id)
|
||||
end
|
||||
|
||||
if not noAutoEquip then
|
||||
-- Autoequip it
|
||||
for _, slot in ipairs(self.orderedSlots) do
|
||||
if not slot.nodeId and slot.selItemId == 0 and slot:IsShown() and self:IsItemValidForSlot(item, slot.slotName) then
|
||||
slot:SetSelItemId(item.id)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add it to the list
|
||||
self.list[item.id] = item
|
||||
itemLib.buildItemModList(item)
|
||||
end
|
||||
|
||||
-- Adds the current display item to the build's item list
|
||||
function ItemsTabClass:AddDisplayItem(noAutoEquip)
|
||||
-- Add it to the list and clear the current display item
|
||||
self:AddItem(self.displayItem, noAutoEquip)
|
||||
self:SetDisplayItem()
|
||||
|
||||
self:PopulateSlots()
|
||||
self:AddUndoState()
|
||||
self.build.buildFlag = true
|
||||
end
|
||||
|
||||
-- Sorts the build's item list
|
||||
function ItemsTabClass:SortItemList()
|
||||
table.sort(self.orderList, function(a, b)
|
||||
local itemA = self.list[a]
|
||||
local itemB = self.list[b]
|
||||
local primSlotA = itemLib.getPrimarySlotForItem(itemA)
|
||||
local primSlotB = itemLib.getPrimarySlotForItem(itemB)
|
||||
if primSlotA ~= primSlotB then
|
||||
if not self.slotOrder[primSlotA] then
|
||||
return false
|
||||
elseif not self.slotOrder[primSlotB] then
|
||||
return true
|
||||
end
|
||||
return self.slotOrder[primSlotA] < self.slotOrder[primSlotB]
|
||||
end
|
||||
local equipSlotA = self:GetEquippedSlotForItem(itemA)
|
||||
local equipSlotB = self:GetEquippedSlotForItem(itemB)
|
||||
if equipSlotA and equipSlotB then
|
||||
return self.slotOrder[equipSlotA.slotName] < self.slotOrder[equipSlotB.slotName]
|
||||
elseif equipSlotA then
|
||||
return true
|
||||
elseif equipSlotB then
|
||||
return false
|
||||
end
|
||||
return itemA.name < itemB.name
|
||||
end)
|
||||
self:AddUndoState()
|
||||
end
|
||||
|
||||
-- Deletes an item
|
||||
function ItemsTabClass:DeleteItem(item)
|
||||
for _, slot in pairs(self.slots) do
|
||||
if slot.selItemId == item.id then
|
||||
slot:SetSelItemId(0)
|
||||
self.build.buildFlag = true
|
||||
end
|
||||
end
|
||||
for index, id in pairs(self.orderList) do
|
||||
if id == item.id then
|
||||
t_remove(self.orderList, index)
|
||||
break
|
||||
end
|
||||
end
|
||||
for _, spec in pairs(self.build.treeTab.specList) do
|
||||
for nodeId, itemId in pairs(spec.jewels) do
|
||||
if itemId == item.id then
|
||||
spec.jewels[nodeId] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
self.list[item.id] = nil
|
||||
self:PopulateSlots()
|
||||
self:AddUndoState()
|
||||
end
|
||||
|
||||
-- Attempt to create a new item from the given item raw text and sets it as the new display item
|
||||
function ItemsTabClass:CreateDisplayItemFromRaw(itemRaw, normalise)
|
||||
local newItem = itemLib.makeItemFromRaw(itemRaw)
|
||||
if newItem then
|
||||
if normalise then
|
||||
itemLib.normaliseQuality(newItem)
|
||||
end
|
||||
self:SetDisplayItem(newItem)
|
||||
end
|
||||
end
|
||||
|
||||
-- Sets the display item to the given item
|
||||
function ItemsTabClass:SetDisplayItem(item)
|
||||
self.displayItem = item
|
||||
if item then
|
||||
-- Update the display item controls
|
||||
self.controls.displayItemVariant.list = item.variantList
|
||||
self.controls.displayItemVariant.sel = item.variant
|
||||
self:UpdateDisplayItemRangeLines()
|
||||
self.controls.scrollBarH:SetOffset(self.controls.scrollBarH.offsetMax)
|
||||
item.craftable = item.crafted and item.affixes and item.affixLimit > 0
|
||||
if item.craftable then
|
||||
local prefixList = { }
|
||||
local suffixList = { }
|
||||
for name, data in pairs(item.affixes) do
|
||||
if not data.exclude or (not data.exclude[item.base.subType] and not data.exclude[item.baseName]) then
|
||||
if data.type == "Prefix" then
|
||||
t_insert(prefixList, name)
|
||||
elseif data.type == "Suffix" then
|
||||
t_insert(suffixList, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(prefixList)
|
||||
t_insert(prefixList, 1, "None")
|
||||
table.sort(suffixList)
|
||||
t_insert(suffixList, 1, "None")
|
||||
local prefixTable = { }
|
||||
local suffixTable = { }
|
||||
for list, out in pairs({[prefixList] = prefixTable, [suffixList] = suffixTable}) do
|
||||
for i, name in pairs(list) do
|
||||
out[i] = {
|
||||
label = name,
|
||||
value = name,
|
||||
}
|
||||
if item.affixes[name] then
|
||||
out[i].label = out[i].label .. " ^8[" .. table.concat(item.affixes[name], "/") .. "]"
|
||||
end
|
||||
end
|
||||
end
|
||||
for i = 1, item.affixLimit/2 do
|
||||
local pre = self.controls["displayItemAffix"..i]
|
||||
pre.list = prefixTable
|
||||
pre.outputTable = "prefixes"
|
||||
pre.outputIndex = i
|
||||
pre.sel = isValueInArray(prefixList, item.prefixes[i] or "None") or 1
|
||||
local suf = self.controls["displayItemAffix"..(i+item.affixLimit/2)]
|
||||
suf.list = suffixTable
|
||||
suf.outputTable = "suffixes"
|
||||
suf.outputIndex = i
|
||||
suf.sel = isValueInArray(suffixList, item.suffixes[i] or "None") or 1
|
||||
end
|
||||
end
|
||||
else
|
||||
self.controls.scrollBarH:SetOffset(0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Updates the range line dropdown and range slider for the current display item
|
||||
function ItemsTabClass:UpdateDisplayItemRangeLines()
|
||||
if self.displayItem and self.displayItem.rangeLineList[1] then
|
||||
wipeTable(self.controls.displayItemRangeLine.list)
|
||||
for _, modLine in ipairs(self.displayItem.rangeLineList) do
|
||||
t_insert(self.controls.displayItemRangeLine.list, modLine.line)
|
||||
end
|
||||
self.controls.displayItemRangeLine.sel = 1
|
||||
self.controls.displayItemRangeSlider.val = self.displayItem.rangeLineList[1].range
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns the first slot in which the given item is equipped
|
||||
function ItemsTabClass:GetEquippedSlotForItem(item)
|
||||
for _, slot in ipairs(self.orderedSlots) do
|
||||
if not slot.inactive and slot.selItemId == item.id then
|
||||
return slot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if the given item could be equipped in the given slot, taking into account possible conflicts with currently equipped items
|
||||
-- For example, a shield is not valid for Weapon 2 if Weapon 1 is a staff, and a wand is not valid for Weapon 2 if Weapon 1 is a dagger
|
||||
function ItemsTabClass:IsItemValidForSlot(item, slotName)
|
||||
if item.type == slotName:gsub(" %d+","") then
|
||||
return true
|
||||
elseif slotName == "Weapon 1" or slotName == "Weapon 1 Swap" or slotName == "Weapon" then
|
||||
return item.base.weapon ~= nil
|
||||
elseif slotName == "Weapon 2" or slotName == "Weapon 2 Swap" then
|
||||
local weapon1Sel = self.slots[slotName == "Weapon 2" and "Weapon 1" or "Weapon 1 Swap"].selItemId or 0
|
||||
local weapon1Type = weapon1Sel > 0 and self.list[weapon1Sel].base.type or "None"
|
||||
if weapon1Type == "None" then
|
||||
return item.type == "Quiver" or item.type == "Shield" or (data.weaponTypeInfo[item.type] and data.weaponTypeInfo[item.type].oneHand)
|
||||
elseif weapon1Type == "Bow" then
|
||||
return item.type == "Quiver"
|
||||
elseif data.weaponTypeInfo[weapon1Type].oneHand then
|
||||
return item.type == "Shield" or (data.weaponTypeInfo[item.type] and data.weaponTypeInfo[item.type].oneHand and ((weapon1Type == "Wand" and item.type == "Wand") or (weapon1Type ~= "Wand" and item.type ~= "Wand")))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Opens the item crafting popup
|
||||
function ItemsTabClass:CraftItem()
|
||||
local controls = { }
|
||||
@@ -638,179 +845,6 @@ function ItemsTabClass:EnchantDisplayItem()
|
||||
main:OpenPopup(550, 130, "Enchant Item", controls)
|
||||
end
|
||||
|
||||
-- Attempt to create a new item from the given item raw text and sets it as the new display item
|
||||
function ItemsTabClass:CreateDisplayItemFromRaw(itemRaw, normalise)
|
||||
local newItem = itemLib.makeItemFromRaw(itemRaw)
|
||||
if newItem then
|
||||
if normalise then
|
||||
itemLib.normaliseQuality(newItem)
|
||||
end
|
||||
self:SetDisplayItem(newItem)
|
||||
end
|
||||
end
|
||||
|
||||
-- Sets the display item to the given item
|
||||
function ItemsTabClass:SetDisplayItem(item)
|
||||
self.displayItem = item
|
||||
if item then
|
||||
-- Update the display item controls
|
||||
self.controls.displayItemVariant.list = item.variantList
|
||||
self.controls.displayItemVariant.sel = item.variant
|
||||
self:UpdateDisplayItemRangeLines()
|
||||
self.controls.scrollBarH:SetOffset(self.controls.scrollBarH.offsetMax)
|
||||
item.craftable = item.crafted and item.affixes and item.affixLimit > 0
|
||||
if item.craftable then
|
||||
local prefixList = { }
|
||||
local suffixList = { }
|
||||
for name, data in pairs(item.affixes) do
|
||||
if not data.exclude or (not data.exclude[item.base.subType] and not data.exclude[item.baseName]) then
|
||||
if data.type == "Prefix" then
|
||||
t_insert(prefixList, name)
|
||||
elseif data.type == "Suffix" then
|
||||
t_insert(suffixList, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(prefixList)
|
||||
t_insert(prefixList, 1, "None")
|
||||
table.sort(suffixList)
|
||||
t_insert(suffixList, 1, "None")
|
||||
local prefixTable = { }
|
||||
local suffixTable = { }
|
||||
for list, out in pairs({[prefixList] = prefixTable, [suffixList] = suffixTable}) do
|
||||
for i, name in pairs(list) do
|
||||
out[i] = {
|
||||
label = name,
|
||||
value = name,
|
||||
}
|
||||
if item.affixes[name] then
|
||||
out[i].label = out[i].label .. " ^8[" .. table.concat(item.affixes[name], "/") .. "]"
|
||||
end
|
||||
end
|
||||
end
|
||||
for i = 1, item.affixLimit/2 do
|
||||
local pre = self.controls["displayItemAffix"..i]
|
||||
pre.list = prefixTable
|
||||
pre.outputTable = "prefixes"
|
||||
pre.outputIndex = i
|
||||
pre.sel = isValueInArray(prefixList, item.prefixes[i] or "None") or 1
|
||||
local suf = self.controls["displayItemAffix"..(i+item.affixLimit/2)]
|
||||
suf.list = suffixTable
|
||||
suf.outputTable = "suffixes"
|
||||
suf.outputIndex = i
|
||||
suf.sel = isValueInArray(suffixList, item.suffixes[i] or "None") or 1
|
||||
end
|
||||
end
|
||||
else
|
||||
self.controls.scrollBarH:SetOffset(0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Updates the range line dropdown and range slider for the current display item
|
||||
function ItemsTabClass:UpdateDisplayItemRangeLines()
|
||||
if self.displayItem and self.displayItem.rangeLineList[1] then
|
||||
wipeTable(self.controls.displayItemRangeLine.list)
|
||||
for _, modLine in ipairs(self.displayItem.rangeLineList) do
|
||||
t_insert(self.controls.displayItemRangeLine.list, modLine.line)
|
||||
end
|
||||
self.controls.displayItemRangeLine.sel = 1
|
||||
self.controls.displayItemRangeSlider.val = self.displayItem.rangeLineList[1].range
|
||||
end
|
||||
end
|
||||
|
||||
-- Adds the given item to the build's item list
|
||||
function ItemsTabClass:AddItem(item, noAutoEquip)
|
||||
if not item.id then
|
||||
-- Find an unused item ID
|
||||
item.id = 1
|
||||
while self.list[item.id] do
|
||||
item.id = item.id + 1
|
||||
end
|
||||
|
||||
-- Add it to the end of the display order list
|
||||
t_insert(self.orderList, item.id)
|
||||
|
||||
if not noAutoEquip then
|
||||
-- Autoequip it
|
||||
for _, slotName in ipairs(baseSlots) do
|
||||
if self.slots[slotName].selItemId == 0 and self:IsItemValidForSlot(item, slotName) then
|
||||
self.slots[slotName]:SetSelItemId(item.id)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add it to the list
|
||||
self.list[item.id] = item
|
||||
itemLib.buildItemModList(item)
|
||||
end
|
||||
|
||||
-- Adds the current display item to the build's item list
|
||||
function ItemsTabClass:AddDisplayItem(noAutoEquip)
|
||||
-- Add it to the list and clear the current display item
|
||||
self:AddItem(self.displayItem, noAutoEquip)
|
||||
self:SetDisplayItem()
|
||||
|
||||
self:PopulateSlots()
|
||||
self:AddUndoState()
|
||||
self.build.buildFlag = true
|
||||
end
|
||||
|
||||
function ItemsTabClass:DeleteItem(item)
|
||||
for _, slot in pairs(self.slots) do
|
||||
if slot.selItemId == item.id then
|
||||
slot:SetSelItemId(0)
|
||||
self.build.buildFlag = true
|
||||
end
|
||||
end
|
||||
for index, id in pairs(self.orderList) do
|
||||
if id == item.id then
|
||||
t_remove(self.orderList, index)
|
||||
break
|
||||
end
|
||||
end
|
||||
for _, spec in pairs(self.build.treeTab.specList) do
|
||||
for nodeId, itemId in pairs(spec.jewels) do
|
||||
if itemId == item.id then
|
||||
spec.jewels[nodeId] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
self.list[item.id] = nil
|
||||
self:PopulateSlots()
|
||||
self:AddUndoState()
|
||||
end
|
||||
|
||||
-- Returns the first slot in which the given item is equipped
|
||||
function ItemsTabClass:GetEquippedSlotForItem(item)
|
||||
for _, slot in ipairs(self.orderedSlots) do
|
||||
if not slot.inactive and slot.selItemId == item.id then
|
||||
return slot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if the given item could be equipped in the given slot, taking into account possible conflicts with currently equipped items
|
||||
-- For example, a shield is not valid for Weapon 2 if Weapon 1 is a staff, and a wand is not valid for Weapon 2 if Weapon 1 is a dagger
|
||||
function ItemsTabClass:IsItemValidForSlot(item, slotName)
|
||||
if item.type == slotName:gsub(" %d+","") then
|
||||
return true
|
||||
elseif slotName == "Weapon 1" or slotName == "Weapon 1 Swap" or slotName == "Weapon" then
|
||||
return item.base.weapon ~= nil
|
||||
elseif slotName == "Weapon 2" or slotName == "Weapon 2 Swap" then
|
||||
local weapon1Sel = self.slots[slotName == "Weapon 2" and "Weapon 1" or "Weapon 1 Swap"].selItemId or 0
|
||||
local weapon1Type = weapon1Sel > 0 and self.list[weapon1Sel].base.type or "None"
|
||||
if weapon1Type == "None" then
|
||||
return item.type == "Quiver" or item.type == "Shield" or (data.weaponTypeInfo[item.type] and data.weaponTypeInfo[item.type].oneHand)
|
||||
elseif weapon1Type == "Bow" then
|
||||
return item.type == "Quiver"
|
||||
elseif data.weaponTypeInfo[weapon1Type].oneHand then
|
||||
return item.type == "Shield" or (data.weaponTypeInfo[item.type] and data.weaponTypeInfo[item.type].oneHand and ((weapon1Type == "Wand" and item.type == "Wand") or (weapon1Type ~= "Wand" and item.type ~= "Wand")))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ItemsTabClass:AddItemTooltip(item, slot, dbMode)
|
||||
-- Item name
|
||||
local rarityCode = data.colorCodes[item.rarity]
|
||||
@@ -888,10 +922,10 @@ function ItemsTabClass:AddItemTooltip(item, slot, dbMode)
|
||||
if base.armour.blockChance and armourData.BlockChance > 0 then
|
||||
main:AddTooltipLine(16, s_format("^x7F7F7FChance to Block: %s%d%%", armourData.BlockChance ~= base.armour.blockChance and data.colorCodes.MAGIC or "^7", armourData.BlockChance))
|
||||
end
|
||||
for _, def in ipairs({{var="Armour",label="Armour"},{var="Evasion",label="Evasion Rating"},{var="EnergyShield",label="Energy Shield"}}) do
|
||||
local itemVal = armourData[def.var]
|
||||
for _, defence in ipairs({{var="Armour",label="Armour"},{var="Evasion",label="Evasion Rating"},{var="EnergyShield",label="Energy Shield"}}) do
|
||||
local itemVal = armourData[defence.var]
|
||||
if itemVal and itemVal > 0 then
|
||||
main:AddTooltipLine(16, s_format("^x7F7F7F%s: %s%d", def.label, itemVal ~= base.armour[def.var:sub(1,1):lower()..def.var:sub(2,-1).."Base"] and data.colorCodes.MAGIC or "^7", itemVal))
|
||||
main:AddTooltipLine(16, s_format("^x7F7F7F%s: %s%d", defence.label, itemVal ~= base.armour[defence.var:sub(1,1):lower()..defence.var:sub(2,-1).."Base"] and data.colorCodes.MAGIC or "^7", itemVal))
|
||||
end
|
||||
end
|
||||
elseif base.flask then
|
||||
@@ -978,7 +1012,7 @@ function ItemsTabClass:AddItemTooltip(item, slot, dbMode)
|
||||
end
|
||||
main:AddTooltipSeparator(14)
|
||||
|
||||
-- Mod differences
|
||||
-- Stat differences
|
||||
local calcFunc, calcBase = self.build.calcsTab:GetMiscCalculator()
|
||||
if calcFunc then
|
||||
if base.flask then
|
||||
@@ -1120,7 +1154,10 @@ end
|
||||
function ItemsTabClass:RestoreUndoState(state)
|
||||
self.useSecondWeaponSet = state.useSecondWeaponSet
|
||||
self.list = state.list
|
||||
self.orderList = state.orderList
|
||||
wipeTable(self.orderList)
|
||||
for k, v in pairs(state.orderList) do
|
||||
self.orderList[k] = v
|
||||
end
|
||||
for slotName, selItemId in pairs(state.slotSelItemId) do
|
||||
self.slots[slotName]:SetSelItemId(selItemId)
|
||||
end
|
||||
|
||||
331
Classes/ListControl.lua
Normal file
331
Classes/ListControl.lua
Normal file
@@ -0,0 +1,331 @@
|
||||
-- Path of Building
|
||||
--
|
||||
-- Class: List Control
|
||||
-- Basic list control.
|
||||
--
|
||||
-- This is an abstract base class; derived classes can supply these properties and methods to configure the list control:
|
||||
-- .label [Adds a label above the top left corner]
|
||||
-- .dragTargetList [List of controls that can receive drag events from this list control]
|
||||
-- .showRowSeparators [Shows separators between rows]
|
||||
-- :GetColumnOffset(column) [Called to get the offset of the given column]
|
||||
-- :GetRowValue(column, index, value) [Required; called to retrieve the text for the given column of the given list value]
|
||||
-- :AddValueTooltip(index, value) [Called to add the tooltip for the given list value]
|
||||
-- :GetDragValue(index, value) [Called to retrieve the drag type and object for the given list value]
|
||||
-- :CanReceiveDrag(type, value) [Called on drag target to determine if it can receive this value]
|
||||
-- :ReceiveDrag(type, value, source) [Called on the drag target when a drag completes]
|
||||
-- :OnDragSend(index, value, target) [Called after a drag event]
|
||||
-- :OnOrderChange() [Called after list order is changed through dragging]
|
||||
-- :OnSelect(index, value) [Called when a list value is selected]
|
||||
-- :OnSelClick(index, value, doubleClick) [Called when a list value is clicked]
|
||||
-- :OnSelCopy(index, value) [Called when Ctrl+C is pressed while a list value is selected]
|
||||
-- :OnSelDelete(index, value) [Called when backspace or delete is pressed while a list value is selected]
|
||||
-- :OnSelKeyDown(index, value) [Called when any other key is pressed while a list value is selected]
|
||||
--
|
||||
local launch, main = ...
|
||||
|
||||
local ipairs = ipairs
|
||||
local t_insert = table.insert
|
||||
local t_remove = table.remove
|
||||
local m_min = math.min
|
||||
local m_max = math.max
|
||||
local m_floor = math.floor
|
||||
|
||||
local ListClass = common.NewClass("ListControl", "Control", "ControlHost", function(self, anchor, x, y, width, height, rowHeight, isMutable, list)
|
||||
self.Control(anchor, x, y, width, height)
|
||||
self.ControlHost()
|
||||
self.rowHeight = rowHeight
|
||||
self.isMutable = isMutable
|
||||
self.list = list or { }
|
||||
self.controls.scrollBar = common.New("ScrollBarControl", {"RIGHT",self,"RIGHT"}, -1, 0, 16, 0, rowHeight * 2)
|
||||
self.controls.scrollBar.height = function()
|
||||
local width, height = self:GetSize()
|
||||
return height - 2
|
||||
end
|
||||
end)
|
||||
|
||||
function ListClass:SelectIndex(index)
|
||||
self.selValue = self.list[index]
|
||||
if self.selValue then
|
||||
self.selIndex = index
|
||||
local width, height = self:GetSize()
|
||||
self.controls.scrollBar:SetContentDimension(#self.list * self.rowHeight, height - 4)
|
||||
self.controls.scrollBar:ScrollIntoView((index - 2) * self.rowHeight, self.rowHeight * 3)
|
||||
if self.OnSelect then
|
||||
self:OnSelect(self.selIndex, self.selValue)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ListClass:GetColumnOffset(column)
|
||||
if column == 1 then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
function ListClass:IsMouseOver()
|
||||
if not self:IsShown() then
|
||||
return
|
||||
end
|
||||
return self:IsMouseInBounds() or self:GetMouseOverControl()
|
||||
end
|
||||
|
||||
function ListClass:Draw(viewPort)
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local rowHeight = self.rowHeight
|
||||
local list = self.list
|
||||
local scrollBar = self.controls.scrollBar
|
||||
scrollBar:SetContentDimension(#list * rowHeight, height - 4)
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if self.selValue and self.selDragging and not self.selDragActive and (cursorX-self.selCX)*(cursorX-self.selCX)+(cursorY-self.selCY)*(cursorY-self.selCY) > 100 then
|
||||
self.selDragActive = true
|
||||
if self.dragTargetList then
|
||||
self.dragType, self.dragValue = self:GetDragValue(self.selIndex, self.selValue)
|
||||
for _, target in ipairs(self.dragTargetList) do
|
||||
if not target.CanReceiveDrag or target:CanReceiveDrag(self.dragType, self.dragValue) then
|
||||
target.otherDragSource = self
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self.selDragIndex = nil
|
||||
if (self.selDragActive or self.otherDragSource) and self.isMutable then
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + scrollBar.offset) / rowHeight + 0.5) + 1
|
||||
if not self.selIndex or index < self.selIndex or index > self.selIndex + 1 then
|
||||
self.selDragIndex = m_min(index, #list + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.selDragActive and self.dragTargetList then
|
||||
self.dragTarget = nil
|
||||
for _, target in ipairs(self.dragTargetList) do
|
||||
if not self.dragTarget and target.otherDragSource == self and target:IsMouseOver() then
|
||||
self.dragTarget = target
|
||||
target.otherDragTargeting = true
|
||||
else
|
||||
target.otherDragTargeting = false
|
||||
end
|
||||
end
|
||||
end
|
||||
local label = self:GetProperty("label")
|
||||
if label then
|
||||
DrawString(x, y - 20, "LEFT", 16, "VAR", label)
|
||||
end
|
||||
if self.otherDragSource then
|
||||
SetDrawColor(0.2, 0.6, 0.2)
|
||||
elseif self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, x, y, width, height)
|
||||
if self.otherDragSource then
|
||||
SetDrawColor(0, 0.05, 0)
|
||||
else
|
||||
SetDrawColor(0, 0, 0)
|
||||
end
|
||||
DrawImage(nil, x + 1, y + 1, width - 2, height - 2)
|
||||
self:DrawControls(viewPort)
|
||||
SetViewport(x + 2, y + 2, width - 20, height - 4)
|
||||
local textOffsetY = self.showRowSeparators and 2 or 0
|
||||
local textHeight = rowHeight - textOffsetY * 2
|
||||
local ttIndex, ttValue, ttX, ttY, ttWidth
|
||||
local minIndex = m_floor(scrollBar.offset / rowHeight + 1)
|
||||
local maxIndex = m_min(m_floor((scrollBar.offset + height) / rowHeight + 1), #list)
|
||||
local column = 1
|
||||
local elipWidth = DrawStringWidth(textHeight, "VAR", "...")
|
||||
while true do
|
||||
local colOffset = self:GetColumnOffset(column)
|
||||
if not colOffset then
|
||||
break
|
||||
end
|
||||
local colWidth = (self:GetColumnOffset(column + 1) or width - 20) - colOffset
|
||||
for index = minIndex, maxIndex do
|
||||
local lineY = rowHeight * (index - 1) - scrollBar.offset
|
||||
local value = list[index]
|
||||
local text = self:GetRowValue(column, index, value)
|
||||
local textWidth = DrawStringWidth(textHeight, "VAR", text)
|
||||
if textWidth > colWidth - 2 then
|
||||
local clipIndex = DrawStringCursorIndex(textHeight, "VAR", text, colWidth - elipWidth - 2, 0)
|
||||
text = text:sub(1, clipIndex - 1) .. "..."
|
||||
textWidth = DrawStringWidth(textHeight, "VAR", text)
|
||||
end
|
||||
if not scrollBar.dragging and not self.selDragActive then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
local relX = cursorX - (x + 2)
|
||||
local relY = cursorY - (y + 2)
|
||||
if relX >= colOffset and relX < width - 20 and relY >= 0 and relY >= lineY and relY < height - 2 and relY < lineY + rowHeight then
|
||||
ttIndex = index
|
||||
ttValue = value
|
||||
ttX = x + 2 + colOffset
|
||||
ttY = lineY + y + 2
|
||||
ttWidth = m_max(textWidth + 8, relX - colOffset)
|
||||
end
|
||||
end
|
||||
if self.showRowSeparators then
|
||||
if self.hasFocus and value == self.selValue then
|
||||
SetDrawColor(1, 1, 1)
|
||||
elseif value == ttValue then
|
||||
SetDrawColor(0.8, 0.8, 0.8)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, colOffset, lineY, colWidth, rowHeight)
|
||||
if (value == self.selValue or value == ttValue) then
|
||||
SetDrawColor(0.33, 0.33, 0.33)
|
||||
elseif index % 2 == 0 then
|
||||
SetDrawColor(0.05, 0.05, 0.05)
|
||||
else
|
||||
SetDrawColor(0, 0, 0)
|
||||
end
|
||||
DrawImage(nil, colOffset, lineY + 1, colWidth, rowHeight - 2)
|
||||
elseif value == self.selValue or value == ttValue then
|
||||
if self.hasFocus and value == self.selValue then
|
||||
SetDrawColor(1, 1, 1)
|
||||
elseif value == ttValue then
|
||||
SetDrawColor(0.8, 0.8, 0.8)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, colOffset, lineY, colWidth, rowHeight)
|
||||
SetDrawColor(0.15, 0.15, 0.15)
|
||||
DrawImage(nil, colOffset, lineY + 1, colWidth, rowHeight - 2)
|
||||
end
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawString(colOffset, lineY + textOffsetY, "LEFT", textHeight, "VAR", text)
|
||||
end
|
||||
column = column + 1
|
||||
end
|
||||
if self.selDragIndex then
|
||||
local lineY = rowHeight * (self.selDragIndex - 1) - scrollBar.offset
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawImage(nil, 0, lineY - 1, width - 20, 3)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, 0, lineY, width - 20, 1)
|
||||
end
|
||||
SetViewport()
|
||||
if self.selDragActive and self.dragTargetList and (not self.isMutable or not self:IsMouseOver()) then
|
||||
local text = self:GetRowValue(1, self.selIndex, self.selValue)
|
||||
local strWidth = DrawStringWidth(16, "VAR", text)
|
||||
SetDrawLayer(nil, 90)
|
||||
SetDrawColor(0.15, 0.15, 0.15, 0.75)
|
||||
DrawImage(nil, cursorX, cursorY - 8, strWidth + 2, 18)
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawString(cursorX + 1, cursorY - 7, "LEFT", 16, "VAR", text)
|
||||
SetDrawLayer(nil, 0)
|
||||
end
|
||||
if ttIndex and self.AddValueTooltip then
|
||||
local col, center = self:AddValueTooltip(ttIndex, ttValue)
|
||||
SetDrawLayer(nil, 100)
|
||||
main:DrawTooltip(ttX, ttY, ttWidth, rowHeight, viewPort, col, center)
|
||||
SetDrawLayer(nil, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function ListClass:OnKeyDown(key, doubleClick)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
local mOverControl = self:GetMouseOverControl()
|
||||
if mOverControl and mOverControl.OnKeyDown then
|
||||
return mOverControl:OnKeyDown(key)
|
||||
end
|
||||
if not self:IsMouseOver() and key:match("BUTTON") then
|
||||
return
|
||||
end
|
||||
if key == "LEFTBUTTON" then
|
||||
self.selValue = nil
|
||||
self.selIndex = nil
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + self.controls.scrollBar.offset) / self.rowHeight) + 1
|
||||
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
|
||||
end
|
||||
end
|
||||
elseif #self.list > 0 then
|
||||
if key == "UP" then
|
||||
self:SelectIndex(((self.selIndex or 1) - 2) % #self.list + 1)
|
||||
elseif key == "DOWN" then
|
||||
self:SelectIndex((self.selIndex or #self.list) % #self.list + 1)
|
||||
elseif key == "HOME" then
|
||||
self:SelectIndex(1)
|
||||
elseif key == "END" then
|
||||
self:SelectIndex(#self.list)
|
||||
elseif self.selValue then
|
||||
if key == "c" and IsKeyDown("CTRL") then
|
||||
if self.OnSelCopy then
|
||||
self:OnSelCopy(self.selIndex, self.selValue)
|
||||
end
|
||||
elseif key == "BACK" or key == "DELETE" then
|
||||
if self.OnSelDelete then
|
||||
self:OnSelDelete(self.selIndex, self.selValue)
|
||||
end
|
||||
elseif self.OnSelKeyDown then
|
||||
self:OnSelKeyDown(self.selIndex, self.selValue, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function ListClass:OnKeyUp(key)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
if key == "WHEELDOWN" then
|
||||
self.controls.scrollBar:Scroll(1)
|
||||
elseif key == "WHEELUP" then
|
||||
self.controls.scrollBar:Scroll(-1)
|
||||
elseif self.selValue then
|
||||
if key == "LEFTBUTTON" then
|
||||
self.selDragging = false
|
||||
if self.selDragActive then
|
||||
self.selDragActive = false
|
||||
if self.selDragIndex and self.selDragIndex ~= self.selIndex then
|
||||
t_remove(self.list, self.selIndex)
|
||||
if self.selDragIndex > self.selIndex then
|
||||
self.selDragIndex = self.selDragIndex - 1
|
||||
end
|
||||
t_insert(self.list, self.selDragIndex, self.selValue)
|
||||
if self.OnOrderChange then
|
||||
self:OnOrderChange()
|
||||
end
|
||||
self.selValue = nil
|
||||
elseif self.dragTarget then
|
||||
self.dragTarget:ReceiveDrag(self.dragType, self.dragValue, self)
|
||||
if self.OnDragSend then
|
||||
self:OnDragSend(self.selIndex, self.selValue, self.dragTarget)
|
||||
end
|
||||
self.selValue = nil
|
||||
end
|
||||
if self.dragTargetList then
|
||||
for _, target in ipairs(self.dragTargetList) do
|
||||
target.otherDragSource = nil
|
||||
target.otherDragTargeting = false
|
||||
end
|
||||
end
|
||||
self.dragType = nil
|
||||
self.dragValue = nil
|
||||
self.dragTarget = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -5,247 +5,91 @@
|
||||
--
|
||||
local launch, main = ...
|
||||
|
||||
local ipairs = ipairs
|
||||
local t_insert = table.insert
|
||||
local t_remove = table.remove
|
||||
local m_min = math.min
|
||||
local m_max = math.max
|
||||
local m_floor = math.floor
|
||||
local s_format = string.format
|
||||
|
||||
local MinionListClass = common.NewClass("MinionList", "Control", "ControlHost", function(self, anchor, x, y, width, height, list, mutable, dest)
|
||||
self.Control(anchor, x, y, width, height)
|
||||
self.ControlHost()
|
||||
self.list = list
|
||||
self.mutable = mutable
|
||||
local MinionListClass = common.NewClass("MinionList", "ListControl", function(self, anchor, x, y, width, height, list, dest)
|
||||
self.ListControl(anchor, x, y, width, height, 16, not dest, list)
|
||||
self.dest = dest
|
||||
self.controls.scrollBar = common.New("ScrollBarControl", {"RIGHT",self,"RIGHT"}, -1, 0, 16, 0, 32)
|
||||
self.controls.scrollBar.height = function()
|
||||
local width, height = self:GetSize()
|
||||
return height - 2
|
||||
end
|
||||
if mutable then
|
||||
self.controls.delete = common.New("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, 0, -2, 60, 18, "Remove", function()
|
||||
self:DeleteSel()
|
||||
end)
|
||||
self.controls.delete.enabled = function()
|
||||
return self.selValue ~= nil
|
||||
end
|
||||
else
|
||||
if dest then
|
||||
self.dragTargetList = { dest }
|
||||
self.label = "^7Available Spectres:"
|
||||
self.controls.add = common.New("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, 0, -2, 60, 18, "Add", function()
|
||||
self:AddSel()
|
||||
end)
|
||||
self.controls.add.enabled = function()
|
||||
return self.selValue ~= nil and not isValueInArray(dest.list, self.selValue)
|
||||
end
|
||||
else
|
||||
self.label = "^7Spectres in Build:"
|
||||
self.controls.delete = common.New("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, 0, -2, 60, 18, "Remove", function()
|
||||
self:OnSelDelete(self.selIndex, self.selValue)
|
||||
end)
|
||||
self.controls.delete.enabled = function()
|
||||
return self.selValue ~= nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function MinionListClass:SelectIndex(index)
|
||||
self.selValue = self.list[index]
|
||||
if self.selValue then
|
||||
self.selIndex = index
|
||||
self.controls.scrollBar:ScrollIntoView((index - 2) * 16, 48)
|
||||
end
|
||||
end
|
||||
|
||||
function MinionListClass:AddSel()
|
||||
if self.selValue and self.dest and not isValueInArray(self.dest.list, self.selValue) then
|
||||
if self.dest and not isValueInArray(self.dest.list, self.selValue) then
|
||||
t_insert(self.dest.list, self.selValue)
|
||||
end
|
||||
end
|
||||
|
||||
function MinionListClass:DeleteSel()
|
||||
if self.selIndex and self.mutable then
|
||||
t_remove(self.list, self.selIndex)
|
||||
function MinionListClass:GetRowValue(column, index, minionId)
|
||||
local minion = data.minions[minionId]
|
||||
if column == 1 then
|
||||
return minion.name
|
||||
end
|
||||
end
|
||||
|
||||
function MinionListClass:AddValueTooltip(index, minionId)
|
||||
local minion = data.minions[minionId]
|
||||
main:AddTooltipLine(18, "^7"..minion.name)
|
||||
main:AddTooltipLine(14, s_format("^7Life multiplier: x%.2f", minion.life))
|
||||
if minion.energyShield then
|
||||
main:AddTooltipLine(14, s_format("^7Energy Shield: %d%% of base Life", minion.energyShield * 100))
|
||||
end
|
||||
main:AddTooltipLine(14, s_format("^7Resistances: %s%d^7/%s%d^7/%s%d^7/%s%d",
|
||||
data.colorCodes.FIRE, minion.fireResist,
|
||||
data.colorCodes.COLD, minion.coldResist,
|
||||
data.colorCodes.LIGHTNING, minion.lightningResist,
|
||||
data.colorCodes.CHAOS, minion.chaosResist
|
||||
))
|
||||
main:AddTooltipLine(14, s_format("^7Base damage: x%.2f", minion.damage))
|
||||
main:AddTooltipLine(14, s_format("^7Base attack speed: %.2f", 1 / minion.attackTime))
|
||||
for _, skillId in ipairs(minion.skillList) do
|
||||
if data.skills[skillId] then
|
||||
main:AddTooltipLine(14, "^7Skill: "..data.skills[skillId].name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MinionListClass:GetDragValue(index, value)
|
||||
return "MinionId", value
|
||||
end
|
||||
|
||||
function MinionListClass:CanReceiveDrag(type, value)
|
||||
return type == "MinionId" and not isValueInArray(self.list, value)
|
||||
end
|
||||
|
||||
function MinionListClass:ReceiveDrag(type, value, source)
|
||||
t_insert(self.list, self.selDragIndex or #self.list + 1, value)
|
||||
end
|
||||
|
||||
function MinionListClass:OnSelClick(index, minionId, doubleClick)
|
||||
if doubleClick and self.dest then
|
||||
self:AddSel()
|
||||
end
|
||||
end
|
||||
|
||||
function MinionListClass:OnSelDelete(index, minionId)
|
||||
if not self.dest then
|
||||
t_remove(self.list, index)
|
||||
self.selIndex = nil
|
||||
self.selValue = nil
|
||||
end
|
||||
end
|
||||
|
||||
function MinionListClass:IsMouseOver()
|
||||
if not self:IsShown() then
|
||||
return
|
||||
end
|
||||
return self:IsMouseInBounds() or self:GetMouseOverControl()
|
||||
end
|
||||
|
||||
function MinionListClass:Draw(viewPort)
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local list = self.list
|
||||
local scrollBar = self.controls.scrollBar
|
||||
scrollBar:SetContentDimension(#list * 16, height - 4)
|
||||
self.selDragIndex = nil
|
||||
if (self.selValue and self.selDragging) or self.otherDragActive then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if not self.selDragActive and not self.otherDragActive and (cursorX-self.selCX)*(cursorX-self.selCX)+(cursorY-self.selCY)*(cursorY-self.selCY) > 100 then
|
||||
self.selDragActive = true
|
||||
end
|
||||
if (self.selDragActive or self.otherDragActive) and self.mutable then
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + scrollBar.offset) / 16 + 0.5) + 1
|
||||
if not self.selIndex or index < self.selIndex or index > self.selIndex + 1 then
|
||||
self.selDragIndex = m_min(index, #list + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.dest then
|
||||
self.dest.otherDragActive = self.dest:IsMouseOver()
|
||||
end
|
||||
end
|
||||
DrawString(x, y - 20, "LEFT", 16, "VAR", self.mutable and "^7Spectres in Build:" or "^7Available Spectres:")
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, x, y, width, height)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, x + 1, y + 1, width - 2, height - 2)
|
||||
self:DrawControls(viewPort)
|
||||
SetViewport(x + 2, y + 2, width - 20, height - 4)
|
||||
local ttValue, ttY, ttWidth
|
||||
local minIndex = m_floor(scrollBar.offset / 16 + 1)
|
||||
local maxIndex = m_min(m_floor((scrollBar.offset + height) / 16 + 1), #list)
|
||||
for index = minIndex, maxIndex do
|
||||
local value = list[index]
|
||||
local minion = data.minions[value]
|
||||
local lineY = 16 * (index - 1) - scrollBar.offset
|
||||
local label = minion.name
|
||||
local nameWidth = DrawStringWidth(16, "VAR", label)
|
||||
if not scrollBar.dragging and not self.selDragActive then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
local relX = cursorX - (x + 2)
|
||||
local relY = cursorY - (y + 2)
|
||||
if relX >= 0 and relX < width - 17 and relY >= 0 and relY >= lineY and relY < height - 2 and relY < lineY + 16 then
|
||||
ttValue = value
|
||||
ttWidth = m_max(nameWidth + 8, relX)
|
||||
ttY = lineY + y + 2
|
||||
end
|
||||
end
|
||||
if value == ttValue or value == self.selValue then
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, 0, lineY, width - 20, 16)
|
||||
SetDrawColor(0.15, 0.15, 0.15)
|
||||
DrawImage(nil, 0, lineY + 1, width - 20, 14)
|
||||
end
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawString(0, lineY, "LEFT", 16, "VAR", label)
|
||||
end
|
||||
if self.selDragIndex then
|
||||
local lineY = 16 * (self.selDragIndex - 1) - scrollBar.offset
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawImage(nil, 0, lineY - 1, width - 20, 3)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, 0, lineY, width - 20, 1)
|
||||
end
|
||||
SetViewport()
|
||||
if ttValue then
|
||||
local minion = data.minions[ttValue]
|
||||
main:AddTooltipLine(18, "^7"..minion.name)
|
||||
main:AddTooltipLine(14, s_format("^7Life multiplier: x%.2f", minion.life))
|
||||
if minion.energyShield then
|
||||
main:AddTooltipLine(14, s_format("^7Energy Shield: %d%% of base Life", minion.energyShield * 100))
|
||||
end
|
||||
main:AddTooltipLine(14, s_format("^7Resistances: %s%d^7/%s%d^7/%s%d^7/%s%d",
|
||||
data.colorCodes.FIRE, minion.fireResist, data.colorCodes.COLD, minion.coldResist,
|
||||
data.colorCodes.LIGHTNING, minion.lightningResist, data.colorCodes.CHAOS, minion.chaosResist))
|
||||
main:AddTooltipLine(14, s_format("^7Base damage: x%.2f", minion.damage))
|
||||
main:AddTooltipLine(14, s_format("^7Base attack speed: %.2f", 1 / minion.attackTime))
|
||||
for _, skillId in ipairs(minion.skillList) do
|
||||
if data.skills[skillId] then
|
||||
main:AddTooltipLine(14, "^7Skill: "..data.skills[skillId].name)
|
||||
end
|
||||
end
|
||||
SetDrawLayer(nil, 100)
|
||||
main:DrawTooltip(x + 2, ttY, ttWidth, 16, viewPort)
|
||||
SetDrawLayer(nil, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function MinionListClass:OnKeyDown(key, doubleClick)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
local mOverControl = self:GetMouseOverControl()
|
||||
if mOverControl and mOverControl.OnKeyDown then
|
||||
return mOverControl:OnKeyDown(key)
|
||||
end
|
||||
if not self:IsMouseOver() and key:match("BUTTON") then
|
||||
return
|
||||
end
|
||||
if key == "LEFTBUTTON" then
|
||||
self.selValue = nil
|
||||
self.selIndex = nil
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + self.controls.scrollBar.offset) / 16) + 1
|
||||
local selValue = self.list[index]
|
||||
if selValue then
|
||||
self.selValue = selValue
|
||||
self.selIndex = index
|
||||
if doubleClick then
|
||||
self:AddSel()
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.selValue then
|
||||
self.selCX = cursorX
|
||||
self.selCY = cursorY
|
||||
self.selDragging = true
|
||||
self.selDragActive = false
|
||||
end
|
||||
elseif #self.list > 0 then
|
||||
if key == "UP" then
|
||||
self:SelectIndex(((self.selIndex or 1) - 2) % #self.list + 1)
|
||||
elseif key == "DOWN" then
|
||||
self:SelectIndex((self.selIndex or #self.list) % #self.list + 1)
|
||||
elseif key == "HOME" then
|
||||
self:SelectIndex(1)
|
||||
elseif key == "END" then
|
||||
self:SelectIndex(#list)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function MinionListClass:OnKeyUp(key)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
if key == "WHEELDOWN" then
|
||||
self.controls.scrollBar:Scroll(1)
|
||||
elseif key == "WHEELUP" then
|
||||
self.controls.scrollBar:Scroll(-1)
|
||||
elseif self.selValue then
|
||||
if key == "BACK" or key == "DELETE" then
|
||||
self:DeleteSel()
|
||||
elseif key == "LEFTBUTTON" then
|
||||
self.selDragging = false
|
||||
if self.selDragActive then
|
||||
self.selDragActive = false
|
||||
if self.selDragIndex and self.selDragIndex ~= self.selIndex then
|
||||
t_remove(self.list, self.selIndex)
|
||||
if self.selDragIndex > self.selIndex then
|
||||
self.selDragIndex = self.selDragIndex - 1
|
||||
end
|
||||
t_insert(self.list, self.selDragIndex, self.selValue)
|
||||
self.selValue = nil
|
||||
elseif self.dest and self.dest.otherDragActive then
|
||||
if self.dest.selDragIndex and not isValueInArray(self.dest.list, self.selValue) then
|
||||
t_insert(self.dest.list, self.dest.selDragIndex, self.selValue)
|
||||
end
|
||||
self.dest.otherDragActive = false
|
||||
self.selValue = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -97,7 +97,7 @@ function ModDBClass:Sum(modType, cfg, ...)
|
||||
source = cfg.source
|
||||
tabulate = cfg.tabulate
|
||||
if tabulate then
|
||||
cfg = copyTable(cfg)
|
||||
cfg = copyTable(cfg, true)
|
||||
cfg.tabulate = false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -73,7 +73,7 @@ function ModListClass:Sum(modType, cfg, ...)
|
||||
source = cfg.source
|
||||
tabulate = cfg.tabulate
|
||||
if tabulate then
|
||||
cfg = copyTable(cfg)
|
||||
cfg = copyTable(cfg, true)
|
||||
cfg.tabulate = false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,244 +7,98 @@ local launch, main = ...
|
||||
|
||||
local t_insert = table.insert
|
||||
local t_remove = table.remove
|
||||
local m_min = math.min
|
||||
local m_max = math.max
|
||||
local m_floor = math.floor
|
||||
|
||||
local PassiveSpecListClass = common.NewClass("PassiveSpecList", "Control", "ControlHost", function(self, anchor, x, y, width, height, treeTab)
|
||||
self.Control(anchor, x, y, width, height)
|
||||
self.ControlHost()
|
||||
local PassiveSpecListClass = common.NewClass("PassiveSpecList", "ListControl", function(self, anchor, x, y, width, height, treeTab)
|
||||
self.ListControl(anchor, x, y, width, height, 16, true, treeTab.specList)
|
||||
self.treeTab = treeTab
|
||||
self.controls.scrollBar = common.New("ScrollBarControl", {"RIGHT",self,"RIGHT"}, -1, 0, 16, 0, 32)
|
||||
self.controls.scrollBar.height = function()
|
||||
local width, height = self:GetSize()
|
||||
return height - 2
|
||||
end
|
||||
self.controls.copy = common.New("ButtonControl", {"BOTTOMLEFT",self,"TOP"}, 2, -4, 60, 18, "Copy", function()
|
||||
local prevSel = self.selSpec
|
||||
self.selSpec = common.New("PassiveSpec", treeTab.build)
|
||||
self.selSpec.title = prevSel.title
|
||||
self.selSpec.jewels = copyTable(prevSel.jewels)
|
||||
self.selSpec:DecodeURL(prevSel:EncodeURL())
|
||||
self:RenameSel(true)
|
||||
local newSpec = common.New("PassiveSpec", treeTab.build)
|
||||
newSpec.title = self.selValue.title
|
||||
newSpec.jewels = copyTable(self.selValue.jewels)
|
||||
newSpec:DecodeURL(self.selValue:EncodeURL())
|
||||
self:RenameSpec(newSpec, true)
|
||||
end)
|
||||
self.controls.copy.enabled = function()
|
||||
return self.selSpec ~= nil
|
||||
return self.selValue ~= nil
|
||||
end
|
||||
self.controls.delete = common.New("ButtonControl", {"LEFT",self.controls.copy,"RIGHT"}, 4, 0, 60, 18, "Delete", function()
|
||||
self:OnKeyUp("DELETE")
|
||||
self:OnSelDelete(self.selIndex, self.selValue)
|
||||
end)
|
||||
self.controls.delete.enabled = function()
|
||||
return self.selSpec ~= nil and #treeTab.specList > 1
|
||||
return self.selValue ~= nil and #self.list > 1
|
||||
end
|
||||
self.controls.rename = common.New("ButtonControl", {"BOTTOMRIGHT",self,"TOP"}, -2, -4, 60, 18, "Rename", function()
|
||||
self:RenameSel()
|
||||
self:RenameSpec(self.selValue)
|
||||
end)
|
||||
self.controls.rename.enabled = function()
|
||||
return self.selSpec ~= nil
|
||||
return self.selValue ~= nil
|
||||
end
|
||||
self.controls.new = common.New("ButtonControl", {"RIGHT",self.controls.rename,"LEFT"}, -4, 0, 60, 18, "New", function()
|
||||
self.selSpec = common.New("PassiveSpec", treeTab.build)
|
||||
self:RenameSel(true)
|
||||
local newSpec = common.New("PassiveSpec", treeTab.build)
|
||||
self:RenameSpec(newSpec, true)
|
||||
end)
|
||||
end)
|
||||
|
||||
function PassiveSpecListClass:SelectIndex(index)
|
||||
self.selSpec = self.treeTab.specList[index]
|
||||
if self.selSpec then
|
||||
self.selSpec = index
|
||||
self.controls.scrollBar:ScrollIntoView((index - 2) * 16, 48)
|
||||
end
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:RenameSel(addOnName)
|
||||
local popup
|
||||
popup = main:OpenPopup(370, 100, self.selSpec.title and "Rename" or "Set Name", {
|
||||
common.New("LabelControl", nil, 0, 20, 0, 16, "^7Enter name for this passive tree:"),
|
||||
edit = common.New("EditControl", nil, 0, 40, 350, 20, self.selSpec.title, nil, nil, 100, function(buf)
|
||||
popup.controls.save.enabled = buf:match("%S")
|
||||
end),
|
||||
save = common.New("ButtonControl", nil, -45, 70, 80, 20, "Save", function()
|
||||
self.selSpec.title = popup.controls.edit.buf
|
||||
self.treeTab.modFlag = true
|
||||
if addOnName then
|
||||
t_insert(self.treeTab.specList, self.selSpec)
|
||||
self.selIndex = #self.treeTab.specList
|
||||
end
|
||||
main:ClosePopup()
|
||||
end),
|
||||
cancel = common.New("ButtonControl", nil, 45, 70, 80, 20, "Cancel", function()
|
||||
if addOnName then
|
||||
self.selSpec = nil
|
||||
end
|
||||
main:ClosePopup()
|
||||
end),
|
||||
}, "save", "edit", "cancel")
|
||||
popup.controls.save.enabled = false
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:IsMouseOver()
|
||||
if not self:IsShown() then
|
||||
return
|
||||
end
|
||||
return self:IsMouseInBounds() or self:GetMouseOverControl()
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:Draw(viewPort)
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local list = self.treeTab.specList
|
||||
local scrollBar = self.controls.scrollBar
|
||||
scrollBar:SetContentDimension(#list * 16, height - 4)
|
||||
self.selDragIndex = nil
|
||||
if self.selSpec and self.selDragging then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if not self.selDragActive and (cursorX-self.selCX)*(cursorX-self.selCX)+(cursorY-self.selCY)*(cursorY-self.selCY) > 100 then
|
||||
self.selDragActive = true
|
||||
function PassiveSpecListClass:RenameSpec(spec, addOnName)
|
||||
local controls = { }
|
||||
controls.label = common.New("LabelControl", nil, 0, 20, 0, 16, "^7Enter name for this passive tree:")
|
||||
controls.edit = common.New("EditControl", nil, 0, 40, 350, 20, spec.title, nil, nil, 100, function(buf)
|
||||
controls.save.enabled = buf:match("%S")
|
||||
end)
|
||||
controls.save = common.New("ButtonControl", nil, -45, 70, 80, 20, "Save", function()
|
||||
spec.title = controls.edit.buf
|
||||
self.treeTab.modFlag = true
|
||||
if addOnName then
|
||||
t_insert(self.list, spec)
|
||||
self.selIndex = #self.list
|
||||
self.selValue = spec
|
||||
end
|
||||
if self.selDragActive then
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + scrollBar.offset) / 16 + 0.5) + 1
|
||||
if index < self.selIndex or index > self.selIndex + 1 then
|
||||
self.selDragIndex = m_min(index, #list + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, x, y, width, height)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, x + 1, y + 1, width - 2, height - 2)
|
||||
self:DrawControls(viewPort)
|
||||
SetViewport(x + 2, y + 2, width - 20, height - 4)
|
||||
local ttSpec, ttY, ttWidth
|
||||
local minIndex = m_floor(scrollBar.offset / 16 + 1)
|
||||
local maxIndex = m_min(m_floor((scrollBar.offset + height) / 16 + 1), #list)
|
||||
for index = minIndex, maxIndex do
|
||||
local spec = list[index]
|
||||
local lineY = 16 * (index - 1) - scrollBar.offset
|
||||
main:ClosePopup()
|
||||
end)
|
||||
controls.save.enabled = false
|
||||
controls.cancel = common.New("ButtonControl", nil, 45, 70, 80, 20, "Cancel", function()
|
||||
main:ClosePopup()
|
||||
end)
|
||||
main:OpenPopup(370, 100, spec.title and "Rename" or "Set Name", controls, "save", "edit")
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:GetRowValue(column, index, spec)
|
||||
if column == 1 then
|
||||
local used = spec:CountAllocNodes()
|
||||
local label = (spec.title or "Default") .. " (" .. (spec.curAscendClassName ~= "None" and spec.curAscendClassName or spec.curClassName) .. ", " .. used .. " points)"
|
||||
local nameWidth = DrawStringWidth(16, "VAR", label)
|
||||
if not scrollBar.dragging and not self.selDragActive then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
local relX = cursorX - (x + 2)
|
||||
local relY = cursorY - (y + 2)
|
||||
if relX >= 0 and relX < width - 17 and relY >= 0 and relY >= lineY and relY < height - 2 and relY < lineY + 16 then
|
||||
ttSpec = spec
|
||||
ttWidth = m_max(nameWidth + 8, relX)
|
||||
ttY = lineY + y + 2
|
||||
end
|
||||
end
|
||||
if spec == ttSpec or spec == self.selSpec then
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
return (spec.title or "Default") .. " (" .. (spec.curAscendClassName ~= "None" and spec.curAscendClassName or spec.curClassName) .. ", " .. used .. " points)" .. (index == self.treeTab.activeSpec and " ^9(Current)" or "")
|
||||
end
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:OnOrderChange()
|
||||
self.treeTab.activeSpec = isValueInArray(self.list, self.treeTab.build.spec)
|
||||
self.treeTab.modFlag = true
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:OnSelClick(index, spec, doubleClick)
|
||||
if doubleClick and index ~= self.treeTab.activeSpec then
|
||||
self.treeTab:SetActiveSpec(index)
|
||||
end
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:OnSelDelete(index, spec)
|
||||
if #self.list > 1 then
|
||||
main:OpenConfirmPopup("Delete Spec", "Are you sure you want to delete '"..(spec.title or "Default").."'?", "Delete", function()
|
||||
t_remove(self.list, index)
|
||||
self.selIndex = nil
|
||||
self.selValue = nil
|
||||
if index == self.treeTab.activeSpec then
|
||||
self.treeTab:SetActiveSpec(m_max(1, index - 1))
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
self.treeTab.activeSpec = isValueInArray(self.list, self.treeTab.build.spec)
|
||||
end
|
||||
DrawImage(nil, 0, lineY, width - 20, 16)
|
||||
SetDrawColor(0.15, 0.15, 0.15)
|
||||
DrawImage(nil, 0, lineY + 1, width - 20, 14)
|
||||
end
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawString(0, lineY, "LEFT", 16, "VAR", label)
|
||||
self.treeTab.modFlag = true
|
||||
end)
|
||||
end
|
||||
if self.selDragIndex then
|
||||
local lineY = 16 * (self.selDragIndex - 1) - scrollBar.offset
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawImage(nil, 0, lineY - 1, width - 20, 3)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, 0, lineY, width - 20, 1)
|
||||
end
|
||||
SetViewport()
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:OnKeyDown(key, doubleClick)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
function PassiveSpecListClass:OnSelKeyDown(index, spec, key)
|
||||
if key == "F2" then
|
||||
self:RenameSpec(spec)
|
||||
end
|
||||
local mOverControl = self:GetMouseOverControl()
|
||||
if mOverControl and mOverControl.OnKeyDown then
|
||||
return mOverControl:OnKeyDown(key)
|
||||
end
|
||||
if not self:IsMouseOver() and key:match("BUTTON") then
|
||||
return
|
||||
end
|
||||
if key == "LEFTBUTTON" then
|
||||
self.selSpec = nil
|
||||
self.selIndex = nil
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + self.controls.scrollBar.offset) / 16) + 1
|
||||
local selSpec = self.treeTab.specList[index]
|
||||
if selSpec then
|
||||
self.selSpec = selSpec
|
||||
self.selIndex = index
|
||||
end
|
||||
end
|
||||
if self.selSpec then
|
||||
self.selCX = cursorX
|
||||
self.selCY = cursorY
|
||||
self.selDragging = true
|
||||
self.selDragActive = false
|
||||
end
|
||||
elseif #self.treeTab.specList > 0 then
|
||||
if key == "UP" then
|
||||
self:SelectIndex(((self.selIndex or 1) - 2) % #self.treeTab.specList + 1)
|
||||
elseif key == "DOWN" then
|
||||
self:SelectIndex((self.selIndex or #self.treeTab.specList) % #self.treeTab.specList + 1)
|
||||
elseif key == "HOME" then
|
||||
self:SelectIndex(1)
|
||||
elseif key == "END" then
|
||||
self:SelectIndex(#self.treeTab.specList)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function PassiveSpecListClass:OnKeyUp(key)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
if key == "WHEELDOWN" then
|
||||
self.controls.scrollBar:Scroll(1)
|
||||
elseif key == "WHEELUP" then
|
||||
self.controls.scrollBar:Scroll(-1)
|
||||
elseif self.selSpec then
|
||||
if key == "BACK" or key == "DELETE" then
|
||||
if #self.treeTab.specList > 1 then
|
||||
main:OpenConfirmPopup("Delete Spec", "Are you sure you want to delete '"..(self.selSpec.title or "Default").."'?", "Delete", function()
|
||||
t_remove(self.treeTab.specList, self.selIndex)
|
||||
self.selSpec = nil
|
||||
if self.selIndex == self.treeTab.activeSpec then
|
||||
self.treeTab:SetActiveSpec(m_max(1, self.selIndex - 1))
|
||||
end
|
||||
end)
|
||||
end
|
||||
elseif key == "F2" then
|
||||
self:RenameSel()
|
||||
elseif key == "LEFTBUTTON" then
|
||||
self.selDragging = false
|
||||
if self.selDragActive then
|
||||
self.selDragActive = false
|
||||
if self.selDragIndex and self.selDragIndex ~= self.selIndex then
|
||||
local activeSpec = self.treeTab.specList[self.treeTab.activeSpec]
|
||||
t_remove(self.treeTab.specList, self.selIndex)
|
||||
if self.selDragIndex > self.selIndex then
|
||||
self.selDragIndex = self.selDragIndex - 1
|
||||
end
|
||||
t_insert(self.treeTab.specList, self.selDragIndex, self.selSpec)
|
||||
self.selSpec = nil
|
||||
self.treeTab.activeSpec = isValueInArray(self.treeTab.specList, activeSpec)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -372,10 +372,10 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
|
||||
if self.showHeatMap then
|
||||
if not node.alloc and node.type ~= "classStart" and node.type ~= "ascendClassStart" then
|
||||
-- Calculate color based on DPS and defensive powers
|
||||
local dps = m_max(node.power.dps or 0, 0)
|
||||
local def = m_max(node.power.def or 0, 0)
|
||||
local dpsCol = (dps / build.calcsTab.powerMax.dps * 1.5) ^ 0.5
|
||||
local defCol = (def / build.calcsTab.powerMax.def * 1.5) ^ 0.5
|
||||
local offence = m_max(node.power.offence or 0, 0)
|
||||
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)
|
||||
else
|
||||
SetDrawColor(1, 1, 1)
|
||||
@@ -554,9 +554,9 @@ function PassiveTreeViewClass:AddNodeTooltip(node, build)
|
||||
|
||||
-- Node name
|
||||
self:AddNodeName(node)
|
||||
if launch.devMode and IsKeyDown("ALT") and node.power and node.power.dps then
|
||||
if launch.devMode and IsKeyDown("ALT") and node.power and node.power.offence then
|
||||
-- Power debugging info
|
||||
main:AddTooltipLine(16, string.format("DPS power: %g Defence power: %g", node.power.dps, node.power.def))
|
||||
main:AddTooltipLine(16, string.format("DPS power: %g Defence power: %g", node.power.offence, node.power.defence))
|
||||
end
|
||||
|
||||
-- Node description
|
||||
|
||||
@@ -5,41 +5,38 @@
|
||||
--
|
||||
local launch, main = ...
|
||||
|
||||
local ipairs = ipairs
|
||||
local t_insert = table.insert
|
||||
local t_remove = table.remove
|
||||
local m_min = math.min
|
||||
local m_max = math.max
|
||||
local m_floor = math.floor
|
||||
|
||||
local SkillListClass = common.NewClass("SkillList", "Control", "ControlHost", function(self, anchor, x, y, width, height, skillsTab)
|
||||
self.Control(anchor, x, y, width, height)
|
||||
self.ControlHost()
|
||||
local SkillListClass = common.NewClass("SkillList", "ListControl", function(self, anchor, x, y, width, height, skillsTab)
|
||||
self.ListControl(anchor, x, y, width, height, 16, true, skillsTab.socketGroupList)
|
||||
self.skillsTab = skillsTab
|
||||
self.controls.scrollBar = common.New("ScrollBarControl", {"RIGHT",self,"RIGHT"}, -1, 0, 16, 0, 32)
|
||||
self.controls.scrollBar.height = function()
|
||||
local width, height = self:GetSize()
|
||||
return height - 2
|
||||
end
|
||||
self.label = "^7Socket Groups:"
|
||||
self.controls.delete = common.New("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, 0, -2, 60, 18, "Delete", function()
|
||||
self:OnKeyUp("DELETE")
|
||||
self:OnSelDelete(self.selIndex, self.selValue)
|
||||
end)
|
||||
self.controls.delete.enabled = function()
|
||||
return self.selGroup ~= nil and self.selGroup.source == nil
|
||||
return self.selValue ~= nil and self.selValue.source == nil
|
||||
end
|
||||
self.controls.paste = common.New("ButtonControl", {"RIGHT",self.controls.delete,"LEFT"}, -4, 0, 60, 18, "Paste", function()
|
||||
self.skillsTab:PasteSocketGroup()
|
||||
skillsTab:PasteSocketGroup()
|
||||
end)
|
||||
self.controls.copy = common.New("ButtonControl", {"RIGHT",self.controls.paste,"LEFT"}, -4, 0, 60, 18, "Copy", function()
|
||||
self.skillsTab:CopySocketGroup(self.selGroup)
|
||||
skillsTab:CopySocketGroup(self.selValue)
|
||||
end)
|
||||
self.controls.copy.enabled = function()
|
||||
return self.selGroup ~= nil and self.selGroup.source == nil
|
||||
return self.selValue ~= nil and self.selValue.source == nil
|
||||
end
|
||||
self.controls.new = common.New("ButtonControl", {"RIGHT",self.controls.copy,"LEFT"}, -4, 0, 60, 18, "New", function()
|
||||
local newGroup = { label = "", enabled = true, gemList = { } }
|
||||
t_insert(self.skillsTab.socketGroupList, newGroup)
|
||||
self.selGroup = newGroup
|
||||
local newGroup = {
|
||||
label = "",
|
||||
enabled = true,
|
||||
gemList = { }
|
||||
}
|
||||
t_insert(self.list, newGroup)
|
||||
self.selIndex = #self.skillsTab.socketGroupList
|
||||
self.selValue = newGroup
|
||||
self.skillsTab:SetDisplayGroup(newGroup)
|
||||
self.skillsTab:AddUndoState()
|
||||
self.skillsTab.build.buildFlag = true
|
||||
@@ -47,280 +44,133 @@ local SkillListClass = common.NewClass("SkillList", "Control", "ControlHost", fu
|
||||
end)
|
||||
end)
|
||||
|
||||
function SkillListClass:SelectIndex(index)
|
||||
self.selGroup = self.skillsTab.socketGroupList[index]
|
||||
if self.selGroup then
|
||||
self.selIndex = index
|
||||
self.skillsTab:SetDisplayGroup(self.selGroup)
|
||||
self.controls.scrollBar:ScrollIntoView((index - 2) * 16, 48)
|
||||
end
|
||||
end
|
||||
|
||||
function SkillListClass:IsMouseOver()
|
||||
if not self:IsShown() then
|
||||
return
|
||||
end
|
||||
return self:IsMouseInBounds() or self:GetMouseOverControl()
|
||||
end
|
||||
|
||||
function SkillListClass:Draw(viewPort)
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local list = self.skillsTab.socketGroupList
|
||||
local scrollBar = self.controls.scrollBar
|
||||
scrollBar:SetContentDimension(#list * 16, height - 4)
|
||||
self.selDragIndex = nil
|
||||
if self.selGroup and self.selDragging then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if not self.selDragActive and (cursorX-self.selCX)*(cursorX-self.selCX)+(cursorY-self.selCY)*(cursorY-self.selCY) > 100 then
|
||||
self.selDragActive = true
|
||||
end
|
||||
if self.selDragActive then
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + scrollBar.offset) / 16 + 0.5) + 1
|
||||
if index < self.selIndex or index > self.selIndex + 1 then
|
||||
self.selDragIndex = m_min(index, #list + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
DrawString(x, y - 20, "LEFT", 16, "VAR", "^7Socket Groups:")
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, x, y, width, height)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, x + 1, y + 1, width - 2, height - 2)
|
||||
self:DrawControls(viewPort)
|
||||
SetViewport(x + 2, y + 2, width - 20, height - 4)
|
||||
local ttGroup, ttY, ttWidth
|
||||
local minIndex = m_floor(scrollBar.offset / 16 + 1)
|
||||
local maxIndex = m_min(m_floor((scrollBar.offset + height) / 16 + 1), #list)
|
||||
for index = minIndex, maxIndex do
|
||||
local socketGroup = list[index]
|
||||
local lineY = 16 * (index - 1) - scrollBar.offset
|
||||
function SkillListClass:GetRowValue(column, index, socketGroup)
|
||||
if column == 1 then
|
||||
local label = socketGroup.displayLabel or "?"
|
||||
if not socketGroup.enabled or not socketGroup.slotEnabled then
|
||||
label = label .. " (Disabled)"
|
||||
label = "^x7F7F7F" .. label .. " (Disabled)"
|
||||
end
|
||||
local nameWidth = DrawStringWidth(16, "VAR", label)
|
||||
if not scrollBar.dragging and not self.selDragActive and (not self.skillsTab.selControl or self.hasFocus) then
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
local relX = cursorX - (x + 2)
|
||||
local relY = cursorY - (y + 2)
|
||||
if relX >= 0 and relX < width - 17 and relY >= 0 and relY >= lineY and relY < height - 2 and relY < lineY + 16 then
|
||||
ttGroup = socketGroup
|
||||
ttWidth = m_max(nameWidth + 8, relX)
|
||||
ttY = lineY + y + 2
|
||||
end
|
||||
end
|
||||
if socketGroup == ttGroup or socketGroup == self.selGroup then
|
||||
if self.hasFocus then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawImage(nil, 0, lineY, width - 20, 16)
|
||||
SetDrawColor(0.15, 0.15, 0.15)
|
||||
DrawImage(nil, 0, lineY + 1, width - 20, 14)
|
||||
end
|
||||
if socketGroup.enabled and socketGroup.slotEnabled then
|
||||
SetDrawColor(1, 1, 1)
|
||||
else
|
||||
SetDrawColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
DrawString(0, lineY, "LEFT", 16, "VAR", label)
|
||||
return label
|
||||
end
|
||||
if self.selDragIndex then
|
||||
local lineY = 16 * (self.selDragIndex - 1) - scrollBar.offset
|
||||
SetDrawColor(1, 1, 1)
|
||||
DrawImage(nil, 0, lineY - 1, width - 20, 3)
|
||||
SetDrawColor(0, 0, 0)
|
||||
DrawImage(nil, 0, lineY, width - 20, 1)
|
||||
end
|
||||
|
||||
function SkillListClass:AddValueTooltip(index, socketGroup)
|
||||
if not socketGroup.displaySkillList then
|
||||
return
|
||||
end
|
||||
SetViewport()
|
||||
if ttGroup and ttGroup.displaySkillList then
|
||||
if ttGroup.enabled and not ttGroup.slotEnabled then
|
||||
main:AddTooltipLine(16, "^7Note: this group is disabled because it is socketed in the inactive weapon set.")
|
||||
end
|
||||
if ttGroup.sourceItem then
|
||||
main:AddTooltipLine(18, "^7Source: "..data.colorCodes[ttGroup.sourceItem.rarity]..ttGroup.sourceItem.name)
|
||||
if socketGroup.enabled and not socketGroup.slotEnabled then
|
||||
main:AddTooltipLine(16, "^7Note: this group is disabled because it is socketed in the inactive weapon set.")
|
||||
end
|
||||
if socketGroup.sourceItem then
|
||||
main:AddTooltipLine(18, "^7Source: "..data.colorCodes[socketGroup.sourceItem.rarity]..socketGroup.sourceItem.name)
|
||||
main:AddTooltipSeparator(10)
|
||||
end
|
||||
local gemShown = { }
|
||||
for index, activeSkill in ipairs(socketGroup.displaySkillList) do
|
||||
if index > 1 then
|
||||
main:AddTooltipSeparator(10)
|
||||
end
|
||||
local gemShown = { }
|
||||
for index, activeSkill in ipairs(ttGroup.displaySkillList) do
|
||||
if index > 1 then
|
||||
main:AddTooltipSeparator(10)
|
||||
end
|
||||
main:AddTooltipLine(16, "^7Active Skill #"..index..":")
|
||||
for _, gem in ipairs(activeSkill.gemList) do
|
||||
main:AddTooltipLine(20, string.format("%s%s ^7%d%s/%d%s",
|
||||
data.skillColorMap[gem.data.color],
|
||||
gem.name,
|
||||
gem.level,
|
||||
(gem.srcGem and gem.level > gem.srcGem.level) and data.colorCodes.MAGIC.."+"..(gem.level - gem.srcGem.level).."^7" or "",
|
||||
gem.quality,
|
||||
(gem.srcGem and gem.quality > gem.srcGem.quality) and data.colorCodes.MAGIC.."+"..(gem.quality - gem.srcGem.quality).."^7" or ""
|
||||
))
|
||||
if gem.srcGem then
|
||||
gemShown[gem.srcGem] = true
|
||||
end
|
||||
end
|
||||
if activeSkill.minion then
|
||||
main:AddTooltipSeparator(10)
|
||||
main:AddTooltipLine(16, "^7Active Skill #"..index.."'s Main Minion Skill:")
|
||||
local gem = activeSkill.minion.mainSkill.gemList[1]
|
||||
main:AddTooltipLine(20, string.format("%s%s ^7%d%s/%d%s",
|
||||
data.skillColorMap[gem.data.color],
|
||||
gem.name,
|
||||
gem.level,
|
||||
(gem.srcGem and gem.level > gem.srcGem.level) and data.colorCodes.MAGIC.."+"..(gem.level - gem.srcGem.level).."^7" or "",
|
||||
gem.quality,
|
||||
(gem.srcGem and gem.quality > gem.srcGem.quality) and data.colorCodes.MAGIC.."+"..(gem.quality - gem.srcGem.quality).."^7" or ""
|
||||
))
|
||||
if gem.srcGem then
|
||||
gemShown[gem.srcGem] = true
|
||||
end
|
||||
main:AddTooltipLine(16, "^7Active Skill #"..index..":")
|
||||
for _, gem in ipairs(activeSkill.gemList) do
|
||||
main:AddTooltipLine(20, string.format("%s%s ^7%d%s/%d%s",
|
||||
data.skillColorMap[gem.data.color],
|
||||
gem.name,
|
||||
gem.level,
|
||||
(gem.srcGem and gem.level > gem.srcGem.level) and data.colorCodes.MAGIC.."+"..(gem.level - gem.srcGem.level).."^7" or "",
|
||||
gem.quality,
|
||||
(gem.srcGem and gem.quality > gem.srcGem.quality) and data.colorCodes.MAGIC.."+"..(gem.quality - gem.srcGem.quality).."^7" or ""
|
||||
))
|
||||
if gem.srcGem then
|
||||
gemShown[gem.srcGem] = true
|
||||
end
|
||||
end
|
||||
local showOtherHeader = true
|
||||
for _, gem in ipairs(ttGroup.gemList) do
|
||||
if not gemShown[gem] then
|
||||
if showOtherHeader then
|
||||
showOtherHeader = false
|
||||
main:AddTooltipSeparator(10)
|
||||
main:AddTooltipLine(16, "^7Inactive Gems:")
|
||||
end
|
||||
local reason = ""
|
||||
local displayGem = gem.displayGem or gem
|
||||
if not gem.data then
|
||||
reason = "(Unsupported)"
|
||||
elseif not gem.enabled then
|
||||
reason = "(Disabled)"
|
||||
elseif not ttGroup.enabled or not ttGroup.slotEnabled then
|
||||
elseif gem.data.support then
|
||||
if displayGem.superseded then
|
||||
reason = "(Superseded)"
|
||||
elseif not next(displayGem.isSupporting) and #ttGroup.displaySkillList > 0 then
|
||||
reason = "(Cannot apply to any of the active skills)"
|
||||
end
|
||||
end
|
||||
main:AddTooltipLine(20, string.format("%s%s ^7%d%s/%d%s %s",
|
||||
gem.color,
|
||||
gem.name or gem.nameSpec,
|
||||
displayGem.level,
|
||||
displayGem.level > gem.level and data.colorCodes.MAGIC.."+"..(displayGem.level - gem.level).."^7" or "",
|
||||
displayGem.quality,
|
||||
displayGem.quality > gem.quality and data.colorCodes.MAGIC.."+"..(displayGem.quality - gem.quality).."^7" or "",
|
||||
reason
|
||||
))
|
||||
if activeSkill.minion then
|
||||
main:AddTooltipSeparator(10)
|
||||
main:AddTooltipLine(16, "^7Active Skill #"..index.."'s Main Minion Skill:")
|
||||
local gem = activeSkill.minion.mainSkill.gemList[1]
|
||||
main:AddTooltipLine(20, string.format("%s%s ^7%d%s/%d%s",
|
||||
data.skillColorMap[gem.data.color],
|
||||
gem.name,
|
||||
gem.level,
|
||||
(gem.srcGem and gem.level > gem.srcGem.level) and data.colorCodes.MAGIC.."+"..(gem.level - gem.srcGem.level).."^7" or "",
|
||||
gem.quality,
|
||||
(gem.srcGem and gem.quality > gem.srcGem.quality) and data.colorCodes.MAGIC.."+"..(gem.quality - gem.srcGem.quality).."^7" or ""
|
||||
))
|
||||
if gem.srcGem then
|
||||
gemShown[gem.srcGem] = true
|
||||
end
|
||||
end
|
||||
SetDrawLayer(nil, 100)
|
||||
main:DrawTooltip(x + 2, ttY, ttWidth, 16, viewPort)
|
||||
SetDrawLayer(nil, 0)
|
||||
end
|
||||
local showOtherHeader = true
|
||||
for _, gem in ipairs(socketGroup.gemList) do
|
||||
if not gemShown[gem] then
|
||||
if showOtherHeader then
|
||||
showOtherHeader = false
|
||||
main:AddTooltipSeparator(10)
|
||||
main:AddTooltipLine(16, "^7Inactive Gems:")
|
||||
end
|
||||
local reason = ""
|
||||
local displayGem = gem.displayGem or gem
|
||||
if not gem.data then
|
||||
reason = "(Unsupported)"
|
||||
elseif not gem.enabled then
|
||||
reason = "(Disabled)"
|
||||
elseif not socketGroup.enabled or not socketGroup.slotEnabled then
|
||||
elseif gem.data.support then
|
||||
if displayGem.superseded then
|
||||
reason = "(Superseded)"
|
||||
elseif not next(displayGem.isSupporting) and #socketGroup.displaySkillList > 0 then
|
||||
reason = "(Cannot apply to any of the active skills)"
|
||||
end
|
||||
end
|
||||
main:AddTooltipLine(20, string.format("%s%s ^7%d%s/%d%s %s",
|
||||
gem.color,
|
||||
gem.name or gem.nameSpec,
|
||||
displayGem.level,
|
||||
displayGem.level > gem.level and data.colorCodes.MAGIC.."+"..(displayGem.level - gem.level).."^7" or "",
|
||||
displayGem.quality,
|
||||
displayGem.quality > gem.quality and data.colorCodes.MAGIC.."+"..(displayGem.quality - gem.quality).."^7" or "",
|
||||
reason
|
||||
))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SkillListClass:OnKeyDown(key, doubleClick)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
end
|
||||
local mOverControl = self:GetMouseOverControl()
|
||||
if mOverControl and mOverControl.OnKeyDown then
|
||||
return mOverControl:OnKeyDown(key)
|
||||
end
|
||||
if not self:IsMouseOver() and key:match("BUTTON") then
|
||||
return
|
||||
end
|
||||
if key == "LEFTBUTTON" then
|
||||
self.selGroup = nil
|
||||
self.selIndex = nil
|
||||
local x, y = self:GetPos()
|
||||
local width, height = self:GetSize()
|
||||
local cursorX, cursorY = GetCursorPos()
|
||||
if cursorX >= x + 2 and cursorY >= y + 2 and cursorX < x + width - 18 and cursorY < y + height - 2 then
|
||||
local index = math.floor((cursorY - y - 2 + self.controls.scrollBar.offset) / 16) + 1
|
||||
local selGroup = self.skillsTab.socketGroupList[index]
|
||||
if selGroup then
|
||||
self.selGroup = selGroup
|
||||
self.selIndex = index
|
||||
self.skillsTab:SetDisplayGroup(selGroup)
|
||||
end
|
||||
end
|
||||
if self.selGroup then
|
||||
self.selCX = cursorX
|
||||
self.selCY = cursorY
|
||||
self.selDragging = true
|
||||
self.selDragActive = false
|
||||
end
|
||||
elseif key == "c" and IsKeyDown("CTRL") then
|
||||
if self.selGroup and not self.selGroup.source then
|
||||
self.skillsTab:CopySocketGroup(self.selGroup)
|
||||
end
|
||||
elseif #self.skillsTab.socketGroupList > 0 then
|
||||
if key == "UP" then
|
||||
self:SelectIndex(((self.selIndex or 1) - 2) % #self.skillsTab.socketGroupList + 1)
|
||||
elseif key == "DOWN" then
|
||||
self:SelectIndex((self.selIndex or #self.skillsTab.socketGroupList) % #self.skillsTab.socketGroupList + 1)
|
||||
elseif key == "HOME" then
|
||||
self:SelectIndex(1)
|
||||
elseif key == "END" then
|
||||
self:SelectIndex(#self.skillsTab.socketGroupList)
|
||||
end
|
||||
end
|
||||
return self
|
||||
function SkillListClass:OnOrderChange()
|
||||
self.skillsTab:AddUndoState()
|
||||
self.skillsTab.build.buildFlag = true
|
||||
end
|
||||
|
||||
function SkillListClass:OnKeyUp(key)
|
||||
if not self:IsShown() or not self:IsEnabled() then
|
||||
return
|
||||
function SkillListClass:OnSelect(index, socketGroup)
|
||||
self.skillsTab:SetDisplayGroup(socketGroup)
|
||||
end
|
||||
|
||||
function SkillListClass:OnSelCopy(index, socketGroup)
|
||||
if not socketGroup.source then
|
||||
self.skillsTab:CopySocketGroup(socketGroup)
|
||||
end
|
||||
if key == "WHEELDOWN" then
|
||||
self.controls.scrollBar:Scroll(1)
|
||||
elseif key == "WHEELUP" then
|
||||
self.controls.scrollBar:Scroll(-1)
|
||||
elseif self.selGroup then
|
||||
if key == "BACK" or key == "DELETE" then
|
||||
if self.selGroup.source then
|
||||
main:OpenMessagePopup("Delete Socket Group", "This socket group cannot be deleted as it is created by an equipped item.")
|
||||
elseif not self.selGroup.gemList[1] then
|
||||
t_remove(self.skillsTab.socketGroupList, self.selIndex)
|
||||
if self.skillsTab.displayGroup == self.selGroup then
|
||||
self.skillsTab.displayGroup = nil
|
||||
end
|
||||
self.skillsTab:AddUndoState()
|
||||
self.skillsTab.build.buildFlag = true
|
||||
self.selGroup = nil
|
||||
else
|
||||
main:OpenConfirmPopup("Delete Socket Group", "Are you sure you want to delete '"..self.selGroup.displayLabel.."'?", "Delete", function()
|
||||
t_remove(self.skillsTab.socketGroupList, self.selIndex)
|
||||
if self.skillsTab.displayGroup == self.selGroup then
|
||||
self.skillsTab.displayGroup = nil
|
||||
end
|
||||
self.skillsTab:AddUndoState()
|
||||
self.skillsTab.build.buildFlag = true
|
||||
self.selGroup = nil
|
||||
end)
|
||||
end
|
||||
elseif key == "LEFTBUTTON" then
|
||||
self.selDragging = false
|
||||
if self.selDragActive then
|
||||
self.selDragActive = false
|
||||
if self.selDragIndex and self.selDragIndex ~= self.selIndex then
|
||||
t_remove(self.skillsTab.socketGroupList, self.selIndex)
|
||||
if self.selDragIndex > self.selIndex then
|
||||
self.selDragIndex = self.selDragIndex - 1
|
||||
end
|
||||
t_insert(self.skillsTab.socketGroupList, self.selDragIndex, self.selGroup)
|
||||
self.skillsTab:AddUndoState()
|
||||
self.skillsTab.build.buildFlag = true
|
||||
self.selGroup = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SkillListClass:OnSelDelete(index, socketGroup)
|
||||
if socketGroup.source then
|
||||
main:OpenMessagePopup("Delete Socket Group", "This socket group cannot be deleted as it is created by an equipped item.")
|
||||
elseif not socketGroup.gemList[1] then
|
||||
t_remove(self.list, index)
|
||||
if self.skillsTab.displayGroup == socketGroup then
|
||||
self.skillsTab.displayGroup = nil
|
||||
end
|
||||
self.skillsTab:AddUndoState()
|
||||
self.skillsTab.build.buildFlag = true
|
||||
self.selValue = nil
|
||||
else
|
||||
main:OpenConfirmPopup("Delete Socket Group", "Are you sure you want to delete '"..socketGroup.displayLabel.."'?", "Delete", function()
|
||||
t_remove(self.list, index)
|
||||
if self.skillsTab.displayGroup == socketGroup then
|
||||
self.skillsTab.displayGroup = nil
|
||||
end
|
||||
self.skillsTab:AddUndoState()
|
||||
self.skillsTab.build.buildFlag = true
|
||||
self.selValue = nil
|
||||
end)
|
||||
end
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
@@ -220,8 +220,8 @@ function SkillsTabClass:PasteSocketGroup()
|
||||
end
|
||||
if #newGroup.gemList > 0 then
|
||||
t_insert(self.socketGroupList, newGroup)
|
||||
self.controls.groupList.selGroup = newGroup
|
||||
self.controls.groupList.selIndex = #self.socketGroupList
|
||||
self.controls.groupList.selValue = newGroup
|
||||
self:SetDisplayGroup(newGroup)
|
||||
self:AddUndoState()
|
||||
self.build.buildFlag = true
|
||||
@@ -487,31 +487,9 @@ function SkillsTabClass:CreateUndoState()
|
||||
local state = { }
|
||||
state.socketGroupList = { }
|
||||
for _, socketGroup in ipairs(self.socketGroupList) do
|
||||
local newGroup = {
|
||||
label = socketGroup.label,
|
||||
slot = socketGroup.slot,
|
||||
enabled = socketGroup.enabled,
|
||||
source = socketGroup.source,
|
||||
mainActiveSkill = socketGroup.mainActiveSkill,
|
||||
mainActiveSkillCalcs = socketGroup.mainActiveSkillCalcs,
|
||||
gemList = { }
|
||||
}
|
||||
local newGroup = copyTable(socketGroup, true)
|
||||
for index, gem in pairs(socketGroup.gemList) do
|
||||
newGroup.gemList[index] = {
|
||||
nameSpec = gem.nameSpec,
|
||||
level = gem.level,
|
||||
quality = gem.quality,
|
||||
enabled = gem.enabled,
|
||||
skillPart = gem.skillPart,
|
||||
skillPartCalcs = gem.skillPartCalcs,
|
||||
skillMinion = gem.skillMinion,
|
||||
skillMinionCalcs = gem.skillMinionCalcs,
|
||||
skillMinionSkill = gem.skillMinionSkill,
|
||||
skillMinionSkillCalcs = gem.skillMinionSkillCalcs,
|
||||
name = gem.name,
|
||||
data = gem.data,
|
||||
errMsg = gem.errMsg,
|
||||
}
|
||||
newGroup.gemList[index] = copyTable(gem, true)
|
||||
end
|
||||
t_insert(state.socketGroupList, newGroup)
|
||||
end
|
||||
@@ -520,9 +498,12 @@ end
|
||||
|
||||
function SkillsTabClass:RestoreUndoState(state)
|
||||
local displayId = isValueInArray(self.socketGroupList, self.displayGroup)
|
||||
self.socketGroupList = state.socketGroupList
|
||||
wipeTable(self.socketGroupList)
|
||||
for k, v in pairs(state.socketGroupList) do
|
||||
self.socketGroupList[k] = v
|
||||
end
|
||||
self:SetDisplayGroup(displayId and self.socketGroupList[displayId])
|
||||
if self.controls.groupList.selGroup then
|
||||
self.controls.groupList.selGroup = self.socketGroupList[self.controls.groupList.selIndex]
|
||||
if self.controls.groupList.selValue then
|
||||
self.controls.groupList.selValue = self.socketGroupList[self.controls.groupList.selIndex]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -180,6 +180,7 @@ function TreeTabClass:Save(xml)
|
||||
spec:Save(child)
|
||||
t_insert(xml, child)
|
||||
end
|
||||
self.modFlag = false
|
||||
end
|
||||
|
||||
function TreeTabClass:SetActiveSpec(specId)
|
||||
|
||||
@@ -554,7 +554,7 @@ function buildMode:OnFrame(inputEvents)
|
||||
self.calcsTab:Draw(tabViewPort, inputEvents)
|
||||
end
|
||||
|
||||
self.unsaved = self.modFlag or self.notesTab.modFlag or self.configTab.modFlag or self.spec.modFlag or self.skillsTab.modFlag or self.itemsTab.modFlag or self.calcsTab.modFlag
|
||||
self.unsaved = self.modFlag or self.notesTab.modFlag or self.configTab.modFlag or self.treeTab.modFlag or self.spec.modFlag or self.skillsTab.modFlag or self.itemsTab.modFlag or self.calcsTab.modFlag
|
||||
|
||||
SetDrawLayer(5)
|
||||
|
||||
@@ -651,8 +651,8 @@ function buildMode:OpenSpectreLibrary()
|
||||
return data.minions[a].name < data.minions[b].name
|
||||
end
|
||||
end)
|
||||
controls.list = common.New("MinionList", nil, -100, 40, 190, 250, destList, true)
|
||||
controls.source = common.New("MinionList", nil, 100, 40, 190, 250, sourceList, false, controls.list)
|
||||
controls.list = common.New("MinionList", nil, -100, 40, 190, 250, destList)
|
||||
controls.source = common.New("MinionList", nil, 100, 40, 190, 250, sourceList, controls.list)
|
||||
controls.save = common.New("ButtonControl", nil, -45, 300, 80, 20, "Save", function()
|
||||
self.spectreList = destList
|
||||
self.modFlag = true
|
||||
|
||||
@@ -7,7 +7,6 @@ local launch, main = ...
|
||||
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local t_insert = table.insert
|
||||
|
||||
local listMode = common.New("ControlHost")
|
||||
|
||||
@@ -17,25 +16,27 @@ function listMode:Init(selBuildName)
|
||||
return main.screenW / 2
|
||||
end
|
||||
|
||||
self.list = { }
|
||||
|
||||
self.controls.new = common.New("ButtonControl", {"TOP",self.anchor,"TOP"}, -210, 0, 60, 20, "New", function()
|
||||
main:SetMode("BUILD", false, "Unnamed build")
|
||||
end)
|
||||
self.controls.open = common.New("ButtonControl", {"LEFT",self.controls.new,"RIGHT"}, 8, 0, 60, 20, "Open", function()
|
||||
self:LoadSel()
|
||||
self.controls.buildList:LoadBuild(self.controls.buildList.selValue)
|
||||
end)
|
||||
self.controls.open.enabled = function() return self.sel ~= nil end
|
||||
self.controls.open.enabled = function() return self.controls.buildList.selValue ~= nil end
|
||||
self.controls.copy = common.New("ButtonControl", {"LEFT",self.controls.open,"RIGHT"}, 8, 0, 60, 20, "Copy", function()
|
||||
self:CopySel()
|
||||
self.controls.buildList:RenameBuild(self.controls.buildList.selValue, true)
|
||||
end)
|
||||
self.controls.copy.enabled = function() return self.sel ~= nil end
|
||||
self.controls.copy.enabled = function() return self.controls.buildList.selValue ~= nil end
|
||||
self.controls.rename = common.New("ButtonControl", {"LEFT",self.controls.copy,"RIGHT"}, 8, 0, 60, 20, "Rename", function()
|
||||
self:RenameSel()
|
||||
self.controls.buildList:RenameBuild(self.controls.buildList.selValue)
|
||||
end)
|
||||
self.controls.rename.enabled = function() return self.sel ~= nil end
|
||||
self.controls.rename.enabled = function() return self.controls.buildList.selValue ~= nil end
|
||||
self.controls.delete = common.New("ButtonControl", {"LEFT",self.controls.rename,"RIGHT"}, 8, 0, 60, 20, "Delete", function()
|
||||
self:DeleteSel()
|
||||
self.controls.buildList:DeleteBuild(self.controls.buildList.selValue)
|
||||
end)
|
||||
self.controls.delete.enabled = function() return self.sel ~= nil end
|
||||
self.controls.delete.enabled = function() return self.controls.buildList.selValue ~= nil end
|
||||
self.controls.sort = common.New("DropDownControl", {"LEFT",self.controls.delete,"RIGHT"}, 8, 0, 140, 20, {{val="NAME",label="Sort by Name"},{val="CLASS",label="Sort by Class"},{val="EDITED",label="Sort by Last Edited"}}, function(sel, val)
|
||||
main.buildSortMode = val.val
|
||||
self:SortList()
|
||||
@@ -48,7 +49,7 @@ function listMode:Init(selBuildName)
|
||||
end
|
||||
|
||||
self:BuildList()
|
||||
self:SelByFileName(selBuildName and selBuildName..".xml")
|
||||
self.controls.buildList:SelByFileName(selBuildName and selBuildName..".xml")
|
||||
self:SelectControl(self.controls.buildList)
|
||||
end
|
||||
|
||||
@@ -56,19 +57,6 @@ function listMode:Shutdown()
|
||||
end
|
||||
|
||||
function listMode:OnFrame(inputEvents)
|
||||
for id, event in ipairs(inputEvents) do
|
||||
if event.type == "KeyDown" then
|
||||
if self.edit then
|
||||
if event.key == "RETURN" then
|
||||
self:EditFinish()
|
||||
inputEvents[id] = nil
|
||||
elseif event.key == "ESCAPE" then
|
||||
self:EditCancel()
|
||||
inputEvents[id] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self:ProcessControlsInput(inputEvents, main.viewPort)
|
||||
|
||||
main:DrawBackground(main.viewPort)
|
||||
@@ -107,7 +95,7 @@ function listMode:BuildList()
|
||||
end
|
||||
|
||||
function listMode:SortList()
|
||||
local oldSelFileName = self.sel and self.list[self.sel] and self.list[self.sel].fileName
|
||||
local oldSelFileName = self.controls.buildList.selValue and self.controls.buildList.selValue.fileName
|
||||
table.sort(self.list, function(a, b)
|
||||
if main.buildSortMode == "EDITED" then
|
||||
return a.modified > b.modified
|
||||
@@ -125,131 +113,8 @@ function listMode:SortList()
|
||||
return a.fileName:upper() < b.fileName:upper()
|
||||
end)
|
||||
if oldSelFileName then
|
||||
self:SelByFileName(oldSelFileName)
|
||||
self.controls.buildList:SelByFileName(oldSelFileName)
|
||||
end
|
||||
self.controls.buildList:ScrollSelIntoView()
|
||||
end
|
||||
|
||||
function listMode:SelByFileName(selFileName)
|
||||
self.sel = nil
|
||||
for index, build in ipairs(self.list) do
|
||||
if build.fileName == selFileName then
|
||||
self.sel = index
|
||||
self.controls.buildList:ScrollSelIntoView()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function listMode:EditInit(prompt, finFunc)
|
||||
self.edit = self.sel
|
||||
self.editFinFunc = finFunc
|
||||
self.controls.buildList:ScrollSelIntoView()
|
||||
self.controls.buildList.controls.nameEdit.prompt = prompt
|
||||
self.controls.buildList.controls.nameEdit:SetText(self.list[self.sel].buildName or "")
|
||||
end
|
||||
|
||||
function listMode:EditFinish()
|
||||
if not self.edit then
|
||||
return
|
||||
end
|
||||
local msg = self.editFinFunc(self.controls.buildList.controls.nameEdit.buf)
|
||||
if msg then
|
||||
main:OpenMessagePopup("Message", msg)
|
||||
return
|
||||
end
|
||||
self.edit = nil
|
||||
self:SelectControl(self.controls.buildList)
|
||||
end
|
||||
|
||||
function listMode:EditCancel()
|
||||
self.sel = nil
|
||||
self.edit = nil
|
||||
self:BuildList()
|
||||
self:SelectControl(self.controls.buildList)
|
||||
end
|
||||
|
||||
function listMode:LoadSel()
|
||||
if self.edit or not self.sel or not self.list[self.sel] then
|
||||
return
|
||||
end
|
||||
main:SetMode("BUILD", main.buildPath..self.list[self.sel].fileName, self.list[self.sel].buildName)
|
||||
end
|
||||
|
||||
function listMode:CopySel()
|
||||
if self.edit or not self.sel or not self.list[self.sel] then
|
||||
return
|
||||
end
|
||||
local srcName = self.list[self.sel].fileName
|
||||
table.insert(self.list, self.sel + 1, copyTable(self.list[self.sel]))
|
||||
self.sel = self.sel + 1
|
||||
self.list[self.sel].fileName = srcName:gsub("%.xml$","") .. " (copy)"
|
||||
self:EditInit("Enter new name", function(buf)
|
||||
if #buf < 1 then
|
||||
return "No name entered"
|
||||
end
|
||||
local inFile, msg = io.open(main.buildPath..srcName, "r")
|
||||
if not inFile then
|
||||
return "Couldn't copy '"..srcName.."': "..msg
|
||||
end
|
||||
local dstName = buf .. ".xml"
|
||||
local outFile, msg = io.open(main.buildPath..dstName, "r")
|
||||
if outFile then
|
||||
outFile:close()
|
||||
return "'"..dstName.."' already exists"
|
||||
end
|
||||
outFile, msg = io.open(main.buildPath..dstName, "w")
|
||||
if not outFile then
|
||||
return "Couldn't create '"..dstName.."': "..msg
|
||||
end
|
||||
outFile:write(inFile:read("*a"))
|
||||
inFile:close()
|
||||
outFile:close()
|
||||
self.list[self.edit].fileName = dstName
|
||||
self.list[self.edit].buildName = buf
|
||||
self:BuildList()
|
||||
end)
|
||||
end
|
||||
|
||||
function listMode:RenameSel()
|
||||
if self.edit or not self.sel or not self.list[self.sel] then
|
||||
return
|
||||
end
|
||||
local oldName = self.list[self.sel].fileName
|
||||
self:EditInit("Enter new name", function(buf)
|
||||
if #buf < 1 then
|
||||
return "No name entered"
|
||||
end
|
||||
local newName = buf .. ".xml"
|
||||
if newName == oldName then
|
||||
return
|
||||
end
|
||||
if newName:lower() ~= oldName:lower() then
|
||||
local newFile = io.open(main.buildPath..newName, "r")
|
||||
if newFile then
|
||||
newFile:close()
|
||||
return "'"..newName.."' already exists"
|
||||
end
|
||||
end
|
||||
local res, msg = os.rename(main.buildPath..oldName, main.buildPath..newName)
|
||||
if not res then
|
||||
return "Couldn't rename '"..oldName.."' to '"..newName.."': "..msg
|
||||
end
|
||||
self.list[self.edit].fileName = newName
|
||||
self.list[self.edit].buildName = buf
|
||||
self:SortList()
|
||||
end)
|
||||
end
|
||||
|
||||
function listMode:DeleteSel()
|
||||
if self.edit or not self.sel or not self.list[self.sel] then
|
||||
return
|
||||
end
|
||||
main:OpenConfirmPopup("Confirm Delete", "Are you sure you want to delete build:\n"..self.list[self.sel].buildName.."\nThis cannot be undone.", "Delete", function()
|
||||
os.remove(main.buildPath..self.list[self.sel].fileName)
|
||||
self:BuildList()
|
||||
self.sel = nil
|
||||
end)
|
||||
end
|
||||
|
||||
return listMode
|
||||
@@ -69,44 +69,46 @@ end
|
||||
-- Create an active skill using the given active gem and list of support gems
|
||||
-- It will determine the base flag set, and check which of the support gems can support this skill
|
||||
function calcs.createActiveSkill(activeGem, supportList, summonSkill)
|
||||
local activeSkill = { }
|
||||
activeSkill.activeGem = activeGem
|
||||
activeSkill.gemList = { activeSkill.activeGem }
|
||||
activeSkill.supportList = supportList
|
||||
activeSkill.summonSkill = summonSkill
|
||||
local activeSkill = {
|
||||
activeGem = activeGem,
|
||||
supportList = supportList,
|
||||
summonSkill = summonSkill,
|
||||
skillData = { },
|
||||
}
|
||||
|
||||
-- Initialise skill types
|
||||
activeSkill.skillTypes = copyTable(activeGem.data.skillTypes)
|
||||
if activeGem.data.minionSkillTypes then
|
||||
activeSkill.minionSkillTypes = copyTable(activeGem.data.minionSkillTypes)
|
||||
end
|
||||
|
||||
activeSkill.skillData = { }
|
||||
|
||||
-- Initialise skill flag set ('attack', 'projectile', etc)
|
||||
local skillFlags = copyTable(activeGem.data.baseFlags)
|
||||
activeSkill.skillFlags = skillFlags
|
||||
skillFlags.hit = activeSkill.skillTypes[SkillType.Attack] or activeSkill.skillTypes[SkillType.Hit] or activeSkill.skillTypes[SkillType.Projectile]
|
||||
|
||||
for _, gem in ipairs(supportList) do
|
||||
if calcLib.gemCanSupport(gem, activeSkill) then
|
||||
if gem.data.addFlags then
|
||||
-- Support gem adds flags to supported skills (eg. Remote Mine adds 'mine')
|
||||
for k in pairs(gem.data.addFlags) do
|
||||
skillFlags[k] = true
|
||||
end
|
||||
end
|
||||
for _, skillType in pairs(gem.data.addSkillTypes) do
|
||||
-- Process support skills
|
||||
activeSkill.gemList = { activeGem }
|
||||
for _, supportGem in ipairs(supportList) do
|
||||
-- Pass 1: Add skill types from compatible supports
|
||||
if calcLib.gemCanSupport(supportGem, activeSkill) then
|
||||
for _, skillType in pairs(supportGem.data.addSkillTypes) do
|
||||
activeSkill.skillTypes[skillType] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Process support gems
|
||||
for _, gem in ipairs(supportList) do
|
||||
if calcLib.gemCanSupport(gem, activeSkill) then
|
||||
t_insert(activeSkill.gemList, gem)
|
||||
if gem.isSupporting then
|
||||
gem.isSupporting[activeGem.name] = true
|
||||
for _, supportGem in ipairs(supportList) do
|
||||
-- Pass 2: Add all compatible supports
|
||||
if calcLib.gemCanSupport(supportGem, activeSkill) then
|
||||
t_insert(activeSkill.gemList, supportGem)
|
||||
if supportGem.isSupporting then
|
||||
supportGem.isSupporting[activeGem.name] = true
|
||||
end
|
||||
if supportGem.data.addFlags and not summonSkill then
|
||||
-- Support skill adds flags to supported skills (eg. Remote Mine adds 'mine')
|
||||
for k in pairs(supportGem.data.addFlags) do
|
||||
skillFlags[k] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -231,19 +231,30 @@ function calcs.initEnv(build, mode, override)
|
||||
-- Build and merge item modifiers, and create list of radius jewels
|
||||
env.radiusJewelList = wipeTable(env.radiusJewelList)
|
||||
env.player.itemList = { }
|
||||
env.itemGrantedSkills = { }
|
||||
env.flasks = { }
|
||||
env.modDB.conditions["UsingAllCorruptedItems"] = true
|
||||
for slotName, slot in pairs(build.itemsTab.slots) do
|
||||
local item
|
||||
if slot.weaponSet and slot.weaponSet ~= (build.itemsTab.useSecondWeaponSet and 2 or 1) then
|
||||
item = nil
|
||||
elseif slotName == override.repSlotName then
|
||||
if slotName == override.repSlotName then
|
||||
item = override.repItem
|
||||
elseif slot.nodeId and override.spec then
|
||||
item = build.itemsTab.list[env.spec.jewels[slot.nodeId]]
|
||||
else
|
||||
item = build.itemsTab.list[slot.selItemId]
|
||||
end
|
||||
if item then
|
||||
-- Find skills granted by this item
|
||||
for _, skill in ipairs(item.grantedSkills) do
|
||||
local grantedSkill = copyTable(skill)
|
||||
grantedSkill.sourceItem = item
|
||||
grantedSkill.slotName = slotName
|
||||
t_insert(env.itemGrantedSkills, grantedSkill)
|
||||
end
|
||||
end
|
||||
if slot.weaponSet and slot.weaponSet ~= (build.itemsTab.useSecondWeaponSet and 2 or 1) then
|
||||
item = nil
|
||||
end
|
||||
if slot.weaponSet == 2 and build.itemsTab.useSecondWeaponSet then
|
||||
slotName = slotName:gsub(" Swap","")
|
||||
end
|
||||
@@ -337,64 +348,53 @@ function calcs.initEnv(build, mode, override)
|
||||
|
||||
if env.mode == "MAIN" then
|
||||
-- Process extra skills granted by items
|
||||
local markList = { }
|
||||
for _, mod in ipairs(modDB.mods["ExtraSkill"] or { }) do
|
||||
if mod.value.name ~= "Unknown" then
|
||||
-- Extract the name of the slot containing the item this skill was granted by
|
||||
local slotName
|
||||
for _, tag in ipairs(mod.tagList) do
|
||||
if tag.type == "SocketedIn" then
|
||||
slotName = tag.slotName
|
||||
local markList = wipeTable(tempTable1)
|
||||
for _, grantedSkill in ipairs(env.itemGrantedSkills) do
|
||||
-- Check if a matching group already exists
|
||||
local group
|
||||
for index, socketGroup in pairs(build.skillsTab.socketGroupList) do
|
||||
if socketGroup.source == grantedSkill.source and socketGroup.slot == grantedSkill.slotName then
|
||||
if socketGroup.gemList[1] and socketGroup.gemList[1].nameSpec == grantedSkill.name then
|
||||
group = socketGroup
|
||||
markList[socketGroup] = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not group then
|
||||
-- Create a new group for this skill
|
||||
group = { label = "", enabled = true, gemList = { }, source = grantedSkill.source, slot = grantedSkill.slotName }
|
||||
t_insert(build.skillsTab.socketGroupList, group)
|
||||
markList[group] = true
|
||||
end
|
||||
|
||||
-- Check if a matching group already exists
|
||||
local group
|
||||
for index, socketGroup in pairs(build.skillsTab.socketGroupList) do
|
||||
if socketGroup.source == mod.source and socketGroup.slot == slotName then
|
||||
if socketGroup.gemList[1] and socketGroup.gemList[1].nameSpec == mod.value.name then
|
||||
group = socketGroup
|
||||
markList[socketGroup] = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not group then
|
||||
-- Create a new group for this skill
|
||||
group = { label = "", enabled = true, gemList = { }, source = mod.source, slot = slotName }
|
||||
t_insert(build.skillsTab.socketGroupList, group)
|
||||
markList[group] = true
|
||||
end
|
||||
|
||||
-- Update the group
|
||||
group.sourceItem = build.itemsTab.list[tonumber(mod.source:match("Item:(%d+):"))]
|
||||
local activeGem = group.gemList[1] or {
|
||||
nameSpec = mod.value.name,
|
||||
quality = 0,
|
||||
enabled = true,
|
||||
fromItem = true,
|
||||
}
|
||||
activeGem.level = mod.value.level
|
||||
wipeTable(group.gemList)
|
||||
t_insert(group.gemList, activeGem)
|
||||
if mod.value.noSupports then
|
||||
group.noSupports = true
|
||||
else
|
||||
for _, socketGroup in pairs(build.skillsTab.socketGroupList) do
|
||||
-- Look for other groups that are socketed in the item
|
||||
if socketGroup.slot == slotName and not socketGroup.source then
|
||||
-- Add all support gems to the skill's group
|
||||
for _, gem in ipairs(socketGroup.gemList) do
|
||||
if gem.data and gem.data.support then
|
||||
t_insert(group.gemList, gem)
|
||||
end
|
||||
-- Update the group
|
||||
group.sourceItem = grantedSkill.sourceItem
|
||||
local activeGem = group.gemList[1] or {
|
||||
nameSpec = grantedSkill.name,
|
||||
quality = 0,
|
||||
enabled = true,
|
||||
fromItem = true,
|
||||
}
|
||||
activeGem.level = grantedSkill.level
|
||||
wipeTable(group.gemList)
|
||||
t_insert(group.gemList, activeGem)
|
||||
if grantedSkill.noSupports then
|
||||
group.noSupports = true
|
||||
else
|
||||
for _, socketGroup in pairs(build.skillsTab.socketGroupList) do
|
||||
-- Look for other groups that are socketed in the item
|
||||
if socketGroup.slot == grantedSkill.slotName and not socketGroup.source then
|
||||
-- Add all support gems to the skill's group
|
||||
for _, gem in ipairs(socketGroup.gemList) do
|
||||
if gem.data and gem.data.support then
|
||||
t_insert(group.gemList, gem)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
build.skillsTab:ProcessSocketGroup(group)
|
||||
end
|
||||
build.skillsTab:ProcessSocketGroup(group)
|
||||
end
|
||||
|
||||
-- Remove any socket groups that no longer have a matching item
|
||||
@@ -434,12 +434,12 @@ function calcs.initEnv(build, mode, override)
|
||||
|
||||
-- Build list of active skills
|
||||
env.activeSkillList = { }
|
||||
local groupCfg = wipeTable(tempTable1)
|
||||
for index, socketGroup in pairs(build.skillsTab.socketGroupList) do
|
||||
local socketGroupSkillList = { }
|
||||
local slot = socketGroup.slot and build.itemsTab.slots[socketGroup.slot]
|
||||
socketGroup.slotEnabled = not slot or not slot.weaponSet or slot.weaponSet == (build.itemsTab.useSecondWeaponSet and 2 or 1)
|
||||
if index == env.mainSocketGroup or (socketGroup.enabled and socketGroup.slotEnabled) then
|
||||
local groupCfg = wipeTable(tempTable1)
|
||||
groupCfg.slotName = socketGroup.slot
|
||||
local propertyModList = env.modDB:Sum("LIST", groupCfg, "GemProperty")
|
||||
|
||||
@@ -454,14 +454,17 @@ function calcs.initEnv(build, mode, override)
|
||||
name = gemData.name,
|
||||
data = gemData,
|
||||
level = value.level,
|
||||
quality = 0,
|
||||
enabled = true,
|
||||
quality = 0,
|
||||
enabled = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, gem in ipairs(socketGroup.gemList) do
|
||||
-- Add support gems from this group
|
||||
if env.mode == "MAIN" then
|
||||
gem.displayGem = nil
|
||||
end
|
||||
if gem.enabled and gem.data and gem.data.support then
|
||||
local supportGem = copyTable(gem, true)
|
||||
supportGem.srcGem = gem
|
||||
|
||||
@@ -145,16 +145,25 @@ function isMouseInRegion(region)
|
||||
end
|
||||
|
||||
-- Make a copy of a table and all subtables
|
||||
function copyTable(tbl, noRecurse)
|
||||
local out = {}
|
||||
for k, v in pairs(tbl) do
|
||||
if not noRecurse and type(v) == "table" then
|
||||
out[k] = copyTable(v)
|
||||
else
|
||||
out[k] = v
|
||||
do
|
||||
local subTableMap = { }
|
||||
function copyTable(tbl, noRecurse, isSubTable)
|
||||
local out = {}
|
||||
if not noRecurse then
|
||||
subTableMap[tbl] = out
|
||||
end
|
||||
for k, v in pairs(tbl) do
|
||||
if not noRecurse and type(v) == "table" then
|
||||
out[k] = subTableMap[v] or copyTable(v, false, true)
|
||||
else
|
||||
out[k] = v
|
||||
end
|
||||
end
|
||||
if not noRecurse and not isSubTable then
|
||||
wipeTable(subTableMap)
|
||||
end
|
||||
return out
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
-- Wipe all keys from the table and return it, or return a new table if no table provided
|
||||
|
||||
@@ -620,7 +620,7 @@ function itemLib.buildItemModList(item)
|
||||
if not item.base then
|
||||
return
|
||||
end
|
||||
local baseList = { }
|
||||
local baseList = common.New("ModList")
|
||||
if item.base.weapon then
|
||||
item.weaponData = { }
|
||||
elseif item.base.armour then
|
||||
@@ -652,14 +652,25 @@ function itemLib.buildItemModList(item)
|
||||
if modLine.buff then
|
||||
t_insert(item.buffModList, mod)
|
||||
else
|
||||
t_insert(baseList, mod)
|
||||
baseList:AddMod(mod)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
item.grantedSkills = { }
|
||||
for _, skill in ipairs(baseList:Sum("LIST", nil, "ExtraSkill")) do
|
||||
if skill.name ~= "Unknown" then
|
||||
t_insert(item.grantedSkills, {
|
||||
name = skill.name,
|
||||
level = skill.level,
|
||||
noSupports = skill.noSupports,
|
||||
source = item.modSource,
|
||||
})
|
||||
end
|
||||
end
|
||||
if item.name == "Tabula Rasa, Simple Robe" or item.name == "Skin of the Loyal, Simple Robe" or item.name == "Skin of the Lords, Simple Robe" then
|
||||
-- Hack to remove the energy shield
|
||||
t_insert(baseList, { name = "ArmourData", type = "LIST", value = { key = "EnergyShield" }, flags = 0, keywordFlags = 0, tagList = { } })
|
||||
baseList:NewMod("ArmourData", "LIST", { key = "EnergyShield" })
|
||||
end
|
||||
if item.base.weapon or item.type == "Ring" then
|
||||
item.slotModList = { }
|
||||
|
||||
@@ -38,6 +38,7 @@ local classList = {
|
||||
"ScrollBarControl",
|
||||
"SliderControl",
|
||||
"TextListControl",
|
||||
"ListControl",
|
||||
-- Misc
|
||||
"PopupDialog",
|
||||
-- Mode: Build list
|
||||
@@ -327,7 +328,7 @@ function main:OpenUpdatePopup()
|
||||
end
|
||||
end
|
||||
local controls = { }
|
||||
controls.changeLog = common.New("TextListControl", nil, 0, 20, 780, 190, nil, changeList)
|
||||
controls.changeLog = common.New("TextListControl", nil, 0, 20, 780, 192, nil, changeList)
|
||||
controls.update = common.New("ButtonControl", nil, -45, 220, 80, 20, "Update", function()
|
||||
self:ClosePopup()
|
||||
local ret = self:CallMode("CanExit", "UPDATE")
|
||||
@@ -446,7 +447,7 @@ function main:RenderCircle(x, y, width, height, oX, oY, radius)
|
||||
end
|
||||
end
|
||||
for ly = minY, maxY do
|
||||
DrawImage(nil, x + minX[ly], y + ly, maxX[ly] - minX[ly], 1)
|
||||
DrawImage(nil, x + minX[ly], y + ly, maxX[ly] - minX[ly] + 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -712,17 +712,17 @@ local specialModList = {
|
||||
["socketed gems gain (%d+)%% of physical damage as extra lightning damage"] = function(num) return { mod("PhysicalDamageGainAsLightning", "BASE", num, { type = "SocketedIn" }) } end,
|
||||
["socketed red gems get (%d+)%% physical damage as extra fire damage"] = function(num) return { mod("PhysicalDamageGainAsFire", "BASE", num, { type = "SocketedIn", keyword = "strength" }) } end,
|
||||
-- Extra skill/support
|
||||
["grants level (%d+) (.+)"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["casts level (%d+) (.+) when equipped"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["cast level (%d+) (.+) when you deal a critical strike"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["cast level (%d+) (.+) when hit"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["cast level (%d+) (.+) when you kill an enemy"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["%d+%% chance to attack with level (%d+) (.+) on melee hit"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["%d+%% chance to cast level (%d+) (.+) on hit"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["%d+%% chance to cast level (%d+) (.+) on kill"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["attack with level (%d+) (.+) when you kill a bleeding enemy"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
["curse enemies with (%D+) on %a+"] = function(_, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill] or "Unknown", level = 1, noSupports = true }, { type = "SocketedIn" }) } end,
|
||||
["curse enemies with level (%d+) (.+) on %a+"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill] or "Unknown", level = num, noSupports = true }, { type = "SocketedIn" }) } end,
|
||||
["grants level (%d+) (.+)"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["casts level (%d+) (.+) when equipped"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["cast level (%d+) (.+) when you deal a critical strike"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["cast level (%d+) (.+) when hit"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["cast level (%d+) (.+) when you kill an enemy"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["%d+%% chance to attack with level (%d+) (.+) on melee hit"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["%d+%% chance to cast level (%d+) (.+) on hit"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["%d+%% chance to cast level (%d+) (.+) on kill"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["attack with level (%d+) (.+) when you kill a bleeding enemy"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill:gsub(" skill","")] or "Unknown", level = num }) } end,
|
||||
["curse enemies with (%D+) on %a+"] = function(_, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill] or "Unknown", level = 1, noSupports = true }) } end,
|
||||
["curse enemies with level (%d+) (.+) on %a+"] = function(num, _, skill) return { mod("ExtraSkill", "LIST", { name = gemNameLookup[skill] or "Unknown", level = num, noSupports = true }) } end,
|
||||
["socketed [%a+]* ?gems a?r?e? ?supported by level (%d+) (.+)"] = function(num, _, support) return { mod("ExtraSupport", "LIST", { name = gemNameLookup[support] or gemNameLookup[support:gsub("^increased ","")] or "Unknown", level = num }, { type = "SocketedIn" }) } end,
|
||||
-- Conversion
|
||||
["increases and reductions to minion damage also affects? you"] = { flag("MinionDamageAppliesToPlayer") },
|
||||
|
||||
@@ -76,6 +76,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Classes", "Classes", "{7EE4
|
||||
Classes\ItemSlotControl.lua = Classes\ItemSlotControl.lua
|
||||
Classes\ItemsTab.lua = Classes\ItemsTab.lua
|
||||
Classes\LabelControl.lua = Classes\LabelControl.lua
|
||||
Classes\ListControl.lua = Classes\ListControl.lua
|
||||
Classes\MinionListControl.lua = Classes\MinionListControl.lua
|
||||
Classes\ModDB.lua = Classes\ModDB.lua
|
||||
Classes\ModList.lua = Classes\ModList.lua
|
||||
|
||||
@@ -53,6 +53,13 @@ If you'd like to help support the development of Path of Building, I have a [Pat
|
||||

|
||||
|
||||
## Changelog
|
||||
### 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
|
||||
* Consolidated the program's various list controls; their appearence and behaviour should be largely unchanged,
|
||||
aside from some minor enhancements
|
||||
* Various minor tweaks and fixes
|
||||
|
||||
### 1.4.10 - 2017/05/12
|
||||
* Added support for weapon swap:
|
||||
* You can switch between the two weapon sets using the new buttons above the Weapon 1 slot on the Items tab
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
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
|
||||
* Consolidated the program's various list controls; their appearence and behaviour should be largely unchanged,
|
||||
aside from some minor enhancements
|
||||
* Various minor tweaks and fixes
|
||||
VERSION[1.4.10][2017/05/12]
|
||||
* Added support for weapon swap:
|
||||
* You can switch between the two weapon sets using the new buttons above the Weapon 1 slot on the Items tab
|
||||
|
||||
51
manifest.xml
51
manifest.xml
@@ -1,64 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<PoBVersion>
|
||||
<Version number="1.4.10"/>
|
||||
<Version number="1.4.11"/>
|
||||
<Source part="program" url="https://raw.githubusercontent.com/Openarl/PathOfBuilding/{branch}/"/>
|
||||
<Source part="tree" url="https://raw.githubusercontent.com/Openarl/PathOfBuilding/{branch}/tree.zip"/>
|
||||
<Source url="https://raw.githubusercontent.com/Openarl/PathOfBuilding/{branch}/runtime-win32.zip" part="runtime" platform="win32"/>
|
||||
<File sha1="7912b22666567d5f0ff46378f5cb22e589e84efd" name="Launch.lua" part="program"/>
|
||||
<File sha1="d8e42beeb38baabcc197d658e4c0af33419eeff3" name="UpdateCheck.lua" part="program"/>
|
||||
<File sha1="4f17937f2b37784e169a3792b235f2a0a3961e61" name="UpdateApply.lua" part="program"/>
|
||||
<File sha1="735c96cf5f40f0d1b6fcf5f299d9b291cb0f3893" name="changelog.txt" part="program"/>
|
||||
<File sha1="26815100a18550b05f99cec9ca8ebff8e0e2a567" name="Classes/BuildListControl.lua" part="program"/>
|
||||
<File sha1="b0e42a8db9250e9b5be96b4471a3745f9079c9bb" name="changelog.txt" part="program"/>
|
||||
<File sha1="dd954f662b98ee5c2e5a1a3559a30a3578662188" name="Classes/BuildListControl.lua" part="program"/>
|
||||
<File sha1="dc2ffb55b4aae04b86886b25bbf219a301b21340" name="Classes/ButtonControl.lua" part="program"/>
|
||||
<File sha1="9391d403c4ad8e59fd02fba76158acb4159e0562" name="Classes/CalcBreakdownControl.lua" part="program"/>
|
||||
<File sha1="f7bced0e554bd4d99ef56bd87cf43294957cd179" name="Classes/CalcSectionControl.lua" part="program"/>
|
||||
<File sha1="125e891b36ba51345662be93e53a10d2733e63c8" name="Classes/CalcsTab.lua" part="program"/>
|
||||
<File sha1="e43c0c851f7cfb022baba23bcbdc4c96b4078a53" name="Classes/CalcsTab.lua" part="program"/>
|
||||
<File sha1="573b791867ada18da1e93de8fc33ce6cf9ec9ab3" name="Classes/CheckBoxControl.lua" part="program"/>
|
||||
<File sha1="aaf31303ab6d70877517d53db9673faa131514e3" name="Classes/ConfigTab.lua" part="program"/>
|
||||
<File sha1="4a83db8e6a6c83756795192e81c3237839ef3cb3" name="Classes/ConfigTab.lua" part="program"/>
|
||||
<File sha1="bbb08f183746d6ec023e2bd08fb7a89d365381da" name="Classes/Control.lua" part="program"/>
|
||||
<File sha1="45be3d636d1eaff18bed7095478c22abfd0590ef" name="Classes/ControlHost.lua" part="program"/>
|
||||
<File sha1="9f05f72260f896eea09c1a8fb28f58973ce4d3ff" name="Classes/DropDownControl.lua" part="program"/>
|
||||
<File sha1="4fadcbb94abdd8793c8041fab9269e0f41ebc73a" name="Classes/EditControl.lua" part="program"/>
|
||||
<File sha1="f3de897d524a19b7838ada898aae9af23d12cd21" name="Classes/GemSelectControl.lua" part="program"/>
|
||||
<File sha1="d6c2758c03ef6b052678210396d8c2f5cb7a0946" name="Classes/ImportTab.lua" part="program"/>
|
||||
<File sha1="973a8e8aef65bcaf71812707fb671ee090b67793" name="Classes/ItemDBControl.lua" part="program"/>
|
||||
<File sha1="5ecb01b4b82c19420b15a116027e00530f673045" name="Classes/ItemListControl.lua" part="program"/>
|
||||
<File sha1="bda86df3dca469c831eb6d0bc2721d73cf3096b1" name="Classes/ItemSlotControl.lua" part="program"/>
|
||||
<File sha1="9094c1f5a94d7bb919e144af6c5f939520db477b" name="Classes/ItemsTab.lua" part="program"/>
|
||||
<File sha1="7bde7b84e4925162ab869ed788c52453d7ad1c44" name="Classes/ItemDBControl.lua" part="program"/>
|
||||
<File sha1="9ddb90cd201b691298ec2fd97004f5807271b153" name="Classes/ItemListControl.lua" part="program"/>
|
||||
<File sha1="0d8d46af9ea346867e2a4f324baa835022a42267" name="Classes/ItemSlotControl.lua" part="program"/>
|
||||
<File sha1="d1d5d7a65e6c860bf112da90f5d267313b1da3d9" name="Classes/ItemsTab.lua" part="program"/>
|
||||
<File sha1="62138c7db82d57d638a16610a26acd0de75d3486" name="Classes/LabelControl.lua" part="program"/>
|
||||
<File sha1="f1b5e6a85fff1677c6cdc27a431b9ddbea21f9b4" name="Classes/MinionListControl.lua" part="program"/>
|
||||
<File sha1="91a2c0ef3e7f097f5f9ff3fd6d849ab784fbf3c2" name="Classes/ModDB.lua" part="program"/>
|
||||
<File sha1="00c1906b36492a5906d84e33966b763ac1ca88bd" name="Classes/ModList.lua" part="program"/>
|
||||
<File sha1="c0df07903c315e415fd2690763437f93aadd09f7" name="Classes/ListControl.lua" part="program"/>
|
||||
<File sha1="75c943489d007c34793f6568c28cee2bc1843e75" name="Classes/MinionListControl.lua" part="program"/>
|
||||
<File sha1="ed86df273035636fea3589ad48f9bcc18aba5346" name="Classes/ModDB.lua" part="program"/>
|
||||
<File sha1="d4911a6780f4f8cf2b30cd88565a801fa9563fef" name="Classes/ModList.lua" part="program"/>
|
||||
<File sha1="9bc0d8791e7825e52070e96e7894d29fad70cf98" name="Classes/NotesTab.lua" part="program"/>
|
||||
<File sha1="cf400bb69d6668bdb44f595572b84194ac728b72" name="Classes/PassiveSpec.lua" part="program"/>
|
||||
<File sha1="178c1dcab43b126240b029d3d29721f0af6cd84c" name="Classes/PassiveSpecListControl.lua" part="program"/>
|
||||
<File sha1="2802110b05a2ebdf39e62c1e9cfcf72d9538f359" name="Classes/PassiveSpecListControl.lua" part="program"/>
|
||||
<File sha1="bcd74b6409a4d39d27b2f4db8106daf763d97f47" name="Classes/PassiveTree.lua" part="program"/>
|
||||
<File sha1="6d0093e408730224046d4e5499e2b89bda5d6f9d" name="Classes/PassiveTreeView.lua" part="program"/>
|
||||
<File sha1="c66811dc709dc18d88ce9fcaec53161c7ca650fe" name="Classes/PassiveTreeView.lua" part="program"/>
|
||||
<File sha1="9d91ef81ac4fd8d5a1e16be17bdf199545209d87" name="Classes/PopupDialog.lua" part="program"/>
|
||||
<File sha1="86fee3127d9520144fc741f6fccc3c1d9f1aa532" name="Classes/ScrollBarControl.lua" part="program"/>
|
||||
<File sha1="261dcf54a4542e6160fd7024d8edf4fc095d9c71" name="Classes/SectionControl.lua" part="program"/>
|
||||
<File sha1="9848d55768c97c189e001014db6ce606dbed3e46" name="Classes/SkillListControl.lua" part="program"/>
|
||||
<File sha1="0dbb779f1e3f38f37645328c480942bc7a5f82f0" name="Classes/SkillsTab.lua" part="program"/>
|
||||
<File sha1="0d6551c10866549a2f808c5b11be05e2cfa70fe3" name="Classes/SkillListControl.lua" part="program"/>
|
||||
<File sha1="560bd7cfeb4b354e4b7c9b8b28862714569b0683" name="Classes/SkillsTab.lua" part="program"/>
|
||||
<File sha1="6317bd9ba391832dccafcb62409a5ce2988d1928" name="Classes/SliderControl.lua" part="program"/>
|
||||
<File sha1="ada27b91a3c466689111429105edd4ee28ad0c3f" name="Classes/TextListControl.lua" part="program"/>
|
||||
<File sha1="e3361a87d74bb7c6febad7d43c30868ab21ec1fd" name="Classes/TreeTab.lua" part="program"/>
|
||||
<File sha1="73f7b9a0657e616be4252dcc5e57e8bb057d2606" name="Classes/TreeTab.lua" part="program"/>
|
||||
<File sha1="4b7675c8b4fe71cade7dd3d70793df1ed8022d01" name="Classes/UndoHandler.lua" part="program"/>
|
||||
<File sha1="50b76f0db57d437329987ff08481ad65446129ce" name="Modules/Build.lua" part="program"/>
|
||||
<File sha1="9407e4de58446eaaa420bd5e7a324ae827a3b50a" name="Modules/BuildList.lua" part="program"/>
|
||||
<File sha1="c77abfd2020a3cec7f270ff8bbb1f1e10896c08a" name="Modules/CalcActiveSkill.lua" part="program"/>
|
||||
<File sha1="c01971cdd5bc9ed758cacdace3403bbeda71aef9" name="Modules/Build.lua" part="program"/>
|
||||
<File sha1="e5fba9a6bf560a005e7b756ac5b703e36eb8ba59" name="Modules/BuildList.lua" part="program"/>
|
||||
<File sha1="403311a61d926adb1150a75d8100032f45c2ef17" name="Modules/CalcActiveSkill.lua" part="program"/>
|
||||
<File sha1="b2b8d55258d9763d7c7a4a9ca1f99be3973528a8" name="Modules/CalcBreakdown.lua" part="program"/>
|
||||
<File sha1="8647664477fef0e771500b96342496c83ab3fe4f" name="Modules/CalcDefence.lua" part="program"/>
|
||||
<File sha1="a8758ac6817d509cc3c5913402d38fb022185651" name="Modules/CalcOffence.lua" part="program"/>
|
||||
<File sha1="a91717945f21ce2c65d12dc8e5573c7c21a2f489" name="Modules/CalcPerform.lua" part="program"/>
|
||||
<File sha1="23c918fa7005af4413a9875571fe56946c76a931" name="Modules/Calcs.lua" part="program"/>
|
||||
<File sha1="39a28dc4f69724dfda868d8253fd65943bd9e325" name="Modules/CalcSections.lua" part="program"/>
|
||||
<File sha1="54b6e97cb2fe4e7e619ce3382dd7745561e8b5b9" name="Modules/CalcSetup.lua" part="program"/>
|
||||
<File sha1="5308683d3c078886b6217418b12e6766b75623f4" name="Modules/CalcSetup.lua" part="program"/>
|
||||
<File sha1="d15500aeb71f04993850bc9401d1e20e3436c795" name="Modules/CalcTools.lua" part="program"/>
|
||||
<File sha1="1333f0be1dec8f99e971d4175574296f82691fac" name="Modules/Common.lua" part="program"/>
|
||||
<File sha1="1a3f16372f27e7b94d373e6c61affb4ebe478b13" name="Modules/Common.lua" part="program"/>
|
||||
<File sha1="b87a64e3b2d14246dcc2e19fa65bb44eed1428f8" name="Modules/Data.lua" part="program"/>
|
||||
<File sha1="a2143caa5362ecb9a85d88ba497b042269038b0a" name="Modules/ItemTools.lua" part="program"/>
|
||||
<File sha1="a739ed77abd79ef4972d6c130ba4779b45ae2191" name="Modules/Main.lua" part="program"/>
|
||||
<File sha1="0361406ebcf01f1d8f8de0f5a943d24a2886ef4c" name="Modules/ModParser.lua" part="program"/>
|
||||
<File sha1="d5d22f2fca12cd9148ec17016aa2741ee844a692" name="Modules/ItemTools.lua" part="program"/>
|
||||
<File sha1="ae4b307aceb643ac23d6fd2ea5ec02e5234a43e9" name="Modules/Main.lua" part="program"/>
|
||||
<File sha1="6f572a9c9c5b6d85739f4c0cfda8386b4874af34" name="Modules/ModParser.lua" part="program"/>
|
||||
<File sha1="08bfd94f291b10dbdc75c94d7f2928c8bbd1a1d7" name="Modules/ModTools.lua" part="program"/>
|
||||
<File sha1="c345cdcf374d271411aa424ab150c0edbb5a362d" name="Assets/game_ui_small.png" part="program"/>
|
||||
<File sha1="97b020d8213e09c313536a91528ba5d5ebc4ca0a" name="Assets/patreon_logo.png" part="program"/>
|
||||
|
||||
Reference in New Issue
Block a user