Nenue@97: -- Veneer Nenue@97: -- ArtifactPower.lua Nenue@97: -- Created: 1/15/2017 11:44 PM Nenue@97: -- %file-revision% Nenue@97: -- Nenue@97: Nenue@97: local print = DEVIAN_WORKSPACE and function(...) print('VnAP', ...) end or nop Nenue@97: VeneerArtifactPowerMixin = { Nenue@97: Nenue@97: anchorPoint = 'TOP', Nenue@97: anchorFrom = 'TOP', Nenue@97: } Nenue@97: local ap = VeneerArtifactPowerMixin Nenue@97: local BAGS_TO_SCAN = {BACKPACK_CONTAINER } Nenue@97: local TOOLTIP_NAME = 'VeneerAPScanner' Nenue@98: local POINT_COSTS = { Nenue@98: 100, 300, 325, 350, 375, Nenue@98: 400, 425, 450, 525, 625, Nenue@98: 750, 875, 1000, 6840, 8830, Nenue@98: 11280, 14400, 18620, 24000, 30600, Nenue@98: 39520, 50880, 64800, 82500, 105280, Nenue@98: 138650, 182780, 240870, 325520, 417560, Nenue@98: 546000, 718200, 946660, 1245840, 1635200, Nenue@98: 191500, 2010000, 2110000, 2215000, 2325000, Nenue@98: 2440000, 2560000, 2690000, 2825000, 2965000, Nenue@98: 3115000, 3270000, 3435000, 3605000, 3785000, Nenue@98: 3975000, 4175000, 4385000, 4605000 Nenue@98: } Nenue@97: Nenue@97: function ap:OnLoad() Nenue@97: self:RegisterEvent('BAG_UPDATE') -- use to obtain bag IDs to scan Nenue@97: self:RegisterEvent('BAG_UPDATE_DELAYED') -- use to trigger actual scan activity Nenue@97: self:RegisterEvent('BANKFRAME_OPENED') -- determine when bank info is available Nenue@97: self:RegisterEvent('BANKFRAME_CLOSED') -- " " " Nenue@97: self:RegisterEvent('ARTIFACT_UPDATE') -- when artifact data has changed Nenue@98: self:RegisterEvent('ARTIFACT_XP_UPDATE') -- when artifact xp has changed (but not necessarily data) Nenue@97: self:RegisterEvent('MODIFIER_STATE_CHANGED') Nenue@97: self:RegisterEvent('PLAYER_REGEN_ENABLED') Nenue@97: self:RegisterEvent('PLAYER_REGEN_DISABLED') Nenue@97: Veneer:AddHandler(self, self.anchorPoint, true) Nenue@97: SLASH_VENEER_AP1 = "/vap" Nenue@97: SLASH_VENEER_AP2 = "/veneerap" Nenue@98: SlashCmdList.VENEER_AP = function(arg) Nenue@98: if arg == 'fishing' then Nenue@98: if VeneerData.ArtifactPower.EnableFishing then Nenue@98: VeneerData.ArtifactPower.EnableFishing = nil Nenue@98: else Nenue@98: VeneerData.ArtifactPower.EnableFishing = true Nenue@98: end Nenue@98: self:Print('Show Underlight Angler:', (VeneerData.ArtifactPower.EnableFishing and 'ON' or 'OFF')) Nenue@98: self:Update() Nenue@98: Nenue@98: else Nenue@98: self:Show() Nenue@98: end Nenue@97: end Nenue@97: Nenue@97: self.tooltip = CreateFrame('GameTooltip', TOOLTIP_NAME, self, 'GameTooltipTemplate') Nenue@97: Nenue@97: end Nenue@97: Nenue@97: local defaultSettings = { Nenue@97: } Nenue@97: Nenue@97: function ap:Setup() Nenue@97: print(self:GetName()..':Setup()') Nenue@97: local guid = UnitGUID('player') Nenue@97: VeneerData.ArtifactPower = VeneerData.ArtifactPower or defaultSettings Nenue@97: VeneerData.ArtifactPower[guid] = VeneerData.ArtifactPower[guid] or {} Nenue@97: self.profile = VeneerData.ArtifactPower[guid] Nenue@97: self.profile.bagslots = self.profile.bagslots or {} Nenue@97: self.profile.artifacts = self.profile.artifacts or {} Nenue@97: self.updateSummary = true Nenue@97: Nenue@97: -- Bagnon compatibility Nenue@97: -- todo: ArkInventory, Elv, etc Nenue@97: if IsAddOnLoaded('Bagnon') then Nenue@97: local oToggleAllBags = ToggleAllBags Nenue@97: ToggleAllBags = function() Nenue@97: print('|cFFFF0088ToggleAllBags') Nenue@97: oToggleAllBags() Nenue@97: if BagnonFrameinventory:IsShown() then Nenue@97: self:Show() Nenue@97: else Nenue@97: self.enabled = nil Nenue@97: self:Hide() Nenue@97: end Nenue@97: end Nenue@97: else Nenue@97: hooksecurefunc("OpenBackpack", function() Nenue@97: self:Show() Nenue@97: end) Nenue@97: hooksecurefunc("CloseBackpack", function() Nenue@97: self.enabled = nil Nenue@97: self:Hide() Nenue@97: end) Nenue@97: end Nenue@97: Nenue@97: Nenue@97: end Nenue@97: local UNDERLIGHT_ANGLER_ID = 133755 Nenue@98: function ap:SetArtifact(itemID, name, texture, currentXP, pointsSpent) Nenue@98: print('|cFF00FF00SetArtifact()|r') Nenue@97: if not self.profile then Nenue@97: return Nenue@97: end Nenue@97: local artifacts = self.profile.artifacts Nenue@97: Nenue@97: Nenue@97: if itemID then Nenue@98: artifacts[itemID] = artifacts[itemID] or {} Nenue@98: table.wipe(artifacts[itemID]) Nenue@98: local artifact = artifacts[itemID] Nenue@97: Nenue@98: artifact.name = name Nenue@98: artifact.texture = texture Nenue@98: artifact.currentXP = currentXP Nenue@98: artifact.level = pointsSpent Nenue@98: local cost = C_ArtifactUI.GetCostForPointAtRank(pointsSpent) Nenue@98: artifact.cost = cost Nenue@97: Nenue@98: local pointsAvailable = pointsSpent Nenue@98: local actualCost = cost Nenue@98: local actualXP = currentXP Nenue@98: while actualXP >= actualCost do Nenue@98: pointsAvailable = pointsAvailable + 1 Nenue@98: actualXP = actualXP - actualCost Nenue@98: print(pointsAvailable, '-', actualCost, '=', actualXP) Nenue@98: actualCost = C_ArtifactUI.GetCostForPointAtRank(pointsAvailable) Nenue@98: end Nenue@98: print('updating', itemID, name, currentXP, pointsSpent, pointsAvailable, actualXP) Nenue@98: artifact.actualXP = actualXP Nenue@98: artifact.actualLevel = pointsAvailable Nenue@98: artifact.actualCost = actualCost Nenue@97: Nenue@97: end Nenue@97: end Nenue@97: function ap:QueueBag(containerID) Nenue@97: containerID = tonumber(containerID) Nenue@97: if not containerID then Nenue@97: return Nenue@97: end Nenue@97: Nenue@97: if not tContains(BAGS_TO_SCAN, containerID) then Nenue@97: print(' queueing', containerID, type(containerID), #BAGS_TO_SCAN , 'in line') Nenue@97: BAGS_TO_SCAN[#BAGS_TO_SCAN + 1] = containerID Nenue@97: end Nenue@97: end Nenue@97: Nenue@97: function ap:OnShow() Nenue@97: self.enabled = true Nenue@97: self:Update() Nenue@97: Veneer:DynamicReanchor() Nenue@97: end Nenue@97: function ap:OnHide() Nenue@97: Veneer:DynamicReanchor() Nenue@97: end Nenue@97: Nenue@97: function ap:OnEnter() Nenue@97: Nenue@97: GameTooltip:SetOwner(self, 'ANCHOR_CURSOR') Nenue@97: Nenue@97: GameTooltip:AddLine(self.bagAP) Nenue@97: GameTooltip:AddLine(self.bankAP) Nenue@97: Nenue@97: end Nenue@97: Nenue@97: function ap:OnEvent(event, ...) Nenue@97: print(self:GetName()..':OnEvent()', event, ...) Nenue@97: if event == 'BAG_UPDATE' then Nenue@97: local containerID = ... Nenue@97: self:QueueBag(containerID) Nenue@97: elseif event == 'PLAYER_BANKSLOTS_CHANGED' then Nenue@98: self:ScanAllBags(true) Nenue@98: self:Update() Nenue@97: elseif event == 'BAG_UPDATE_DELAYED' then Nenue@98: self:ScanAllBags(self.bankAccess) Nenue@97: elseif event == 'BANKFRAME_OPENED' then Nenue@97: self.bankAccess = true Nenue@98: self:ScanAllBags(true) Nenue@97: elseif event == 'BANKFRAME_CLOSED' then Nenue@97: self.bankAccess = false Nenue@97: elseif event == 'ARTIFACT_UPDATE' then Nenue@98: local newItem = ... Nenue@98: if newItem then Nenue@98: local itemID, _, name, texture, currentXP, pointsSpent = C_ArtifactUI:GetArtifactInfo() Nenue@98: self:SetArtifact(itemID, name, texture, currentXP, pointsSpent) Nenue@98: self:ScanAllBags(self.bankAccess) Nenue@98: end Nenue@98: elseif event == 'ARTIFACT_XP_UPDATE' then Nenue@98: local itemID, _, name, texture, currentXP, pointsSpent = C_ArtifactUI:GetEquippedArtifactInfo() Nenue@98: self:SetArtifact(itemID, name, texture, currentXP, pointsSpent) Nenue@98: self:ScanAllBags(self.bankAccess) Nenue@97: elseif event == 'PLAYER_REGEN_ENABLED' then Nenue@97: if self.enabled then Nenue@97: self:Show() Nenue@97: end Nenue@97: Nenue@97: elseif event == 'PLAYER_REGEN_DISABLED' then Nenue@97: self:Hide() Nenue@97: end Nenue@97: end Nenue@97: Nenue@97: function ap:OnMouseDown() Nenue@97: self.enabled = nil Nenue@97: self:Hide() Nenue@97: end Nenue@97: Nenue@97: function ap:Update() Nenue@97: if not self:IsShown() then Nenue@97: return Nenue@97: end Nenue@97: print('|cFF00FFFFUpdate()|r') Nenue@97: Nenue@97: local bankText, bagText Nenue@97: if not (self.bankAP and self.bagAP) then Nenue@97: bankText = '|cFFFF0000Open bank frame to count all AP|r ' Nenue@97: else Nenue@98: if (self.bagAP + self.bankAP) == 0 then Nenue@98: bankText = '|cFF00FFFFNo Items|r' Nenue@98: else Nenue@98: if self.bagAP and (self.bagAP > 0) then Nenue@98: bankText = '|cFFFFFFFF' .. tostring(self.bagAP) .. '|r' Nenue@98: end Nenue@98: if self.bankAP and (self.bankAP > 0) then Nenue@98: bankText = (bankText and (bankText .. ' | ') or '') .. '|cFFFFFF00'..tostring(self.bankAP)..'|r' Nenue@98: end Nenue@98: end Nenue@97: end Nenue@97: self.SummaryHeader:SetText(bankText) Nenue@97: Nenue@97: -- Artifact icons, in no particular order Nenue@97: local equippedID = C_ArtifactUI.GetEquippedArtifactInfo() Nenue@97: local numButtons = 0 Nenue@97: local lastFrame Nenue@98: local fishingRod, fishingID, fishingData Nenue@98: local index, button Nenue@97: for itemID, artifact in pairs(self.profile.artifacts) do Nenue@98: local isFishingRod = (itemID == UNDERLIGHT_ANGLER_ID) Nenue@98: if isFishingRod then Nenue@98: if VeneerData.ArtifactPower.EnableFishing then Nenue@98: fishingID = itemID Nenue@98: fishingData = artifact Nenue@98: end Nenue@97: Nenue@98: else Nenue@98: numButtons = numButtons + 1 Nenue@98: button = self.Artifact[numButtons] Nenue@98: lastFrame = button:SetButton(itemID, artifact, lastFrame) Nenue@97: end Nenue@97: Nenue@98: end Nenue@97: Nenue@98: if fishingData then Nenue@98: numButtons = numButtons + 1 Nenue@98: local button = self.Artifact[GetNumSpecializations()+1] Nenue@98: button:SetButton(fishingID, fishingData, lastFrame) Nenue@98: end Nenue@97: Nenue@98: for i = numButtons+ (fishingRod and 2 or 1), #self.Artifact do Nenue@97: print('hide', i) Nenue@97: self.Artifact[i]:Hide() Nenue@97: end Nenue@97: Nenue@97: Nenue@97: Nenue@98: self:SetWidth(64*numButtons + 4 * (numButtons+1)) Nenue@98: self:SetHeight(12 + self.SummaryHeader:GetHeight() + 64) Nenue@97: self:Reanchor() Nenue@97: Nenue@97: end Nenue@97: Nenue@97: function ap:ScanBag(id) Nenue@97: print('|cFF00FFFFScanBag()|r', id, IsBagOpen(id), GetContainerNumSlots(id)) Nenue@97: local numSlots = GetContainerNumSlots(id) Nenue@97: local requiresUpdate Nenue@97: if numSlots == 0 then Nenue@97: return nil Nenue@97: end Nenue@97: Nenue@97: Nenue@97: self.profile.bagslots[id] = self.profile.bagslots[id] or {} Nenue@97: table.wipe(self.profile.bagslots[id]) Nenue@97: local bagData = self.profile.bagslots[id] Nenue@97: bagData.totalAP = 0 Nenue@97: for slotID = 1, numSlots do Nenue@97: local texture, count, locked, quality, readable, lootable, link = GetContainerItemInfo(id, slotID) Nenue@97: local itemID = GetContainerItemID(id, slotID) Nenue@97: Nenue@97: if link then Nenue@97: self.tooltip:SetOwner(self, 'ANCHOR_NONE') Nenue@97: self.tooltip:SetHyperlink(link) Nenue@97: self.tooltip:Show() Nenue@97: local numLines = self.tooltip:NumLines() Nenue@97: if numLines >= 3 then Nenue@97: local subText = _G[TOOLTIP_NAME .. 'TextLeft2']:GetText() Nenue@97: if subText and subText:match(ARTIFACT_POWER) then Nenue@97: for i = 3, numLines do Nenue@97: local text = _G[TOOLTIP_NAME .. 'TextLeft'.. i]:GetText() Nenue@97: if text and text:match(ARTIFACT_POWER) then Nenue@97: text = text:gsub('[,%D]', '') Nenue@97: print(link, '-', tonumber(text)) Nenue@97: local itemAP = tonumber(text) Nenue@97: if itemAP then Nenue@98: requiresUpdate = true Nenue@97: bagData.numItems = (bagData.numItems or 0) + 1 Nenue@97: bagData.totalAP = (bagData.totalAP or 0) + itemAP Nenue@97: bagData.items = bagData.items or {} Nenue@97: if not bagData.items[itemID] then Nenue@97: bagData.numUnique = (bagData.numUnique or 0) + 1 Nenue@97: end Nenue@97: bagData.items[itemID] = (bagData.items[itemAP] or 0) + 1 Nenue@97: end Nenue@97: end Nenue@97: end Nenue@97: end Nenue@97: end Nenue@97: end Nenue@97: Nenue@97: if self.profile.artifacts[itemID] then Nenue@97: print('artfiact weapon', itemID, link, id, slotID) Nenue@97: self.profile.artifacts[itemID].containerID = id Nenue@97: self.profile.artifacts[itemID].slotID = slotID Nenue@97: end Nenue@97: Nenue@97: end Nenue@97: Nenue@97: end Nenue@97: Nenue@98: local BAG_SLOTS = {0, 1, 2, 3, 4 } Nenue@98: local BANK_SLOTS = {-1, 5, 6,7, 8, 9, 10, 11, 12} Nenue@98: Nenue@98: function ap:ScanAllBags(checkBank) Nenue@97: print('|cFFFF0088ScanAllBags()|r') Nenue@97: Nenue@98: for _, bagID in ipairs(BAG_SLOTS) do Nenue@98: self:ScanBag(bagID) Nenue@97: end Nenue@97: Nenue@98: if checkBank then Nenue@98: for _, bagID in ipairs(BANK_SLOTS) do Nenue@98: self:ScanBag(bagID) Nenue@98: end Nenue@98: end Nenue@98: Nenue@98: self.bankAP = 0 Nenue@98: self.bagAP = 0 Nenue@98: for id, bagData in pairs(self.profile.bagslots) do Nenue@98: print(id, GetBagName(id), bagData.totalAP) Nenue@98: id = tonumber(id) Nenue@98: if bagData.totalAP then Nenue@98: if (id == BANK_CONTAINER) or (id >= 5) then Nenue@98: self.bankAP = self.bankAP + bagData.totalAP Nenue@98: else Nenue@98: self.bagAP = self.bagAP + bagData.totalAP Nenue@97: end Nenue@98: end Nenue@97: Nenue@97: end Nenue@98: self.lastUpdate = GetTime() Nenue@98: self:Update() Nenue@97: self.updateSummary = nil Nenue@97: end Nenue@97: Nenue@97: VeneerArtifactButtonMixin = {} Nenue@98: Nenue@98: function VeneerArtifactButtonMixin:SetButton(itemID, artifact, lastFrame) Nenue@98: print(artifact.name, artifact.texture, artifact.currentXP) Nenue@98: self:SetID(itemID) Nenue@98: for k,v in pairs(artifact) do Nenue@98: --print('::',k,v) Nenue@98: self[k] = v Nenue@98: end Nenue@98: Nenue@98: -- this can change between artifact parses Nenue@98: local potentialPoints = self.actualLevel Nenue@98: local totalAP = (itemID == UNDERLIGHT_ANGLER_ID) and ((self:GetParent().bankAP or 0) + (self:GetParent().bagAP or 0)) or (self.fishingAP or 0) Nenue@98: local potentialXP = self.actualXP + totalAP Nenue@98: self.potentialXP = potentialXP Nenue@98: local potentialCost = C_ArtifactUI.GetCostForPointAtRank(potentialPoints) Nenue@98: while potentialXP >= potentialCost do Nenue@98: potentialXP = potentialXP - potentialCost Nenue@98: potentialPoints = potentialPoints + 1 Nenue@98: print('inc estimate', potentialXP, potentialPoints) Nenue@98: potentialCost = C_ArtifactUI.GetCostForPointAtRank(potentialPoints) Nenue@98: end Nenue@98: self.potentialCost = potentialCost Nenue@98: self.potentialLevel = potentialPoints Nenue@98: self.potentialAdjustedXP = potentialXP Nenue@98: Nenue@98: Nenue@98: Nenue@98: self.isEquipped = (equippedID == itemID) Nenue@98: self.relativeFrame = lastFrame Nenue@98: self:Update() Nenue@98: self:Show() Nenue@98: return self Nenue@98: end Nenue@98: Nenue@97: function VeneerArtifactButtonMixin:Update() Nenue@97: Nenue@97: if self.actualLevel ~= self.level then Nenue@97: self.Level:SetText(self.actualLevel) Nenue@97: self.Level:SetTextColor(0,1,0) Nenue@97: self.CurrentXP:SetText(self.adjustedXP) Nenue@97: self.CurrentXP:SetTextColor(0,1,0) Nenue@97: else Nenue@97: self.Level:SetText(self.level, 1, 1, 1) Nenue@97: self.Level:SetTextColor(1,1,1) Nenue@97: self.CurrentXP:SetText(self.currentXP) Nenue@97: self.CurrentXP:SetTextColor(1,1,0) Nenue@97: end Nenue@97: Nenue@97: if self.isEquipped then Nenue@97: self:SetNormalTexture([[Interface\Buttons\ButtonHilight-Square]]) Nenue@97: self:GetNormalTexture():SetBlendMode('ADD') Nenue@97: self:GetNormalTexture():SetVertexColor(0,1,0) Nenue@97: else Nenue@97: self:SetNormalTexture(nil, 'ADD') Nenue@97: end Nenue@97: Nenue@97: self:ClearAllPoints() Nenue@97: if self.relativeFrame then Nenue@98: self:SetPoint('TOPLEFT', self.relativeFrame, 'TOPRIGHT', 4, 0) Nenue@97: else Nenue@98: self:SetPoint('TOPLEFT', 4, -4) Nenue@97: end Nenue@98: local currentProgress = (self.currentXP < self.cost) and (self.currentXP / self.cost) or 1 Nenue@98: if self.level <= 53 then Nenue@98: self.CurrentProgress.animateFrom = self.CurrentProgress:GetHeight() or 1 Nenue@98: self.CurrentProgress.animateTo = currentProgress * self:GetHeight() Nenue@98: self.CurrentProgress:Show() Nenue@98: else Nenue@98: self.CurrentProgress:Hide() Nenue@98: end Nenue@98: print(currentProgress) Nenue@98: if self.potentialXP > self.currentXP then Nenue@98: local projectedProgress = (self.potentialAdjustedXP < self.potentialCost) and (self.potentialAdjustedXP / self.potentialCost) or 1 Nenue@98: print(projectedProgress) Nenue@98: if (projectedProgress > currentProgress) then Nenue@98: self.AdjustedProgress:SetPoint('BOTTOM', self.CurrentProgress, 'TOP') Nenue@98: projectedProgress = projectedProgress - currentProgress Nenue@98: print(projectedProgress) Nenue@98: else Nenue@98: self.AdjustedProgress:SetPoint('BOTTOM', self, 'BOTTOM') Nenue@98: end Nenue@98: self.AdjustedProgress.animateFrom = self.AdjustedProgress:GetHeight() or 1 Nenue@98: self.AdjustedProgress.animateTo = projectedProgress * self:GetHeight() Nenue@97: Nenue@98: self.AdjustedProgress:Show() Nenue@98: else Nenue@98: self.AdjustedProgress:Hide() Nenue@98: end Nenue@97: Nenue@97: self.Icon:SetTexture(self.texture) Nenue@97: self.Name:SetText(self.name) Nenue@97: self:SetSize(64,64) Nenue@97: end Nenue@97: Nenue@98: Nenue@98: function VeneerArtifactButtonMixin:AnimateProgress(region) Nenue@98: local cTime = GetTime() Nenue@98: if not region.animateStart then Nenue@98: region.animateStart = cTime Nenue@98: end Nenue@98: local progressTo, progressFrom = region.animateTo, region.animateFrom Nenue@98: local elapsed = cTime - region.animateStart Nenue@98: if elapsed >= .5 then Nenue@98: region:SetHeight(progressTo) Nenue@98: region.animateTo = nil Nenue@98: region.animateStart = nil Nenue@98: region.animateFrom = nil Nenue@98: else Nenue@98: local progress = elapsed / .5 Nenue@98: local height = (progressFrom + (progressTo - progressFrom) * progress) Nenue@98: --print(self:GetName(), progressTo, progressFrom, (progressTo - progressFrom), ceil(progress*10)/10, ceil(height)) Nenue@98: region:SetHeight(height) Nenue@98: end Nenue@98: end Nenue@98: Nenue@98: function VeneerArtifactButtonMixin:OnUpdate(sinceLast) Nenue@98: if self.CurrentProgress.animateTo then Nenue@98: self:AnimateProgress(self.CurrentProgress) Nenue@98: end Nenue@98: Nenue@98: if self.AdjustedProgress.animateTo then Nenue@98: self:AnimateProgress(self.AdjustedProgress) Nenue@98: end Nenue@98: Nenue@98: end Nenue@98: Nenue@97: function VeneerArtifactButtonMixin:OnEnter() Nenue@97: GameTooltip:SetOwner(self, 'ANCHOR_CURSOR') Nenue@97: GameTooltip:SetText(self.name) Nenue@98: GameTooltip:AddLine(tostring(self.currentXP) .. ' / '..tostring(self.cost), 1, 1, 0) Nenue@98: if self.potentialXP > self.currentXP then Nenue@98: GameTooltip:AddLine(tostring(self.potentialXP) .. ' potential XP', 0, 1, 1) Nenue@98: if self.adjustedXP ~= self.potentialXP then Nenue@98: GameTooltip:AddLine(tostring(self.potentialAdjustedXP) .. ' / ' .. tostring(self.potentialAdjustedCost).. ' after spending', 0, 1, 0) Nenue@98: end Nenue@97: end Nenue@97: GameTooltip:Show() Nenue@97: end Nenue@97: function VeneerArtifactButtonMixin:OnLeave() Nenue@97: if GameTooltip:IsOwned(self) then Nenue@97: GameTooltip:Hide() Nenue@97: end Nenue@97: end Nenue@97: Nenue@97: function VeneerArtifactButtonMixin:OnClick(button, down) Nenue@97: if self.isEquipped then Nenue@97: SocketInventoryItem(16) Nenue@97: else Nenue@97: SocketContainerItem(self.containerID, self.slotID) Nenue@97: end Nenue@97: end