annotate ClassPlan.lua @ 36:21bcff08b0f4

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