Mercurial > wow > worldplan
view ClassPlan.lua @ 3:c006ce87a147
prototype structure
author | Nenue |
---|---|
date | Sat, 15 Oct 2016 09:54:56 -0400 |
parents | b8a19781f79b |
children | 4c7e9efec4b5 |
line wrap: on
line source
local wipe = table.wipe local pairs, ipairs = pairs, ipairs local GetTime = GetTime local GI_currentTime = time() local blockTemplate = { point = 'TOPLEFT', relativePoint ='TOPLEFT', } SLASH_CLASSPLAN1 = "/classplan" SLASH_CLASSPLAN2 = "/cp" SlashCmdList.CLASSPLAN = function(args) ClassOrderPlan:Toggle() end ClassOrderPlanCore = { events = {}, freeBlocks = {}, blocks = {}, sortedItems = {}, timers = {}, shipments = {}, playerFirst = false, prototypes = {} } ClassPlanBlockMixin = { templateName = 'ClassPlanBlock', events = {'GARRISON_MISSION_LIST_UPDATE', 'GARRISON_MISSION_FINISHED', 'GARRISON_MISSION_FINISHED'},} ClassPlanShipmentMixin = { templateName = 'ClassPlanShipment', parent = false, point = 'TOPRIGHT', relativePoint ='TOPRIGHT', events = {'GARRISON_LANDINGPAGE_SHIPMENTS', 'GARRISON_TALENT_UPDATE', "GARRISON_TALENT_COMPLETE", 'GARRISON_TALENT_COMPLETE', 'GARRISON_SHIPMENT_RECEIVED', "GARRISON_SHIPMENT_RECEIVED"}, } setmetatable(ClassPlanShipmentMixin, {__index = ClassPlanBlockMixin}) local core, MissionsHandler, ShipmentsHandler = ClassOrderPlanCore, ClassPlanBlockMixin, ClassPlanShipmentMixin local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop MissionsHandler.GetPlayerData = function(self) if not self.profile then return end self.items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0) if #self.items >= 1 then wipe(self.profile.missions) for index, data in ipairs(self.items) do print(' ',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime)) tinsert(self.profile.missions, data) end print('items update pending') self.isStale = true end if self:IsVisible() then self:Refresh() end end MissionsHandler.SortHandler = function (a,b) local result = false if not a or not b then result = 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 result = ( b.missionEndTime > a.missionEndTime) end end return result end ShipmentsHandler.OnGetItem = function(data) if data.shipmentsTotal then local timeLeft = data.creationTime + data.duration - GI_currentTime if (timeLeft <= 0) and (data.shipmentsReady < data.shipmentsTotal) then local numOrders = -1*floor(timeLeft/data.duration) data.originalCreationTime = data.creationTime data.originalShipmentsReady = data.shipmentsReady data.creationTime = data.creationTime + numOrders*data.duration data.shipmentsReady = data.shipmentsReady + numOrders print(data.profileKey, 'shipment "'.. data.name..'" reconciling', numOrders, 'lapsed orders. -->', data.creationTime, data.shipmentsReady) end end end ShipmentsHandler.SortHandler = function(a, b) if b.isComplete ~= a.isComplete then return a.isComplete and true or false end return (a.creationTime) < (b.creationTime) end ShipmentsHandler.GetPlayerData = function (self) if not self.profile then return end wipe(self.shipments) local garrisonType = LE_GARRISON_TYPE_7_0 local buildings = C_Garrison.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 = C_Garrison.GetLandingPageShipmentInfo(buildingID); tinsert(self.shipments, { shipmentType = 'Work Order', name = name, icon = texture, shipmentCapacity = shipmentCapacity, shipmentsReady = shipmentsReady, shipmentsTotal = shipmentsTotal, creationTime = creationTime, duration = duration, timeleftString = timeleftString, itemName = itemName, itemIcon = itemIcon, itemQuality = itemQuality, itemID = itemID }) end --print('Follower:') local followerShipments = C_Garrison.GetFollowerShipments(garrisonType); for i = 1, #followerShipments do local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, _, _, _, _, followerID = C_Garrison.GetLandingPageShipmentInfoByContainerID(followerShipments[i]); tinsert(self.shipments, { shipmentType = '', name = name, icon = texture, shipmentCapacity = shipmentCapacity, shipmentsReady = shipmentsReady, shipmentsTotal = shipmentsTotal, creationTime = creationTime, duration = duration, timeleftString = timeleftString, followerID = followerID, }) end --print('Loose:') local looseShipments = C_Garrison.GetLooseShipments(garrisonType) for i = 1, #looseShipments do local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString = C_Garrison.GetLandingPageShipmentInfoByContainerID(looseShipments[i]); tinsert(self.shipments, { shipmentType = '', name = name, icon = texture, shipmentCapacity = shipmentCapacity, shipmentsReady = shipmentsReady, shipmentsTotal = shipmentsTotal, creationTime = creationTime, duration = duration, timeleftString = timeleftString, }) end local talentTrees = C_Garrison.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 = C_Garrison.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) then showTalent = true; end if (talent.id == completeTalentID) then showTalent = true; end if (showTalent) then print(talent.name) talent.creationTime = talent.researchStartTime talent.duration = talent.researchDuration talent.shipmentType = 'Talent: ' tinsert(self.shipments, talent) end end end end self.profile.shipments = self.profile.shipments or {} if #self.shipments >= 1 then wipe(self.profile.shipments) for index, data in ipairs(self.shipments) do print(' ', data.shipmentType .. data.name, data.creationTime, data.duration) tinsert(self.profile.shipments, data) end self.isStale = true end if self:IsVisible() then self:Refresh() end end function core:OnLoad () self:RegisterUnitEvent('UNIT_PORTRAIT_UPDATE', 'player') self:RegisterEvent('PLAYER_LOGIN') self:RegisterEvent('PLAYER_ENTERING_WORLD') self:RegisterEvent('ADDON_LOADED') self:RegisterEvent('PLAYER_REGEN_ENABLED') self:AddHandler('missions', MissionsHandler) self:AddHandler('shipments', ShipmentsHandler) end function core:AddHandler(name, prototype) self.prototypes[name] = setmetatable(prototype, { __index = blockTemplate, __tostring = function() return name end }) for i, event in ipairs(prototype.events) do if not self.events[event] then self:RegisterEvent(event) self.events[event] = {} print('|cFF00FF00registering', event) end prototype.numBlocks = 0 if not self.events[event][name] then print('adding', name, 'to', event) self.events[event][name] = prototype.GetPlayerData end end self.sortedItems[name] = {} end function core:OnEvent (event, ...) print(event) if event == 'UNIT_PORTRAIT_UPDATE' then SetPortraitTexture(self.portrait, 'player') elseif event == 'PLAYER_LOGIN' then if not self.initialized then if IsLoggedIn() then WorldPlanData.OrderHall = WorldPlanData.OrderHall or {} self.data = WorldPlanData.OrderHall local name, realm = UnitName('player') realm = realm or GetRealmName() self.profileKey = name .. '-' .. realm if not self.data[self.profileKey] then self.data[self.profileKey] = {} end self.profile = self.data[self.profileKey] self.profile.shipments = self.profile.shipments or {} self.profile.missions = self.profile.missions or {} self.profile.classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))] C_Garrison.RequestLandingPageShipmentInfo(); if self.data.IsShown then self:Show() end self.initialized = true end end elseif self.events[event] then for ptype, eventFunc in pairs(self.events[event]) do print('|cFF88FF00' .. tostring(ptype) .. '|r:GetPlayerData()') eventFunc(self, event) end end end function core:UpdateNotifications() end function core:RefreshItems(configKey, prototype) local sortedItems = self.sortedItems[configKey] self.blocks[configKey] = self.blocks[configKey] or {} local blocks = self.blocks[configKey] local lastProfile local numItems = #sortedItems local totalHeight = 0 for i, data in ipairs(sortedItems) do local block = blocks[i] if not block then block = CreateFrame('Button', nil, self, prototype.templateName) block:SetID(i) prototype.numBlocks = prototype.numBlocks + 1 if prototype.lastBlock then block:SetPoint('TOPLEFT', prototype.lastBlock, 'BOTTOMLEFT', 0, 0) else block:SetPoint(prototype.point, self[prototype.parent] or self, prototype.relativePoint, 0, 0) end prototype.lastBlock = block blocks[i] = block end totalHeight = totalHeight + block:GetHeight() block.lastProfile = lastProfile block:Refresh(data) block:Show() lastProfile = data.profileKey end for i = numItems + 1, prototype.numBlocks do if blocks[i] then blocks[i]:Hide() end end return totalHeight end local max = math.max function core:Refresh() if self.isStale then self:SortItems() end self.isStale = nil self.currentHeight = 0 for name, info in pairs(self.prototypes) do local itemsHeight = self:RefreshItems(name, info) self.currentHeight = max(itemsHeight, self.currentHeight) end if OrderHallCommandBar and OrderHallCommandBar:IsVisible() then self:ClearAllPoints() self:SetPoint('TOP', OrderHallCommandBar, 'BOTTOM') else local posX = self.data.posX or 0 local posY = self.data.posY or -24 local point = self.point or 'TOP' local relativePoint = self.point or 'TOP' self:SetPoint(point, UIParent, relativePoint, posX, posY) end self:SetHeight(self.currentHeight) end function core:Toggle() if self:IsVisible() then self:Hide() else self:Show() end if self.data then self.data.IsShown = self:IsVisible() end end function core:OnUpdate() if self.fadeTimer and self.fadeTimer < GetTime() then self:Hide() end end function core:OnShow() if self.isStale then print('updating items on show') self:Refresh() end ClassPlanButton:SetPoint('TOP', self, 'TOP', 0, 0) end function core:OnHide() ClassPlanButton:SetPoint('TOP', UIParent, 'TOP', 0, 0) end local GI_profileKey, GI_profile, GI_isMine local GetItemList = function (source, dest, onGetItem) if not source then return end local numItems = 0 for index, data in ipairs(source) do data.classColor = GI_profile.classColor or {r = 0.7, g = 0.7, b =0.7} data.profileKey = GI_profileKey data.isMine = GI_isMine if onGetItem then onGetItem(data) end numItems = numItems + 1 tinsert(dest, data) end return numItems end function core:SortItems() print('|cFF0088FFSortItems()|r') GI_currentTime = time() for key, sortedItems in pairs(self.sortedItems) do wipe(sortedItems) local ptype = self.prototypes[key] print( 'object:', ptype) for name, profile in pairs(self.data.characters) do GI_profileKey = name GI_profile = profile GI_isMine = (profile == self.profile) local results = GetItemList(profile[key], sortedItems, ptype.OnGetItem) print(' - ', name, results, 'items') end if ptype.SortHandler then print(' sorting', key, #sortedItems) table.sort(sortedItems, ptype.SortHandler) end end end function core:UpdateItems () end function MissionsHandler:OnComplete() self.data.isComplete = true self:Refresh() end 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 function MissionsHandler:OnUpdate() if self.data.isComplete then return end if self.missionEndTime then 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 else self.TimeLeft:SetText(self.missionEndTime) end end local SetClassColors = function(self, data) if self.lastProfile ~= data.profileKey then self.Owner:SetText(data.profileKey) self.Owner:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b) else self.Owner:SetText(nil) end self.Background:SetColorTexture(data.classColor.r, data.classColor.g, data.classColor.b, (data.isComplete and 0.5 or 0.1)) end function MissionsHandler:Refresh(data) data = data or self.data self.data = data self.isComplete = data.isComplete self.missionEndTime = data.missionEndTime local r,g,b = 1, 1, 1 if data.isRare then r,g,b = 0.1, 0.4, 1 end --self.missionData = data self.Label:SetText(data.name) self.Label:SetTextColor(r, g, b) if #data.rewards >= 1 then self.Icon:SetTexture(data.rewards[1].icon or GetItemIcon(data.rewards[1].itemID)) self.rewardInfo = data.rewards[1] else self.Icon:SetAtlas(data.typeAtlas, false) end if self.isComplete then self.TimeLeft:SetText('Complete!') end SetClassColors(self, data) end function MissionsHandler:OnEnter() if self.rewardInfo and self.rewardInfo.itemID then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:SetItemByID(self.rewardInfo.itemID) GameTooltip:Show() end end function MissionsHandler:OnLeave() if GameTooltip:IsOwned(self) then GameTooltip:Hide() end end function ShipmentsHandler:Refresh(data) data = data or self.data --[[ self.icon = data.icon self.shipmentCapacity = data.shipmentCapacity self.shipmentsReady = data.shipmentsReady self.shipmentsTotal = data.shipmentsTotal self.creationTime = data.creationTime self.duration = data.duration self.itemID = data.itemID self.itemQuality = data.itemQuality icon = texture, shipmentCapacity = shipmentCapacity, shipmentsReady = shipmentsReady, shipmentsTotal = shipmentsTotal, creationTime = creationTime, duration = duration, timeleftString = timeleftString, itemName = itemName, itemIcon = itemIcon, itemQuality = itemQuality, itemID = itemID --]] self.Icon:SetTexture(data.icon) self.data = data local isComplete = data.isComplete self.Name:SetText(data.shipmentType .. data.name) self.Count:SetText(data.shipmentsReady) self.Done:SetShown(data.shipmentsReady and (data.shipmentsReady >= 1)) -- flag as complete if ( data.shipmentsReady == data.shipmentsTotal ) and (not data.isBeingResearched) then self.Swipe:SetCooldownUNIX(0, 0); self.Done:Show(); isComplete = true else self.Swipe:SetCooldownUNIX(data.creationTime or 0 , data.duration or 0); end data.isComplete = isComplete SetClassColors(self, data) end function ShipmentsHandler:OnUpdate() local data = self.data if (data.shipmentsReady and data.shipmentsTotal) and (data.shipmentsReady ~= data.shipmentsTotal) then local timeLeft = data.creationTime + data.duration - time() self.TimeLeft:SetText('Next: '.. GetTimeLeftString(timeLeft) .. ' |cFFFFFF00'..data.shipmentsTotal..' orders|r') elseif data.isStale then self.TimeLeft:SetText('|cFFFF0000Needs refresh|r') elseif data.isBeingResearched then self.TimeLeft:SetText(GetTimeLeftString(data.researchStartTime + data.researchDuration - time())) else self.TimeLeft:SetText('Complete!') end end function ShipmentsHandler:OnEnter() local data = self.data if ( data.shipmentsReady and data.shipmentsTotal ) then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:AddLine(data.shipmentsReady .. ' of '.. data.shipmentsTotal) GameTooltip:Show() end end function ShipmentsHandler:OnLeave() if GameTooltip:IsOwned(self) then GameTooltip:Hide() end end function ShipmentsHandler:OnClick(button) if button == 'RightButton' then for name, profile in pairs(ClassOrderPlan.data) do for index, shipment in pairs(profile.shipments) do if shipment == self.data then profile.shipments[index] = nil ClassOrderPlan:Refresh() end end end end end