comparison ClassPlan.lua @ 32:e8679ecb48d8

ClassPlan: - Available missions are now recorded; the mission list can be toggled between in-progress and available by clicking the heading.
author Nenue
date Tue, 01 Nov 2016 10:48:50 -0400
parents 4a7e89bffbcb
children 26dfa661daa7
comparison
equal deleted inserted replaced
31:d0114b51cdea 32:e8679ecb48d8
1 local wipe, tinsert, sort = table.wipe, tinsert, table.sort 1 local wipe, tinsert, sort = table.wipe, tinsert, table.sort
2 local pairs, ipairs = pairs, ipairs 2 local pairs, ipairs = pairs, ipairs
3 local floor, mod, time = floor, mod, time 3 local floor, mod, time = floor, mod, time
4 local max, min = math.max, math.min
4 local GetTime = GetTime 5 local GetTime = GetTime
5 local GI_currentTime = time() 6 local GI_currentTime = time()
6 7 local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop
7 local BOUND_FRAMES = {} 8
8 local blockTemplate = { 9 local CG_GetBuildings = C_Garrison.GetBuildings
9 point = 'TOPLEFT', 10 local CG_GetFollowerShipments = C_Garrison.GetFollowerShipments
10 relativePoint ='TOPLEFT', 11 local CG_GetLooseShipments = C_Garrison.GetLooseShipments
12 local CG_GetTalentTrees = C_Garrison.GetTalentTrees
13 local CG_GetCompleteTalent = C_Garrison.GetCompleteTalent
14 local CG_GetLandingPageShipmentInfo = C_Garrison.GetLandingPageShipmentInfo
15 local CG_GetLandingPageShipmentInfoByContainerID = C_Garrison.GetLandingPageShipmentInfoByContainerID
16
17 local CP_REPLACE_LANDINGPAGE = true
18 local CP_HEADER_SIZE = 24
19 local CP_BACKGROUND_COLOR = {
20 inProgress = {0, 0, 0, 0.5},
21 shipmentsReady = {0, 0, 0, 0.25},
22 complete = {0.5, 0.5, 0.5, 0.5}
11 } 23 }
12 24
13 SLASH_CLASSPLAN1 = "/classplan" 25 local GetTimeLeftString = function(timeLeft)
14 SLASH_CLASSPLAN2 = "/cp" 26 local days = floor(timeLeft/(24*3600))
15 SlashCmdList.CLASSPLAN = function(args) 27 local hours = floor(mod(timeLeft, (24*3600)) / 3600)
16 ClassOrderPlan:Toggle() 28 local minutes = floor(mod(timeLeft, 3600) / 60)
17 end 29 local seconds = mod(timeLeft, 60)
30 if days >= 1 then
31 return (days .. 'd' .. ' ') .. ((hours > 0) and (hours .. 'h') or '')
32 else
33 return ((hours > 0) and (hours .. 'h') or '') .. ((minutes > 0) and (' ' ..minutes .. ' min') or '')
34 end
35 end
36
18 37
19 ClassOrderPlanCore = { 38 ClassOrderPlanCore = {
20 events = {}, 39 events = {},
21 freeBlocks = {}, 40 freeBlocks = {},
22 blocks = {}, 41 blocks = {},
25 shipments = {}, 44 shipments = {},
26 playerFirst = false, 45 playerFirst = false,
27 prototypes = {}, 46 prototypes = {},
28 Queued = {} 47 Queued = {}
29 } 48 }
30 49 local MissionList = {
31 ClassPlanMissionMixin = {
32 templateName = 'ClassPlanMissionEntry', 50 templateName = 'ClassPlanMissionEntry',
51 listKey = {'missions', 'available'},
52 listTitle = {'In Progress', 'Available'},
53
54 point = 'TOPLEFT',
55 relativePoint ='TOPLEFT',
33 events = { 56 events = {
34 'GARRISON_MISSION_LIST_UPDATE', 57 'GARRISON_MISSION_LIST_UPDATE',
35 'GARRISON_MISSION_STARTED', 58 'GARRISON_LANDINGPAGE_SHIPMENTS'},
36 'GARRISON_MISSION_FINISHED', 59 }
37 'GARRISON_LANDINGPAGE_SHIPMENTS'},} 60 local ShipmentList = {
38 ClassPlanShipmentMixin = {
39 templateName = 'ClassPlanShipmentEntry', 61 templateName = 'ClassPlanShipmentEntry',
40 parent = false, 62 listKey = {'shipments'},
41 point = 'TOPRIGHT', 63 listTitle = {'Work Orders'},
42 relativePoint ='TOPRIGHT',
43 events = { 64 events = {
65 'GARRISON_MISSION_LIST_UPDATE',
44 'GARRISON_LANDINGPAGE_SHIPMENTS', 66 'GARRISON_LANDINGPAGE_SHIPMENTS',
45 'GARRISON_TALENT_UPDATE', 67 'GARRISON_TALENT_UPDATE',
46 "GARRISON_TALENT_COMPLETE", 68 "GARRISON_TALENT_COMPLETE",
47 "GARRISON_SHIPMENT_RECEIVED", 69 "GARRISON_SHIPMENT_RECEIVED",
48 'GARRISON_FOLLOWER_LIST_UPDATE', 70 'GARRISON_FOLLOWER_LIST_UPDATE',
49 'GARRISON_SHOW_LANDING_PAGE'}, 71 'GARRISON_SHOW_LANDING_PAGE'},
50 } 72 }
51 setmetatable(ClassPlanShipmentMixin, {__index = ClassPlanMissionMixin}) 73 local SharedHandlers = {
52 local core, MissionsHandler, ShipmentsHandler = ClassOrderPlanCore, ClassPlanMissionMixin, ClassPlanShipmentMixin 74 numBlocks = 0,
53 local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop 75 isStale = true,
54 76 }
55 local GetTimeLeftString = function(timeLeft) 77 local SharedEntry = {}
56 local days = floor(timeLeft/(24*3600)) 78 local ShipmentEntry = {}
57 local hours = floor(mod(timeLeft, (24*3600)) / 3600) 79 local MissionEntry = {}
58 local minutes = floor(mod(timeLeft, 3600) / 60) 80
59 local seconds = mod(timeLeft, 60) 81 local ClassPlan = ClassOrderPlanCore
60 if days >= 1 then 82
61 return (days .. 'd' .. ' ') .. ((hours > 0) and (hours .. 'h') or '') 83 function ClassPlan:OnLoad ()
62 else 84 self:RegisterEvent('PLAYER_LOGIN')
63 return ((hours > 0) and (hours .. 'h') or '') .. ((minutes > 0) and (' ' ..minutes .. ' min') or '') 85 self:RegisterEvent('ADDON_LOADED')
64 end 86 self:RegisterEvent('PLAYER_REGEN_ENABLED')
65 end 87 self:RegisterEvent('PLAYER_REGEN_DISABLED')
66 88 self:RegisterForDrag('LeftButton')
67 89 self:SetMovable(true)
68 90 self:SetToplevel(true)
69 MissionsHandler.GetPlayerData = function(self) 91
70 if not self.profile then 92
93 SLASH_CLASSPLAN1 = "/classplan"
94 SLASH_CLASSPLAN2 = "/cp"
95 SlashCmdList.CLASSPLAN = function(args)
96 self:Toggle()
97 end
98
99 end
100
101 function ClassPlan:GetCurrentProfile()
102 WorldPlanData.OrderHall = WorldPlanData.OrderHall or {}
103 local db = WorldPlanData.OrderHall
104 self.data = db
105
106 local characters = db.characters or {}
107 db.characters = characters
108
109 local name, realm = UnitName('player')
110 realm = realm or GetRealmName()
111 local profileName = name .. '-' .. realm
112
113 self.profile = characters[profileName] or {}
114 self.characters = characters
115 characters[profileName] = self.profile
116
117
118 local classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))]
119 local className = UnitClass('player')
120
121 print('|cFFFFFF00Loaded:|r', classColor.hex, className, profileName)
122 self.Background:SetColorTexture(classColor.r, classColor.g, classColor.b, 0.5)
123 self.profile.classColor = classColor
124 self.profile.className = className
125 return self.profile
126 end
127
128 function ClassPlan:SetupHandler(handler)
129 print('|cFF00FF00'..handler:GetName()..' loaded')
130 for i, event in ipairs(handler.events) do
131 print('|cFF00FF00 event', event)
132 handler:RegisterEvent(event)
133 end
134 for index, listKey in ipairs(handler.listKey) do
135 self.profile[listKey] = self.profile[listKey] or {}
136 local listTitle = handler.listTitle[index]
137 setmetatable(self.profile[listKey], { __tostring = listTitle })
138 end
139 handler:SetList(1)
140 handler.sortedItems = {}
141 end
142
143 function ClassPlan:OnEvent (event, arg)
144 print(event, arg)
145 if event == 'PLAYER_REGEN_DISABLED' then
146 if self:IsVisible() then
147 self.combatHide = true
148 self:SetShown(false)
149 end
150
151 elseif event == 'PLAYER_REGEN_ENABLED' then
152 if self.combatHide == true then
153 self.combatHide = nil
154 self:SetShown(true)
155 end
156 elseif event == 'ADDON_LOADED' then
157 if arg == 'Blizzard_GarrisonUI' then
158 self:Reanchor()
159 end
160 elseif event == 'PLAYER_LOGIN' then
161 if not self.initialized then
162 self:Setup()
163 end
164 end
165 end
166
167 function ClassPlan:Setup()
168 if IsLoggedIn() then
169 print('|cFFFFFF00'..self:GetName()..':Setup()|r')
170
171 self:GetCurrentProfile()
172 for _, handler in ipairs(self.Handlers) do
173 self:SetupHandler(handler)
174 end
175 self.initialized = true
176 self:SetShown(self.data.IsShown)
177 end
178 end
179
180
181 --- Update space
182
183 local max = math.max
184 function ClassPlan:Update()
185 print('|cFF00FFFFRefresh()|r')
186 self.currentHeight = 0
187 for index, handler in pairs(self.Handlers) do
188 if handler.isStale then
189 print(' |cFF00FF00'..index..' '..handler:GetName()..'|r')
190 local sortedItems = handler.sortedItems
191 local activeKey = handler.activeKey
192 handler.profile = self.profile[handler.activeKey]
193
194 wipe(sortedItems)
195 handler:GetPlayerData(self.profile)
196 for key, profile in pairs(self.data.characters) do
197 print('profile', key, activeKey)
198 local profileList = profile[activeKey]
199 if profileList and #profileList >= 1 then
200 local classColor = profile.classColor or defaultClassColor
201 local isMine = (profile == self.profile)
202 for index, data in ipairs(profileList) do
203 data.classColor = classColor
204 data.profileKey = key
205 data.isMine = isMine
206 if handler.OnGetItem then
207 handler.OnGetItem(data)
208 end
209 tinsert(sortedItems, data)
210 end
211 end
212 end
213
214 if handler.SortHandler then
215 sort(sortedItems, handler.SortHandler)
216 end
217
218 end
219 handler.isStale = nil
220 local itemsHeight = handler:UpdateItems()
221 self.currentHeight = max(itemsHeight, self.currentHeight)
222
223 end
224
225 self.isStale = nil
226 self:Reanchor()
227 self:SetHeight(self.currentHeight + CP_HEADER_SIZE)
228 end
229
230
231 function ClassPlan:Toggle()
232 if self:IsShown() then
233 self:Hide()
234 else
235 self:Show()
236 end
237
238 if self.data then
239 self.data.IsShown = self:IsShown()
240 end
241 end
242
243 function ClassPlan:OnUpdate()
244 if self.isStale then
245 print('|cFFFF4400An illusion! What are you hiding?|r')
246 self:Update()
247 end
248 end
249
250 function ClassPlan:OnShow()
251 print('|cFF00FFFFShow()')
252 if self.isStale then
253 self:Update()
254 end
255 self:Reanchor()
256 end
257
258 function ClassPlan:OnHide()
259 print('|cFF00FFFFHide()')
260 end
261
262 function ClassPlan:Reanchor()
263 self:ClearAllPoints()
264 self:SetPoint('CENTER', self.data.positionX, self.data.positionY)
265
266 for index, frame in ipairs(self.Handlers) do
267 frame:Reanchor()
268 end
269 end
270
271 function ClassPlan:OnDragStart()
272 self:StartMoving()
273 end
274 function ClassPlan:OnDragStop()
275
276 self:StopMovingOrSizing()
277 local x,y = self:GetCenter()
278 if x and y then
279 x = (x - GetScreenWidth()/2)
280 y = (y - GetScreenHeight()/2) * -1
281 self.data.positionX, self.data.positionY = x,y
282 print('saving positions:', x, y)
283 end
284 end
285
286 function SharedHandlers:SetList(index)
287 if not index then
288 if self.currentListIndex == #self.listKey then
289 index = 1
290 else
291 index = self.currentListIndex + 1
292 end
293 end
294
295 print('|cFF0088FF'..self:GetName()..'|r:SetList()', index)
296 self.currentListIndex = index
297 self.activeKey = self.listKey[index]
298 self.activeTitle = self.listTitle[index]
299
300 self.isStale = true
301 end
302
303 function SharedHandlers:RequestData()
304 print('|cFF0088FF'..self:GetName()..':RequestData()')
305 self.isStale = true
306 end
307
308 function SharedHandlers:OnEvent(event, arg)
309 if (event == 'GARRISON_MISSION_LIST_UPDATE') and (arg ~= LE_FOLLOWER_TYPE_GARRISON_7_0) then
310 -- ignore non-OrderHall updates
71 return 311 return
72 end 312 end
313 print('|cFF00FF88'..self:GetName()..':OnEvent()|r', event, arg)
314 if self:IsVisible() then
315 print('|cFF88FF00 frame visible; get busy')
316 self:RequestData()
317 else
318 if not self.NextData then
319 print('|cFF88FF00 setting timer')
320 self.NextData = C_Timer.NewTimer(0.25, function()
321 if self.initialized then
322 self:RequestData()
323 self.NextData:Cancel()
324 self.NextData = nil
325 print('|cFF88FF00'..self:GetName()..' clearing timer')
326 end
327
328 end)
329 end
330 end
331 end
332 function SharedHandlers:OnUpdate()
333 if self.isStale then
334 self:GetParent():Update()
335 end
336 end
337
338
339 -- Stuff set on every list item
340 function SharedHandlers:SetOwnerData (self, data)
341 local name, realm = string.match(data.profileKey, "(.+)%-(.+)")
342 local ownerText = '|c'.. data.classColor.colorStr .. name .. '|r'
343 self.Owner:SetText(ownerText)
344 self.Name:SetText(self.name)
345 self.Name:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b)
346 end
347
348 function SharedHandlers:UpdateItems()
349 local sortedItems = self.sortedItems
350
351 self.blocks = self.blocks or {}
352 local blocks = self.blocks
353
354 local lastProfile
355 local numItems = #sortedItems
356 local totalHeight = 0
357 self.lastBlock = nil
358 self.numActive = 0
359 for i, data in ipairs(sortedItems) do
360 local block = blocks[i]
361 if not block then
362 block = CreateFrame('Button', nil, self, self.templateName)
363 block:SetID(i)
364 block.listType = self.activeKey
365 block.handler = self
366 self.numBlocks = self.numBlocks + 1
367 blocks[i] = block
368 end
369
370 print('RefreshItem', block)
371 self.numActive = self.numActive + 1
372
373 if self.lastBlock then
374 block:SetPoint('TOPLEFT', self.lastBlock, 'BOTTOMLEFT', 0, 0)
375 print('--', i, data.isComplete, data.missionEndTime, data.name)
376 else
377 block:SetPoint('TOPLEFT', 0, 0)
378 print('--top')
379 end
380 self.lastBlock = block
381
382 totalHeight = totalHeight + block:GetHeight()
383 block.lastProfile = lastProfile
384 -- blot out arbitrary flags
385 block.offerEndTime = nil
386 block.missionEndTime = nil
387 block.creationTime = nil
388 block.duration = nil
389 block.throttle = 5
390
391 for k,v in pairs(data) do
392 if type(block[k]) ~= 'function' then
393 block[k] = v
394 end
395 end
396
397 block:Update()
398 self:SetOwnerData(block, data)
399
400 block:Show()
401 lastProfile = data.profileKey
402 end
403
404 for i = numItems + 1, self.numBlocks do
405 if blocks[i] then
406 blocks[i]:Hide()
407 end
408 end
409
410 self:Reanchor()
411
412 return totalHeight
413 end
414
415
416 function ShipmentList:Reanchor()
417 print('|cFF00FFFF'..self:GetName()..':Reanchor|r')
418 self:SetPoint('TOPLEFT', 0, -24)
419 self:SetPoint('BOTTOMRIGHT', -ClassOrderPlan:GetWidth()/2, 0)
420 end
421
422 function MissionList:Reanchor()
423 self:SetPoint('TOPRIGHT', 0, -24)
424 self:SetPoint('BOTTOMLEFT', ClassOrderPlan:GetWidth()/2, 0)
425
426 self.ListTab:ClearAllPoints()
427 self.ListTab:SetPoint('TOPLEFT', self, 'TOPLEFT', 0, CP_HEADER_SIZE)
428 self.ListTab:SetPoint('BOTTOMRIGHT', self, 'TOPRIGHT', 0, 0)
429 self.ListTab.Label:SetText(self.listTitle[self.currentListIndex])
430 self.ListTab:Show()
431 print(self.ListTab:GetSize())
432 end
433
434 function MissionList:GetPlayerData (profile)
435 wipe(profile.missions)
436 wipe(profile.available)
437
438 local items = C_Garrison.GetAvailableMissions(GetPrimaryGarrisonFollowerType(LE_GARRISON_TYPE_7_0));
439 for i = 1, #items do
440 if (not items[i].isBuilding and items[i].isZoneSupport) then
441 else
442
443 tinsert(profile.available, items[i])
444 end
445 end
446
73 local items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0) 447 local items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0)
74 wipe(self.profile.missions)
75 for index, data in ipairs(items) do 448 for index, data in ipairs(items) do
76 print(' -',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime)) 449 print(' -',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime))
77 tinsert(self.profile.missions, data) 450 tinsert(profile.missions, data)
78 end 451 end
79 ClassOrderPlan.isStale = true 452 return true
80 end 453 end
81 454
82 MissionsHandler.OnGetItem = function(data) 455 do
83 if data.missionEndTime < GI_currentTime then 456 local ShipmentsInfo = {}
457 local AddShipmentInfo = function(shipmentType, name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID, followerID)
458 -- early login queries may return empty tables, causing the sorter to compare nil
459 if not creationTime then
460 return
461 end
462 --print(shipmentType, name, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString)
463 tinsert(ShipmentsInfo,
464 {
465 shipmentType = shipmentType,
466 name = name,
467 icon = texture,
468 shipmentCapacity = shipmentCapacity,
469 shipmentsReady = shipmentsReady,
470 shipmentsTotal = shipmentsTotal,
471 creationTime = creationTime,
472 duration = duration,
473 timeleftString = timeleftString,
474 itemName = itemName,
475 itemIcon = itemIcon,
476 itemQuality = itemQuality,
477 itemID = itemID,
478 followerID = followerID,
479 })
480 end
481 function ShipmentList:GetPlayerData (profile)
482 if not profile then
483 return false
484 end
485 local profileList = profile.shipments
486 wipe(ShipmentsInfo)
487
488 local garrisonType = LE_GARRISON_TYPE_7_0
489 local buildings = CG_GetBuildings(garrisonType);
490 local shipmentIndex = 0
491 --print('Buildings:')
492 for i = 1, #buildings do
493 local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID = CG_GetLandingPageShipmentInfo(buildingID);
494 AddShipmentInfo('Building', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID)
495 end
496
497 --print('Follower:')
498 local followerShipments = CG_GetFollowerShipments(garrisonType);
499 for i = 1, #followerShipments do
500 local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, _, _, _, _, followerID = CG_GetLandingPageShipmentInfoByContainerID(followerShipments[i]);
501 AddShipmentInfo('Follower', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, nil, nil, nil, nil, followerID)
502 end
503
504 --print('Loose:')
505 local looseShipments = CG_GetLooseShipments(garrisonType)
506 for i = 1, #looseShipments do
507 local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString = CG_GetLandingPageShipmentInfoByContainerID(looseShipments[i]);
508 AddShipmentInfo('Misc', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString)
509 end
510
511 local talentTrees = CG_GetTalentTrees(garrisonType, select(3, UnitClass("player")));
512 -- this is a talent that has completed, but has not been seen in the talent UI yet.
513 local completeTalentID = CG_GetCompleteTalent(garrisonType);
514 --print('Talents:')
515 if (talentTrees) then
516 for treeIndex, tree in ipairs(talentTrees) do
517 for talentIndex, talent in ipairs(tree) do
518 local showTalent = false;
519 if (talent.isBeingResearched) or (talent.id == completeTalentID) then
520 AddShipmentInfo('Talent', talent.name, talent.icon, 1, (talent.isBeingResearched and 0 or 1), 1, talent.researchStartTime, talent.researchDuration, talent.timeleftString)
521 end
522 end
523 end
524 end
525
526 wipe(profileList)
527 for index, data in ipairs(ShipmentsInfo) do
528 --DEFAULT_CHAT_FRAME:AddMessage(data.shipmentType ..' '.. tostring(data.name) ..' '.. tostring(data.creationTime) ..' '.. tostring(data.duration))
529 tinsert(profileList, data)
530 end
531 self.isStale = true
532 return true
533 end
534 end
535 MissionList.OnGetItem = function(data)
536 if data.missionEndTime and (data.missionEndTime < GI_currentTime) then
84 data.isComplete = true 537 data.isComplete = true
85 end 538 end
86 end 539 end
87 540
88 MissionsHandler.FreeBlock = function(self, block) 541 MissionList.FreeBlock = function(self, block)
89 end 542 end
90 543
91 MissionsHandler.SortHandler = function (a,b) 544 MissionList.SortHandler = function (a,b)
92 local result = false 545 local result = false
93 --if not a or not b then 546 --if not a or not b then
94 -- return true 547 -- return true
95 --else 548 --else
96 --if (a.isMine ~= b.isMine) then 549 --if (a.isMine ~= b.isMine) then
97 -- result = a.isMine 550 -- result = a.isMine
98 --else 551 --else
99 --if (not b.missionEndTime) or (not a.missionEndTime) then 552 --if (not b.missionEndTime) or (not a.missionEndTime) then
100 -- print('missing article', b.missionEndTime, a.missionEndTime) 553 -- print('missing article', b.missionEndTime, a.missionEndTime)
101 --end 554 --end
102 return ( b.missionEndTime > a.missionEndTime) 555 if b.isComplete ~= a.isComplete then
556 return a.isComplete
557 elseif b.isMine ~= a.isMine then
558 return a.isMine
559 elseif b.missionEndTime then
560 return ( b.missionEndTime > a.missionEndTime)
561 else
562 return ( b.offerEndTime > a.offerEndTime)
563 end
564
103 --end 565 --end
104 --end 566 --end
105 end 567 end
106 568
107 ShipmentsHandler.OnGetItem = function(data) 569
570 function MissionList:OnShow()
571 print('|cFF00FF88'..self:GetName()..':OnShow()|r')
572 end
573
574 function ShipmentList:OnLoad()
575 C_Garrison.RequestLandingPageShipmentInfo();
576 end
577 function ShipmentList:OnShow()
578 print('|cFF00FF88'..self:GetName()..':OnShow()|r')
579 C_Garrison.RequestLandingPageShipmentInfo()
580 end
581
582 -- Update shipment flags data
583 local SetActualShipmentTime = function(self)
584
585 if self.isComplete then
586 print('|cFF00FF88isComplete '..self.name..'|r')
587 return true
588 end
589
590 local timestamp = time()
591 local timeLeft = self.creationTime + self.duration - timestamp
592 local justFinished = false
593 while (self.shipmentsReady < self.shipmentsTotal) and (timeLeft <= 0) do
594 if not self.originalReady then
595 self.originalReady = self.shipmentsReady
596 self.originalCreationTime = self.creationTime
597 end
598
599
600 self.shipmentsReady = self.shipmentsReady + 1
601 self.creationTime = self.creationTime + self.duration
602 timeLeft = timeLeft + self.duration
603 print('|cFF00FF88udpating '..self.name..'|r', 'timeLeft:', timeLeft, 'shipments:', self.shipmentsReady, self.shipmentsTotal)
604 end
605
606 if (timeLeft <= 0) and (not self.isBeingResearched) then
607 self.isComplete = true
608 self.isStale = true
609 end
610
611 return timeLeft
612 end
613
614 ShipmentList.OnGetItem = function(data)
615 print('OnGetItem()')
108 if data.shipmentsTotal then 616 if data.shipmentsTotal then
109 local timeLeft = data.creationTime + data.duration - GI_currentTime 617 SetActualShipmentTime(data)
110 if (timeLeft <= 0) and (data.shipmentsReady < data.shipmentsTotal) then 618 end
111 local numOrders = min(-1*floor(timeLeft/data.duration), (data.shipmentsTotal - data.shipmentsReady)) 619 end
112 620
113 if not data.originalCreationTime then 621 ShipmentList.SortHandler = function(a, b)
114 data.originalCreationTime = data.creationTime
115 data.originalShipmentsReady = data.shipmentsReady
116 end
117
118 data.creationTime = data.creationTime + numOrders*data.duration
119 data.shipmentsReady = data.shipmentsReady + numOrders
120 print(data.profileKey, 'shipment "'.. data.name..'" reconciling', numOrders, 'lapsed orders. -->', data.creationTime, data.shipmentsReady)
121 end
122 end
123 end
124
125 ShipmentsHandler.SortHandler = function(a, b)
126 if b.isComplete ~= a.isComplete then 622 if b.isComplete ~= a.isComplete then
127 return a.isComplete and true or false 623 return a.isComplete and true or false
128 elseif a.shipmentsReady or b.shipmentsReady then 624 elseif a.shipmentsReady or b.shipmentsReady then
129 return (a.shipmentsReady or 0) > (b.shipmentsReady or 0) 625 return (a.shipmentsReady or 0) > (b.shipmentsReady or 0)
130 else 626 else
131 return (a.creationTime) < (b.creationTime) 627 return (a.creationTime) < (b.creationTime)
132 end 628 end
133 end 629 end
134 630
135 local ShipmentsInfo = {} 631
136 local AddShipmentInfo = function(shipmentType, name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID, followerID) 632 function MissionEntry:OnComplete()
137 -- early login queries may return empty tables, causing the sorter to compare nil 633 print('flagging complete', self.name)
138 if not creationTime then 634 self:Update()
635 end
636
637 function MissionEntry:OnUpdate(sinceLast)
638 self.throttle = (self.throttle or .5) + sinceLast
639 if self.throttle < .5 then
139 return 640 return
140 end 641 else
141 --print(shipmentType, name, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString)
142 tinsert(ShipmentsInfo,
143 {
144 shipmentType = shipmentType,
145 name = name,
146 icon = texture,
147 shipmentCapacity = shipmentCapacity,
148 shipmentsReady = shipmentsReady,
149 shipmentsTotal = shipmentsTotal,
150 creationTime = creationTime,
151 duration = duration,
152 timeleftString = timeleftString,
153 itemName = itemName,
154 itemIcon = itemIcon,
155 itemQuality = itemQuality,
156 itemID = itemID,
157 followerID = followerID,
158 })
159 end
160 ShipmentsHandler.GetPlayerData = function (self)
161 if not self.profile then
162 return
163 end
164 wipe(ShipmentsInfo)
165
166 local garrisonType = LE_GARRISON_TYPE_7_0
167 local buildings = C_Garrison.GetBuildings(garrisonType);
168 local shipmentIndex = 0
169 --print('Buildings:')
170 for i = 1, #buildings do
171 local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID = C_Garrison.GetLandingPageShipmentInfo(buildingID);
172 AddShipmentInfo('Building', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID)
173 end
174
175 --print('Follower:')
176 local followerShipments = C_Garrison.GetFollowerShipments(garrisonType);
177 for i = 1, #followerShipments do
178 local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, _, _, _, _, followerID = C_Garrison.GetLandingPageShipmentInfoByContainerID(followerShipments[i]);
179 AddShipmentInfo('Follower', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, nil, nil, nil, nil, followerID)
180 end
181
182 --print('Loose:')
183 local looseShipments = C_Garrison.GetLooseShipments(garrisonType)
184 for i = 1, #looseShipments do
185 local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString = C_Garrison.GetLandingPageShipmentInfoByContainerID(looseShipments[i]);
186 AddShipmentInfo('Misc', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString)
187 end
188
189 local talentTrees = C_Garrison.GetTalentTrees(garrisonType, select(3, UnitClass("player")));
190 -- this is a talent that has completed, but has not been seen in the talent UI yet.
191 local completeTalentID = C_Garrison.GetCompleteTalent(garrisonType);
192 --print('Talents:')
193 if (talentTrees) then
194 for treeIndex, tree in ipairs(talentTrees) do
195 for talentIndex, talent in ipairs(tree) do
196 local showTalent = false;
197 if (talent.isBeingResearched) or (talent.id == completeTalentID) then
198 AddShipmentInfo('Talent', talent.name, talent.icon, 1, (talent.isBeingResearched and 0 or 1), 1, talent.researchStartTime, talent.researchDuration, talent.timeleftString)
199 end
200 end
201 end
202 end
203
204 self.profile.shipments = self.profile.shipments or {}
205 wipe(self.profile.shipments)
206 for index, data in ipairs(ShipmentsInfo) do
207 --DEFAULT_CHAT_FRAME:AddMessage(data.shipmentType ..' '.. tostring(data.name) ..' '.. tostring(data.creationTime) ..' '.. tostring(data.duration))
208 tinsert(self.profile.shipments, data)
209 end
210 ClassOrderPlan.isStale = true
211 end
212
213 function core:OnLoad ()
214 self:RegisterEvent('PLAYER_LOGIN')
215 self:RegisterEvent('ADDON_LOADED')
216 self:RegisterEvent('PLAYER_REGEN_ENABLED')
217 self:RegisterEvent('PLAYER_REGEN_DISABLED')
218 -- Blizzard_GarrisonUI already fires a shipment data request for GARRISON_SHIPMENT_RECEIVED; this is unlikely to
219 self:AddHandler('missions', MissionsHandler)
220 self:AddHandler('shipments', ShipmentsHandler)
221 self:Reanchor()
222 C_Garrison.RequestLandingPageShipmentInfo();
223 end
224
225 local parentFrames = {'VeneerWorldState', 'OrderHallCommandBar'}
226 function core:Reanchor()
227 self:ClearAllPoints()
228 self.anchorParent = UIParent
229 local anchorTo = 'TOP'
230 for i, name in ipairs(parentFrames) do
231 local frame = _G[name]
232 if frame then
233 if not BOUND_FRAMES[frame] then
234 BOUND_FRAMES[frame] = {visible = (frame:IsVisible() and frame:IsShown())}
235 hooksecurefunc(frame, 'Show', function()
236 BOUND_FRAMES[frame].visible = true
237 print(frame:GetName(), 'Show', 'reanchor trigger')
238 self:Reanchor()
239 end)
240 hooksecurefunc(frame, 'Hide', function()
241 BOUND_FRAMES[frame].visible = nil
242 print(frame:GetName(), 'Hide', 'reanchor trigger')
243 self:Reanchor()
244 end)
245 end
246 print('f:', frame:GetName(), BOUND_FRAMES[frame].visible)
247 if BOUND_FRAMES[frame].visible then
248 self.anchorParent = frame
249 anchorTo = 'BOTTOM'
250 break
251 end
252 end
253 end
254 print('|cFFFF8800Using ' .. tostring(self.anchorParent:GetName()) .. '-'..anchorTo..' as anchor point')
255
256 if self:IsShown() then
257 ClassPlanButton.Background:Show()
258 ClassPlanButton:SetWidth(600)
259 else
260 ClassPlanButton.Background:Hide()
261 ClassPlanButton:SetWidth(200)
262 end
263
264 self:SetPoint('TOP', ClassPlanButton, 'BOTTOM', 0, 0)
265 ClassPlanButton:ClearAllPoints()
266 ClassPlanButton:SetPoint('TOP', self.anchorParent, anchorTo, 0, 0)
267
268 print(ClassPlanButton:GetPoint(1))
269 end
270
271 function core:AddHandler(name, prototype)
272 self.prototypes[name] = setmetatable(prototype, {
273 __index = blockTemplate,
274 __tostring = function() return name end
275 })
276
277 for i, event in ipairs(prototype.events) do
278 if not self.events[event] then
279 self:RegisterEvent(event)
280 self.events[event] = {}
281 print('|cFF00FF00registering', event)
282 end
283
284 prototype.numBlocks = 0
285 if not self.events[event][name] then
286 print('adding', name, 'to', event)
287 self.events[event][name] = prototype.GetPlayerData
288 end
289 end
290 self.sortedItems[name] = {}
291 end
292
293 function core:Setup()
294 if IsLoggedIn() then
295 WorldPlanData.OrderHall = WorldPlanData.OrderHall or {}
296 self.data = WorldPlanData.OrderHall
297 self.data.characters = self.data.characters or {}
298
299 local name, realm = UnitName('player')
300 realm = realm or GetRealmName()
301 self.profileKey = name .. '-' .. realm
302 if not self.data.characters[self.profileKey] then
303 self.data.characters[self.profileKey] = {}
304 end
305 self.profile = self.data.characters[self.profileKey]
306
307 self.profile.shipments = self.profile.shipments or {}
308 self.profile.missions = self.profile.missions or {}
309 self.profile.classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))]
310
311 if self.data.IsShown then
312 self:Show()
313 end
314 self.initialized = true
315 self.isStale = true
316 end
317 end
318
319 local last_invoc = {}
320 function core:OnEvent (event, ...)
321 print(event)
322 if event == 'PLAYER_REGEN_DISABLED' then
323 if self:IsVisible() then
324 self.combatHide = true
325 self:SetShown(false)
326 end
327
328 elseif event == 'PLAYER_REGEN_ENABLED' then
329 if self.combatHide == true then
330 self.combatHide = nil
331 self:SetShown(true)
332 end
333 elseif event == 'PLAYER_LOGIN' then
334 if not self.initialized then
335 self:Setup()
336 end
337 elseif self.initialized and self.events[event] then
338 self.isStale = true
339 if self:IsVisible() then
340
341 else
342 for handler, func in pairs(self.events[event]) do
343 if not self.Queued[handler] then
344 print('scheduling update for handler', handler)
345 self.Queued[handler] = C_Timer.NewTimer(0.25, function()
346 func(handler)
347 self.Queued[handler] = nil
348 end)
349 end
350 end
351 end
352 end
353 end
354
355 function core:UpdateNotifications()
356 end
357
358
359 local SetOwnerData = function(self, data)
360 local name, realm = string.match(data.profileKey, "(.+)%-(.+)")
361 local ownerText = '|c'.. data.classColor.colorStr .. name .. '|r'
362 --if realm ~= GI_currentRealm then
363 --ownerText = ownerText .. ' (' .. realm .. ')'
364 --end
365 self.Owner:SetText(ownerText)
366 self.Name:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b)
367 end
368
369 function core:RefreshItems(configKey, prototype)
370 local sortedItems = self.sortedItems[configKey]
371
372 self.blocks[configKey] = self.blocks[configKey] or {}
373 local blocks = self.blocks[configKey]
374
375 local lastProfile
376 local numItems = #sortedItems
377 local totalHeight = 0
378 for i, data in ipairs(sortedItems) do
379 local block = blocks[i]
380
381 if not block then
382 block = CreateFrame('Button', nil, self, prototype.templateName)
383 block:SetID(i)
384 block.handler = prototype
385 prototype.numBlocks = prototype.numBlocks + 1
386
387 if prototype.lastBlock then
388 block:SetPoint('TOPLEFT', prototype.lastBlock, 'BOTTOMLEFT', 0, 0)
389 else
390 block:SetPoint(prototype.point, self[prototype.parent] or self, prototype.relativePoint, 0, 0)
391 end
392 prototype.lastBlock = block
393 blocks[i] = block
394 end
395
396 totalHeight = totalHeight + block:GetHeight()
397 block.lastProfile = lastProfile
398 for k,v in pairs(data) do
399 if type(block[k]) ~= 'function' then
400 block[k] = v
401 end
402 end
403 block:Refresh(data)
404 print(block.isComplete, block.missionEndTime, block.name)
405 SetOwnerData(block, data)
406
407 block:Show()
408 lastProfile = data.profileKey
409 end
410
411 for i = numItems + 1, prototype.numBlocks do
412 if blocks[i] then
413 blocks[i]:Hide()
414 end
415 end
416
417 return totalHeight
418 end
419
420
421 local GI_profileKey, GI_profile, GI_isMine
422 local defaultClassColor = {r = 0.7, g = 0.7, b =0.7, colorStr = "ffffffff"}
423 local DoItemList = function (source, dest, onGetItem)
424 local numItems = 0
425 for index, data in ipairs(source) do
426 data.classColor = GI_profile.classColor or defaultClassColor
427 data.profileKey = GI_profileKey
428 data.isMine = GI_isMine
429 if onGetItem then
430 onGetItem(data)
431 end
432 numItems = numItems + 1
433 tinsert(dest, data)
434 end
435 return numItems
436 end
437
438 local max = math.max
439 function core:Refresh()
440 print('|cFF00FFFFRefresh()|r')
441 self.currentHeight = 0
442 for name, ptype in pairs(self.prototypes) do
443 print(' |cFF00FF00'..name..'|r')
444 if self.isStale then
445 ptype.GetPlayerData(self)
446 self.sortedItems[name] = self.sortedItems[name] or {}
447
448 wipe(self.sortedItems[name])
449 --print( 'object:', ptype)
450 for key, profile in pairs(self.data.characters) do
451 if profile[name] and #profile[name] >= 1 then
452 print(' ', #profile[name], key)
453 GI_profileKey = key
454 GI_profile = profile
455 GI_isMine = (profile == self.profile)
456 local results = DoItemList(profile[name], self.sortedItems[name], ptype.OnGetItem)
457 end
458
459 end
460
461 if ptype.SortHandler then
462 sort(self.sortedItems[name], ptype.SortHandler)
463 end
464 end
465
466 local itemsHeight = self:RefreshItems(name, ptype)
467 self.currentHeight = max(itemsHeight, self.currentHeight)
468 end
469
470 self:Reanchor()
471 self:SetHeight(self.currentHeight)
472 self.isStale = nil
473 end
474
475 function core:Toggle()
476 if self:IsShown() then
477 self:Hide()
478 else
479 self:Show()
480 end
481
482 if self.data then
483 self.data.IsShown = self:IsShown()
484 end
485 end
486
487 function core:OnUpdate()
488 if self.isStale then
489 print('update requested internally')
490 self:Refresh()
491 end
492 end
493
494 function core:OnShow()
495 print('|cFF00FFFFShow()')
496 if self.isStale then
497 print('on-show update')
498 self:Refresh()
499 end
500 ClassPlanButton.Background:Show()
501 ClassPlanButton.Grip:SetShown(true)
502 end
503 function core:OnHide()
504 print('|cFF00FFFFHide()')
505 ClassPlanButton.Background:Hide()
506 ClassPlanButton.Grip:SetShown(false)
507 end
508
509
510 function core:SortItems(ptype)
511 print('|cFF0088FFSortItems('..tostring(ptype)..')|r')
512 GI_currentTime = time()
513
514 end
515
516 function MissionsHandler:OnComplete()
517 print('flagging complete', self.name)
518 self:Refresh()
519 end
520
521 function MissionsHandler:OnUpdate(sinceLast)
522 if self.isComplete then
523 return
524 end
525 self.throttle = (self.throttle or .5) + sinceLast
526 if self.throttle >= .5 then
527 self.throttle = self.throttle - .5 642 self.throttle = self.throttle - .5
528 else 643 end
529 return 644 if self.offerEndTime then
530 end 645 local timeLeft = self.offerEndTime
531 646 self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
532 if self.missionEndTime then 647 self.TimeLeft:SetTextColor(1,1,1)
648 elseif self.missionEndTime then
649
650 if self.isComplete then
651 return
652 end
533 local timeLeft = self.missionEndTime - time() 653 local timeLeft = self.missionEndTime - time()
534 if timeLeft < 0 then 654 if timeLeft < 0 then
535 self:OnComplete() 655 self:OnComplete()
536 else 656 else
537 self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) 657 self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
555 r = 1-((progress-0.5)*2) 675 r = 1-((progress-0.5)*2)
556 else 676 else
557 g = min(progress * 2, 1) 677 g = min(progress * 2, 1)
558 r = 1 678 r = 1
559 end 679 end
560 self.ProgressBar:SetColorTexture(r,g,0,1) 680 self.ProgressBar:SetColorTexture(r,g,0,.4)
561 self.ProgressBG:SetColorTexture(r,g,0,0.125) 681 self.ProgressBG:SetColorTexture(r,g,0,0.125)
562 end 682 end
563 self.ProgressBG:Show() 683 self.ProgressBG:Show()
564 self.ProgressBar:Show() 684 self.ProgressBar:Show()
565 else 685 else
569 else 689 else
570 self.TimeLeft:SetText(self.missionEndTime) 690 self.TimeLeft:SetText(self.missionEndTime)
571 end 691 end
572 end 692 end
573 693
574 function MissionsHandler:Refresh() 694 function MissionEntry:OnLoad()
695 print('|cFFFF4400',self:GetName() or tostring(self), 'onload')
696 self.Count = self.Overlay.Count
697 self.Name = self.Overlay.Name
698 self.TimeLeft = self.Overlay.TimeLeft
699 self.Owner = self.Overlay.Owner
700
701 self.Icon:SetDesaturated(false)
702 self.Done:Hide()
703 end
704
705 function MissionEntry:Update()
575 local r,g,b = 1, 1, 1 706 local r,g,b = 1, 1, 1
576 if self.isRare then 707 if self.isRare then
577 r,g,b = 0.1, 0.4, 1 708 r,g,b = 0.1, 0.4, 1
578 self.IconBorder:SetVertexColor(r, g, b, 1) 709 self.IconBorder:SetVertexColor(r, g, b, 1)
579 end 710 end
585 self.rewardInfo = self.rewards[1] 716 self.rewardInfo = self.rewards[1]
586 else 717 else
587 self.Icon:SetAtlas(self.typeAtlas, false) 718 self.Icon:SetAtlas(self.typeAtlas, false)
588 end 719 end
589 720
590 if self.isComplete then 721
591 self.Done:Show()
592 else
593 self.Done:Hide()
594 end
595 722
596 if self.isComplete then 723 if self.isComplete then
597 self.TimeLeft:SetText('Complete!') 724 self.TimeLeft:SetText('Complete!')
598 self.Background:SetColorTexture(.25,.25,.25,1) 725 self.Background:SetColorTexture(.25,.25,.25,1)
599 else 726 else
600 self.Background:SetColorTexture(0,0,0,0.5) 727 self.Background:SetColorTexture(0,0,0,0.5)
601 end 728 end
602 end 729 end
603 730
604 function MissionsHandler:OnEnter() 731 function MissionEntry:OnEnter()
605 if self.rewardInfo and self.rewardInfo.itemID then 732 if self.rewardInfo and self.rewardInfo.itemID then
606 GameTooltip:SetOwner(self, 'ANCHOR_LEFT') 733 GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
607 GameTooltip:SetItemByID(self.rewardInfo.itemID) 734 GameTooltip:SetItemByID(self.rewardInfo.itemID)
608 GameTooltip:Show() 735 GameTooltip:Show()
609 end 736 end
610 end 737 end
611 738
612 function MissionsHandler:OnLeave() 739 function MissionEntry:OnLeave()
613 if GameTooltip:IsOwned(self) then 740 if GameTooltip:IsOwned(self) then
614 GameTooltip:Hide() 741 GameTooltip:Hide()
615 end 742 end
616 end 743 end
617 744
618 function ShipmentsHandler:Refresh() 745 function ShipmentEntry:OnLoad()
619 --[[ 746 MissionEntry.OnLoad(self)
620 self.icon = data.icon 747 end
621 self.shipmentCapacity = data.shipmentCapacity 748
622 self.shipmentsReady = data.shipmentsReady 749
623 self.shipmentsTotal = data.shipmentsTotal 750 function ShipmentEntry:Update()
624 self.creationTime = data.creationTime 751 print('|cFF0088FF'.. self.name..'|r:Update()')
625 self.duration = data.duration
626 self.itemID = data.itemID
627 self.itemQuality = data.itemQuality
628 icon = texture,
629 shipmentCapacity = shipmentCapacity,
630 shipmentsReady = shipmentsReady,
631 shipmentsTotal = shipmentsTotal,
632 creationTime = creationTime,
633 duration = duration,
634 timeleftString = timeleftString,
635 itemName = itemName,
636 itemIcon = itemIcon,
637 itemQuality = itemQuality,
638 itemID = itemID
639
640 --]]
641 self.Icon:SetTexture(self.icon) 752 self.Icon:SetTexture(self.icon)
642 self.Name:SetText(self.name)
643 self.Count:SetText(self.shipmentsReady) 753 self.Count:SetText(self.shipmentsReady)
644 self.Done:SetShown(self.shipmentsReady and (self.shipmentsReady >= 1)) 754 self.Done:SetShown(self.shipmentsReady and (self.shipmentsReady >= 1))
645 755
646 -- flag as complete 756 -- flag as complete
757
758 local bgColor = CP_BACKGROUND_COLOR.inProgress
647 if ( self.shipmentsReady >= self.shipmentsTotal ) and (not self.isBeingResearched) then 759 if ( self.shipmentsReady >= self.shipmentsTotal ) and (not self.isBeingResearched) then
648 self.Swipe:SetCooldownUNIX(0, 0); 760 self.Swipe:SetCooldownUNIX(0, 0);
649 self.Done:Show(); 761 self.Done:Show();
650 self.isComplete = true 762 bgColor = CP_BACKGROUND_COLOR.complete
651 else 763 else
764 if (self.shipmentsReady >= 1) and (self.shipmentsReady < self.shipmentsTotal) then
765 bgColor = CP_BACKGROUND_COLOR.shipmentsReady
766 end
652 self.Swipe:SetCooldownUNIX(self.creationTime or 0 , self.duration or 0); 767 self.Swipe:SetCooldownUNIX(self.creationTime or 0 , self.duration or 0);
653 end 768 end
654 769 self.Background:SetColorTexture(unpack(bgColor))
655 if self.isComplete then 770
656 self.TimeLeft:SetText('Complete!') 771 SetActualShipmentTime(self)
657 self.Background:SetColorTexture(0.5,0.5,0.5) 772
658 elseif (self.shipmentsReady and (self.shipmentsReady > 0)) then 773 if self.originalReady then
659 self.Background:SetColorTexture(0.5,0.5,0.5,.5) 774 print('|cFF00FF88'..self.name..'|r', 'starting ready:', self.originalReady, 'starting time:', self.originalCreationTime)
660 else 775 end
661 self.Background:SetColorTexture(0,0,0,0.5) 776 end
662 end 777
663 end 778 function ShipmentEntry:OnUpdate(sinceLast)
664
665 local time = time
666 function ShipmentsHandler:OnUpdate(sinceLast)
667 self.throttle = (self.throttle or 1) + sinceLast 779 self.throttle = (self.throttle or 1) + sinceLast
668 if self.throttle >= 1 then 780 if self.throttle >= 1 then
669 self.throttle = self.throttle - 1 781 self.throttle = self.throttle - 1
670 else 782 else
671 return 783 return
672 end 784 end
673 785
786
674 if (self.shipmentsReady and self.shipmentsTotal) and (self.shipmentsReady < self.shipmentsTotal) then 787 if (self.shipmentsReady and self.shipmentsTotal) and (self.shipmentsReady < self.shipmentsTotal) then
675 local timeLeft = self.creationTime + self.duration - time() 788 local timeLeft = SetActualShipmentTime(self)
676 if self.shipmentsReady >= 1 then 789
790 if self.isComplete then
791 self.TimeLeft:SetText('Complete!')
792 self.TimeLeft:SetTextColor(0,0.5,1)
793 elseif self.shipmentsReady >= 1 then
677 self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) 794 self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
678 self.TimeLeft:SetTextColor(0,1,0) 795 self.TimeLeft:SetTextColor(0,1,0)
679 else 796 else
680 self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) 797 self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
681 self.TimeLeft:SetTextColor(1,1,1) 798 self.TimeLeft:SetTextColor(1,1,1)
682 end 799 end
683 if (timeLeft < 0) then 800
684 if self.shipmentsReady < self.shipmentsTotal then
685 self.shipmentsReady = self.shipmentsReady + 1
686 self.creationTime = self.creationTime + self.duration
687 -- text will be set on next update
688 end
689 end
690 elseif self.isBeingResearched then 801 elseif self.isBeingResearched then
691 self.TimeLeft:SetText(GetTimeLeftString(self.researchStartTime + self.researchDuration - time())) 802 self.TimeLeft:SetText(GetTimeLeftString(self.researchStartTime + self.researchDuration - time()))
692 self.TimeLeft:SetTextColor(1,1,0) 803 self.TimeLeft:SetTextColor(1,1,0)
693 else 804 else
694 self.TimeLeft:SetText('Complete!') 805 self.TimeLeft:SetText('Complete!')
710 r = 1-((progress-0.5)*2) 821 r = 1-((progress-0.5)*2)
711 else 822 else
712 g = min(progress * 2, 1) 823 g = min(progress * 2, 1)
713 r = 1 824 r = 1
714 end 825 end
715 self.ProgressBar:SetColorTexture(r, g, 0, 1) 826 self.ProgressBar:SetColorTexture(r, g, 0, .4)
716 self.ProgressBG:SetColorTexture(r, g, 0, .125) 827 self.ProgressBG:SetColorTexture(r, g, 0, .125)
717 self.ProgressBG:Show() 828 self.ProgressBG:Show()
718 self.ProgressBar:Show() 829 self.ProgressBar:Show()
719 else 830 else
720 self.ProgressBG:Hide() 831 self.ProgressBG:Hide()
721 self.ProgressBar:Hide() 832 self.ProgressBar:Hide()
722 end 833 end
723 end 834 end
724 835
725 function ShipmentsHandler:OnEnter() 836 function ShipmentEntry:OnEnter()
726 if ( self.shipmentsReady and self.shipmentsTotal ) then 837 if ( self.shipmentsReady and self.shipmentsTotal ) then
727 GameTooltip:SetOwner(self, 'ANCHOR_LEFT') 838 GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
728 GameTooltip:AddLine(self.Owner:GetText(), self.Owner:GetTextColor()) 839 GameTooltip:AddLine(self.Owner:GetText(), self.Owner:GetTextColor())
729 GameTooltip:AddLine(self.shipmentType) 840 GameTooltip:AddLine(self.shipmentType)
730 GameTooltip:AddLine(self.shipmentsReady .. ' of '.. self.shipmentsTotal) 841 GameTooltip:AddLine(self.shipmentsReady .. ' of '.. self.shipmentsTotal)
731 GameTooltip:Show() 842 GameTooltip:Show()
732 end 843 end
733 end 844 end
734 845
735 function ShipmentsHandler:OnLeave() 846 function ShipmentEntry:OnLeave()
736 if GameTooltip:IsOwned(self) then 847 if GameTooltip:IsOwned(self) then
737 GameTooltip:Hide() 848 GameTooltip:Hide()
738 end 849 end
739 end 850 end
740 851
741 function ShipmentsHandler:OnClick(button) 852 function ShipmentEntry:OnClick(button)
742 if button == 'RightButton' then 853 if button == 'RightButton' then
743 self.handler:FreeBlock(self) 854 self.handler:FreeBlock(self)
744 end 855 end
745 end 856 end
857
858 ClassPlanMissionHandler = Mixin(MissionList, SharedHandlers)
859 ClassPlanShipmentHandler = Mixin(ShipmentList, SharedHandlers)
860 ClassPlanMissionEntryMixin = Mixin(MissionEntry, SharedEntry)
861 ClassPlanShipmentEntryMixin = Mixin(ShipmentEntry,SharedEntry)
862
863 ClassPlanHeaderMixin = {
864 OnClick = function(self)
865 self:GetParent():SetList()
866 self:GetParent().isStale = true
867 ClassOrderPlan:Update()
868 end
869 }