Nenue@2: local wipe = table.wipe Nenue@2: local pairs, ipairs = pairs, ipairs Nenue@2: local GetTime = GetTime Nenue@2: local blockTemplate = { Nenue@2: point = 'TOPLEFT', Nenue@2: relativePoint ='TOPLEFT', Nenue@2: } Nenue@2: Nenue@1: SLASH_CLASSPLAN1 = "/classplan" Nenue@1: SLASH_CLASSPLAN2 = "/cp" Nenue@1: SlashCmdList.CLASSPLAN = function(args) Nenue@1: if ClassOrderPlan:IsVisible() then Nenue@1: ClassOrderPlan:Hide() Nenue@1: else Nenue@1: ClassOrderPlan:Show() Nenue@1: DEFAULT_CHAT_FRAME:AddMessage('|cFF88FF00WorldPlan|r: Order Hall Panel') Nenue@1: end Nenue@1: end Nenue@1: Nenue@1: ClassOrderPlanCore = { Nenue@2: freeBlocks = {}, Nenue@1: blocks = {}, Nenue@2: shipmentBlocks = {}, Nenue@2: freeShipmentBlocks = {}, Nenue@2: sortedShipments = {}, Nenue@2: sortedMissions = {}, Nenue@2: timers = {}, Nenue@2: shipments = {}, Nenue@2: playerFirst = false, Nenue@2: templates = setmetatable({}, { Nenue@2: __newindex = function(t,k ,v) Nenue@2: if type(v) == 'table' then Nenue@2: setmetatable(v, {__index = blockTemplate}) Nenue@2: rawset(t,k,v) Nenue@2: end Nenue@2: end Nenue@2: }) Nenue@1: } Nenue@2: ClassPlanBlockMixin = {} Nenue@2: ClassPlanShipmentMixin = setmetatable({}, {__index = ClassPlanBlockMixin}) Nenue@2: local core, block, shipment = ClassOrderPlanCore, ClassPlanBlockMixin, ClassPlanShipmentMixin Nenue@1: local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop Nenue@1: Nenue@2: Nenue@2: Nenue@1: function core:OnLoad () Nenue@1: self:RegisterUnitEvent('UNIT_PORTRAIT_UPDATE', 'player') Nenue@1: self:RegisterEvent('PLAYER_LOGIN') Nenue@1: self:RegisterEvent('PLAYER_ENTERING_WORLD') Nenue@2: self:RegisterEvent('PLAYER_REGEN_ENABLED') Nenue@2: Nenue@2: self:RegisterEvent('GARRISON_MISSION_LIST_UPDATE') Nenue@2: self:RegisterEvent('GARRISON_MISSION_FINISHED') Nenue@2: self:RegisterEvent("GARRISON_LANDINGPAGE_SHIPMENTS"); Nenue@2: self:RegisterEvent("GARRISON_SHIPMENT_RECEIVED"); Nenue@2: self:RegisterEvent("GARRISON_TALENT_UPDATE"); Nenue@2: self:RegisterEvent("GARRISON_TALENT_COMPLETE"); Nenue@1: end Nenue@1: Nenue@2: core.templates.ClassPlanBlock = { Nenue@2: SetItemData = function(block, data) Nenue@2: block.isComplete = data.isComplete Nenue@2: block.missionEndTime = data.missionEndTime Nenue@2: end Nenue@2: } Nenue@2: Nenue@2: core.templates.ClassPlanShipment = { Nenue@2: Nenue@2: parent = false, Nenue@2: point = 'TOPRIGHT', Nenue@2: relativePoint ='TOPRIGHT', Nenue@2: SetItemData = function(block, data) Nenue@2: block.icon = data.icon Nenue@2: block.shipmentCapacity = data.shipmentCapacity Nenue@2: block.shipmentsReady = data.shipmentsReady Nenue@2: block.shipmentsTotal = data.shipmentsTotal Nenue@2: block.creationTime = data.creationTime Nenue@2: block.duration = data.duration Nenue@2: block.itemID = data.itemID Nenue@2: block.itemQuality = data.itemQuality Nenue@2: --[[ Nenue@2: icon = texture, Nenue@2: shipmentCapacity = shipmentCapacity, Nenue@2: shipmentsReady = shipmentsReady, Nenue@2: shipmentsTotal = shipmentsTotal, Nenue@2: creationTime = creationTime, Nenue@2: duration = duration, Nenue@2: timeleftString = timeleftString, Nenue@2: itemName = itemName, Nenue@2: itemIcon = itemIcon, Nenue@2: itemQuality = itemQuality, Nenue@2: itemID = itemID Nenue@2: Nenue@2: --]] Nenue@2: end Nenue@2: } Nenue@1: Nenue@1: function core:OnEvent (event, ...) Nenue@2: print(event) Nenue@1: if event == 'UNIT_PORTRAIT_UPDATE' then Nenue@1: SetPortraitTexture(self.portrait, 'player') Nenue@1: elseif event == 'PLAYER_LOGIN' then Nenue@1: if not self.initialized then Nenue@1: if IsLoggedIn() then Nenue@1: WorldPlanData.OrderHall = WorldPlanData.OrderHall or {} Nenue@1: self.data = WorldPlanData.OrderHall Nenue@1: Nenue@1: Nenue@1: local name, realm = UnitName('player') Nenue@1: realm = realm or GetRealmName() Nenue@1: self.profileKey = name .. '-' .. realm Nenue@1: if not self.data[self.profileKey] then Nenue@1: self.data[self.profileKey] = {} Nenue@1: end Nenue@1: self.profile = self.data[self.profileKey] Nenue@1: Nenue@2: self.profile.shipments = self.profile.shipments or {} Nenue@2: self.profile.missions = self.profile.missions or {} Nenue@2: self.profile.classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))] Nenue@2: Nenue@2: C_Garrison.RequestLandingPageShipmentInfo(); Nenue@1: self.initialized = true Nenue@1: end Nenue@1: end Nenue@2: elseif event == 'GARRISON_LANDINGPAGE_SHIPMENTS' or event == 'GARRISON_TALENT_UPDATE' then Nenue@2: self:UpdateShipments() Nenue@2: elseif event == 'PLAYER_REGEN_ENABLED' or event == 'GARRISON_MISSION_FINISHED' or event == 'GARRISON_TALENT_COMPLETE' or event == 'GARRISON_SHIPMENT_RECEIVED' then Nenue@2: self:UpdateNotifications() Nenue@1: else Nenue@2: self:UpdateItems () Nenue@1: end Nenue@1: end Nenue@1: Nenue@2: function core:UpdateNotifications() Nenue@2: end Nenue@1: Nenue@2: function core:RefreshItems(sortedItems, templateName) Nenue@2: self.blocks[templateName] = self.blocks[templateName] or {} Nenue@2: local blocks = self.blocks[templateName] Nenue@2: local template = self.templates[templateName] or { Nenue@2: parent = self.portrait, Nenue@2: point = 'TOPLEFT', Nenue@2: relativePoint ='TOPRIGHT', Nenue@2: } Nenue@2: Nenue@2: local lastProfile Nenue@2: local numItems = #sortedItems Nenue@2: for i, data in ipairs(sortedItems) do Nenue@2: local block = blocks[i] Nenue@2: Nenue@2: if not block then Nenue@2: block = CreateFrame('Frame', nil, self, templateName) Nenue@2: block:SetID(i) Nenue@2: template.numBlocks = (template.numBlocks or 0) + 1 Nenue@2: Nenue@2: if template.lastBlock then Nenue@2: block:SetPoint('TOPLEFT', template.lastBlock, 'BOTTOMLEFT', 0, 0) Nenue@2: else Nenue@2: block:SetPoint(template.point, self[template.parent] or self, template.relativePoint, 0, 0) Nenue@2: end Nenue@2: template.lastBlock = block Nenue@2: blocks[i] = block Nenue@2: end Nenue@2: Nenue@2: if template.SetItemData then Nenue@2: template.SetItemData(block, data) Nenue@2: end Nenue@2: Nenue@2: Nenue@2: block.lastProfile = lastProfile Nenue@2: block:Refresh(data) Nenue@2: block:Show() Nenue@2: lastProfile = data.profileKey Nenue@2: end Nenue@2: Nenue@2: for i = numItems + 1, template.numBlocks do Nenue@2: if blocks[i] then Nenue@2: blocks[i]:Hide() Nenue@2: end Nenue@2: end Nenue@2: end Nenue@2: Nenue@2: function core:Refresh() Nenue@2: if self.isStale then Nenue@2: self:SortLists() Nenue@2: end Nenue@2: self.isStale = nil Nenue@2: Nenue@2: self:RefreshItems(self.sortedMissions, 'ClassPlanBlock') Nenue@2: self:RefreshItems(self.sortedShipments, 'ClassPlanShipment') Nenue@2: Nenue@2: Nenue@2: local posX = self.data.posX or 0 Nenue@2: local posY = self.data.posY or -24 Nenue@2: local point = self.point or 'TOP' Nenue@2: local relativePoint = self.point or 'TOP' Nenue@2: self:SetPoint(point, UIParent, relativePoint, posX, posY) Nenue@2: Nenue@2: Nenue@2: end Nenue@2: Nenue@2: function core:OnUpdate() Nenue@2: if self.fadeTimer and self.fadeTimer < GetTime() then Nenue@2: self:Hide() Nenue@2: end Nenue@2: end Nenue@2: Nenue@2: function core:OnShow() Nenue@2: if self.isStale then Nenue@2: print('updating items on show') Nenue@2: self:Refresh() Nenue@2: end Nenue@2: Nenue@2: end Nenue@2: Nenue@2: function core:SortLists() Nenue@2: Nenue@2: wipe(self.sortedShipments) Nenue@2: wipe(self.sortedMissions) Nenue@1: for name, profile in pairs(self.data) do Nenue@1: local isMine = (profile == self.profile) Nenue@1: for index, data in pairs(profile.missions) do Nenue@1: Nenue@1: data.classColor = profile.classColor or {r = 0.7, g = 0.7, b =0.7} Nenue@1: data.profileKey = name Nenue@1: data.isMine = (profile == self.profile) Nenue@1: tinsert(self.sortedMissions, data) Nenue@1: end Nenue@2: Nenue@2: if not profile.shipments then Nenue@2: profile.shipments = {} Nenue@2: profile.shipment = nil Nenue@2: end Nenue@2: Nenue@2: for index, data in pairs(profile.shipments) do Nenue@2: data.classColor = profile.classColor or {r = 0.7, g = 0.7, b =0.7} Nenue@2: data.profileKey = name Nenue@2: data.isMine = (profile == self.profile) Nenue@2: tinsert(self.sortedShipments, data) Nenue@2: end Nenue@1: end Nenue@1: Nenue@2: table.sort(self.sortedMissions, function (a,b) Nenue@1: local result = false Nenue@1: if not a or not b then Nenue@1: result = true Nenue@1: else Nenue@1: if (a.isMine ~= b.isMine) and self.playerFirst then Nenue@1: result = a.isMine Nenue@1: else Nenue@1: if (not b.missionEndTime) or (not a.missionEndTime) then Nenue@1: print('missing article', b.missionEndTime, a.missionEndTime) Nenue@1: end Nenue@1: result = ( b.missionEndTime > a.missionEndTime) Nenue@1: end Nenue@1: end Nenue@1: Nenue@2: --print('cmp', (b and (b.missionEndTime .. ' ' .. tostring(b.isMine)) or '-'), '>', (a and (a.missionEndTime .. ' ' .. tostring(a.isMine)) or '-'), result, n) Nenue@1: return result Nenue@1: end) Nenue@1: Nenue@2: end Nenue@1: Nenue@2: function core:UpdateShipments() Nenue@2: print('|cFF0088FFShipments|r:', self.profileKey) Nenue@2: if not self.profile then Nenue@2: return Nenue@2: end Nenue@2: wipe(self.shipments) Nenue@2: Nenue@2: Nenue@2: local garrisonType = LE_GARRISON_TYPE_7_0 Nenue@2: local buildings = C_Garrison.GetBuildings(garrisonType); Nenue@2: local shipmentIndex = 0 Nenue@2: print('Buildings:') Nenue@2: for i = 1, #buildings do Nenue@2: local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID = C_Garrison.GetLandingPageShipmentInfo(buildingID); Nenue@2: print(buildings[i], name, creationTime, duration) Nenue@2: tinsert(self.shipments, Nenue@2: { Nenue@2: shipmentType = 'Work Order', Nenue@2: name = name, Nenue@2: icon = texture, Nenue@2: shipmentCapacity = shipmentCapacity, Nenue@2: shipmentsReady = shipmentsReady, Nenue@2: shipmentsTotal = shipmentsTotal, Nenue@2: creationTime = creationTime, Nenue@2: duration = duration, Nenue@2: timeleftString = timeleftString, Nenue@2: itemName = itemName, Nenue@2: itemIcon = itemIcon, Nenue@2: itemQuality = itemQuality, Nenue@2: itemID = itemID Nenue@2: }) Nenue@2: end Nenue@2: Nenue@2: print('Follower:') Nenue@2: local followerShipments = C_Garrison.GetFollowerShipments(garrisonType); Nenue@2: for i = 1, #followerShipments do Nenue@2: local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, _, _, _, _, followerID = C_Garrison.GetLandingPageShipmentInfoByContainerID(followerShipments[i]); Nenue@2: print(followerShipments[i], name, creationTime, duration) Nenue@2: tinsert(self.shipments, Nenue@2: { Nenue@2: shipmentType = '', Nenue@2: name = name, Nenue@2: icon = texture, Nenue@2: shipmentCapacity = shipmentCapacity, Nenue@2: shipmentsReady = shipmentsReady, Nenue@2: shipmentsTotal = shipmentsTotal, Nenue@2: creationTime = creationTime, Nenue@2: duration = duration, Nenue@2: timeleftString = timeleftString, Nenue@2: followerID = followerID, Nenue@2: }) Nenue@2: end Nenue@2: Nenue@2: print('Loose:') Nenue@2: local looseShipments = C_Garrison.GetLooseShipments(garrisonType) Nenue@2: for i = 1, #looseShipments do Nenue@2: local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString = C_Garrison.GetLandingPageShipmentInfoByContainerID(looseShipments[i]); Nenue@2: print(looseShipments[i], name, creationTime, duration) Nenue@2: tinsert(self.shipments, Nenue@2: { Nenue@2: shipmentType = '', Nenue@2: name = name, Nenue@2: icon = texture, Nenue@2: shipmentCapacity = shipmentCapacity, Nenue@2: shipmentsReady = shipmentsReady, Nenue@2: shipmentsTotal = shipmentsTotal, Nenue@2: creationTime = creationTime, Nenue@2: duration = duration, Nenue@2: timeleftString = timeleftString, Nenue@2: }) Nenue@2: end Nenue@2: Nenue@2: local talentTrees = C_Garrison.GetTalentTrees(garrisonType, select(3, UnitClass("player"))); Nenue@2: -- this is a talent that has completed, but has not been seen in the talent UI yet. Nenue@2: local completeTalentID = C_Garrison.GetCompleteTalent(garrisonType); Nenue@2: print('Talents:') Nenue@2: if (talentTrees) then Nenue@2: for treeIndex, tree in ipairs(talentTrees) do Nenue@2: for talentIndex, talent in ipairs(tree) do Nenue@2: local showTalent = false; Nenue@2: if (talent.isBeingResearched) then Nenue@2: showTalent = true; Nenue@2: end Nenue@2: if (talent.id == completeTalentID) then Nenue@2: showTalent = true; Nenue@2: end Nenue@2: if (showTalent) then Nenue@2: print(talent.name) Nenue@2: talent.creationTime = talent.researchStartTime Nenue@2: talent.duration = talent.researchDuration Nenue@2: talent.shipmentType = 'Talent: ' Nenue@2: tinsert(self.shipments, talent) Nenue@2: end Nenue@1: end Nenue@1: end Nenue@2: end Nenue@1: Nenue@2: self.profile.shipments = self.profile.shipments or {} Nenue@2: if #self.shipments >= 1 then Nenue@2: Nenue@2: wipe(self.profile.shipments) Nenue@2: for index, shipment in ipairs(self.shipments) do Nenue@2: tinsert(self.profile.shipments, shipment) Nenue@1: end Nenue@2: self.isStale = true Nenue@2: end Nenue@1: Nenue@2: if self:IsVisible() then Nenue@2: self:Refresh() Nenue@1: end Nenue@1: end Nenue@1: Nenue@2: function core:UpdateItems () Nenue@1: if not self.profile then Nenue@1: return Nenue@1: end Nenue@1: self.items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0) Nenue@1: Nenue@1: Nenue@1: Nenue@1: Nenue@2: print('|cFF0088FFLandingPageItems|r:', self.profileKey) Nenue@1: if #self.items >= 1 then Nenue@2: wipe(self.profile.missions) Nenue@1: for index, data in ipairs(self.items) do Nenue@1: print('', data.name) Nenue@1: print(' |cFF00FF00', data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime)) Nenue@1: tinsert(self.profile.missions, data) Nenue@1: end Nenue@2: print('items update pending') Nenue@2: self.isStale = true Nenue@1: end Nenue@1: Nenue@1: if self:IsVisible() then Nenue@2: self:Refresh() Nenue@2: end Nenue@2: end Nenue@2: Nenue@2: function block:OnComplete() Nenue@2: self.isComplete = true Nenue@2: self:Refresh() Nenue@2: end Nenue@2: Nenue@2: local GetTimeLeftString = function(timeLeft) Nenue@2: Nenue@2: local days = floor(timeLeft/(24*3600)) Nenue@2: local hours = floor(mod(timeLeft, (24*3600)) / 3600) Nenue@2: local minutes = floor(mod(timeLeft, 3600) / 60) Nenue@2: local seconds = mod(timeLeft, 60) Nenue@2: if days >= 1 then Nenue@2: return (days .. 'd' .. ' ') .. ((hours > 0) and (hours .. 'h ') or '') Nenue@1: else Nenue@2: return ((hours > 0) and (hours .. 'h ') or '') .. ((minutes > 0) and (minutes .. ' min') or '') Nenue@1: end Nenue@1: end Nenue@1: Nenue@1: function block:OnUpdate() Nenue@2: if self.isComplete then Nenue@2: return Nenue@2: end Nenue@2: Nenue@1: if self.missionEndTime then Nenue@1: local timeLeft = self.missionEndTime - time() Nenue@1: if timeLeft < 0 then Nenue@2: self:OnComplete() Nenue@1: else Nenue@2: self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) Nenue@2: Nenue@2: if timeLeft > 3600 then Nenue@2: self.TimeLeft:SetTextColor(1,1,1) Nenue@2: else Nenue@2: self.TimeLeft:SetTextColor(1,1,0) Nenue@2: end Nenue@2: Nenue@1: end Nenue@1: else Nenue@1: self.TimeLeft:SetText(self.missionEndTime) Nenue@1: end Nenue@2: end Nenue@2: Nenue@2: local SetClassColors = function(self, data) Nenue@2: Nenue@2: if self.lastProfile ~= data.profileKey then Nenue@2: self.Owner:SetText(data.profileKey) Nenue@2: self.Owner:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b) Nenue@2: else Nenue@2: self.Owner:SetText(nil) Nenue@2: end Nenue@2: self.Background:SetColorTexture(data.classColor.r, data.classColor.g, data.classColor.b, Nenue@2: (data.isComplete and 0.5 or 0.1)) Nenue@2: end Nenue@2: Nenue@2: function block:Refresh(data) Nenue@2: data = data or self.data Nenue@2: self.data = data Nenue@2: Nenue@2: local r,g,b = 1, 1, 1 Nenue@2: if data.isRare then Nenue@2: r,g,b = 0.1, 0.4, 1 Nenue@2: end Nenue@2: Nenue@2: Nenue@2: --self.missionData = data Nenue@2: self.Label:SetText(data.name) Nenue@2: self.Label:SetTextColor(r, g, b) Nenue@2: Nenue@2: if #data.rewards >= 1 then Nenue@2: self.Icon:SetTexture(data.rewards[1].icon or GetItemIcon(data.rewards[1].itemID)) Nenue@2: self.rewardInfo = data.rewards[1] Nenue@2: else Nenue@2: self.Icon:SetAtlas(data.typeAtlas, false) Nenue@2: end Nenue@2: Nenue@2: SetClassColors(self, data) Nenue@2: Nenue@2: if self.isComplete then Nenue@2: self.TimeLeft:SetText('Complete!') Nenue@2: end Nenue@2: end Nenue@2: Nenue@2: Nenue@2: function block:OnEnter() Nenue@2: if self.rewardInfo and self.rewardInfo.itemID then Nenue@2: GameTooltip:SetOwner(self, 'ANCHOR_LEFT') Nenue@2: GameTooltip:SetItemByID(self.rewardInfo.itemID) Nenue@2: GameTooltip:Show() Nenue@2: end Nenue@2: end Nenue@2: function block:OnLeave() Nenue@2: if GameTooltip:IsOwned(self) then Nenue@2: GameTooltip:Hide() Nenue@2: end Nenue@2: end Nenue@2: Nenue@2: Nenue@2: Nenue@2: function shipment:Refresh(data) Nenue@2: data = data or self.data Nenue@2: self.Icon:SetTexture(data.icon) Nenue@2: self.data = data Nenue@2: Nenue@2: self.Name:SetText(data.shipmentType .. data.name) Nenue@2: self.Count:SetText(data.shipmentsReady) Nenue@2: Nenue@2: self.Done:SetShown(data.shipmentsReady and (data.shipmentsReady >= 1)) Nenue@2: Nenue@2: if ( data.shipmentsReady == data.shipmentsTotal ) then Nenue@2: self.Swipe:SetCooldownUNIX(0, 0); Nenue@2: self.Done:Show(); Nenue@2: if not data.isBeingResearched then Nenue@2: data.isComplete = true Nenue@2: end Nenue@2: else Nenue@2: self.Swipe:SetCooldownUNIX(data.creationTime or 0 , data.duration or 0); Nenue@2: end Nenue@2: Nenue@2: Nenue@2: Nenue@2: SetClassColors(self, data) Nenue@2: end Nenue@2: function shipment:UpdateShipment() Nenue@2: Nenue@2: local data = self.data Nenue@2: if data.shipmentsTotal then Nenue@2: local timeLeft = data.creationTime + data.duration - time() Nenue@2: if timeLeft < 0 then Nenue@2: local numReady = floor((1*timeLeft) / data.duration) Nenue@2: data.shipmentsReady = data.shipmentsReady + numReady Nenue@2: data.creationTime = data.creationTime + (numReady * data.duration) Nenue@2: self:Refresh() Nenue@2: end Nenue@2: end Nenue@2: end Nenue@2: function shipment:OnUpdate() Nenue@2: local data = self.data Nenue@2: if (data.shipmentsReady and data.shipmentsTotal) and (data.shipmentsReady ~= data.shipmentsTotal) then Nenue@2: local timeLeft = data.creationTime + data.duration - time() Nenue@2: if timeLeft < 0 then Nenue@2: self:UpdateShipment() Nenue@2: return Nenue@2: end Nenue@2: Nenue@2: self.TimeLeft:SetText('Next: '.. GetTimeLeftString(timeLeft) .. ' |cFFFFFF00'..data.shipmentsTotal..' orders|r') Nenue@2: Nenue@2: Nenue@2: elseif data.isBeingResearched then Nenue@2: self.TimeLeft:SetText(GetTimeLeftString(data.researchStartTime + data.researchDuration - time())) Nenue@2: else Nenue@2: self.TimeLeft:SetText('Complete!') Nenue@2: end Nenue@2: Nenue@2: end Nenue@2: Nenue@2: function shipment:OnEnter() Nenue@2: local data = self.data Nenue@2: if ( data.shipmentsReady and data.shipmentsTotal ) then Nenue@2: GameTooltip:SetOwner(self, 'ANCHOR_LEFT') Nenue@2: GameTooltip:AddLine(data.shipmentsReady .. ' of '.. data.shipmentsTotal) Nenue@2: GameTooltip:Show() Nenue@2: end Nenue@2: end Nenue@2: Nenue@2: function shipment:OnLeave() Nenue@2: if GameTooltip:IsOwned(self) then Nenue@2: GameTooltip:Hide() Nenue@2: end Nenue@2: end Nenue@2: Nenue@2: function shipment:OnClick(button) Nenue@2: --todo: trigger cleanup script for dead shipment data Nenue@1: end