annotate Turok/Modules/Timer/Cooldown.lua @ 6:a9b8b0866ece

clear out log jam
author Nenue
date Sun, 21 Feb 2016 08:32:53 -0500
parents
children 9400a0ff8540
rev   line source
Nenue@6 1
Nenue@6 2 --- ${PACKAGE_NAME}
Nenue@6 3 -- @file-author@
Nenue@6 4 -- @project-revision@ @project-hash@
Nenue@6 5 -- @file-revision@ @file-hash@
Nenue@6 6 -- Created: 12/25/2015 5:33 AM
Nenue@6 7 --- Spell cooldown tracking resides here.
Nenue@6 8 --
Nenue@6 9 -- Workflow of cooldown tracking:
Nenue@6 10 -- A tracked spell cast is detected. (UNIT_SPELLCAST_*)
Nenue@6 11 -- That spell ID enters the timer table.
Nenue@6 12 -- The table is read by a handler that fires on the next frame, when cooldown information is available. (COOLDOWN_*)
Nenue@6 13 -- Set() is called on the corresponding timer frame, and frame script takes over.
Nenue@6 14 -- Timer table spells are polled on each COOLDOWN_* event, re-applying Set() when certain conditions are met.
Nenue@6 15 -- The framescript or certain handlers will remove the timer table entry when there are no more positive conditions.
Nenue@6 16 --
Nenue@6 17 local tostring, tonumber, tinsert = tostring, tonumber, tinsert
Nenue@6 18 local GetTime, GetSpellInfo, GetInventoryItemCooldown, GetSpellCooldown, PlaySoundFile = GetTime, GetSpellInfo, GetInventoryItemCooldown, GetSpellCooldown, PlaySoundFile
Nenue@6 19 local GetSpellCharges, GetSpellCount, GetInventoryItemCount, UnitAura = GetSpellCharges, GetSpellCount, GetInventoryItemCount, UnitAura
Nenue@6 20 local IsUsableItem, IsUsableSpell, GetItemSpell = IsUsableItem, IsUsableSpell, GetItemSpell
Nenue@6 21 local xpcall = xpcall
Nenue@6 22
Nenue@6 23 local CD_SLOT, CD_ITEM, CD_SPELL = 1, 2, 3
Nenue@6 24 local HIDDEN, PASSIVE, ACTIVE = 0, 1, 2
Nenue@6 25 local format, ceil = string.format, math.ceil
Nenue@6 26 local strrep, gsub, pairs = string.rep, string.gsub, pairs
Nenue@6 27 local mod = Turok.modules.TimerControl
Nenue@6 28 local T = Turok
Nenue@6 29 local db
Nenue@6 30 local FADE_TIME = 0.2
Nenue@6 31 --@debug@
Nenue@6 32 local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool
Nenue@6 33 local print = function(...) print('Cooldown', ...) end
Nenue@6 34 local function GetPrint (trace)
Nenue@6 35 return trace and print or function() end
Nenue@6 36 end
Nenue@6 37
Nenue@6 38
Nenue@6 39 local item_spells = {
Nenue@6 40 ['PvP Trinket'] = 42292,
Nenue@6 41 ['Burning Mirror'] = 184270,
Nenue@6 42 }
Nenue@6 43
Nenue@6 44 T.defaults.spirit.cooldown = {
Nenue@6 45
Nenue@6 46 alpha = 1,
Nenue@6 47 alpha_ooc = 0.2,
Nenue@6 48 inverse = false,
Nenue@6 49 persist = false,
Nenue@6 50 desaturated = false,
Nenue@6 51 fill_inverse = true,
Nenue@6 52 size = 24,
Nenue@6 53 counterText = "%p",
Nenue@6 54 subCounterText = "%.p",
Nenue@6 55 chargesText = "%s",
Nenue@6 56 justifyH = 'CENTER',
Nenue@6 57 justifyV = 'TOP',
Nenue@6 58
Nenue@6 59 iconText = "%p",
Nenue@6 60 leftText = "%p",
Nenue@6 61 rightText = "%n / %d",
Nenue@6 62 passive = {
Nenue@6 63 icon = {
Nenue@6 64 desaturated = false,
Nenue@6 65 color = {1, 1, 1, 1},
Nenue@6 66 blend = 'BLEND'
Nenue@6 67 }
Nenue@6 68 },
Nenue@6 69 active = {
Nenue@6 70 icon = {
Nenue@6 71 desaturated = false,
Nenue@6 72 color = {1, 1, 1, .6},
Nenue@6 73 blend = 'ADD'
Nenue@6 74 }
Nenue@6 75 },
Nenue@6 76
Nenue@6 77 --- control displays of aura information in cooldown displays
Nenue@6 78 showAura = false,
Nenue@6 79 cooldownAura = {
Nenue@6 80 icon = {
Nenue@6 81 desaturated = true,
Nenue@6 82 color = {0,1,0,1},
Nenue@6 83 }
Nenue@6 84 }
Nenue@6 85 }
Nenue@6 86
Nenue@6 87 local p = mod.prototype.trigger.cooldown
Nenue@6 88 --@end-debug@
Nenue@6 89 p.class = 'trigger'
Nenue@6 90 p.type = 'cooldown'
Nenue@6 91 p.cvars = {
Nenue@6 92 }
Nenue@6 93 --- Sets initial values before dry Event is fired to check for presence
Nenue@6 94 p.Init = function(self, spellID, caster, tristate, minValue, maxValue)
Nenue@6 95 local print = GetPrint(self.trace)
Nenue@6 96
Nenue@6 97 self.spellID = spellID and spellID or self.spellID
Nenue@6 98 self.unit = caster and caster or self.unit
Nenue@6 99 self.persist = tristate and tristate or self.persist
Nenue@6 100 self.minValue = minValue and minValue or tonumber(self.minValue)
Nenue@6 101 self.maxValue = maxValue and maxValue or tonumber(self.maxValue)
Nenue@6 102
Nenue@6 103 --- current and last state values need to be flipped for inverted conditional
Nenue@6 104 --- last state is defined in case it needs to be overridden to ensure proper frame update
Nenue@6 105 print(cWord('Load:'),cNum(self.spellID or self.inventoryID or self.itemID), cText(self.spellName or GetItemSpell('player', self.inventoryID or self.itemID)) )
Nenue@6 106 print(cWord(' inverse=')..cBool(self.cvars.inverse))
Nenue@6 107 if self.cvars.inverse then
Nenue@6 108 self.flags = {
Nenue@6 109 active = HIDDEN,
Nenue@6 110 active_prev = ACTIVE,
Nenue@6 111 passive = PASSIVE,
Nenue@6 112 passive_prev = PASSIVE,
Nenue@6 113 hidden = PASSIVE,
Nenue@6 114 hidden_prev = HIDDEN,
Nenue@6 115 }
Nenue@6 116 else
Nenue@6 117 self.flags = {
Nenue@6 118 active = ACTIVE,
Nenue@6 119 active_prev = HIDDEN,
Nenue@6 120 passive = PASSIVE,
Nenue@6 121 passive_prev = HIDDEN,
Nenue@6 122 hidden = HIDDEN,
Nenue@6 123 hidden_prev = PASSIVE
Nenue@6 124 }
Nenue@6 125 end
Nenue@6 126 if not (self.spellID or self.spellName) then
Nenue@6 127 self.debug_info('No valid spell ID or Name')
Nenue@6 128 end
Nenue@6 129 end
Nenue@6 130
Nenue@6 131 local GetItemCooldown, GetItemInfo = GetItemCooldown, GetItemInfo
Nenue@6 132 p.Query = function(self)
Nenue@6 133 local print = GetPrint(self.trace)
Nenue@6 134 local id = self.inventoryID or self.itemID or self.spellID
Nenue@6 135 local name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration, count
Nenue@6 136
Nenue@6 137 --- checked in order of precedence
Nenue@6 138 if self.inventoryID then
Nenue@6 139 print(cText(' type'), cWord('inventory slot'), cNum(id))
Nenue@6 140 self.cooldownType = CD_SLOT
Nenue@6 141 start, duration, enabled = GetInventoryItemCooldown('player', id)
Nenue@6 142 charges, maxCharges, chargeStart, chargeDuration = nil, nil, nil, nil
Nenue@6 143 count = GetInventoryItemCount('player', id)
Nenue@6 144 usable = name and true or false
Nenue@6 145 elseif self.itemID then
Nenue@6 146 self.cooldownType = CD_ITEM
Nenue@6 147
Nenue@6 148 start, duration, enabled = GetItemCooldown(self.itemID)
Nenue@6 149 print(GetItemCooldown(self.itemID))
Nenue@6 150 print(GetItemInfo(id))
Nenue@6 151
Nenue@6 152 elseif self.spellID then
Nenue@6 153 self.cooldownType = CD_SPELL
Nenue@6 154 name = GetSpellInfo(self.spellID)
Nenue@6 155 start, duration, enabled = GetSpellCooldown(self.spellID)
Nenue@6 156 charges, maxCharges, chargeStart, chargeDuration = GetSpellCharges(self.spellID)
Nenue@6 157 count = GetSpellCount(self.spellID)
Nenue@6 158 usable = true -- they still exist even when dead
Nenue@6 159 else
Nenue@6 160 self.unit = 'notaunit'
Nenue@6 161 T:Print('Timer \''..tostring(self.timerName)..'\' doesn\'t have a valid status ID.')
Nenue@6 162 end
Nenue@6 163
Nenue@6 164 -- may not have been stored for some reason
Nenue@6 165 if charges and not self.maxCharges then
Nenue@6 166 self.maxCharges = maxCharges
Nenue@6 167 end
Nenue@6 168
Nenue@6 169 print('cooldown.Query(',id,')', name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration)
Nenue@6 170 return name, usable, start, duration, enabled, charges, chargeStart, chargeDuration, count
Nenue@6 171 end
Nenue@6 172
Nenue@6 173 p.Set = function(self, ...)
Nenue@6 174 local print = GetPrint(self.trace)
Nenue@6 175
Nenue@6 176 --name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration, count
Nenue@6 177 local name
Nenue@6 178 name, self.usable, self.start, self.duration, self.enabled, self.charges, self.chargeStart, self.chargeDuration, self.count = ...
Nenue@6 179 if name then
Nenue@6 180 self.spellName = name
Nenue@6 181 end
Nenue@6 182
Nenue@6 183 if self.duration and self.start then
Nenue@6 184 self.expires = self.start + self.duration
Nenue@6 185 else
Nenue@6 186 self.expires = 0
Nenue@6 187 end
Nenue@6 188 end
Nenue@6 189
Nenue@6 190 p.Value = function(self)
Nenue@6 191 return (self.charges and self.charges < self.maxCharges) and ((GetTime() - self.chargeStart) / self.chargeDuration) or ((GetTime() - self.start) / self.duration)
Nenue@6 192 end
Nenue@6 193
Nenue@6 194 p.SetText = mod.SetText
Nenue@6 195
Nenue@6 196 --- Assign where meaning won't be amibiguous
Nenue@6 197 local Cooldown_OnCast = function(self)
Nenue@6 198 self.triggerState = true
Nenue@6 199 end
Nenue@6 200
Nenue@6 201 local Cooldown_OnUpdate = function(self, event)
Nenue@6 202 local print = GetPrint(self.trace)
Nenue@6 203
Nenue@6 204 if self.triggerState then
Nenue@6 205 print(cWord('Event'), cText(self.timerName))
Nenue@6 206 if not event then
Nenue@6 207 print(' *', cWord('Poke'))
Nenue@6 208 end
Nenue@6 209 local diff = 'start='..cText(self.start)..' duration='..cText(self.duration)..' charges='..
Nenue@6 210 cText(self.charges).. ' chargeStart='..cText(self.chargeStart).. ' chargeDuration='..cText(self.chargeDuration)
Nenue@6 211 local name, usable, start, duration, enabled, charges, chargeStart, chargeDuration, count = self:Query()
Nenue@6 212
Nenue@6 213 -- If we want and can, pull aura data and use that in place of cooldown information
Nenue@6 214 local expires, hasAura, _
Nenue@6 215 if self.cvars.showAura then
Nenue@6 216 print(cText('UnitAura'), self.unit, self.spellName, nil, 'HELPFUL')
Nenue@6 217 local name, _, _, count, _, auraDuration, auraExpires = UnitAura(self.unit , self.spellName, nil, 'HELPFUL')
Nenue@6 218 if name and (auraDuration ~= self.auraDuration or auraExpires ~= self.auraExpires) then
Nenue@6 219
Nenue@6 220 print(cText('aura check ='), cBool(name), 's='..cNum(count), 'd='..cNum(auraDuration), 'e='..cNum(auraExpires))
Nenue@6 221 start = auraExpires - auraDuration
Nenue@6 222 duration = auraDuration
Nenue@6 223 expires = auraExpires
Nenue@6 224 end
Nenue@6 225 end
Nenue@6 226
Nenue@6 227 -- print(name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration, count)
Nenue@6 228 if duration ~= self.duration or
Nenue@6 229 start ~= self.start or
Nenue@6 230 chargeStart ~= self.chargeStart
Nenue@6 231 or charges ~= self.charges then
Nenue@6 232 print('a variable has changed')
Nenue@6 233 local state
Nenue@6 234
Nenue@6 235
Nenue@6 236 if duration == 0 and charges == self.maxCharges then
Nenue@6 237 print(cText(' cooldown has reset, drop it from the queue'))
Nenue@6 238 state = self.cvars.persist and self.flags.passive or self.flags.hidden
Nenue@6 239 self.triggerState = nil
Nenue@6 240 print(' ', cText('dropping'), cWord(self.timerName), cText('from spell tracking'))
Nenue@6 241
Nenue@6 242
Nenue@6 243 self:Stats(state)
Nenue@6 244 else
Nenue@6 245 if duration ~= 0 then
Nenue@6 246 print(cText(' cooldown has a hard duration'))
Nenue@6 247 if duration > T.GCD and self.displayState ~= self.flags.active then
Nenue@6 248 print(cText(' and its > GCD, update it'))
Nenue@6 249 state = self.flags.active
Nenue@6 250 end
Nenue@6 251 end
Nenue@6 252
Nenue@6 253 if charges then
Nenue@6 254 print(cText(' cooldown has charges'))
Nenue@6 255 if charges ~= self.charges or chargeStart ~= self.chargeStart then
Nenue@6 256 print(cText(' charges count or starting time has changed'))
Nenue@6 257 state = self.flags.active
Nenue@6 258 end
Nenue@6 259 end
Nenue@6 260
Nenue@6 261 self:Stats(state)
Nenue@6 262 end
Nenue@6 263
Nenue@6 264
Nenue@6 265 -- form ID, id type, displayState, prevState
Nenue@6 266 --T:Dispatch('TK_COOLDOWN_UPDATE', self.spellID, self.cooldownType, state, self.displayState)
Nenue@6 267 if state then
Nenue@6 268 self:Set(name, usable, start, duration, enabled, charges, chargeStart, chargeDuration, count)
Nenue@6 269 self.expires = charges and (self.chargeStart + self.chargeDuration) or (self.start + self.duration)
Nenue@6 270 self:SetState(state)
Nenue@6 271 --print(' ', cText('SetState'), cNum(self.displayState), 'from', cNum(self.prevState), cWord(self.timerName))
Nenue@6 272 print(' ',diff)
Nenue@6 273 print(' start='..cText(self.start)..' duration='..cText(self.duration)..' charges='..
Nenue@6 274 cText(self.charges).. ' chargeStart='..cText(self.chargeStart).. ' chargeDuration='..cText(self.chargeDuration))
Nenue@6 275 end
Nenue@6 276 elseif self.cooldownType == CD_SPELL then
Nenue@6 277 if duration == 0 and charges == self.maxCharges and self.displayState == HIDDEN then
Nenue@6 278 print(cKey(self.timerName), cText('post-framescript clean-up'))
Nenue@6 279 self.triggerState = nil
Nenue@6 280 end
Nenue@6 281 end
Nenue@6 282 end
Nenue@6 283 --self:DumpMessages()
Nenue@6 284
Nenue@6 285 end
Nenue@6 286
Nenue@6 287 p.Stats = function(self, state)
Nenue@6 288 print(self.unit, self.spellName)
Nenue@6 289 local auraName, _, _, auraCharges, _, auraDuration, auraExpires = UnitAura(self.unit, self.spellName, nil, 'HELPFUL')
Nenue@6 290 local name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration, count = self:Query()
Nenue@6 291 print('# GCD =', T.GCD)
Nenue@6 292 print('# SpellCooldown', 's =', start, 'd =', duration, 's =', charges and (charges..'/'..maxCharges) or 'NA')
Nenue@6 293 print('# Aura', auraName and 'yes' or 'no', auraName and ('d='..cNum(auraDuration)) or '', auraName and ('e='..auraExpires))
Nenue@6 294 print('# Frame', 'state1 =', self.displayState, 'state2 =', self.previousState, state and ('change to '..cWord(state)) or '')
Nenue@6 295
Nenue@6 296
Nenue@6 297 end
Nenue@6 298
Nenue@6 299 --- Event pointers
Nenue@6 300 p.events = {
Nenue@6 301 ['UNIT_SPELLCAST_SUCCEEDED'] = Cooldown_OnCast,
Nenue@6 302 ['UNIT_SPELLCAST_CHANNEL_START'] = Cooldown_OnCast,
Nenue@6 303 ['BAG_UPDATE_COOLDOWN'] = Cooldown_OnUpdate,
Nenue@6 304 ['SPELL_UPDATE_COOLDOWN'] = Cooldown_OnUpdate,
Nenue@6 305 ['SPELL_UPDATE_USABLE'] = Cooldown_OnUpdate,
Nenue@6 306 ['SPELL_UPDATE_CHARGES'] = Cooldown_OnUpdate,
Nenue@6 307 }
Nenue@6 308
Nenue@6 309 local unpack, select, debugstack = unpack, select, debugstack
Nenue@6 310 p.Event = function(self, e, ...)
Nenue@6 311 local print = GetPrint(self.trace)
Nenue@6 312
Nenue@6 313 self.event = e
Nenue@6 314 --- dry event case
Nenue@6 315 if not e then
Nenue@6 316 print('onEvent', self.timerName, e)
Nenue@6 317 self.triggerState = true
Nenue@6 318 Cooldown_OnUpdate(self, e, ...)
Nenue@6 319 else
Nenue@6 320 local unit = select(1,...)
Nenue@6 321 if self.unit and unit ~= self.unit and e ~= 'SPELL_UPDATE_COOLDOWN' then
Nenue@6 322 return
Nenue@6 323 end
Nenue@6 324 local args = {...}
Nenue@6 325 local success, d = xpcall(function() self.events[e](self, e, unpack(args)) end, function(m) print(self.name .."\n".. m .. "\n".. debugstack(3)) end)
Nenue@6 326
Nenue@6 327 end
Nenue@6 328 end
Nenue@6 329
Nenue@6 330 p.triggerList = {
Nenue@6 331 ['on_cooldown'] = function(self)
Nenue@6 332 local start, duration, enabled = GetSpellCooldown(self.spellID)
Nenue@6 333 local charges, _, cStart, cDuration = GetSpellCharges(self.spellID)
Nenue@6 334 return (enabled and (duration ~= 0 or start ~= 0 or charges ~= self.maxCharges)), start, duration, enabled, charges, cStart, cDuration
Nenue@6 335 end,
Nenue@6 336 ['not_on_cooldown'] = function(self)
Nenue@6 337 local start, duration, enabled = GetSpellCooldown(self.spellID)
Nenue@6 338 local charges, _, cStart, cDuration = GetSpellCharges(self.spellID)
Nenue@6 339 return (duration == 0 and start == 0 and charges == self.maxCharges), start, duration, enabled, charges, cStart, cDuration
Nenue@6 340 end,
Nenue@6 341 ['buff_active'] = function(self)
Nenue@6 342 local name, rank, icon, count, dispelType, duration, expires, caster, isStealable, shouldConsolidate, spellID, canApplyAura, isBossDebuff, value1, value2, value3 = UnitAura(self.unit, self.spellName, self.filters)
Nenue@6 343 return (name and true or false), expires - duration, duration, true, count, 0, 0
Nenue@6 344 end
Nenue@6 345 }