| Nenue@6 | 1 --- Turok | 
| Nenue@6 | 2 -- Castbar.lua | 
| Nenue@6 | 3 -- Created: 12/4/2015 11:17 PM | 
| Nenue@6 | 4 -- @file-author@ | 
| Nenue@6 | 5 -- @project-revision@ @project-hash@ | 
| Nenue@6 | 6 -- @file-revision@ @file-hash@ | 
| Nenue@6 | 7 -- Deals with casting events and works the castingbar interface | 
| Nenue@6 | 8 local print, tostring, tonumber, rep, pairs, min, format, unpack, select, strpad = print, tostring, tonumber, string.rep, pairs, math.min, string.format, unpack, select, string.rep | 
| Nenue@6 | 9 local GetTime, UnitCastingInfo, UnitChannelInfo, GetSpellInfo, GetSpellTabInfo = GetTime, UnitCastingInfo, UnitChannelInfo, GetSpellInfo, GetSpellTabInfo | 
| Nenue@6 | 10 local floor = math.floor | 
| Nenue@9 | 11 local T, _G = Turok, _G | 
| Nenue@6 | 12 local db | 
| Nenue@6 | 13 local PING_CEILING = 190 -- transpacific | 
| Nenue@6 | 14 local PING_MIDLINE = 100 | 
| Nenue@6 | 15 local PING_FLOOR = 10 -- transcontinental | 
| Nenue@6 | 16 --@debug | 
| Nenue@6 | 17 local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool | 
| Nenue@6 | 18 local print = function(...) | 
| Nenue@6 | 19   if _G.Devian and _G.DevianDB.workspace ~= 1 then | 
| Nenue@6 | 20     _G.print('Tek', ...) | 
| Nenue@6 | 21   end | 
| Nenue@6 | 22 end | 
| Nenue@9 | 23 local uprint = function(...) | 
| Nenue@9 | 24   if _G.Devian and _G.DevianDB.workspace ~= 1 then | 
| Nenue@9 | 25     _G.print('Update', ...) | 
| Nenue@9 | 26   end | 
| Nenue@9 | 27 end | 
| Nenue@9 | 28 local mprint = function(...) | 
| Nenue@9 | 29   if _G.Devian and _G.DevianDB.workspace ~= 1 then | 
| Nenue@9 | 30     _G.print('Main', ...) | 
| Nenue@9 | 31   end | 
| Nenue@9 | 32 end | 
| Nenue@6 | 33 | 
| Nenue@6 | 34 local EVENT_COLOR = '|cFF44FF44' | 
| Nenue@6 | 35 local EVENT_COLOR2 = '|cFF88FF88' | 
| Nenue@6 | 36 local DATA_COLOR = '|cFFDD77DD' | 
| Nenue@6 | 37 --@end-debug@ | 
| Nenue@6 | 38 | 
| Nenue@6 | 39 local mod = T:NewModule("Tek") | 
| Nenue@6 | 40 function mod:OnInitialize() | 
| Nenue@6 | 41   self.db = T.db.tek | 
| Nenue@6 | 42   self.castbar = {} | 
| Nenue@6 | 43   self.UNIT_SPELLCAST_SENT          = self.SpellCastRequest | 
| Nenue@6 | 44   self.UNIT_SPELLCAST_START           = self.SpellCastEvent | 
| Nenue@6 | 45   self.UNIT_SPELLCAST_DELAYED         = self.SpellCastEvent | 
| Nenue@6 | 46   self.UNIT_SPELLCAST_SUCCEEDED       = self.SpellCastEvent | 
| Nenue@6 | 47   self.UNIT_SPELLCAST_STOP            = self.SpellCastEvent | 
| Nenue@6 | 48   self.UNIT_SPELLCAST_FAILED          = self.SpellCastEvent | 
| Nenue@6 | 49   self.UNIT_SPELLCAST_INTERRUPTED     = self.SpellCastEvent | 
| Nenue@6 | 50   self.UNIT_SPELLCAST_CHANNEL_START   = self.SpellCastEvent | 
| Nenue@6 | 51   self.UNIT_SPELLCAST_CHANNEL_STOP    = self.SpellCastEvent | 
| Nenue@6 | 52   self.UNIT_SPELLCAST_CHANNEL_UPDATE  = self.SpellCastEvent | 
| Nenue@6 | 53   self.UNIT_SPELLCAST_INTERRUPTIBLE   = self.SpellCastEvent | 
| Nenue@6 | 54   self.UNIT_SPELLCAST_UNINTERRUPTIBLE = self.SpellCastEvent | 
| Nenue@6 | 55 end | 
| Nenue@6 | 56 | 
| Nenue@6 | 57 --- events & units | 
| Nenue@6 | 58 local TRACKED_UNITS = {'player', 'target', 'focus', 'pet'} | 
| Nenue@6 | 59 local FADE_OUT_TIME, FADE_IN_TIME = 1, .2 | 
| Nenue@6 | 60 | 
| Nenue@6 | 61 local TEXTURE_SUFFIX = { | 
| Nenue@6 | 62   ['CHANNEL_START'] = '_channeling', | 
| Nenue@6 | 63   ['CHANNEL_UPDATE'] = '_channeling', | 
| Nenue@6 | 64   ['CHANNEL_STOPPED'] = '_channeling', | 
| Nenue@6 | 65   ['START'] = '_casting', | 
| Nenue@6 | 66   ['INTERRUPTED'] = '_interrupted', | 
| Nenue@6 | 67   ['SUCCEEDED'] = '_finished', | 
| Nenue@6 | 68 } | 
| Nenue@6 | 69 | 
| Nenue@6 | 70 function mod:OnEnable() | 
| Nenue@6 | 71   db = self.db | 
| Nenue@6 | 72   -- setup castingbar frames | 
| Nenue@6 | 73   local c = self.castbar | 
| Nenue@6 | 74   for _, unit in pairs(TRACKED_UNITS) do | 
| Nenue@6 | 75     local cdb = db[unit] | 
| Nenue@6 | 76     --@debug@ | 
| Nenue@6 | 77     print(DATA_COLOR .. unit .. '|r castbar creation')--@end-debug@ | 
| Nenue@6 | 78 | 
| Nenue@6 | 79     -- Set frames | 
| Nenue@6 | 80     local fn = 'Tek' .. unit .. 'CastBar' | 
| Nenue@6 | 81     c[unit] = CreateFrame('Frame', fn, _G[cdb.parent], 'TurokCastingBar') | 
| Nenue@6 | 82 | 
| Nenue@6 | 83     local pc = c[unit] | 
| Nenue@6 | 84     T.SetFrameLayout(pc, cdb) | 
| Nenue@6 | 85     T.SetTextureLayout(pc.icon, cdb.icon or db.icon) | 
| Nenue@6 | 86     T.SetStatusTextures(pc, cdb.statusbar or db.statusbar) | 
| Nenue@6 | 87 | 
| Nenue@6 | 88     if unit == 'player' then | 
| Nenue@6 | 89       T.SetFontLayout(pc.ping, db.ping) | 
| Nenue@6 | 90       T.SetFontLayout(pc.downtime, db.downtime) | 
| Nenue@6 | 91       pc.pingbar:ClearAllPoints() | 
| Nenue@6 | 92       pc.pingbar:SetPoint('TOPRIGHT', pc.background, 'TOPRIGHT', 0, 0) | 
| Nenue@6 | 93       pc.pingbar:SetHeight(pc.background:GetHeight()) | 
| Nenue@6 | 94     else | 
| Nenue@6 | 95       if pc.interrupt then | 
| Nenue@6 | 96         pc.interrupt:SetSize(pc.icon.size*3, pc.icon.size* 3) | 
| Nenue@6 | 97       end | 
| Nenue@6 | 98 | 
| Nenue@6 | 99     end | 
| Nenue@6 | 100 | 
| Nenue@6 | 101     T.SetFontLayout(pc.casttime, cdb.casttime or db.casttime) | 
| Nenue@6 | 102     T.SetFontLayout(pc.spelltext, cdb.spelltext or db.spelltext) | 
| Nenue@6 | 103 | 
| Nenue@6 | 104     pc:SetAlpha(0) | 
| Nenue@6 | 105     pc.last = nil | 
| Nenue@6 | 106     pc.sent = {} | 
| Nenue@6 | 107     pc.unit = unit | 
| Nenue@6 | 108     pc.SetSpell = self.SetSpell | 
| Nenue@6 | 109     pc.SetState = self.SetState | 
| Nenue@6 | 110     pc.Update = self.Update | 
| Nenue@6 | 111   end | 
| Nenue@6 | 112 | 
| Nenue@6 | 113 | 
| Nenue@6 | 114   -- kill default casting bar | 
| Nenue@6 | 115   -- T.cbscripts = {CastingBarFrame:GetScript('OnUpdate'), CastingBarFrame:GetScript('OnEvent')} | 
| Nenue@6 | 116   CastingBarFrame:SetScript('OnUpdate', nil) | 
| Nenue@6 | 117   CastingBarFrame:SetScript('OnEvent', nil) | 
| Nenue@6 | 118   CastingBarFrame:Hide() | 
| Nenue@6 | 119   PetCastingBarFrame:SetScript('OnUpdate', nil) | 
| Nenue@6 | 120   PetCastingBarFrame:SetScript('OnEvent', nil) | 
| Nenue@6 | 121   PetCastingBarFrame:Hide() | 
| Nenue@6 | 122 end | 
| Nenue@6 | 123 | 
| Nenue@6 | 124 function mod:UpdateLocked() | 
| Nenue@6 | 125     for k, v in pairs(self.castbar) do | 
| Nenue@6 | 126       if T.unlocked then | 
| Nenue@6 | 127         local name, texture, offset, numSpells = GetSpellTabInfo(T.specPage) | 
| Nenue@6 | 128         v.value = offset | 
| Nenue@6 | 129         v.duration = numSpells | 
| Nenue@6 | 130         v.spelltext:SetText(k) | 
| Nenue@6 | 131         v.icon:SetTexture(texture) | 
| Nenue@6 | 132         v:SetAlpha(1) | 
| Nenue@6 | 133         v:Show() | 
| Nenue@6 | 134         v:EnableMouse(true) | 
| Nenue@6 | 135         v:SetMovable(true) | 
| Nenue@6 | 136         v:RegisterForDrag("LeftButton") | 
| Nenue@6 | 137         v:SetScript('OnDragStart', function(self)  self:StartMoving() end) | 
| Nenue@6 | 138         v:SetScript('OnDragStop', function(self) self:StopMovingOrSizing() end) | 
| Nenue@6 | 139       else | 
| Nenue@6 | 140 | 
| Nenue@6 | 141         v:SetScript('OnDragStart', nil) | 
| Nenue@6 | 142         v:SetScript('OnDragStop', nil) | 
| Nenue@6 | 143         v:EnableMouse(false) | 
| Nenue@6 | 144         v:SetMovable(false) | 
| Nenue@6 | 145 | 
| Nenue@6 | 146         print('Saving bar coordinates post unlock') | 
| Nenue@6 | 147 | 
| Nenue@6 | 148         db[k].x = v:GetLeft() | 
| Nenue@6 | 149         db[k].y = v:GetTop() | 
| Nenue@6 | 150         db[k].anchor = 'BOTTOMLEFT' | 
| Nenue@6 | 151         db[k].anchorTo = 'BOTTOMLEFT' | 
| Nenue@6 | 152         db[k].parent = 'UIParent' | 
| Nenue@6 | 153       end | 
| Nenue@6 | 154     end | 
| Nenue@6 | 155 end | 
| Nenue@6 | 156 | 
| Nenue@6 | 157 --- Store spell requests for use in tracking lag time | 
| Nenue@6 | 158 function mod:SpellCastRequest(e, unit, spellName, rank, target, castID) | 
| Nenue@6 | 159   print('|cFFFF4400Request sent:|r ', spellName, castID, target) | 
| Nenue@6 | 160   self.castbar.player.sent[castID] = { | 
| Nenue@6 | 161     spellName = spellName, | 
| Nenue@6 | 162     castID = castID, | 
| Nenue@6 | 163     sendTime = GetTime()*1000, | 
| Nenue@6 | 164   } | 
| Nenue@6 | 165 end | 
| Nenue@6 | 166 | 
| Nenue@6 | 167 --- Handle events pertaining to a cast bar | 
| Nenue@6 | 168 function mod:SpellCastEvent(event, unit, ...) | 
| Nenue@6 | 169   if not self.castbar[unit] then | 
| Nenue@6 | 170     return | 
| Nenue@6 | 171   end | 
| Nenue@6 | 172 | 
| Nenue@6 | 173   local u = T.unit[unit] | 
| Nenue@6 | 174   local c = self.castbar[unit] | 
| Nenue@6 | 175 | 
| Nenue@6 | 176   --- doubling as an invocation source test | 
| Nenue@6 | 177   local spellName, rank, castID, spellID = ... | 
| Nenue@6 | 178 | 
| Nenue@6 | 179   local channelinfo = T.unit[unit].channeling | 
| Nenue@6 | 180   local castinginfo = T.unit[unit].casting | 
| Nenue@6 | 181   local sendq = c.sent | 
| Nenue@6 | 182   local castd = c.last | 
| Nenue@6 | 183   local timestamp = GetTime()*1000 | 
| Nenue@6 | 184 | 
| Nenue@6 | 185   --todo: remove truncation | 
| Nenue@6 | 186   local e = event:match("UNIT_SPELLCAST_([%a_]+)") | 
| Nenue@6 | 187   print(GetTime(), '|cFFFF8747'..e..(strpad(' ',12-#e))..'|r |cFFDDFF00#'..tostring(castID)..'|r', spellName, spellID) | 
| Nenue@6 | 188 | 
| Nenue@6 | 189   c.channeling = channelinfo and channelinfo[1] or nil | 
| Nenue@6 | 190   c.casting    = castinginfo and castinginfo[1] or nil | 
| Nenue@6 | 191   if c.channeling then | 
| Nenue@6 | 192     -- {name, subText, text, texture, startTime, endTime, isTradeSkill, notInterruptible} | 
| Nenue@6 | 193     c.startTime = channelinfo[5] | 
| Nenue@6 | 194     c.endTime = channelinfo[6] | 
| Nenue@6 | 195     c.nonInterruptible = channelinfo[8] | 
| Nenue@6 | 196   elseif c.casting then | 
| Nenue@6 | 197     --name, subText, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible | 
| Nenue@6 | 198     c.startTime = castinginfo[5] | 
| Nenue@6 | 199     c.endTime = castinginfo[6] | 
| Nenue@6 | 200     c.castID = castinginfo[8] | 
| Nenue@6 | 201     c.nonInterruptible = castinginfo[9] | 
| Nenue@6 | 202   else | 
| Nenue@6 | 203     print('  |cFFFF7700internal data was nil|r') | 
| Nenue@6 | 204   end | 
| Nenue@6 | 205 | 
| Nenue@6 | 206   --- process the "event" | 
| Nenue@6 | 207   local setSpell, setState | 
| Nenue@6 | 208   if e == 'START' then | 
| Nenue@6 | 209     setSpell = true | 
| Nenue@6 | 210     setState = true | 
| Nenue@6 | 211 | 
| Nenue@6 | 212     -- player data calculations | 
| Nenue@6 | 213     if unit == 'player' then | 
| Nenue@6 | 214       if sendq[castID] and sendq[castID].spellName == spellName then | 
| Nenue@6 | 215         local sent = sendq[castID] | 
| Nenue@6 | 216         print('  |cFF00AAFFmatched:|r', sent.spellName, castID) | 
| Nenue@6 | 217         c.pingTime = c.startTime - sent.sendTime | 
| Nenue@6 | 218         print('    ping:', c.pingTime) | 
| Nenue@6 | 219         for cid, cdata in pairs(sendq) do | 
| Nenue@6 | 220           if cdata.sendTime <= sent.sendTime then | 
| Nenue@6 | 221             --print('    forgetting #'..cdata.sendTime, cid, cdata.spellName) | 
| Nenue@6 | 222             sendq[cid] = nil | 
| Nenue@6 | 223           end | 
| Nenue@6 | 224         end | 
| Nenue@6 | 225 | 
| Nenue@6 | 226         if castd ~= nil then | 
| Nenue@6 | 227           print('   downtime calc hit') | 
| Nenue@6 | 228           c.downTime = timestamp - castd.endTime | 
| Nenue@6 | 229           castd = nil | 
| Nenue@6 | 230         else | 
| Nenue@6 | 231           c.downTime = nil | 
| Nenue@6 | 232         end | 
| Nenue@6 | 233         c.castID = castID | 
| Nenue@6 | 234       end | 
| Nenue@6 | 235     end | 
| Nenue@6 | 236   elseif e == 'CHANNEL_START' or e == 'CHANNEL_UPDATE' then | 
| Nenue@6 | 237     setSpell = true | 
| Nenue@6 | 238     setState = true | 
| Nenue@6 | 239     c.event = e | 
| Nenue@6 | 240 | 
| Nenue@6 | 241   elseif e == 'STOP' then | 
| Nenue@6 | 242     setState = true | 
| Nenue@6 | 243     c.casting = nil | 
| Nenue@6 | 244     castd = { | 
| Nenue@6 | 245       spellName = spellName, | 
| Nenue@6 | 246       spellID = spellID, | 
| Nenue@6 | 247       castID = castID, | 
| Nenue@6 | 248       endTime = timestamp, | 
| Nenue@6 | 249     } | 
| Nenue@6 | 250     print('    |cFFFFFF00found', timestamp, spellName) | 
| Nenue@6 | 251 | 
| Nenue@6 | 252   elseif e == 'CHANNEL_STOP' then | 
| Nenue@6 | 253     setState = true | 
| Nenue@6 | 254     c.channeling = nil | 
| Nenue@6 | 255     castd = { | 
| Nenue@6 | 256       spellName = spellName, | 
| Nenue@6 | 257       spellID = spellID, | 
| Nenue@6 | 258       castID = castID, | 
| Nenue@6 | 259       endTime = timestamp, | 
| Nenue@6 | 260     } | 
| Nenue@6 | 261     print('    |cFFFF0088found', timestamp, spellName) | 
| Nenue@6 | 262 | 
| Nenue@6 | 263   elseif e == 'SUCCEEDED'  then | 
| Nenue@6 | 264     if c.spellName == spellName and not c.channeling then | 
| Nenue@6 | 265       setState = true | 
| Nenue@6 | 266       print('      |cFFFF4400',c.spellName,'=',spellName,' pushing event', e) | 
| Nenue@6 | 267     end | 
| Nenue@6 | 268     -- if there are 'send' args when this fires, it means it's an instant cast | 
| Nenue@6 | 269     if sendq[castID] and sendq[castID].spellName == spellName then | 
| Nenue@6 | 270       castd = { | 
| Nenue@6 | 271         spellName = spellName, | 
| Nenue@6 | 272         spellID = spellID, | 
| Nenue@6 | 273         castID = castID, | 
| Nenue@6 | 274         endTime = timestamp, | 
| Nenue@6 | 275       } | 
| Nenue@6 | 276       print('    |cFFFFAA00found', timestamp, spellName) | 
| Nenue@6 | 277     end | 
| Nenue@6 | 278 | 
| Nenue@6 | 279   elseif e =='FAILED' then | 
| Nenue@6 | 280     if spellName == c.spellName and not c.channeling then | 
| Nenue@6 | 281       setState = true | 
| Nenue@6 | 282     end | 
| Nenue@6 | 283 | 
| Nenue@6 | 284   elseif e == 'INTERRUPTED' then | 
| Nenue@6 | 285     setState = true | 
| Nenue@6 | 286 | 
| Nenue@6 | 287   end | 
| Nenue@6 | 288 | 
| Nenue@6 | 289 | 
| Nenue@6 | 290 | 
| Nenue@6 | 291 | 
| Nenue@6 | 292   if setSpell then | 
| Nenue@6 | 293     print('      |cFF44FF00setting spell', spellName) | 
| Nenue@6 | 294   end | 
| Nenue@6 | 295   if setState then | 
| Nenue@6 | 296     print('      |cFFFF4400pushing event', e) | 
| Nenue@6 | 297   end | 
| Nenue@6 | 298 | 
| Nenue@6 | 299   if setSpell then | 
| Nenue@6 | 300     c:SetSpell(e) | 
| Nenue@6 | 301   end | 
| Nenue@6 | 302   if setState then | 
| Nenue@6 | 303     c:SetState(e) | 
| Nenue@6 | 304   end | 
| Nenue@6 | 305 end | 
| Nenue@6 | 306 | 
| Nenue@6 | 307 | 
| Nenue@6 | 308 --- Sets all the static elements of the casting bar, such as config values, icon texture, and name | 
| Nenue@6 | 309 function mod.SetSpell(c, event) | 
| Nenue@6 | 310   local _ | 
| Nenue@6 | 311   local time, alpha = GetTime(), c:GetAlpha() | 
| Nenue@6 | 312   local u, cdb  = T.unit[c.unit], c.db | 
| Nenue@6 | 313 | 
| Nenue@6 | 314   c.stopped = nil | 
| Nenue@6 | 315   c.stopping = nil | 
| Nenue@6 | 316   print('New spell:', c.spellName) | 
| Nenue@6 | 317   --- use only internal info | 
| Nenue@6 | 318   local data = (event == 'CHANNEL_START' or event == 'CHANNEL_UPDATE' or event == 'CHANNEL_STOP') and u.channeling or u.casting | 
| Nenue@6 | 319   local spellName, rank, displayName, texture, startTime, endTime, isTradeSkill, castID, nonInterruptible = unpack(data) | 
| Nenue@6 | 320 | 
| Nenue@6 | 321 | 
| Nenue@6 | 322   if spellName == nil then | 
| Nenue@6 | 323     print("  Can't do arithmetic, no data.") | 
| Nenue@6 | 324   else | 
| Nenue@6 | 325     print(cText("  Arithmetic vars:"), cNum(startTime), cNum(endTime)) | 
| Nenue@6 | 326   end | 
| Nenue@6 | 327 | 
| Nenue@6 | 328          c.spellName = spellName | 
| Nenue@6 | 329             c.castID = castID or 0 | 
| Nenue@6 | 330               c.rank = rank | 
| Nenue@6 | 331        c.displayName = displayName | 
| Nenue@6 | 332            c.texture = texture | 
| Nenue@6 | 333   c.nonInterruptible = nonInterruptible | 
| Nenue@6 | 334       c.isTradeSkill = isTradeSkill | 
| Nenue@6 | 335            c.endTime = endTime   or 0 | 
| Nenue@6 | 336          c.startTime = startTime or 0 | 
| Nenue@6 | 337           c.duration = c.endTime - c.startTime | 
| Nenue@6 | 338 | 
| Nenue@6 | 339   if c.unit == 'player' then | 
| Nenue@6 | 340     if c.pingTime then | 
| Nenue@6 | 341       print('     ping',c.pingTime, endTime, startTime, c.duration) | 
| Nenue@6 | 342       local draw_dist = (c.pingTime / c.duration) * (c.fill_width) | 
| Nenue@6 | 343       if draw_dist > c.fill_width then | 
| Nenue@6 | 344         draw_dist = c.fill_width | 
| Nenue@6 | 345       end | 
| Nenue@6 | 346       print('SET AND SHOW PING ', c.pingTime,'on', c.pingbar:GetName()) | 
| Nenue@6 | 347       c.pingbar:SetWidth(draw_dist) | 
| Nenue@6 | 348       c.pingbar:Show() | 
| Nenue@6 | 349 | 
| Nenue@6 | 350       local rv = c.pingTime - PING_FLOOR | 
| Nenue@6 | 351       local rr = PING_MIDLINE - PING_FLOOR | 
| Nenue@6 | 352       local gv = c.pingTime   - PING_MIDLINE | 
| Nenue@6 | 353       local gr = PING_CEILING - PING_MIDLINE | 
| Nenue@6 | 354       local r = c.pingTime > PING_MIDLINE and 1 or (c.pingTime < PING_FLOOR and 0 or (rv / rr)) | 
| Nenue@6 | 355       local g = c.pingTime < PING_MIDLINE and 1 or (c.pingTime > PING_CEILING and 0 or 1-(gv / gr)) | 
| Nenue@6 | 356       print(c.pingTime, rv, '/', rr, '=', r) | 
| Nenue@6 | 357       print(c.pingTime, gv, '/', gr, '=', g) | 
| Nenue@6 | 358 | 
| Nenue@6 | 359       c.ping:SetText(floor(c.pingTime)) | 
| Nenue@6 | 360       c.ping:SetTextColor(r,g,0) | 
| Nenue@6 | 361       c.ping:Show() | 
| Nenue@6 | 362     else | 
| Nenue@6 | 363       c.pingbar:Hide() | 
| Nenue@6 | 364       c.ping:Hide() | 
| Nenue@6 | 365     end | 
| Nenue@6 | 366     if c.downTime then | 
| Nenue@6 | 367       c.downtime:Show() | 
| Nenue@6 | 368       if c.downTime > 1500 then | 
| Nenue@6 | 369         c.downtime:SetText(nil) | 
| Nenue@6 | 370       else | 
| Nenue@6 | 371         c.downtime:SetText(c.downTime) | 
| Nenue@6 | 372       end | 
| Nenue@6 | 373     else | 
| Nenue@6 | 374       c.downtime:Hide() | 
| Nenue@6 | 375     end | 
| Nenue@6 | 376   else | 
| Nenue@6 | 377     if c.nonInterruptible then | 
| Nenue@6 | 378       c.interrupt:Show() | 
| Nenue@6 | 379     else | 
| Nenue@6 | 380       c.interrupt:Hide() | 
| Nenue@6 | 381     end | 
| Nenue@6 | 382   end | 
| Nenue@6 | 383 | 
| Nenue@6 | 384   c.icon:SetTexture(texture) | 
| Nenue@6 | 385   c.spelltext:Show() | 
| Nenue@6 | 386   c.spelltext:SetText(spellName) | 
| Nenue@6 | 387 | 
| Nenue@6 | 388   c.fill_inverse = c.channeling | 
| Nenue@6 | 389   -- set timers | 
| Nenue@6 | 390 end | 
| Nenue@6 | 391 | 
| Nenue@6 | 392 --- Deals with failed/succeeded/interrupted visuals and fading cues | 
| Nenue@6 | 393 -- Fired by one of those events, or cast/channel info is returning nothing | 
| Nenue@6 | 394 function mod:SetState(event) | 
| Nenue@6 | 395   if T.unlocked then | 
| Nenue@6 | 396     return | 
| Nenue@6 | 397   end | 
| Nenue@6 | 398 | 
| Nenue@6 | 399   local time = GetTime() * 1000 | 
| Nenue@6 | 400   print(' ',self:GetName(), '|cFF44FF00event trigger:|r', event) | 
| Nenue@6 | 401 | 
| Nenue@6 | 402   -- We want these to be updating no matter what is happening | 
| Nenue@6 | 403   if TEXTURE_SUFFIX[event] then | 
| Nenue@6 | 404     local cdb = self.db | 
| Nenue@6 | 405     if cdb.foreground_texture then | 
| Nenue@6 | 406       print('   |cFF00AAFFevent|r '..event..', |cFF00AAFFtexture|r ', cdb.foreground_texture) | 
| Nenue@6 | 407       self.foreground:SetVertexColor(unpack(cdb['foreground' .. TEXTURE_SUFFIX[event]] and cdb['foreground' .. TEXTURE_SUFFIX[event]] or cdb.foreground_color)) | 
| Nenue@6 | 408     else | 
| Nenue@6 | 409       self.foreground:SetTexture(unpack(cdb['foreground' .. TEXTURE_SUFFIX[event]] and cdb['foreground' .. TEXTURE_SUFFIX[event]] or cdb.foreground_color)) | 
| Nenue@6 | 410     end | 
| Nenue@6 | 411 | 
| Nenue@6 | 412     if cdb.background_texture then | 
| Nenue@6 | 413       print('  texture=', cdb.background_texture) | 
| Nenue@6 | 414       self.background:SetVertexColor(unpack(cdb['background' .. TEXTURE_SUFFIX[event]] and cdb['background' .. TEXTURE_SUFFIX[event]] or cdb.background_color)) | 
| Nenue@6 | 415     else | 
| Nenue@6 | 416       self.background:SetTexture(unpack(cdb['background' .. TEXTURE_SUFFIX[event]] and cdb['background' .. TEXTURE_SUFFIX[event]] or cdb.background_color)) | 
| Nenue@6 | 417     end | 
| Nenue@6 | 418   end | 
| Nenue@6 | 419 | 
| Nenue@6 | 420   -- are we starting or stopping | 
| Nenue@6 | 421   if event == 'START' or event == 'CHANNEL_START' then | 
| Nenue@6 | 422     print('   |cFF00AAFFStarting display|r ', self.spellName) | 
| Nenue@6 | 423     self:Show() | 
| Nenue@6 | 424     if self.__fade:IsPlaying() then | 
| Nenue@6 | 425       self.__fade:Stop() | 
| Nenue@6 | 426     end | 
| Nenue@6 | 427 | 
| Nenue@6 | 428     self:Fade(FADE_IN_TIME, self.alpha) | 
| Nenue@6 | 429   else | 
| Nenue@6 | 430     if event == 'SUCCEEDED' and not self.channeling then | 
| Nenue@6 | 431       print('   |cFF00AAFFsuccess deduced values|r', self.value, 'to', self.duration) | 
| Nenue@6 | 432       self.percent = 1 | 
| Nenue@6 | 433       self.value = self.duration | 
| Nenue@6 | 434     end | 
| Nenue@6 | 435 | 
| Nenue@6 | 436     -- Actual fading out begins here, anything else is statistical sugar | 
| Nenue@6 | 437     if event == 'STOP' or event == 'CHANNEL_STOP' then | 
| Nenue@6 | 438       print('yeah we done') | 
| Nenue@6 | 439       if self.__fade:IsPlaying() then | 
| Nenue@6 | 440         self.__fade:Stop() | 
| Nenue@6 | 441       end | 
| Nenue@6 | 442       self:Fade(FADE_OUT_TIME, 0) | 
| Nenue@6 | 443     end | 
| Nenue@6 | 444   end | 
| Nenue@6 | 445 end | 
| Nenue@6 | 446 | 
| Nenue@6 | 447 --- Animation loop | 
| Nenue@6 | 448 function mod:Update() | 
| Nenue@6 | 449   local time = GetTime() * 1000 | 
| Nenue@6 | 450   local u = self.unit | 
| Nenue@6 | 451   local s = self | 
| Nenue@6 | 452 | 
| Nenue@6 | 453   -- update vals | 
| Nenue@6 | 454   if s.casting or s.channeling then | 
| Nenue@6 | 455     self.value = s.casting and (time - s.startTime) or (s.endTime - time) | 
| Nenue@6 | 456     self.percent = (time - s.startTime) / self.duration | 
| Nenue@6 | 457     if time > s.endTime then | 
| Nenue@6 | 458       self.value = self.fill_inverse and 0 or s.duration | 
| Nenue@6 | 459       self.percent = self.fill_inverse and 0 or 1 | 
| Nenue@6 | 460       self.elapsed = time - s.endTime | 
| Nenue@6 | 461     end | 
| Nenue@9 | 462     uprint('   ',self.unit, self.value, self.percent) | 
| Nenue@6 | 463   else | 
| Nenue@6 | 464     self.value = 1000 | 
| Nenue@6 | 465     self.percent = 1 | 
| Nenue@6 | 466   end | 
| Nenue@6 | 467   self.casttime:SetText(format("%.2f", self.value / 1000)) | 
| Nenue@6 | 468 | 
| Nenue@6 | 469   self:SetProgress(self.percent) | 
| Nenue@6 | 470 end | 
| Nenue@6 | 471 | 
| Nenue@6 | 472 --- Refresh the CastingBar for things like target change, pet despawn, etc. | 
| Nenue@6 | 473 -- Will attempt to flush out any existing cast action data, then re-invoke SpellCastEvent() with as much data can be acquired. | 
| Nenue@6 | 474 -- There is no event data such as spellID directly available, so this is essentially the biggest constraint we have on what | 
| Nenue@6 | 475 -- the castingbar can depend on. | 
| Nenue@6 | 476 function mod:UpdateUnit(unit) | 
| Nenue@9 | 477   local print = function(...) uprint(...) end | 
| Nenue@6 | 478   print(cText 'GUID changed:|cFFFFFF99', unit) | 
| Nenue@6 | 479   local c = mod.castbar[unit] | 
| Nenue@6 | 480   if c.channeling or c.casting then | 
| Nenue@6 | 481     print(cText '  was casting a spell, run STOP event and hide completely') | 
| Nenue@6 | 482     c:SetState(c.casting and 'STOP' or 'CHANNEL_STOP') | 
| Nenue@6 | 483     c.channeling = nil | 
| Nenue@6 | 484     c.casting = nil | 
| Nenue@6 | 485     c:Hide() | 
| Nenue@6 | 486   end | 
| Nenue@6 | 487 | 
| Nenue@6 | 488   if T.unit[unit].casting then | 
| Nenue@6 | 489     print(cText('  new target is CASTING')) | 
| Nenue@6 | 490     mod:SpellCastEvent('UNIT_SPELLCAST_START', unit) | 
| Nenue@6 | 491   end | 
| Nenue@6 | 492   if T.unit[unit].channeling then | 
| Nenue@6 | 493     print(cText('  new target is CHANNELING')) | 
| Nenue@6 | 494     mod:SpellCastEvent('UNIT_SPELLCAST_CHANNEL_START', unit) | 
| Nenue@6 | 495   end | 
| Nenue@6 | 496 | 
| Nenue@6 | 497   T:UNIT_SPELLCAST(unit)-- name, subText, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible | 
| Nenue@6 | 498   T:UNIT_CHANNEL(unit)  -- name, subText, text, texture, startTime, endTime, isTradeSkill, notInterruptible | 
| Nenue@6 | 499 | 
| Nenue@6 | 500 end | 
| Nenue@6 | 501 | 
| Nenue@6 | 502 function mod:UpdateInterrupt(e, unit, ...) | 
| Nenue@6 | 503     mod.castbar[unit].nonInterruptible = (e == 'UNIT_SPELLCAST_UNINTERRUPTIBLE') and true or false | 
| Nenue@6 | 504   if unit ~= 'player' and unit ~='pet' then | 
| Nenue@6 | 505 | 
| Nenue@6 | 506   end | 
| Nenue@6 | 507 end | 
| Nenue@6 | 508 | 
| Nenue@6 | 509 mod.UNIT_PET = function(self, e, unit) | 
| Nenue@6 | 510   if unit == 'player' then | 
| Nenue@6 | 511     self:UpdateUnit('pet') | 
| Nenue@6 | 512   end | 
| Nenue@6 | 513 end | 
| Nenue@6 | 514 mod.PLAYER_TARGET_CHANGED = function(self, ...) | 
| Nenue@9 | 515   mprint(cPink(self),...) | 
| Nenue@6 | 516   self:UpdateUnit('target') | 
| Nenue@6 | 517 end | 
| Nenue@6 | 518 mod.PLAYER_FOCUS_CHANGED = function(self) | 
| Nenue@6 | 519   self:UpdateUnit('focus') | 
| Nenue@6 | 520 end |