513 lines
19 KiB
Lua
513 lines
19 KiB
Lua
-- Path of Building
|
|
--
|
|
-- Module: Items Tab
|
|
-- Items tab for the current build.
|
|
--
|
|
local launch, main = ...
|
|
|
|
local pairs = pairs
|
|
local ipairs = ipairs
|
|
local t_insert = table.insert
|
|
local t_remove = table.remove
|
|
local s_format = string.format
|
|
|
|
local baseSlots = { "Weapon 1", "Weapon 2", "Helmet", "Body Armour", "Gloves", "Boots", "Amulet", "Ring 1", "Ring 2", "Belt" }
|
|
|
|
local ItemsTabClass = common.NewClass("ItemsTab", "UndoHandler", "ControlHost", "Control", function(self, build)
|
|
self.UndoHandler()
|
|
self.ControlHost()
|
|
self.Control()
|
|
|
|
self.build = build
|
|
|
|
self.socketViewer = common.New("PassiveTreeView")
|
|
|
|
self.list = { }
|
|
self.orderList = { }
|
|
|
|
-- Item slots
|
|
self.slots = { }
|
|
for index, slotName in pairs(baseSlots) do
|
|
t_insert(self.controls, common.New("ItemSlot", {"TOPLEFT",self,"TOPLEFT"}, 100, (index - 1) * 20 + 24, self, slotName))
|
|
end
|
|
self.sockets = { }
|
|
for _, node in pairs(main.tree.nodes) do
|
|
if node.type == "socket" then
|
|
local socketControl = common.New("ItemSlot", {"TOPLEFT",self,"TOPLEFT"}, 100, 0, self, "Jewel "..node.id, "Socket", node.id)
|
|
self.controls["socket"..node.id] = socketControl
|
|
self.sockets[node.id] = socketControl
|
|
end
|
|
end
|
|
self.controls.slotHeader = common.New("LabelControl", {"BOTTOMLEFT",self.slots[baseSlots[1]],"TOPLEFT"}, 0, -4, 0, 16, "^7Equipped items:")
|
|
|
|
-- Build item list
|
|
self.controls.itemList = common.New("ItemList", {"TOPLEFT",self.slots[baseSlots[1]],"TOPRIGHT"}, 20, 0, 360, 308, self)
|
|
|
|
self.controls.selectDBLabel = common.New("LabelControl", {"TOPLEFT",self.controls.itemList,"BOTTOMLEFT"}, 0, 16, 0, 16, "^7Import from:")
|
|
self.controls.selectDB = common.New("DropDownControl", {"LEFT",self.controls.selectDBLabel,"RIGHT"}, 4, 0, 150, 18, { "Uniques", "Rare Templates" })
|
|
|
|
-- Unique database
|
|
self.controls.uniqueDB = common.New("ItemDB", {"TOPLEFT",self.controls.selectDBLabel,"BOTTOMLEFT"}, 0, 48, 360, 276, self, main.uniqueDB)
|
|
self.controls.uniqueDB.shown = function()
|
|
return self.controls.selectDB.sel == 1
|
|
end
|
|
|
|
-- Rare template database
|
|
self.controls.rareDB = common.New("ItemDB", {"TOPLEFT",self.controls.selectDBLabel,"BOTTOMLEFT"}, 0, 48, 360, 276, self, main.rareDB)
|
|
self.controls.rareDB.shown = function()
|
|
return self.controls.selectDB.sel == 2
|
|
end
|
|
|
|
-- Display item
|
|
self.controls.displayItemTip = common.New("LabelControl", {"TOPLEFT",self.controls.itemList,"TOPRIGHT"}, 20, 0, 100, 16, "^7Double-click an item from one of the lists,\nor copy and paste an item from in game\nto view/edit the item and add it to your build.")
|
|
self.controls.displayItemTip.shown = function()
|
|
return self.displayItem == nil
|
|
end
|
|
self.anchorDisplayItem = common.New("Control", {"TOPLEFT",self.controls.itemList,"TOPRIGHT"}, 20, 0, 0, 0)
|
|
self.anchorDisplayItem.shown = function()
|
|
return self.displayItem ~= nil
|
|
end
|
|
self.controls.addDisplayItem = common.New("ButtonControl", {"TOPLEFT",self.anchorDisplayItem,"TOPLEFT"}, 0, 0, 100, 20, "", function()
|
|
self:AddDisplayItem()
|
|
end)
|
|
self.controls.addDisplayItem.label = function()
|
|
return self.list[self.displayItem.id] and "Save" or "Add to build"
|
|
end
|
|
self.controls.removeDisplayItem = common.New("ButtonControl", {"LEFT",self.controls.addDisplayItem,"RIGHT"}, 8, 0, 60, 20, "Cancel", function()
|
|
self:SetDisplayItem()
|
|
end)
|
|
self.controls.displayItemVariant = common.New("DropDownControl", {"LEFT",self.controls.removeDisplayItem,"RIGHT"}, 8, 0, 200, 20, nil, function(sel)
|
|
self.displayItem.variant = sel
|
|
itemLib.buildItemModList(self.displayItem)
|
|
self:UpdateDisplayItemRangeLines()
|
|
end)
|
|
self.controls.displayItemVariant.shown = function()
|
|
return self.displayItem.variantList and #self.displayItem.variantList > 1
|
|
end
|
|
self.controls.displayItemRangeLine = common.New("DropDownControl", {"TOPLEFT",self.controls.addDisplayItem,"BOTTOMLEFT"}, 0, 8, 400, 18, nil, function(sel)
|
|
self.controls.displayItemRangeSlider.val = self.displayItem.rangeLineList[sel].range
|
|
end)
|
|
self.controls.displayItemRangeLine.shown = function()
|
|
return self.displayItem.rangeLineList[1] ~= nil
|
|
end
|
|
self.controls.displayItemRangeSlider = common.New("SliderControl", {"LEFT",self.controls.displayItemRangeLine,"RIGHT"}, 8, 0, 100, 18, function(val)
|
|
self.displayItem.rangeLineList[self.controls.displayItemRangeLine.sel].range = val
|
|
itemLib.buildItemModList(self.displayItem)
|
|
end)
|
|
end)
|
|
|
|
function ItemsTabClass:Load(xml, dbFileName)
|
|
for _, node in ipairs(xml) do
|
|
if node.elem == "Item" then
|
|
local item = { }
|
|
item.raw = ""
|
|
item.id = tonumber(node.attrib.id)
|
|
item.variant = tonumber(node.attrib.variant)
|
|
itemLib.parseItemRaw(item)
|
|
for _, child in ipairs(node) do
|
|
if type(child) == "string" then
|
|
item.raw = child
|
|
itemLib.parseItemRaw(item)
|
|
elseif child.elem == "ModRange" then
|
|
local id = tonumber(child.attrib.id) or 0
|
|
local range = tonumber(child.attrib.range) or 1
|
|
if item.modLines[id] then
|
|
item.modLines[id].range = range
|
|
end
|
|
end
|
|
end
|
|
itemLib.buildItemModList(item)
|
|
self.list[item.id] = item
|
|
t_insert(self.orderList, item.id)
|
|
elseif node.elem == "Slot" then
|
|
if self.slots[node.attrib.name or ""] then
|
|
self.slots[node.attrib.name].selItemId = tonumber(node.attrib.itemId)
|
|
end
|
|
end
|
|
end
|
|
self:ResetUndo()
|
|
self:PopulateSlots()
|
|
end
|
|
|
|
function ItemsTabClass:Save(xml)
|
|
for _, id in ipairs(self.orderList) do
|
|
local item = self.list[id]
|
|
local child = { elem = "Item", attrib = { id = tostring(id), variant = item.variant and tostring(item.variant) } }
|
|
t_insert(child, item.raw)
|
|
for id, modLine in ipairs(item.modLines) do
|
|
if modLine.range then
|
|
t_insert(child, { elem = "ModRange", attrib = { id = tostring(id), range = tostring(modLine.range) } })
|
|
end
|
|
end
|
|
t_insert(xml, child)
|
|
end
|
|
for name, slot in pairs(self.slots) do
|
|
if slot.selItemId ~= 0 then
|
|
t_insert(xml, { elem = "Slot", attrib = { name = name, itemId = tostring(slot.selItemId) }})
|
|
end
|
|
end
|
|
self.modFlag = false
|
|
end
|
|
|
|
function ItemsTabClass:Draw(viewPort, inputEvents)
|
|
self.x = viewPort.x
|
|
self.y = viewPort.y
|
|
self.width = viewPort.width
|
|
self.height = viewPort.height
|
|
|
|
for id, event in ipairs(inputEvents) do
|
|
if event.type == "KeyDown" then
|
|
if event.key == "v" and IsKeyDown("CTRL") then
|
|
local newItem = Paste()
|
|
if newItem then
|
|
self:CreateDisplayItemFromRaw(newItem)
|
|
end
|
|
elseif event.key == "z" and IsKeyDown("CTRL") then
|
|
self:Undo()
|
|
self.build.buildFlag = true
|
|
elseif event.key == "y" and IsKeyDown("CTRL") then
|
|
self:Redo()
|
|
self.build.buildFlag = true
|
|
end
|
|
end
|
|
end
|
|
self:ProcessControlsInput(inputEvents)
|
|
|
|
main:DrawBackground(viewPort)
|
|
|
|
if self.displayItem then
|
|
local extraOffset = self.controls.displayItemRangeLine:IsShown() and 26 or 0
|
|
self:AddItemTooltip(self.displayItem)
|
|
local baseX, baseY = self.anchorDisplayItem:GetPos()
|
|
main:DrawTooltip(baseX, baseY + 28 + extraOffset, nil, nil, viewPort, data.colorCodes[self.displayItem.rarity])
|
|
end
|
|
|
|
self:UpdateSockets()
|
|
|
|
self:DrawControls(viewPort)
|
|
end
|
|
|
|
-- Update the item lists for all the slot controls
|
|
function ItemsTabClass:PopulateSlots()
|
|
for _, slot in pairs(self.slots) do
|
|
slot:Populate()
|
|
end
|
|
end
|
|
|
|
-- Updates the status and position of the socket controls
|
|
function ItemsTabClass:UpdateSockets()
|
|
-- Build a list of active sockets
|
|
local activeSocketList = { }
|
|
for nodeId, slot in pairs(self.sockets) do
|
|
if self.build.spec.allocNodes[nodeId] then
|
|
t_insert(activeSocketList, nodeId)
|
|
slot.inactive = false
|
|
else
|
|
slot.inactive = true
|
|
end
|
|
end
|
|
table.sort(activeSocketList)
|
|
|
|
-- Update the position of the active socket controls
|
|
for index, nodeId in pairs(activeSocketList) do
|
|
self.sockets[nodeId].y = (#baseSlots + index - 1) * 20 + 24
|
|
end
|
|
end
|
|
|
|
-- Returns the slot control and equipped jewel for the given node ID
|
|
function ItemsTabClass:GetSocketAndJewelForNodeID(nodeId)
|
|
return self.sockets[nodeId], self.list[self.sockets[nodeId].selItemId]
|
|
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)
|
|
local newItem = itemLib.makeItemFromRaw(itemRaw)
|
|
if newItem then
|
|
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()
|
|
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 current display item to the build's item list
|
|
function ItemsTabClass:AddDisplayItem()
|
|
if not self.displayItem.id then
|
|
-- Find an unused item ID
|
|
self.displayItem.id = 1
|
|
while self.list[self.displayItem.id] do
|
|
self.displayItem.id = self.displayItem.id + 1
|
|
end
|
|
|
|
-- Add it to the end of the display order list
|
|
t_insert(self.orderList, self.displayItem.id)
|
|
end
|
|
|
|
-- Add it to the list and clear the current display item
|
|
self.list[self.displayItem.id] = self.displayItem
|
|
self:SetDisplayItem()
|
|
|
|
self:PopulateSlots()
|
|
self:AddUndoState()
|
|
end
|
|
|
|
function ItemsTabClass:DeleteItem(item)
|
|
for _, slot in pairs(self.slots) do
|
|
if slot.selItemId == item.id then
|
|
slot.selItemId = 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
|
|
self.list[item.id] = nil
|
|
self:PopulateSlots()
|
|
self:AddUndoState()
|
|
end
|
|
|
|
-- Returns a slot in which the given item is equipped, if one exists
|
|
-- If the item is equipped in multiple slots, the return value may be any of those slots
|
|
function ItemsTabClass:GetEquippedSlotForItem(item)
|
|
for _, slot in pairs(self.slots) 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" then
|
|
return item.base.weapon ~= nil
|
|
elseif slotName == "Weapon 2" then
|
|
local weapon1Sel = self.slots["Weapon 1"].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]
|
|
if item.title then
|
|
main:AddTooltipLine(20, rarityCode..item.title)
|
|
main:AddTooltipLine(20, rarityCode..item.baseName)
|
|
else
|
|
main:AddTooltipLine(20, rarityCode..item.name)
|
|
end
|
|
main:AddTooltipSeperator(10)
|
|
|
|
-- Special fields for database items
|
|
if dbMode and (item.variantList or item.league or item.unreleased) then
|
|
if item.variantList then
|
|
if #item.variantList == 1 then
|
|
main:AddTooltipLine(16, "^xFFFF30Variant: "..item.variantList[1])
|
|
else
|
|
main:AddTooltipLine(16, "^xFFFF30Variant: "..item.variantList[item.variant].." ("..#item.variantList.." variants)")
|
|
end
|
|
end
|
|
if item.league then
|
|
main:AddTooltipLine(16, "^xFF5555Exclusive to: "..item.league)
|
|
end
|
|
if item.unreleased then
|
|
main:AddTooltipLine(16, "^1Not yet available")
|
|
end
|
|
main:AddTooltipSeperator(10)
|
|
end
|
|
|
|
local base = item.base
|
|
local slotNum = slot and slot.slotNum or (IsKeyDown("SHIFT") and 2 or 1)
|
|
local modList = item.modList or item.slotModList[slotNum]
|
|
if base.weapon then
|
|
-- Weapon-specific info
|
|
local weaponPrefix = "weapon"..slotNum.."_"
|
|
main:AddTooltipLine(16, s_format("^x7F7F7F%s", base.type))
|
|
if item.quality > 0 then
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FQuality: "..data.colorCodes.MAGIC.."+%d%%", item.quality))
|
|
end
|
|
local totalDamageTypes = 0
|
|
if modList[weaponPrefix.."physicalDPS"] then
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FPhysical Damage: "..data.colorCodes.MAGIC.."%d-%d (%.1f DPS)", modList[weaponPrefix.."physicalMin"], modList[weaponPrefix.."physicalMax"], modList[weaponPrefix.."physicalDPS"]))
|
|
totalDamageTypes = totalDamageTypes + 1
|
|
end
|
|
if modList[weaponPrefix.."elementalDPS"] then
|
|
local elemLine
|
|
for _, var in ipairs({"fire","cold","lightning"}) do
|
|
if modList[weaponPrefix..var.."DPS"] then
|
|
elemLine = elemLine and elemLine.."^x7F7F7F, " or "^x7F7F7FElemental Damage: "
|
|
elemLine = elemLine..s_format("%s%d-%d", data.colorCodes[var:upper()], modList[weaponPrefix..var.."Min"], modList[weaponPrefix..var.."Max"])
|
|
end
|
|
end
|
|
main:AddTooltipLine(16, elemLine)
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FElemental DPS: "..data.colorCodes.MAGIC.."%.1f", modList[weaponPrefix.."elementalDPS"]))
|
|
totalDamageTypes = totalDamageTypes + 1
|
|
end
|
|
if modList[weaponPrefix.."chaosDPS"] then
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FChaos Damage: "..data.colorCodes.CHAOS.."%d-%d "..data.colorCodes.MAGIC.."(%.1f DPS)", modList[weaponPrefix.."chaosMin"], modList[weaponPrefix.."chaosMax"], modList[weaponPrefix.."chaosDPS"]))
|
|
totalDamageTypes = totalDamageTypes + 1
|
|
end
|
|
if totalDamageTypes > 1 then
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FTotal DPS: "..data.colorCodes.MAGIC.."%.1f", modList[weaponPrefix.."damageDPS"]))
|
|
end
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FCritical Strike Chance: %s%.2f%%", modList[weaponPrefix.."critChanceBase"] ~= base.weapon.critChanceBase and data.colorCodes.MAGIC or "^7", modList[weaponPrefix.."critChanceBase"]))
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FAttacks per Second: %s%.2f", modList[weaponPrefix.."ttackRate"] ~= base.weapon.attackRateBase and data.colorCodes.MAGIC or "^7", modList[weaponPrefix.."attackRate"]))
|
|
elseif base.armour then
|
|
-- Armour-specific info
|
|
if item.quality > 0 then
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FQuality: "..data.colorCodes.MAGIC.."+%d%%", item.quality))
|
|
end
|
|
if base.armour.blockChance and modList.blockChance > 0 then
|
|
main:AddTooltipLine(16, s_format("^x7F7F7FChance to Block: %s%d%%", modList.blockChance ~= base.armour.blockChance and data.colorCodes.MAGIC or "^7", modList.blockChance))
|
|
end
|
|
for _, def in ipairs({{var="armour",label="Armour"},{var="evasion",label="Evasion Rating"},{var="energyShield",label="Energy Shield"}}) do
|
|
local itemVal = modList["slot:"..base.type.."_"..def.var.."Base"]
|
|
if itemVal then
|
|
main:AddTooltipLine(16, s_format("^x7F7F7F%s: %s%d", def.label, itemVal ~= base.armour[def.var.."Base"] and data.colorCodes.MAGIC or "^7", itemVal))
|
|
end
|
|
end
|
|
elseif item.type == "Jewel" then
|
|
-- Jewel-specific info
|
|
if item.jewelRadiusIndex then
|
|
main:AddTooltipLine(16, "^x7F7F7FRadius: ^7"..data.jewelRadius[item.jewelRadiusIndex].label)
|
|
end
|
|
if item.limit then
|
|
main:AddTooltipLine(16, "^x7F7F7FLimited to: ^7"..item.limit)
|
|
end
|
|
end
|
|
main:AddTooltipSeperator(10)
|
|
|
|
-- Implicit/explicit modifiers
|
|
if item.modLines[1] then
|
|
for index, modLine in pairs(item.modLines) do
|
|
if not modLine.variantList or modLine.variantList[item.variant] then
|
|
local line = (not dbMode and modLine.range and itemLib.applyRange(modLine.line, modLine.range)) or modLine.line
|
|
if not line:match("^%+?0[^%.]") and not line:match(" 0%-0 ") then -- Hack to hide 0-value modifiers
|
|
main:AddTooltipLine(16, (modLine.extra and data.colorCodes.NORMAL or data.colorCodes.MAGIC)..line)
|
|
end
|
|
end
|
|
if index == item.implicitLines and item.modLines[index + 1] then
|
|
-- Add seperator between implicit and explicit modifiers
|
|
main:AddTooltipSeperator(10)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Corrupted item label
|
|
if item.corrupted then
|
|
if #item.modLines == item.implicitLines then
|
|
main:AddTooltipSeperator(10)
|
|
end
|
|
main:AddTooltipLine(16, "^1Corrupted")
|
|
end
|
|
main:AddTooltipSeperator(14)
|
|
|
|
-- Mod differences
|
|
local calcFunc, calcBase = self.build.calcsTab:GetItemCalculator()
|
|
if calcFunc then
|
|
self:UpdateSockets()
|
|
-- Build sorted list of slots to compare with
|
|
local compareSlots = { }
|
|
for slotName, slot in pairs(self.slots) do
|
|
local selItem = self.list[slot.selItemId]
|
|
if self:IsItemValidForSlot(item, slotName) and not slot.inactive and (item ~= selItem or item.type == "Jewel") then
|
|
t_insert(compareSlots, slot)
|
|
end
|
|
end
|
|
table.sort(compareSlots, function(a, b)
|
|
if a.selItemId ~= b.selItemId then
|
|
if item == self.list[a.selItemId] then
|
|
return true
|
|
elseif item == self.list[b.selItemId] then
|
|
return false
|
|
end
|
|
end
|
|
local aNum = tonumber(a.slotName:match("%d+"))
|
|
local bNum = tonumber(b.slotName:match("%d+"))
|
|
if aNum and bNum then
|
|
return aNum < bNum
|
|
else
|
|
return a.slotName < b.slotName
|
|
end
|
|
end)
|
|
|
|
-- Add comparisons for each slot
|
|
for _, slot in pairs(compareSlots) do
|
|
local selItem = self.list[slot.selItemId]
|
|
local output = calcFunc(slot.slotName, item ~= selItem and item)
|
|
local header
|
|
if item == selItem then
|
|
header = "^7Removing this jewel will give you:"
|
|
else
|
|
header = string.format("^7Equipping this item in %s%s will give you:", slot.label, selItem and " (replacing "..data.colorCodes[selItem.rarity]..selItem.name.."^7)" or "")
|
|
end
|
|
self.build:AddStatComparesToTooltip(calcBase, output, header)
|
|
end
|
|
end
|
|
|
|
if launch.devMode and IsKeyDown("ALT") then
|
|
-- Modifier debugging info
|
|
main:AddTooltipSeperator(10)
|
|
local nameList = { }
|
|
for k in pairs(modList) do
|
|
t_insert(nameList, k)
|
|
end
|
|
table.sort(nameList)
|
|
for _, name in ipairs(nameList) do
|
|
main:AddTooltipLine(16, "^7"..name.." = "..tostring(modList[name]))
|
|
end
|
|
end
|
|
end
|
|
|
|
function ItemsTabClass:CreateUndoState()
|
|
local state = { }
|
|
state.list = copyTable(self.list)
|
|
state.orderList = copyTable(self.orderList)
|
|
state.slotSelItemId = { }
|
|
for slotName, slot in pairs(self.slots) do
|
|
state.slotSelItemId[slotName] = slot.selItemId
|
|
end
|
|
return state
|
|
end
|
|
|
|
function ItemsTabClass:RestoreUndoState(state)
|
|
self.list = state.list
|
|
self.orderList = state.orderList
|
|
for slotName, selItemId in pairs(state.slotSelItemId) do
|
|
self.slots[slotName].selItemId = selItemId
|
|
end
|
|
self:PopulateSlots()
|
|
end
|