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 }