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