334 lines
12 KiB
Lua
334 lines
12 KiB
Lua
-- Path of Building
|
||
--
|
||
-- Module: Items
|
||
-- Items view for the active build
|
||
--
|
||
local launch, main = ...
|
||
|
||
local t_insert = table.insert
|
||
local s_format = string.format
|
||
|
||
local baseSlots = { "Helmet", "Body Armour", "Gloves", "Boots", "Amulet", "Ring 1", "Ring 2", "Belt", "Weapon 1", "Weapon 2" }
|
||
|
||
local items = { }
|
||
|
||
function items:Init(build)
|
||
self.build = build
|
||
|
||
self.list = { }
|
||
self.orderList = { }
|
||
|
||
self.slots = { }
|
||
|
||
self.controls = { }
|
||
self.controls.addDisplayItem = common.New("ButtonControl", 0, 0, 60, 20, "Add", function()
|
||
self:AddDisplayItem()
|
||
end)
|
||
for index, slotName in pairs(baseSlots) do
|
||
t_insert(self.controls, common.New("ItemSlot", self, 400, (index - 1) * 20, slotName))
|
||
end
|
||
|
||
self.sockets = { }
|
||
for _, node in pairs(main.tree.nodes) do
|
||
if node.type == "socket" then
|
||
self.sockets[node.id] = common.New("ItemSlot", self, 400, 0, "Jewel "..node.id, "Socket")
|
||
end
|
||
end
|
||
end
|
||
|
||
function items:Shutdown()
|
||
self.controls = nil
|
||
self.slots = nil
|
||
self.list = nil
|
||
end
|
||
|
||
function items:Load(xml, dbFileName)
|
||
for _, node in ipairs(xml) do
|
||
if node.elem == "Item" then
|
||
local item = { }
|
||
item.raw = ""
|
||
item.id = tonumber(node.attrib.id)
|
||
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].selItem = tonumber(node.attrib.itemId)
|
||
end
|
||
end
|
||
end
|
||
self:PopulateSlots()
|
||
end
|
||
|
||
function items:Save(xml)
|
||
self.modFlag = false
|
||
for _, id in ipairs(self.orderList) do
|
||
local item = self.list[id]
|
||
local child = { elem = "Item", attrib = { id = tostring(id) } }
|
||
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
|
||
t_insert(xml, { elem = "Slot", attrib = { name = name, itemId = tostring(slot.selItem) }})
|
||
end
|
||
end
|
||
|
||
function items:DrawItems(viewPort, inputEvents)
|
||
common.controlsInput(self, inputEvents)
|
||
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.displayItem = {
|
||
raw = newItem:gsub("^%s+",""):gsub("%s+$",""):gsub("<EFBFBD>","-"):gsub("%b<>",""):gsub("<EFBFBD>","o")
|
||
}
|
||
itemLib.parseItemRaw(self.displayItem)
|
||
if not self.displayItem.baseName then
|
||
self.displayItem = nil
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
if self.displayItem then
|
||
self.controls.addDisplayItem.x = viewPort.x + viewPort.width - 530
|
||
self.controls.addDisplayItem.y = viewPort.y + 4
|
||
self.controls.addDisplayItem.hidden = false
|
||
self.controls.addDisplayItem.label = self.list[self.displayItem.id] and "Save" or "Add"
|
||
self:AddItemTooltip(self.displayItem)
|
||
main:DrawTooltip(viewPort.x + viewPort.width - 500, viewPort.y + 28, nil, nil, viewPort, data.colorCodes[self.displayItem.rarity], true)
|
||
else
|
||
self.controls.addDisplayItem.hidden = true
|
||
end
|
||
|
||
self:UpdateJewels()
|
||
|
||
common.controlsDraw(self, viewPort)
|
||
|
||
for index, id in pairs(self.orderList) do
|
||
local item = self.list[id]
|
||
local rarityCode = data.colorCodes[item.rarity]
|
||
SetDrawColor(rarityCode)
|
||
local x = viewPort.x + 2
|
||
local y = viewPort.y + 2 + 16 * (index - 1)
|
||
DrawString(x, y, "LEFT", 16, "VAR", item.name)
|
||
local cx, cy = GetCursorPos()
|
||
if cx >= x and cx < x + 250 and cy >= y and cy < y + 16 then
|
||
self:AddItemTooltip(item)
|
||
main:DrawTooltip(x, y, 250, 16, viewPort, rarityCode, true)
|
||
end
|
||
end
|
||
end
|
||
|
||
function items:PopulateSlots()
|
||
for _, slot in pairs(self.slots) do
|
||
slot:Populate()
|
||
end
|
||
end
|
||
|
||
function items:UpdateJewels()
|
||
local spec = self.build.spec
|
||
for nodeId, slot in pairs(self.sockets) do
|
||
if not spec.allocNodes[nodeId] then
|
||
slot.inactive = true
|
||
self.controls["socket"..nodeId] = nil
|
||
end
|
||
end
|
||
local socketList = { }
|
||
for nodeId, node in pairs(spec.allocNodes) do
|
||
if node.type == "socket" then
|
||
t_insert(socketList, nodeId)
|
||
end
|
||
end
|
||
table.sort(socketList)
|
||
for index, nodeId in pairs(socketList) do
|
||
local slot = self.sockets[nodeId]
|
||
self.controls["socket"..nodeId] = slot
|
||
slot.inactive = false
|
||
slot.baseY = (#baseSlots + index - 1) * 20
|
||
end
|
||
end
|
||
|
||
function items:GetSocketJewel(nodeId)
|
||
return self.sockets[nodeId], self.list[self.sockets[nodeId].selItem]
|
||
end
|
||
|
||
function items:AddDisplayItem()
|
||
for _, item in pairs(self.list) do
|
||
if item.raw == self.displayItem.raw then
|
||
self.displayItem = nil
|
||
return
|
||
end
|
||
end
|
||
if not self.displayItem.id then
|
||
self.displayItem.id = 1
|
||
while self.list[self.displayItem.id] do
|
||
self.displayItem.id = self.displayItem.id + 1
|
||
end
|
||
t_insert(self.orderList, self.displayItem.id)
|
||
end
|
||
self.list[self.displayItem.id] = self.displayItem
|
||
self.displayItem = nil
|
||
self:PopulateSlots()
|
||
end
|
||
|
||
function items:IsItemValidForSlot(item, slotName)
|
||
if item.type == slotName:gsub(" %d+","") then
|
||
return true
|
||
elseif slotName == "Weapon 1" or slotName == "Weapon" then
|
||
return data.itemBases[item.baseName].weapon ~= nil
|
||
elseif slotName == "Weapon 2" then
|
||
local weapon1Sel = self.slots["Weapon 1"].selItem
|
||
local weapon1Type = weapon1Sel > 0 and data.itemBases[self.list[weapon1Sel].baseName].type or "None"
|
||
if 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 == "None" or (weapon1Type == "Wand" and item.type == "Wand") or (weapon1Type ~= "Wand" and item.type ~= "Wand")))
|
||
end
|
||
end
|
||
end
|
||
|
||
function items:AddItemTooltip(item)
|
||
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
|
||
local base = data.itemBases[item.baseName]
|
||
modList = item.modList
|
||
if base.weapon then
|
||
main:AddTooltipSeperator(10)
|
||
main:AddTooltipLine(16, s_format("^x7F7F7F%s", base.type))
|
||
main:AddTooltipLine(16, "^x7F7F7FQuality: "..data.colorCodes.MAGIC.."+20%")
|
||
local totalDamage = 0
|
||
local totalDamageTypes = 0
|
||
if modList.weaponX_physicalMin then
|
||
totalDamage = totalDamage + (modList.weaponX_physicalMin + modList.weaponX_physicalMax) / 2
|
||
local physicalDPS = (modList.weaponX_physicalMin + modList.weaponX_physicalMax) / 2 * modList.weaponX_attackRate
|
||
main:AddTooltipLine(16, s_format("^x7F7F7FPhysical Damage: "..data.colorCodes.MAGIC.."%d-%d (%.1f DPS)", modList.weaponX_physicalMin, modList.weaponX_physicalMax, physicalDPS))
|
||
totalDamageTypes = totalDamageTypes + 1
|
||
end
|
||
local elemLine
|
||
local elemTotal = 0
|
||
for _, var in ipairs({"fire","cold","lightning"}) do
|
||
local min = modList["weaponX_"..var.."Min"]
|
||
local max = modList["weaponX_"..var.."Max"]
|
||
if min and max then
|
||
elemLine = elemLine and elemLine.."^x7F7F7F, " or "^x7F7F7FElemental Damage: "
|
||
elemLine = elemLine..s_format("%s%d-%d", data.colorCodes[var:upper()], min, max)
|
||
elemTotal = elemTotal + (min + max) / 2
|
||
end
|
||
end
|
||
totalDamage = totalDamage + elemTotal
|
||
if elemLine then
|
||
main:AddTooltipLine(16, elemLine)
|
||
main:AddTooltipLine(16, s_format("^x7F7F7FElemental DPS: "..data.colorCodes.MAGIC.."%.1f", elemTotal * modList.weaponX_attackRate))
|
||
totalDamageTypes = totalDamageTypes + 1
|
||
end
|
||
if modList.weaponX_chaosMin then
|
||
totalDamage = totalDamage + (modList.weaponX_chaosMin + modList.weaponX_chaosMax) / 2
|
||
local chaosDPS = (modList.weaponX_chaosMin + modList.weaponX_chaosMax) / 2 * modList.weaponX_attackRate
|
||
main:AddTooltipLine(16, s_format("^x7F7F7FChaos Damage: "..data.colorCodes.CHAOS.."%d-%d "..data.colorCodes.MAGIC.."(%.1f DPS)", modList.weaponX_chaosMin, modList.weaponX_chaosMax, chaosDPS))
|
||
totalDamageTypes = totalDamageTypes + 1
|
||
end
|
||
if totalDamageTypes > 1 then
|
||
main:AddTooltipLine(16, s_format("^x7F7F7FTotal DPS: "..data.colorCodes.MAGIC.."%.1f", totalDamage * modList.weaponX_attackRate))
|
||
end
|
||
main:AddTooltipLine(16, s_format("^x7F7F7FCritical Strike Chance: %s%.2f%%", modList.weaponX_critChanceBase ~= base.weapon.critChanceBase and data.colorCodes.MAGIC or "^7", modList.weaponX_critChanceBase))
|
||
main:AddTooltipLine(16, s_format("^x7F7F7FAttacks per Second: %s%.2f", modList.weaponX_attackRate ~= base.weapon.attackRateBase and data.colorCodes.MAGIC or "^7", modList.weaponX_attackRate))
|
||
elseif base.armour then
|
||
main:AddTooltipSeperator(10)
|
||
main:AddTooltipLine(16, "^x7F7F7FQuality: "..data.colorCodes.MAGIC.."+20%")
|
||
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[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.radius then
|
||
main:AddTooltipSeperator(10)
|
||
main:AddTooltipLine(16, "^x7F7F7FRadius: ^7"..data.jewelRadius[item.radius].label)
|
||
end
|
||
if item.modLines[1] then
|
||
main:AddTooltipSeperator(10)
|
||
for index, modLine in pairs(item.modLines) do
|
||
local line = modLine.range and itemLib.applyRange(modLine.line, modLine.range) or modLine.line
|
||
main:AddTooltipLine(16, (modLine.extra and data.colorCodes.NORMAL or data.colorCodes.MAGIC)..line)
|
||
if index == item.implicitLines and item.modLines[index + 1] then
|
||
main:AddTooltipSeperator(10)
|
||
end
|
||
end
|
||
end
|
||
if item.corrupted then
|
||
if #item.modLines == item.implicitLines then
|
||
main:AddTooltipSeperator(10)
|
||
end
|
||
main:AddTooltipLine(16, "^1Corrupted")
|
||
end
|
||
self:UpdateJewels()
|
||
for slotName, slot in pairs(self.slots) do
|
||
local selItem = self.list[slot.selItem]
|
||
if items:IsItemValidForSlot(item, slotName) and not slot.inactive and (item ~= selItem or item.type == "Jewel") then
|
||
local calcFunc, calcBase = self.build.calcs:GetItemCalculator()
|
||
if calcFunc then
|
||
local output = calcFunc(slotName, item ~= selItem and item)
|
||
local header = false
|
||
for _, statData in ipairs(self.build.displayStats) do
|
||
if statData.mod then
|
||
local diff = (output[statData.mod] or 0) - (calcBase[statData.mod] or 0)
|
||
if diff > 0.001 or diff < -0.001 then
|
||
if not header then
|
||
main:AddTooltipSeperator(14)
|
||
if item == selItem then
|
||
main:AddTooltipLine(14, "^7Removing this jewel will give you:")
|
||
else
|
||
main:AddTooltipLine(14, 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
|
||
header = true
|
||
end
|
||
main:AddTooltipLine(14, string.format("%s%+"..statData.fmt.." %s", diff > 0 and "^x00FF44" or "^xFF3300", diff * (statData.pc and 100 or 1), statData.label))
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
if launch.devMode and IsKeyDown("ALT") then
|
||
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
|
||
|
||
return items |