Mercurial > wow > worldplan
view ClassPlan.lua @ 33:be4db60219ca
WorldPlan:
- Toggling a reward filter cancels out other types by default. Use right mouse to clear.
- Fixed filter bar info falling out of sync after player-triggered world map updates.
ClassPlan:
- Available missions are now recorded; the mission list can be toggled between in-progress and available by clicking the heading.
author | Nenue |
---|---|
date | Wed, 02 Nov 2016 17:25:07 -0400 |
parents | e8679ecb48d8 |
children | 26dfa661daa7 |
line wrap: on
line source
local wipe, tinsert, sort = table.wipe, tinsert, table.sort local pairs, ipairs = pairs, ipairs local floor, mod, time = floor, mod, time local max, min = math.max, math.min local GetTime = GetTime local GI_currentTime = time() local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop local CG_GetBuildings = C_Garrison.GetBuildings local CG_GetFollowerShipments = C_Garrison.GetFollowerShipments local CG_GetLooseShipments = C_Garrison.GetLooseShipments local CG_GetTalentTrees = C_Garrison.GetTalentTrees local CG_GetCompleteTalent = C_Garrison.GetCompleteTalent local CG_GetLandingPageShipmentInfo = C_Garrison.GetLandingPageShipmentInfo local CG_GetLandingPageShipmentInfoByContainerID = C_Garrison.GetLandingPageShipmentInfoByContainerID local CP_REPLACE_LANDINGPAGE = true local CP_HEADER_SIZE = 24 local CP_BACKGROUND_COLOR = { inProgress = {0, 0, 0, 0.5}, shipmentsReady = {0, 0, 0, 0.25}, complete = {0.5, 0.5, 0.5, 0.5} } local GetTimeLeftString = function(timeLeft) local days = floor(timeLeft/(24*3600)) local hours = floor(mod(timeLeft, (24*3600)) / 3600) local minutes = floor(mod(timeLeft, 3600) / 60) local seconds = mod(timeLeft, 60) if days >= 1 then return (days .. 'd' .. ' ') .. ((hours > 0) and (hours .. 'h') or '') else return ((hours > 0) and (hours .. 'h') or '') .. ((minutes > 0) and (' ' ..minutes .. ' min') or '') end end ClassOrderPlanCore = { events = {}, freeBlocks = {}, blocks = {}, sortedItems = {}, timers = {}, shipments = {}, playerFirst = false, prototypes = {}, Queued = {} } local MissionList = { templateName = 'ClassPlanMissionEntry', listKey = {'missions', 'available'}, listTitle = {'In Progress', 'Available'}, point = 'TOPLEFT', relativePoint ='TOPLEFT', events = { 'GARRISON_MISSION_LIST_UPDATE', 'GARRISON_LANDINGPAGE_SHIPMENTS'}, } local ShipmentList = { templateName = 'ClassPlanShipmentEntry', listKey = {'shipments'}, listTitle = {'Work Orders'}, events = { 'GARRISON_MISSION_LIST_UPDATE', 'GARRISON_LANDINGPAGE_SHIPMENTS', 'GARRISON_TALENT_UPDATE', "GARRISON_TALENT_COMPLETE", "GARRISON_SHIPMENT_RECEIVED", 'GARRISON_FOLLOWER_LIST_UPDATE', 'GARRISON_SHOW_LANDING_PAGE'}, } local SharedHandlers = { numBlocks = 0, isStale = true, } local SharedEntry = {} local ShipmentEntry = {} local MissionEntry = {} local ClassPlan = ClassOrderPlanCore function ClassPlan:OnLoad () self:RegisterEvent('PLAYER_LOGIN') self:RegisterEvent('ADDON_LOADED') self:RegisterEvent('PLAYER_REGEN_ENABLED') self:RegisterEvent('PLAYER_REGEN_DISABLED') self:RegisterForDrag('LeftButton') self:SetMovable(true) self:SetToplevel(true) SLASH_CLASSPLAN1 = "/classplan" SLASH_CLASSPLAN2 = "/cp" SlashCmdList.CLASSPLAN = function(args) self:Toggle() end end function ClassPlan:GetCurrentProfile() WorldPlanData.OrderHall = WorldPlanData.OrderHall or {} local db = WorldPlanData.OrderHall self.data = db local characters = db.characters or {} db.characters = characters local name, realm = UnitName('player') realm = realm or GetRealmName() local profileName = name .. '-' .. realm self.profile = characters[profileName] or {} self.characters = characters characters[profileName] = self.profile local classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))] local className = UnitClass('player') print('|cFFFFFF00Loaded:|r', classColor.hex, className, profileName) self.Background:SetColorTexture(classColor.r, classColor.g, classColor.b, 0.5) self.profile.classColor = classColor self.profile.className = className return self.profile end function ClassPlan:SetupHandler(handler) print('|cFF00FF00'..handler:GetName()..' loaded') for i, event in ipairs(handler.events) do print('|cFF00FF00 event', event) handler:RegisterEvent(event) end for index, listKey in ipairs(handler.listKey) do self.profile[listKey] = self.profile[listKey] or {} local listTitle = handler.listTitle[index] setmetatable(self.profile[listKey], { __tostring = listTitle }) end handler:SetList(1) handler.sortedItems = {} end function ClassPlan:OnEvent (event, arg) print(event, arg) if event == 'PLAYER_REGEN_DISABLED' then if self:IsVisible() then self.combatHide = true self:SetShown(false) end elseif event == 'PLAYER_REGEN_ENABLED' then if self.combatHide == true then self.combatHide = nil self:SetShown(true) end elseif event == 'ADDON_LOADED' then if arg == 'Blizzard_GarrisonUI' then self:Reanchor() end elseif event == 'PLAYER_LOGIN' then if not self.initialized then self:Setup() end end end function ClassPlan:Setup() if IsLoggedIn() then print('|cFFFFFF00'..self:GetName()..':Setup()|r') self:GetCurrentProfile() for _, handler in ipairs(self.Handlers) do self:SetupHandler(handler) end self.initialized = true self:SetShown(self.data.IsShown) end end --- Update space local max = math.max function ClassPlan:Update() print('|cFF00FFFFRefresh()|r') self.currentHeight = 0 for index, handler in pairs(self.Handlers) do if handler.isStale then print(' |cFF00FF00'..index..' '..handler:GetName()..'|r') local sortedItems = handler.sortedItems local activeKey = handler.activeKey handler.profile = self.profile[handler.activeKey] wipe(sortedItems) handler:GetPlayerData(self.profile) for key, profile in pairs(self.data.characters) do print('profile', key, activeKey) local profileList = profile[activeKey] if profileList and #profileList >= 1 then local classColor = profile.classColor or defaultClassColor local isMine = (profile == self.profile) for index, data in ipairs(profileList) do data.classColor = classColor data.profileKey = key data.isMine = isMine if handler.OnGetItem then handler.OnGetItem(data) end tinsert(sortedItems, data) end end end if handler.SortHandler then sort(sortedItems, handler.SortHandler) end end handler.isStale = nil local itemsHeight = handler:UpdateItems() self.currentHeight = max(itemsHeight, self.currentHeight) end self.isStale = nil self:Reanchor() self:SetHeight(self.currentHeight + CP_HEADER_SIZE) end function ClassPlan:Toggle() if self:IsShown() then self:Hide() else self:Show() end if self.data then self.data.IsShown = self:IsShown() end end function ClassPlan:OnUpdate() if self.isStale then print('|cFFFF4400An illusion! What are you hiding?|r') self:Update() end end function ClassPlan:OnShow() print('|cFF00FFFFShow()') if self.isStale then self:Update() end self:Reanchor() end function ClassPlan:OnHide() print('|cFF00FFFFHide()') end function ClassPlan:Reanchor() self:ClearAllPoints() self:SetPoint('CENTER', self.data.positionX, self.data.positionY) for index, frame in ipairs(self.Handlers) do frame:Reanchor() end end function ClassPlan:OnDragStart() self:StartMoving() end function ClassPlan:OnDragStop() self:StopMovingOrSizing() local x,y = self:GetCenter() if x and y then x = (x - GetScreenWidth()/2) y = (y - GetScreenHeight()/2) * -1 self.data.positionX, self.data.positionY = x,y print('saving positions:', x, y) end end function SharedHandlers:SetList(index) if not index then if self.currentListIndex == #self.listKey then index = 1 else index = self.currentListIndex + 1 end end print('|cFF0088FF'..self:GetName()..'|r:SetList()', index) self.currentListIndex = index self.activeKey = self.listKey[index] self.activeTitle = self.listTitle[index] self.isStale = true end function SharedHandlers:RequestData() print('|cFF0088FF'..self:GetName()..':RequestData()') self.isStale = true end function SharedHandlers:OnEvent(event, arg) if (event == 'GARRISON_MISSION_LIST_UPDATE') and (arg ~= LE_FOLLOWER_TYPE_GARRISON_7_0) then -- ignore non-OrderHall updates return end print('|cFF00FF88'..self:GetName()..':OnEvent()|r', event, arg) if self:IsVisible() then print('|cFF88FF00 frame visible; get busy') self:RequestData() else if not self.NextData then print('|cFF88FF00 setting timer') self.NextData = C_Timer.NewTimer(0.25, function() if self.initialized then self:RequestData() self.NextData:Cancel() self.NextData = nil print('|cFF88FF00'..self:GetName()..' clearing timer') end end) end end end function SharedHandlers:OnUpdate() if self.isStale then self:GetParent():Update() end end -- Stuff set on every list item function SharedHandlers:SetOwnerData (self, data) local name, realm = string.match(data.profileKey, "(.+)%-(.+)") local ownerText = '|c'.. data.classColor.colorStr .. name .. '|r' self.Owner:SetText(ownerText) self.Name:SetText(self.name) self.Name:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b) end function SharedHandlers:UpdateItems() local sortedItems = self.sortedItems self.blocks = self.blocks or {} local blocks = self.blocks local lastProfile local numItems = #sortedItems local totalHeight = 0 self.lastBlock = nil self.numActive = 0 for i, data in ipairs(sortedItems) do local block = blocks[i] if not block then block = CreateFrame('Button', nil, self, self.templateName) block:SetID(i) block.listType = self.activeKey block.handler = self self.numBlocks = self.numBlocks + 1 blocks[i] = block end print('RefreshItem', block) self.numActive = self.numActive + 1 if self.lastBlock then block:SetPoint('TOPLEFT', self.lastBlock, 'BOTTOMLEFT', 0, 0) print('--', i, data.isComplete, data.missionEndTime, data.name) else block:SetPoint('TOPLEFT', 0, 0) print('--top') end self.lastBlock = block totalHeight = totalHeight + block:GetHeight() block.lastProfile = lastProfile -- blot out arbitrary flags block.offerEndTime = nil block.missionEndTime = nil block.creationTime = nil block.duration = nil block.throttle = 5 for k,v in pairs(data) do if type(block[k]) ~= 'function' then block[k] = v end end block:Update() self:SetOwnerData(block, data) block:Show() lastProfile = data.profileKey end for i = numItems + 1, self.numBlocks do if blocks[i] then blocks[i]:Hide() end end self:Reanchor() return totalHeight end function ShipmentList:Reanchor() print('|cFF00FFFF'..self:GetName()..':Reanchor|r') self:SetPoint('TOPLEFT', 0, -24) self:SetPoint('BOTTOMRIGHT', -ClassOrderPlan:GetWidth()/2, 0) end function MissionList:Reanchor() self:SetPoint('TOPRIGHT', 0, -24) self:SetPoint('BOTTOMLEFT', ClassOrderPlan:GetWidth()/2, 0) self.ListTab:ClearAllPoints() self.ListTab:SetPoint('TOPLEFT', self, 'TOPLEFT', 0, CP_HEADER_SIZE) self.ListTab:SetPoint('BOTTOMRIGHT', self, 'TOPRIGHT', 0, 0) self.ListTab.Label:SetText(self.listTitle[self.currentListIndex]) self.ListTab:Show() print(self.ListTab:GetSize()) end function MissionList:GetPlayerData (profile) wipe(profile.missions) wipe(profile.available) local items = C_Garrison.GetAvailableMissions(GetPrimaryGarrisonFollowerType(LE_GARRISON_TYPE_7_0)); for i = 1, #items do if (not items[i].isBuilding and items[i].isZoneSupport) then else tinsert(profile.available, items[i]) end end local items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0) for index, data in ipairs(items) do print(' -',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime)) tinsert(profile.missions, data) end return true end do local ShipmentsInfo = {} local AddShipmentInfo = function(shipmentType, name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID, followerID) -- early login queries may return empty tables, causing the sorter to compare nil if not creationTime then return end --print(shipmentType, name, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString) tinsert(ShipmentsInfo, { shipmentType = shipmentType, name = name, icon = texture, shipmentCapacity = shipmentCapacity, shipmentsReady = shipmentsReady, shipmentsTotal = shipmentsTotal, creationTime = creationTime, duration = duration, timeleftString = timeleftString, itemName = itemName, itemIcon = itemIcon, itemQuality = itemQuality, itemID = itemID, followerID = followerID, }) end function ShipmentList:GetPlayerData (profile) if not profile then return false end local profileList = profile.shipments wipe(ShipmentsInfo) local garrisonType = LE_GARRISON_TYPE_7_0 local buildings = CG_GetBuildings(garrisonType); local shipmentIndex = 0 --print('Buildings:') for i = 1, #buildings do local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID = CG_GetLandingPageShipmentInfo(buildingID); AddShipmentInfo('Building', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID) end --print('Follower:') local followerShipments = CG_GetFollowerShipments(garrisonType); for i = 1, #followerShipments do local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, _, _, _, _, followerID = CG_GetLandingPageShipmentInfoByContainerID(followerShipments[i]); AddShipmentInfo('Follower', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, nil, nil, nil, nil, followerID) end --print('Loose:') local looseShipments = CG_GetLooseShipments(garrisonType) for i = 1, #looseShipments do local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString = CG_GetLandingPageShipmentInfoByContainerID(looseShipments[i]); AddShipmentInfo('Misc', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString) end local talentTrees = CG_GetTalentTrees(garrisonType, select(3, UnitClass("player"))); -- this is a talent that has completed, but has not been seen in the talent UI yet. local completeTalentID = CG_GetCompleteTalent(garrisonType); --print('Talents:') if (talentTrees) then for treeIndex, tree in ipairs(talentTrees) do for talentIndex, talent in ipairs(tree) do local showTalent = false; if (talent.isBeingResearched) or (talent.id == completeTalentID) then AddShipmentInfo('Talent', talent.name, talent.icon, 1, (talent.isBeingResearched and 0 or 1), 1, talent.researchStartTime, talent.researchDuration, talent.timeleftString) end end end end wipe(profileList) for index, data in ipairs(ShipmentsInfo) do --DEFAULT_CHAT_FRAME:AddMessage(data.shipmentType ..' '.. tostring(data.name) ..' '.. tostring(data.creationTime) ..' '.. tostring(data.duration)) tinsert(profileList, data) end self.isStale = true return true end end MissionList.OnGetItem = function(data) if data.missionEndTime and (data.missionEndTime < GI_currentTime) then data.isComplete = true end end MissionList.FreeBlock = function(self, block) end MissionList.SortHandler = function (a,b) local result = false --if not a or not b then -- return true --else --if (a.isMine ~= b.isMine) then -- result = a.isMine --else --if (not b.missionEndTime) or (not a.missionEndTime) then -- print('missing article', b.missionEndTime, a.missionEndTime) --end if b.isComplete ~= a.isComplete then return a.isComplete elseif b.isMine ~= a.isMine then return a.isMine elseif b.missionEndTime then return ( b.missionEndTime > a.missionEndTime) else return ( b.offerEndTime > a.offerEndTime) end --end --end end function MissionList:OnShow() print('|cFF00FF88'..self:GetName()..':OnShow()|r') end function ShipmentList:OnLoad() C_Garrison.RequestLandingPageShipmentInfo(); end function ShipmentList:OnShow() print('|cFF00FF88'..self:GetName()..':OnShow()|r') C_Garrison.RequestLandingPageShipmentInfo() end -- Update shipment flags data local SetActualShipmentTime = function(self) if self.isComplete then print('|cFF00FF88isComplete '..self.name..'|r') return true end local timestamp = time() local timeLeft = self.creationTime + self.duration - timestamp local justFinished = false while (self.shipmentsReady < self.shipmentsTotal) and (timeLeft <= 0) do if not self.originalReady then self.originalReady = self.shipmentsReady self.originalCreationTime = self.creationTime end self.shipmentsReady = self.shipmentsReady + 1 self.creationTime = self.creationTime + self.duration timeLeft = timeLeft + self.duration print('|cFF00FF88udpating '..self.name..'|r', 'timeLeft:', timeLeft, 'shipments:', self.shipmentsReady, self.shipmentsTotal) end if (timeLeft <= 0) and (not self.isBeingResearched) then self.isComplete = true self.isStale = true end return timeLeft end ShipmentList.OnGetItem = function(data) print('OnGetItem()') if data.shipmentsTotal then SetActualShipmentTime(data) end end ShipmentList.SortHandler = function(a, b) if b.isComplete ~= a.isComplete then return a.isComplete and true or false elseif a.shipmentsReady or b.shipmentsReady then return (a.shipmentsReady or 0) > (b.shipmentsReady or 0) else return (a.creationTime) < (b.creationTime) end end function MissionEntry:OnComplete() print('flagging complete', self.name) self:Update() end function MissionEntry:OnUpdate(sinceLast) self.throttle = (self.throttle or .5) + sinceLast if self.throttle < .5 then return else self.throttle = self.throttle - .5 end if self.offerEndTime then local timeLeft = self.offerEndTime self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) self.TimeLeft:SetTextColor(1,1,1) elseif self.missionEndTime then if self.isComplete then return end local timeLeft = self.missionEndTime - time() if timeLeft < 0 then self:OnComplete() else self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) if timeLeft > 3600 then self.TimeLeft:SetTextColor(1,1,1) else self.TimeLeft:SetTextColor(1,1,0) end end if not self.isComplete then local progress = (time() - (self.missionEndTime - self.durationSeconds)) / self.durationSeconds local w = self.ProgressBG:GetWidth() if progress >= 1 then self.ProgressBar:SetWidth(w) else self.ProgressBar:SetWidth(progress * w) local r, g = 1, 0 if progress >= 0.5 then g = 1 r = 1-((progress-0.5)*2) else g = min(progress * 2, 1) r = 1 end self.ProgressBar:SetColorTexture(r,g,0,.4) self.ProgressBG:SetColorTexture(r,g,0,0.125) end self.ProgressBG:Show() self.ProgressBar:Show() else self.ProgressBG:Hide() self.ProgressBar:Hide() end else self.TimeLeft:SetText(self.missionEndTime) end end function MissionEntry:OnLoad() print('|cFFFF4400',self:GetName() or tostring(self), 'onload') self.Count = self.Overlay.Count self.Name = self.Overlay.Name self.TimeLeft = self.Overlay.TimeLeft self.Owner = self.Overlay.Owner self.Icon:SetDesaturated(false) self.Done:Hide() end function MissionEntry:Update() local r,g,b = 1, 1, 1 if self.isRare then r,g,b = 0.1, 0.4, 1 self.IconBorder:SetVertexColor(r, g, b, 1) end --self.missionData = data self.Name:SetText(self.name) if #self.rewards >= 1 then self.Icon:SetTexture(self.rewards[1].icon or GetItemIcon(self.rewards[1].itemID)) self.rewardInfo = self.rewards[1] else self.Icon:SetAtlas(self.typeAtlas, false) end if self.isComplete then self.TimeLeft:SetText('Complete!') self.Background:SetColorTexture(.25,.25,.25,1) else self.Background:SetColorTexture(0,0,0,0.5) end end function MissionEntry:OnEnter() if self.rewardInfo and self.rewardInfo.itemID then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:SetItemByID(self.rewardInfo.itemID) GameTooltip:Show() end end function MissionEntry:OnLeave() if GameTooltip:IsOwned(self) then GameTooltip:Hide() end end function ShipmentEntry:OnLoad() MissionEntry.OnLoad(self) end function ShipmentEntry:Update() print('|cFF0088FF'.. self.name..'|r:Update()') self.Icon:SetTexture(self.icon) self.Count:SetText(self.shipmentsReady) self.Done:SetShown(self.shipmentsReady and (self.shipmentsReady >= 1)) -- flag as complete local bgColor = CP_BACKGROUND_COLOR.inProgress if ( self.shipmentsReady >= self.shipmentsTotal ) and (not self.isBeingResearched) then self.Swipe:SetCooldownUNIX(0, 0); self.Done:Show(); bgColor = CP_BACKGROUND_COLOR.complete else if (self.shipmentsReady >= 1) and (self.shipmentsReady < self.shipmentsTotal) then bgColor = CP_BACKGROUND_COLOR.shipmentsReady end self.Swipe:SetCooldownUNIX(self.creationTime or 0 , self.duration or 0); end self.Background:SetColorTexture(unpack(bgColor)) SetActualShipmentTime(self) if self.originalReady then print('|cFF00FF88'..self.name..'|r', 'starting ready:', self.originalReady, 'starting time:', self.originalCreationTime) end end function ShipmentEntry:OnUpdate(sinceLast) self.throttle = (self.throttle or 1) + sinceLast if self.throttle >= 1 then self.throttle = self.throttle - 1 else return end if (self.shipmentsReady and self.shipmentsTotal) and (self.shipmentsReady < self.shipmentsTotal) then local timeLeft = SetActualShipmentTime(self) if self.isComplete then self.TimeLeft:SetText('Complete!') self.TimeLeft:SetTextColor(0,0.5,1) elseif self.shipmentsReady >= 1 then self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) self.TimeLeft:SetTextColor(0,1,0) else self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) self.TimeLeft:SetTextColor(1,1,1) end elseif self.isBeingResearched then self.TimeLeft:SetText(GetTimeLeftString(self.researchStartTime + self.researchDuration - time())) self.TimeLeft:SetTextColor(1,1,0) else self.TimeLeft:SetText('Complete!') self.TimeLeft:SetTextColor(0,1,0) end if not self.isComplete then local progress = ((time() - self.creationTime) / self.duration) local w = self.ProgressBG:GetWidth() if progress >= 1 then self.ProgressBar:SetWidth(w) else self.ProgressBar:SetWidth(progress * w) end local r, g = 1, 0 if progress >= 0.5 then g = 1 r = 1-((progress-0.5)*2) else g = min(progress * 2, 1) r = 1 end self.ProgressBar:SetColorTexture(r, g, 0, .4) self.ProgressBG:SetColorTexture(r, g, 0, .125) self.ProgressBG:Show() self.ProgressBar:Show() else self.ProgressBG:Hide() self.ProgressBar:Hide() end end function ShipmentEntry:OnEnter() if ( self.shipmentsReady and self.shipmentsTotal ) then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:AddLine(self.Owner:GetText(), self.Owner:GetTextColor()) GameTooltip:AddLine(self.shipmentType) GameTooltip:AddLine(self.shipmentsReady .. ' of '.. self.shipmentsTotal) GameTooltip:Show() end end function ShipmentEntry:OnLeave() if GameTooltip:IsOwned(self) then GameTooltip:Hide() end end function ShipmentEntry:OnClick(button) if button == 'RightButton' then self.handler:FreeBlock(self) end end ClassPlanMissionHandler = Mixin(MissionList, SharedHandlers) ClassPlanShipmentHandler = Mixin(ShipmentList, SharedHandlers) ClassPlanMissionEntryMixin = Mixin(MissionEntry, SharedEntry) ClassPlanShipmentEntryMixin = Mixin(ShipmentEntry,SharedEntry) ClassPlanHeaderMixin = { OnClick = function(self) self:GetParent():SetList() self:GetParent().isStale = true ClassOrderPlan:Update() end }