annotate Turok/Modules/Utilities/Toast.lua @ 9:9400a0ff8540

Ugh Timer: - container update directionality - talent update iterates over a non-volatile table to carry out updates - index management steps organized - talentRow status implemented, returns the spell associated with the talent chosen from that row CombatLog: - sort out font controls and unbork arguments
author Nenue
date Sun, 21 Feb 2016 13:08:30 -0500
parents a9b8b0866ece
children 0b1a2f3dbfc4
rev   line source
Nenue@6 1 --- ${PACKAGE_NAME}
Nenue@6 2 -- @file-author@
Nenue@6 3 -- @project-revision@ @project-hash@
Nenue@6 4 -- @file-revision@ @file-hash@
Nenue@6 5 -- Created: 2/2/2016 12:09 AM
Nenue@6 6
Nenue@6 7 local mod = Turok:NewModule("Toast", "AceTimer-3.0")
Nenue@6 8 local _G = _G
Nenue@6 9 local db
Nenue@6 10 local T, tostring, type, max, tinsert, UIParent, loadstring = _G.Turok, tostring, type, max, table.insert, _G.UIParent, loadstring
Nenue@6 11 --@debug@
Nenue@6 12 local DEBUG = true
Nenue@6 13 --@end-debug@
Nenue@6 14 local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool
Nenue@6 15 local print = function(...)
Nenue@6 16 if not DEBUG then return end
Nenue@6 17 if _G.Devian and _G.DevianDB.workspace ~= 1 then
Nenue@6 18 _G.print('Toast', ...)
Nenue@6 19 end
Nenue@6 20 end
Nenue@6 21
Nenue@6 22 -- GLOBALS:BossBanner_OnEvent, BossBanner
Nenue@6 23 -- kill off the default BossBanner
Nenue@6 24 local old_bb = BossBanner_OnEvent
Nenue@6 25 BossBanner_OnEvent = function(self, event, ...)
Nenue@6 26 T:Print(event, ...)
Nenue@6 27 end
Nenue@6 28
Nenue@6 29 T.defaults.toast = {
Nenue@6 30 alert_hold = 2,
Nenue@6 31 alert_fade = 1,
Nenue@6 32 alert_flash = .6,
Nenue@6 33 anchor = 'TOP',
Nenue@6 34 parent = 'UIParent',
Nenue@6 35 anchorTo = 'TOP',
Nenue@6 36 x = 0, y= -56,
Nenue@6 37 loot = {
Nenue@6 38 background_color = {},
Nenue@6 39 }
Nenue@6 40 }
Nenue@6 41
Nenue@6 42 mod.events = {
Nenue@6 43 "ACHIEVEMENT_EARNED",
Nenue@6 44 "CRITERIA_EARNED",
Nenue@6 45 "LFG_COMPLETION_REWARD",
Nenue@6 46 "GUILD_CHALLENGE_COMPLETED",
Nenue@6 47 "CHALLENGE_MODE_COMPLETED",
Nenue@6 48 "LOOT_ITEM_ROLL_WON",
Nenue@6 49 "SHOW_LOOT_TOAST",
Nenue@6 50 "SHOW_LOOT_TOAST_UPGRADE",
Nenue@6 51 "SHOW_PVP_FACTION_LOOT_TOAST",
Nenue@6 52 "PET_BATTLE_CLOSE",
Nenue@6 53 "STORE_PRODUCT_DELIVERED",
Nenue@6 54 "GARRISON_BUILDING_ACTIVATABLE",
Nenue@6 55 "GARRISON_MISSION_FINISHED",
Nenue@6 56 "GARRISON_FOLLOWER_ADDED",
Nenue@6 57 "GARRISON_RANDOM_MISSION_ADDED",
Nenue@6 58 "BOSS_KILL",
Nenue@6 59 "ENCOUNTER_LOOT_RECEIVED",
Nenue@6 60 }
Nenue@6 61
Nenue@6 62 mod.events_args = {
Nenue@6 63 ['ACHIEVEMENT_EARNED'] = {12, false},
Nenue@6 64 ['ACHIEVEMENT_EARNED'] = {12, true},
Nenue@6 65 ['LFG_COMPLETED_REWARD'] = {},
Nenue@6 66 }
Nenue@6 67 local y_factor = -1
Nenue@6 68 local x_factor = 0
Nenue@6 69 local tkAlerts = TkAlertContainer
Nenue@6 70 local AlertFrame_FixPosition = function(alertFrame)
Nenue@6 71 print(' pos:', alertFrame.order, cKey(alertFrame.x), cWord(alertFrame.y))
Nenue@6 72 alertFrame:SetPoint('TOPLEFT', tkAlerts, 'TOPLEFT', alertFrame.x, alertFrame.y)
Nenue@6 73 end
Nenue@6 74
Nenue@6 75 --- Goes through the alert container index and fixes the frame positions
Nenue@6 76 -- used before and after an alert frame changes visibility
Nenue@6 77 local AlertContainer_Update = function(self)
Nenue@6 78 local anum = 1
Nenue@6 79 local offset = 0
Nenue@6 80 for i, alert in ipairs(tkAlerts.alerts) do
Nenue@6 81 if alert:IsShown() then
Nenue@6 82 alert.x = offset * x_factor
Nenue@6 83 alert.y = offset * y_factor
Nenue@6 84 alert.drawHeight = alert.ename:GetStringHeight()+ alert.desc:GetStringHeight()
Nenue@6 85 alert.order = anum
Nenue@6 86 anum = anum + 1
Nenue@6 87 offset = offset + alert.drawHeight
Nenue@6 88 print(' draw height:', i, cText(alert.drawHeight))
Nenue@6 89 print(' position:', i, cPink(offset))
Nenue@6 90 AlertFrame_FixPosition(alert)
Nenue@6 91 print('index', i, 'shifted from position', cNum(alert.order), 'to', cNum(anum), ' at draw point', alert.y)
Nenue@6 92 print(' draw distance update ', cNum(0), 'x', cNum(offset))
Nenue@6 93 else
Nenue@6 94 print('index', i, 'is not visible')
Nenue@6 95 end
Nenue@6 96 end
Nenue@6 97 self:SetHeight(offset)
Nenue@6 98 end
Nenue@6 99
Nenue@6 100 --- config mode blocking command
Nenue@6 101 local AlertFrame_Block = function(alertFrame)
Nenue@6 102 -- only do stuff when configMode is on
Nenue@6 103 if not mod.configMode then
Nenue@6 104 return
Nenue@6 105 end
Nenue@6 106 end
Nenue@6 107
Nenue@6 108 --- if not config mode, then fire at the end of fadeIn animation to queue fadeOut
Nenue@6 109 local AlertFrame_Pin = function(alertFrame)
Nenue@6 110 if not mod.configMode then
Nenue@6 111 alertFrame.fadeOut.a1:SetStartDelay(db.alert_hold)
Nenue@6 112 alertFrame.fadeOut:Play()
Nenue@6 113 end
Nenue@6 114 end
Nenue@6 115
Nenue@6 116 --- if not config mode, then fire at the end of fadeOut to remove the frame from view and trigger positions update
Nenue@6 117 local AlertFrame_Remove = function(alertFrame)
Nenue@6 118 mod.num_events = mod.num_events - 1
Nenue@6 119 alertFrame:Hide()
Nenue@6 120 print(mod.num_events)
Nenue@6 121 AlertContainer_Update(tkAlerts)
Nenue@6 122 end
Nenue@6 123
Nenue@6 124 --- orders all visible frames to fadeOut
Nenue@6 125 -- @param stagger forces the spacing of startDelay times for each frame
Nenue@6 126 local AlertContainer_Clear = function(self, stagger)
Nenue@6 127 stagger = stagger or 0.1
Nenue@6 128 for i = #self.alerts, 1, -1 do
Nenue@6 129 print('clear check', i)
Nenue@6 130 local alert = self.alerts[i]
Nenue@6 131 if alert:IsShown() and not alert.fadeOut:IsPlaying() then
Nenue@6 132 alert.fadeOut.a1:SetStartDelay((#self.alerts-i)* stagger)
Nenue@6 133 alert.fadeOut:Play()
Nenue@6 134 end
Nenue@6 135 end
Nenue@6 136 end
Nenue@6 137 local AlertContainer_Unlock = function()
Nenue@6 138 end
Nenue@6 139
Nenue@6 140 --- Displays a new alert
Nenue@6 141 -- @param name text naming the class of event that occurred
Nenue@6 142 -- @param text alert subtext describing basic info about the event
Nenue@6 143 -- @order order (optional) sets display slot of the alert
Nenue@6 144 local function AlertContainer_ShowAlert(self, name, text, order)
Nenue@6 145 local db = TurokData.toast
Nenue@6 146 mod.num_events = mod.num_events + 1
Nenue@6 147
Nenue@6 148 local alertFrame
Nenue@6 149 if not order then
Nenue@6 150 local i = 1
Nenue@6 151 while i <= #self.alerts and not alertFrame do
Nenue@6 152 if not self.alerts[i]:IsShown() then
Nenue@6 153 alertFrame = self.alerts[i]
Nenue@6 154 print('re-using alert frame #', i)
Nenue@6 155 end
Nenue@6 156 i = i +1
Nenue@6 157 end
Nenue@6 158 else
Nenue@6 159 alertFrame = self.alerts[order]
Nenue@6 160 end
Nenue@6 161
Nenue@6 162 if not alertFrame then
Nenue@6 163 alertFrame = CreateFrame('Frame', 'TkAlertPanel'..(order or #self.alerts+1), self, 'TkAlertFrame')
Nenue@6 164 self.alerts[#self.alerts+1] = alertFrame
Nenue@6 165 print('creating new alert frame', #self.alerts)
Nenue@6 166
Nenue@6 167 alertFrame.Pin = AlertFrame_Pin
Nenue@6 168 alertFrame.Remove = AlertFrame_Remove
Nenue@6 169 end
Nenue@6 170
Nenue@6 171 alertFrame.ename:SetText(name)
Nenue@6 172 local height1 = alertFrame.ename:GetStringHeight()
Nenue@6 173 alertFrame.desc:SetText(text)
Nenue@6 174 local height2 = height1+ alertFrame.desc:GetStringHeight()
Nenue@6 175 alertFrame.desc:SetPoint('TOPLEFT', alertFrame, 'TOPLEFT', 0, -height1)
Nenue@6 176
Nenue@6 177 alertFrame.order = order or mod.num_events
Nenue@6 178 alertFrame:SetSize(300, height2)
Nenue@6 179 alertFrame:Show()
Nenue@6 180 --alertFrame.flashIn.a1:SetDuration(db.alert_flash/2)
Nenue@6 181 --alertFrame.flashIn.a2:SetDuration(db.alert_flash/2)
Nenue@6 182 alertFrame.flashIn:Play()
Nenue@6 183 if not mod.configMode then
Nenue@6 184 AlertContainer_Update(tkAlerts)
Nenue@6 185 end
Nenue@6 186 end
Nenue@6 187
Nenue@6 188
Nenue@6 189 --- updates the completed missions index and returns info on the mission ID if passed
Nenue@6 190 local completedMissions
Nenue@6 191 local Garrison_UpdateCompleteMissions = function(missionID)
Nenue@6 192 completedMissions = C_Garrison.GetCompleteMissions()
Nenue@6 193 --- slide entries around for reference
Nenue@6 194 for i, set in ipairs(completedMissions) do
Nenue@6 195 if i ~= set.missionID then
Nenue@6 196 completedMissions[set.missionID] = set
Nenue@6 197 completedMissions[i] = nil
Nenue@6 198 end
Nenue@6 199 end
Nenue@6 200
Nenue@6 201 if missionID and completedMissions[missionID] then
Nenue@6 202 local m = completedMissions[missionID]
Nenue@6 203 return m.name, m.location, m.locPrefix, m.isRare, m.followers, m.rewards, m.state
Nenue@6 204 else
Nenue@6 205 return false
Nenue@6 206 end
Nenue@6 207 end
Nenue@6 208 --- container events handler
Nenue@6 209 local AlertContainer_OnEvent = function (self, event, ...)
Nenue@6 210 print(event, ...)
Nenue@6 211 tkAlerts:Show()
Nenue@6 212 if event == 'SHOW_LOOT_TOAST' then
Nenue@6 213 local typeIdentifier, itemLink, quantity, specID, sex, isPersonal, lootSource = ...;
Nenue@6 214 if typeIdentifier == "currency" then
Nenue@6 215 AlertContainer_ShowAlert(self, itemLink, 'x'..quantity)
Nenue@6 216 elseif typeIdentifier == "item" then
Nenue@6 217 local _, _, _, ilvl, _, _, _, _, equipSlot = GetItemInfo(itemLink)
Nenue@6 218 AlertContainer_ShowAlert(self, itemLink, tostring(ilvl)..' '..tostring(_G[equipSlot]))
Nenue@6 219 end
Nenue@6 220 elseif event == 'GARRISON_MISSION_FINISHED' then
Nenue@6 221 local missionID = ...
Nenue@6 222 local name, location, locPrefix, isRare, followers, rewards = Garrison_UpdateCompleteMissions(missionID)
Nenue@6 223 local mission_info = {
Nenue@6 224 (isRare and ('|cFF44BBFF') or ('|cFFFFFF00')..name.. '|r'),
Nenue@6 225 }
Nenue@6 226
Nenue@6 227 if followers then
Nenue@6 228 for i, guid in ipairs(followers) do
Nenue@6 229 print(C_Garrison.GetFollowerInfo(guid))
Nenue@6 230 end
Nenue@6 231 end
Nenue@6 232
Nenue@6 233 --'|T:'..icon..':0
Nenue@6 234
Nenue@6 235
Nenue@6 236 AlertContainer_ShowAlert(self, 'Mission Complete')
Nenue@6 237 elseif event == 'GARRISON_BUILDING_ACTIVATABLE' then
Nenue@6 238 local missionID = ...
Nenue@6 239 elseif event == 'ACHIEVEMENT_EARNED' then
Nenue@6 240 elseif event == 'LFG_COMPLETION_REWARD' then
Nenue@6 241 local name, typeID, subtypeID, textureFilename, moneyBase, moneyVar, experienceBase, experienceVar, numStrangers, numRewards = GetLFGCompletionReward()
Nenue@6 242 local _, _, _, _, hasBonusStep, isBonusStepComplete = C_Scenario.GetInfo();
Nenue@6 243
Nenue@6 244 end
Nenue@6 245 end
Nenue@6 246
Nenue@6 247 local AlertContainer_Test = function()
Nenue@6 248 if not mod.configMode then
Nenue@6 249 print('starting test mode')
Nenue@6 250 tkAlerts:Show()
Nenue@6 251 mod.configMode = true
Nenue@6 252
Nenue@6 253 tkAlerts.configBG:Show()
Nenue@6 254 tkAlerts.configBG:SetTexture(0,0.5,0,0.5)
Nenue@6 255 tkAlerts:RegisterForDrag('LeftButton')
Nenue@6 256 tkAlerts:EnableMouse(true)
Nenue@6 257
Nenue@6 258 for i, frame in ipairs(tkAlerts.tools) do
Nenue@6 259 frame:Show()
Nenue@6 260 end
Nenue@6 261 -- test fillers
Nenue@6 262 local _,_, offset, range = GetSpellTabInfo(2)
Nenue@6 263 print(offset, range)
Nenue@6 264
Nenue@6 265 for i, event in ipairs(mod.events) do
Nenue@6 266 --print(i, event)
Nenue@6 267 local _, id = GetSpellBookItemInfo(math.random(offset, offset+range), 'spell')
Nenue@6 268 print(id)
Nenue@6 269
Nenue@6 270 local name = GetSpellLink(id)
Nenue@6 271 local text = GetSpellDescription(id)
Nenue@6 272 if not tkAlerts.alerts[i] then
Nenue@6 273 print('creating alert frame #', i)
Nenue@6 274 AlertContainer_ShowAlert(tkAlerts, name, text, i)
Nenue@6 275 else
Nenue@6 276 print('updating alert frame #', i)
Nenue@6 277 local alert = tkAlerts.alerts[i]
Nenue@6 278 alert:Show()
Nenue@6 279 alert.order = i
Nenue@6 280 alert.ename:SetText(name)
Nenue@6 281 alert.desc:SetText(text)
Nenue@6 282 if alert.fadeOut:IsPlaying() then
Nenue@6 283 alert.fadeOut:Stop()
Nenue@6 284 alert.backdrop:SetAlpha(0.5)
Nenue@6 285 end
Nenue@6 286
Nenue@6 287 alert.flashIn:Play()
Nenue@6 288 end
Nenue@6 289 end
Nenue@6 290 AlertContainer_Update(tkAlerts)
Nenue@6 291 else
Nenue@6 292 tkAlerts:EnableMouse(false)
Nenue@6 293 tkAlerts.configBG:Hide()
Nenue@6 294 mod.configMode = nil
Nenue@6 295 for i, frame in ipairs(tkAlerts.tools) do
Nenue@6 296 frame:Hide()
Nenue@6 297 end
Nenue@6 298 for i, alert in ipairs(tkAlerts.alerts) do
Nenue@6 299 for j, frame in ipairs(alert.tools) do
Nenue@6 300 frame:Hide()
Nenue@6 301 end
Nenue@6 302 alert.fadeOut.a1:SetStartDelay(i*0.2)
Nenue@6 303 alert.fadeOut:Play()
Nenue@6 304 end
Nenue@6 305
Nenue@6 306 end
Nenue@6 307 end
Nenue@6 308
Nenue@6 309 mod.OnEnable = function()
Nenue@6 310 db = TurokData.toast
Nenue@6 311
Nenue@6 312 --- find the closest frame to the center bottom and anchor to that
Nenue@6 313
Nenue@6 314 local cX, cY = (GetScreenWidth() / 2), (GetScreenHeight() / 2)
Nenue@6 315 local min_skewness = cX
Nenue@6 316 local max_centrality, center_frame
Nenue@6 317 for n, f in ipairs({UIParent:GetChildren()}) do
Nenue@6 318 if type(f) == 'table' and f.GetObjectType and f.GetName then
Nenue@6 319 if f.IsForbidden and f:IsForbidden() then
Nenue@6 320 print(n, 'is a forbidden object')
Nenue@6 321 else
Nenue@6 322 local name = f:GetName()
Nenue@6 323
Nenue@6 324 if f:IsVisible() and f:IsMouseEnabled() then
Nenue@6 325 print(name and name or tostring(f):sub(8), 'is a frame!')
Nenue@6 326 local x = f:GetCenter()
Nenue@6 327 local y = f:GetTop() -- Y need center top position
Nenue@6 328 if (x and y) and (y <= cY) then
Nenue@6 329 x = math.abs(x - cX) -- X works in either direction
Nenue@6 330
Nenue@6 331 -- distance of current - distant of record / max to get ratio of 1 where direct center results in 1
Nenue@6 332 local skewness_factor = (cX - x) / cX
Nenue@6 333 local vertness_factor = y / cY
Nenue@6 334 local centrality = skewness_factor * vertness_factor
Nenue@6 335 print('result: (', floor(x), floor(y), ') = ', skewness_factor, 'skew,', vertness_factor, 'vertness.\nTotal score:', cNum(centrality))
Nenue@6 336 if (not max_centrality) or max_centrality < centrality then
Nenue@6 337 center_frame = f
Nenue@6 338 max_centrality = centrality
Nenue@6 339 print(cWord(name and name or tostring(f):sub(8)),cPink(' is the new record!'))
Nenue@6 340 end
Nenue@6 341
Nenue@6 342 end
Nenue@6 343 end
Nenue@6 344 end
Nenue@6 345 end
Nenue@6 346 end
Nenue@6 347
Nenue@6 348 mod.num_events = 0
Nenue@6 349 tkAlerts.alerts = {}
Nenue@6 350 for i, event in ipairs(mod.events) do
Nenue@6 351 tkAlerts:RegisterEvent(event)
Nenue@6 352 end
Nenue@6 353
Nenue@6 354 tkAlerts.Clear = AlertContainer_Clear
Nenue@6 355 tkAlerts.Unlock = AlertContainer_Unlock
Nenue@6 356 tkAlerts.Close = AlertContainer_Test
Nenue@6 357
Nenue@6 358 tkAlerts:ClearAllPoints()
Nenue@6 359 tkAlerts:SetPoint(db.anchor, db.parent, db.anchorTo, db.x, db.y)
Nenue@6 360 tkAlerts.x = db.x
Nenue@6 361 tkAlerts.y = db.y
Nenue@6 362 tkAlerts.parent = db.parent
Nenue@6 363 tkAlerts.anchor = db.anchor
Nenue@6 364 tkAlerts.anchorTo = db.anchorTo
Nenue@6 365 tkAlerts:EnableMouse(false)
Nenue@6 366
Nenue@6 367 tkAlerts:SetScript('OnEvent', AlertContainer_OnEvent)
Nenue@6 368 T:RegisterChatCommand("alert", AlertContainer_Test)
Nenue@6 369 T:RegisterChatCommand("atest", function()
Nenue@6 370 AlertContainer_OnEvent(tkAlerts, 'GARRISON_MISSION_FINISHED', 327)
Nenue@6 371 end)
Nenue@6 372 end