Nenue@6
|
1 --- Turok - Timer/Timer.lua
|
Nenue@6
|
2 -- @file-author@
|
Nenue@6
|
3 -- @project-revision@ @project-hash@
|
Nenue@6
|
4 -- @file-revision@ @file-hash@
|
Nenue@6
|
5 --- Defines common elements for the various timer HUDs
|
Nenue@6
|
6 local ADDON, _A = ...
|
Nenue@6
|
7 local _G, CreateFrame, tconcat, GetInventoryItemsForSlot, GetInventoryItemID = _G, CreateFrame, table.concat, GetInventoryItemsForSlot, GetInventoryItemID
|
Nenue@6
|
8 local T, F, tostring, type, max, tinsert, unpack, UIParent, loadstring = _A.Addon, _A.LibFog, tostring, type, max, table.insert, unpack, _G.UIParent, loadstring
|
Nenue@6
|
9 local mod = T.modules.TimerControl
|
Nenue@6
|
10 local P = mod.prototype
|
Nenue@6
|
11 local db
|
Nenue@6
|
12
|
Nenue@6
|
13 local pairs, ipairs, gsub, sub, setmetatable = pairs, ipairs, string.gsub, string.sub, setmetatable
|
Nenue@6
|
14 local INVTYPE_FINGER, INVSLOT_FINGER1, INVSLOT_FINGER2, INVTYPE_TRINKET, INVSLOT_TRINKET1, INVSLOT_TRINKET2 =
|
Nenue@6
|
15 INVTYPE_FINGER, INVSLOT_FINGER1, INVSLOT_FINGER2, INVTYPE_TRINKET, INVSLOT_TRINKET1, INVSLOT_TRINKET2
|
Nenue@6
|
16 --@debug@
|
Nenue@6
|
17 local DEBUG = true
|
Nenue@6
|
18 --@end-debug@
|
Nenue@6
|
19 local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool
|
Nenue@6
|
20 local print = function(...)
|
Nenue@6
|
21 if not DEBUG then return end
|
Nenue@6
|
22 if _G.Devian and _G.DevianDB.workspace ~= 1 then
|
Nenue@6
|
23 _G.print('Timer', ...)
|
Nenue@6
|
24 end
|
Nenue@6
|
25 end
|
Nenue@6
|
26
|
Nenue@6
|
27 local Timer_GetPrintHandler = function(self)
|
Nenue@6
|
28 if self.trace then
|
Nenue@6
|
29 return function(...)
|
Nenue@6
|
30 print(...)
|
Nenue@6
|
31 _G.print('TimerFocus', ...)
|
Nenue@6
|
32 end else
|
Nenue@6
|
33 return print
|
Nenue@6
|
34 end
|
Nenue@6
|
35 end
|
Nenue@6
|
36 local pb_suppressed = {}
|
Nenue@6
|
37
|
Nenue@6
|
38 function mod:OnInitialize()
|
Nenue@6
|
39
|
Nenue@6
|
40 --@debug@
|
Nenue@6
|
41 TurokData.spirit.timers = Turok.defaults.spirit.timers
|
Nenue@6
|
42 --@end-debug@
|
Nenue@6
|
43 self.db = TurokData.spirit
|
Nenue@6
|
44 db = self.db
|
Nenue@6
|
45 self.active_cooldowns = {}
|
Nenue@6
|
46 self.cast_units = {}
|
Nenue@6
|
47 self.buff_units = {}
|
Nenue@6
|
48 self.loaded_types = {}
|
Nenue@6
|
49 self.loaded_triggers = {}
|
Nenue@6
|
50 self.equipped = {}
|
Nenue@6
|
51 self.containers = {}
|
Nenue@6
|
52 self.timers = {} -- active timers
|
Nenue@6
|
53 self.empty_frames = {} -- foster table for frames released by talent change
|
Nenue@6
|
54
|
Nenue@6
|
55
|
Nenue@6
|
56 T:RegisterChatCommand("tsp", self.Import_Open)
|
Nenue@6
|
57 T:RegisterChatCommand("tka", self.Dialog_Command)
|
Nenue@6
|
58 T:RegisterChatCommand("tki", self.CreateIndex)
|
Nenue@6
|
59 --T:Print("/tsp to import spells. /tka to open create dialog")
|
Nenue@6
|
60 -- suppress cacophony from all cooldowns activating at login
|
Nenue@6
|
61 self.quiet = true
|
Nenue@6
|
62 --self:ScheduleTimer(function() self:Dialog_Command() end, 4)
|
Nenue@6
|
63
|
Nenue@6
|
64 end
|
Nenue@6
|
65
|
Nenue@6
|
66 local mt_single = {
|
Nenue@6
|
67 __mode = "v",
|
Nenue@6
|
68 __newindex = function(t,k,v)
|
Nenue@6
|
69 rawset(t,k,v)
|
Nenue@6
|
70 _G.print('DB', 'TCMeta: adding leaf', k, '=', v)
|
Nenue@6
|
71 end}
|
Nenue@6
|
72 local mt_double = {
|
Nenue@6
|
73 __index = function(t,k)
|
Nenue@6
|
74 t[k] = setmetatable({}, mt_single)
|
Nenue@6
|
75 _G.print('DB', 'TCMeta: add layer', k, '=', t[k])
|
Nenue@6
|
76 return t[k]
|
Nenue@6
|
77 end,
|
Nenue@6
|
78 __newindex = function(t,k,v)
|
Nenue@6
|
79 rawset(t,k,v)
|
Nenue@6
|
80 _G.print('DB', 'TCMeta: adding to top layer', k, '=', v)
|
Nenue@6
|
81 end
|
Nenue@6
|
82 }
|
Nenue@6
|
83 local mt_error = {
|
Nenue@6
|
84 __call =function (t, txt)
|
Nenue@6
|
85 t.disable = true
|
Nenue@6
|
86 tinsert(t, txt)
|
Nenue@6
|
87 end
|
Nenue@6
|
88 }
|
Nenue@6
|
89
|
Nenue@6
|
90 --- Sets and cleans up index data used by event handlers
|
Nenue@6
|
91 local Timer_UpdateIndex = function(self, key)
|
Nenue@6
|
92
|
Nenue@6
|
93 -- Is there already an entry for this key/value?
|
Nenue@6
|
94 if self.frames[key] then
|
Nenue@6
|
95 local lim = #mod.frames[key]
|
Nenue@6
|
96 --[[
|
Nenue@6
|
97 for i = self.frames[key]+1, lim, 1 do
|
Nenue@6
|
98 mod.frames[key][i] = mod.frames[key+1]
|
Nenue@6
|
99 end]]
|
Nenue@6
|
100 --self.frames[key] = nil
|
Nenue@6
|
101 print(' ', cText('mod.frames.')..cWord(key), '=', #mod.frames[key])
|
Nenue@6
|
102 print(' ', cText('self.frames.')..cWord(key), '=', cNum(self.frames[key]))
|
Nenue@6
|
103 end
|
Nenue@6
|
104
|
Nenue@6
|
105 if key then
|
Nenue@6
|
106 local i = #mod.frames[key]+1
|
Nenue@6
|
107 --mod.frames[key][i] = self
|
Nenue@6
|
108 self.frames[key] = i
|
Nenue@6
|
109 print(' ', cText('self.frames.')..cWord(key), '=', #mod.frames[key])
|
Nenue@6
|
110 end
|
Nenue@6
|
111 mod.loaded_types[key] = (#mod.frames[key] == 0) and nil or true
|
Nenue@6
|
112 print(' ',cText(key..'_is_loaded'), '=', cBool(mod.loaded_types[key]))
|
Nenue@6
|
113 end
|
Nenue@6
|
114
|
Nenue@6
|
115 --- Loading initators
|
Nenue@6
|
116 function mod:OnEnable()
|
Nenue@6
|
117 mod.LoadPresets()
|
Nenue@6
|
118 mod.GetIndex()
|
Nenue@6
|
119 -- setup indexes, use nested weak table for status since they implicitly have a key variable
|
Nenue@6
|
120 mod.frames = {}
|
Nenue@6
|
121 for class, p in pairs(mod.prototype.status) do
|
Nenue@6
|
122 print('nested index table', class)
|
Nenue@6
|
123 mod.frames[class] = setmetatable({}, mt_double)
|
Nenue@6
|
124 end
|
Nenue@6
|
125 mod.frames.spellName = setmetatable({}, mt_double)
|
Nenue@6
|
126 for class, p in pairs(mod.prototype.display) do
|
Nenue@6
|
127 mod.frames[class] = setmetatable({}, mt_single)
|
Nenue@6
|
128 end
|
Nenue@6
|
129 for class, p in pairs(mod.prototype.trigger) do
|
Nenue@6
|
130 mod.frames[class] = setmetatable({}, mt_single)
|
Nenue@6
|
131 end
|
Nenue@6
|
132
|
Nenue@6
|
133 local srcIndex = mod.timers
|
Nenue@6
|
134 if T.playerClass and mod.index[T.playerClass] then
|
Nenue@6
|
135 srcIndex = mod.index[T.playerClass]
|
Nenue@6
|
136 print('*** Found index for '..tostring(T.playerClass)..', using that.')
|
Nenue@6
|
137 else
|
Nenue@6
|
138 print(cWord('*** Using global index.'))
|
Nenue@6
|
139 end
|
Nenue@6
|
140 mod.activeSpec = T.specID
|
Nenue@6
|
141
|
Nenue@6
|
142 --- go through that list
|
Nenue@6
|
143 for id, timer in pairs(srcIndex) do
|
Nenue@6
|
144 local result, message = mod:EnableTimer(id, timer)
|
Nenue@6
|
145 end
|
Nenue@6
|
146
|
Nenue@6
|
147 mod.InitTimers()
|
Nenue@6
|
148 --- Delay sound activations so there isn't a giant cacophony on load
|
Nenue@6
|
149 mod:ScheduleTimer(function()
|
Nenue@6
|
150 self.quiet = nil
|
Nenue@6
|
151 end, db.audio_delay or 2)
|
Nenue@6
|
152 end
|
Nenue@6
|
153
|
Nenue@6
|
154 function mod:EnableTimer(id, dvars)
|
Nenue@6
|
155 local print = Timer_GetPrintHandler(dvars)
|
Nenue@6
|
156 print('-{', cPink(dvars.name))
|
Nenue@6
|
157 if not dvars then
|
Nenue@6
|
158 if not mod.index.global[id] then
|
Nenue@6
|
159 return false, "Unable to resolve dvars table."
|
Nenue@6
|
160 end
|
Nenue@6
|
161 dvars = mod.index.global[id]
|
Nenue@6
|
162 end
|
Nenue@6
|
163 if dvars.virtual then
|
Nenue@6
|
164 return
|
Nenue@6
|
165 end
|
Nenue@6
|
166
|
Nenue@6
|
167 local spirit, newFrame = mod:GetTimer(id, dvars)
|
Nenue@6
|
168 if not spirit then return spirit, newFrame end
|
Nenue@6
|
169
|
Nenue@6
|
170 local cvars = spirit.cvars
|
Nenue@6
|
171 local dvars = spirit.dvars
|
Nenue@6
|
172 local trigger = P.trigger[cvars.type]
|
Nenue@6
|
173 local display = P.display[cvars.display]
|
Nenue@6
|
174 local cvars = spirit.cvars
|
Nenue@6
|
175 local index = mod.frames
|
Nenue@6
|
176 local print = Timer_GetPrintHandler(cvars)
|
Nenue@6
|
177
|
Nenue@6
|
178 if spirit.disable then
|
Nenue@6
|
179 return false, "Manually disabled." -- nothing to do, nothing to say
|
Nenue@6
|
180 end
|
Nenue@6
|
181
|
Nenue@6
|
182 --- Interpret STATUS vars
|
Nenue@6
|
183 print(cText(' *** Merging Status Data'))
|
Nenue@6
|
184 spirit.disable = dvars.disable
|
Nenue@6
|
185 local pcount = 1
|
Nenue@6
|
186 for k, handler in pairs(P.status) do
|
Nenue@6
|
187 if cvars[k] then
|
Nenue@6
|
188 if handler.Init then
|
Nenue@6
|
189 print(cWord(' * Firing ')..cKey(k)..cWord('.Init'), cNum(cvars[k]))
|
Nenue@6
|
190 handler.Init(spirit, cvars[k])
|
Nenue@6
|
191 else
|
Nenue@6
|
192 print(' ', cText('skipped'), cKey(k))
|
Nenue@6
|
193 end
|
Nenue@6
|
194 pcount = pcount + 1
|
Nenue@6
|
195 end
|
Nenue@6
|
196 end
|
Nenue@6
|
197
|
Nenue@6
|
198 spirit.Event = trigger.Event
|
Nenue@6
|
199 spirit.Value = trigger.Value
|
Nenue@6
|
200 spirit.SetText = mod.SetText
|
Nenue@6
|
201 spirit.LoadText = mod.LoadText
|
Nenue@6
|
202 spirit.Query = trigger.Query
|
Nenue@6
|
203 spirit.Set = trigger.Set
|
Nenue@6
|
204
|
Nenue@6
|
205 --- Display handler init
|
Nenue@6
|
206 if display.Init then
|
Nenue@6
|
207 print(cText(' * Display Init:'), cKey(dvars.display))
|
Nenue@6
|
208 display.Init(spirit)
|
Nenue@6
|
209 end
|
Nenue@6
|
210
|
Nenue@6
|
211 --- Trigger handler and events Load()
|
Nenue@6
|
212 print(cText(' * Trigger Init:'), cKey(dvars.type))
|
Nenue@6
|
213 trigger.Init(spirit)
|
Nenue@6
|
214
|
Nenue@6
|
215
|
Nenue@6
|
216 if C_PetBattles.IsInBattle() then
|
Nenue@6
|
217 spirit.disable = true
|
Nenue@6
|
218 spirit.debug_info("Hidden for pet battle")
|
Nenue@6
|
219 pb_suppressed[id] = true
|
Nenue@6
|
220 end
|
Nenue@6
|
221
|
Nenue@6
|
222
|
Nenue@6
|
223 if spirit.disable then
|
Nenue@6
|
224 spirit:UnregisterAllEvents()
|
Nenue@6
|
225 spirit.displayState = nil
|
Nenue@6
|
226 spirit.prevState = nil
|
Nenue@6
|
227 spirit:Hide()
|
Nenue@6
|
228 return false, tconcat(spirit.debug_info,"\n")
|
Nenue@6
|
229 else
|
Nenue@6
|
230 print('--', self.disable and cPink('DISABLED') or cNum('ENABLED'), #spirit.debug_info > 0 and tconcat(spirit.debug_info,"\n"), '}')
|
Nenue@6
|
231 return true, tconcat(spirit.debug_info,"\n")
|
Nenue@6
|
232 end
|
Nenue@6
|
233 end
|
Nenue@6
|
234
|
Nenue@6
|
235 function mod:GetTimer(id, dvars)
|
Nenue@6
|
236 local print = Timer_GetPrintHandler(dvars)
|
Nenue@6
|
237 local newFrame
|
Nenue@6
|
238 if not mod.timers[id] then
|
Nenue@6
|
239 print(cKey(' [[CreateTimer'))
|
Nenue@6
|
240 newFrame = true
|
Nenue@6
|
241 --- Compile the cvar table from the various config layers:
|
Nenue@6
|
242 -- Start with timer dvars, overwritten by any container settings, then a disable check, then merge in prototype values
|
Nenue@6
|
243 local cvars = T.Config_Push({}, dvars, nil, cKey('['..id..']')..'.'..cWord('cvars'))
|
Nenue@6
|
244 cvars.name = dvars.name -- push function ignores name keys
|
Nenue@6
|
245
|
Nenue@6
|
246 if dvars.container and db.containers[dvars.container] then
|
Nenue@6
|
247 print(cText(' * Merging Container overrides'))
|
Nenue@6
|
248 T.Config_Push(cvars, db.containers[dvars.container], cvars, cKey('['..id..']')..'.'..cWord('cvars'))
|
Nenue@6
|
249 end
|
Nenue@6
|
250
|
Nenue@6
|
251 --- Stop here if disabled via SavedVars
|
Nenue@6
|
252 if cvars.disable then
|
Nenue@6
|
253 return false, "Manually disabled"
|
Nenue@6
|
254 end
|
Nenue@6
|
255
|
Nenue@6
|
256 --- Localize the stuff we are going to loop over
|
Nenue@6
|
257 local display = P.display[cvars.display]
|
Nenue@6
|
258 local trigger = P.trigger[cvars.type]
|
Nenue@6
|
259 local displayType = cvars.display
|
Nenue@6
|
260 local triggerType = cvars.type
|
Nenue@6
|
261 if not (display and trigger) then
|
Nenue@6
|
262 return nil, "Missing prototype data. Summary: "..tostring(displayType).."="..(display and 'OK' or 'MISSING') ..
|
Nenue@6
|
263 " "..tostring(triggerType).."="..(trigger and 'OK' or 'MISSING')
|
Nenue@6
|
264 end
|
Nenue@6
|
265
|
Nenue@6
|
266 --- Establish the order in which values are merged
|
Nenue@6
|
267 print(cText(' * Merging object CVars'))
|
Nenue@6
|
268 local cvar_class = {cWord('db.'..displayType), cWord('db.'..triggerType), cWord('db.global')}
|
Nenue@6
|
269 local cvar_array = {
|
Nenue@6
|
270 db[displayType],
|
Nenue@6
|
271 db[triggerType],
|
Nenue@6
|
272 db.global,
|
Nenue@6
|
273 }
|
Nenue@6
|
274 local override_class = {cWord('trigger.'..cvars.type), cWord('display.'.. cvars.display)}
|
Nenue@6
|
275 local override_array = {
|
Nenue@6
|
276 display.cvars,
|
Nenue@6
|
277 trigger.cvars }
|
Nenue@6
|
278
|
Nenue@6
|
279 --- Table merge user settings
|
Nenue@6
|
280 for i, p in pairs(cvar_array) do
|
Nenue@6
|
281 print(' '..cNum(i)..' merge ['..cvar_class[i]..']')
|
Nenue@6
|
282 T.Config_Merge(cvars, p, cvars, cKey('['..id..']')..'.'..cWord('cvars'))
|
Nenue@6
|
283 end
|
Nenue@6
|
284
|
Nenue@6
|
285 --- Overwrite with anything defined by the prototype structure because it's important
|
Nenue@6
|
286 local _, odiff
|
Nenue@6
|
287 for i, p in ipairs(override_array) do
|
Nenue@6
|
288 _, odiff = T.Config_Push(cvars, p, cvars, cKey('['..id..']')..'.'..cWord('cvars'))
|
Nenue@6
|
289 end
|
Nenue@6
|
290 local print = Timer_GetPrintHandler(cvars)
|
Nenue@6
|
291
|
Nenue@6
|
292 --- Create the UI frame and seed it with the data we just composed
|
Nenue@6
|
293 local spirit = CreateFrame('Frame', 'TurokTimerFrame'..gsub(dvars.name, "[^%a%d]", ''), UIParent, display.inherits)
|
Nenue@6
|
294 spirit.trace = cvars.trace
|
Nenue@6
|
295 spirit.timerID = id
|
Nenue@6
|
296 spirit.timerName = dvars.name
|
Nenue@6
|
297 spirit.container = dvars.container
|
Nenue@6
|
298 spirit.cvars = cvars
|
Nenue@6
|
299 spirit.dvars = dvars
|
Nenue@6
|
300 spirit.Update = display.Update
|
Nenue@6
|
301 spirit.SetState = display.SetState
|
Nenue@6
|
302 spirit.Report = mod.Report
|
Nenue@6
|
303 spirit.Stats = trigger.Stats
|
Nenue@6
|
304
|
Nenue@6
|
305 --- Set Layout Statics
|
Nenue@6
|
306 T.SetFrameLayout(spirit, cvars)
|
Nenue@6
|
307
|
Nenue@6
|
308 --- Create troubleshooting collection
|
Nenue@6
|
309 spirit.debug_info = setmetatable({}, mt_error)
|
Nenue@6
|
310
|
Nenue@6
|
311 --- Add the frame to corresponding prototype indexes
|
Nenue@6
|
312 spirit.frames = {}
|
Nenue@6
|
313 spirit.events = {}
|
Nenue@6
|
314
|
Nenue@6
|
315 if spirit.display ~= displayType then
|
Nenue@6
|
316 spirit.display = displayType
|
Nenue@6
|
317 Timer_UpdateIndex(spirit, displayType)
|
Nenue@6
|
318 end
|
Nenue@6
|
319 if spirit.type ~= triggerType then
|
Nenue@6
|
320 spirit.type = triggerType
|
Nenue@6
|
321 Timer_UpdateIndex(spirit, triggerType)
|
Nenue@6
|
322 end
|
Nenue@6
|
323 --- Add the frame to global index
|
Nenue@6
|
324 mod.timers[id] = spirit
|
Nenue@6
|
325 end
|
Nenue@6
|
326
|
Nenue@6
|
327 return mod.timers[id], newFrame
|
Nenue@6
|
328 end
|
Nenue@6
|
329
|
Nenue@6
|
330 function mod.InitTimers()
|
Nenue@6
|
331 local print = function(...) _G.print('TimerEvent', ...) end
|
Nenue@6
|
332 print('INIT TIMERS ====================')
|
Nenue@6
|
333 for id, spirit in pairs(mod.timers) do
|
Nenue@6
|
334 if spirit.disable then
|
Nenue@6
|
335 print(id, 'disabled:', tconcat(spirit.debug_info or {}, ', '))
|
Nenue@6
|
336 else
|
Nenue@6
|
337
|
Nenue@6
|
338 print(cText('init'), cNum(id), cWord(spirit.name))
|
Nenue@6
|
339 --- Throw a dry event to initialize values
|
Nenue@6
|
340 print(cText(' *'), cWord('prototype.'..cKey(spirit.dvars.type)..'.'..cWord('Load')))
|
Nenue@6
|
341 P.trigger[spirit.dvars.type].Event(spirit)
|
Nenue@6
|
342
|
Nenue@6
|
343 --- Set loose
|
Nenue@6
|
344 print(cText(' *'), cWord('prototype')..'.'..cKey('events')..'.'..cWord('Load'))
|
Nenue@6
|
345 mod.UpdateEvents(spirit, P.trigger[spirit.dvars.type].events)
|
Nenue@6
|
346 end
|
Nenue@6
|
347 end
|
Nenue@6
|
348 print('INIT DONE =========================')
|
Nenue@6
|
349 end
|
Nenue@6
|
350
|
Nenue@6
|
351 function mod:DisableTimer(name, timer)
|
Nenue@6
|
352 local timer_frame = mod.db.timers[name]
|
Nenue@6
|
353 if timer_frame and not timer_frame.disable then
|
Nenue@6
|
354 timer_frame.disable = true
|
Nenue@6
|
355 timer_frame:UnregisterAllEvents()
|
Nenue@6
|
356 timer_frame:Hide()
|
Nenue@6
|
357 end
|
Nenue@6
|
358 end
|
Nenue@6
|
359
|
Nenue@6
|
360 function mod.UpdateEvents(self, events)
|
Nenue@6
|
361 local print = Timer_GetPrintHandler(self)
|
Nenue@6
|
362
|
Nenue@6
|
363 self:SetScript('OnEvent', nil)
|
Nenue@6
|
364 self:UnregisterAllEvents()
|
Nenue@6
|
365
|
Nenue@6
|
366 local proxy, listen = {}, {}
|
Nenue@6
|
367 for event, handler in pairs(events) do
|
Nenue@6
|
368 if mod[event] then
|
Nenue@6
|
369 tinsert(proxy, cNum(event))
|
Nenue@6
|
370 else
|
Nenue@6
|
371 tinsert(listen, cWord(event))
|
Nenue@6
|
372 self:RegisterEvent(event)
|
Nenue@6
|
373 end
|
Nenue@6
|
374 self.events[event] = handler
|
Nenue@6
|
375 end
|
Nenue@6
|
376
|
Nenue@6
|
377 if #proxy > 0 then
|
Nenue@6
|
378 print( ' -', cKey(self.name), cWord('receiving'), tconcat(proxy, ', '))
|
Nenue@6
|
379 end
|
Nenue@6
|
380 if #listen > 0 then
|
Nenue@6
|
381 print( ' -', cKey(self.name), cText('listening'), tconcat(listen, ', '))
|
Nenue@6
|
382 end
|
Nenue@6
|
383
|
Nenue@6
|
384 self:SetScript('OnEvent', self.Event)
|
Nenue@6
|
385 end
|
Nenue@6
|
386
|
Nenue@6
|
387 local match_sub = {
|
Nenue@6
|
388 {'%%c', "' .. tostring(t.caster).. '"},
|
Nenue@6
|
389 {'%%h', "' .. tostring((t.valueFull >= 60) and (math.floor(t.valueFull/60)) or t.value) .. '"},
|
Nenue@6
|
390 {'%%i', "' .. tostring((t.valueFull >= 60) and (t.value % 60) or ((t.valueFull < 6) and math.floor((t.ValueFull * 100) % 100) or '')) .. '"},
|
Nenue@6
|
391 {'%%n', "' .. tostring(t.spellName) .. '"},
|
Nenue@6
|
392 {'%%p', "' .. tostring(t.value) .. '"},
|
Nenue@6
|
393 {'%%d', "' .. tostring(t.chargeDuration or t.duration) .. '"},
|
Nenue@6
|
394 {'%%%.p', "' .. string.sub(tostring((t.valueFull %% 1) * 100),0,1) .. '"},
|
Nenue@6
|
395 {"%%s", "' .. (t.stacks or t.charges or '') .. '"},
|
Nenue@6
|
396 }
|
Nenue@6
|
397
|
Nenue@6
|
398 -- dot syntax implies use as embedded method
|
Nenue@6
|
399 function mod.LoadText(self)
|
Nenue@6
|
400 print(cKey('parsing textRegions for'), self.timerName, self.timerID)
|
Nenue@6
|
401 self.textTypes = {}
|
Nenue@6
|
402 self.textValues = {}
|
Nenue@6
|
403 for name, region in pairs(self.textRegions) do
|
Nenue@6
|
404 print(' ', cWord('textRegions')..'["'.. cType(self.timerName)..'"].'..cType(name))
|
Nenue@6
|
405 if self.cvars[name..'Text'] then
|
Nenue@6
|
406
|
Nenue@6
|
407 -- todo: collect match counts and index the text fields by match types
|
Nenue@6
|
408 local str = self.cvars[name..'Text']
|
Nenue@6
|
409 for i, args in ipairs(match_sub) do
|
Nenue@6
|
410 if str:match(args[1]) then
|
Nenue@6
|
411 if not self.textTypes[args[1]] then
|
Nenue@6
|
412 self.textTypes[args[1]] = {}
|
Nenue@6
|
413 end
|
Nenue@6
|
414 tinsert(self.textTypes[args[1]], region)
|
Nenue@6
|
415 str = str:gsub(args[1], args[2])
|
Nenue@6
|
416 end
|
Nenue@6
|
417 end
|
Nenue@6
|
418 str = "local t = _G.Turok.modules.TimerControl.timers["..self.timerID.."]\n"
|
Nenue@6
|
419 .. "\n return '" .. str .. "'"
|
Nenue@6
|
420 local func = assert(loadstring(str))
|
Nenue@6
|
421 self.textValues[name] = func
|
Nenue@6
|
422 end
|
Nenue@6
|
423 end
|
Nenue@6
|
424
|
Nenue@6
|
425 --mod.SetText(self)
|
Nenue@6
|
426 end
|
Nenue@6
|
427
|
Nenue@6
|
428 --- generic text setter
|
Nenue@6
|
429 local HIDDEN, PASSIVE, ACTIVE = 0, 1, 2
|
Nenue@6
|
430 mod.SetText = function(self)
|
Nenue@6
|
431 if self.displayState ~= ACTIVE then
|
Nenue@6
|
432 for name, region in pairs(self.textRegions) do
|
Nenue@6
|
433 region:SetText(nil)
|
Nenue@6
|
434 end
|
Nenue@6
|
435 return
|
Nenue@6
|
436 end
|
Nenue@6
|
437
|
Nenue@6
|
438 if not self.textValues then
|
Nenue@6
|
439 self.textValues = {}
|
Nenue@6
|
440 mod.LoadText(self, self.cvars)
|
Nenue@6
|
441 end
|
Nenue@6
|
442
|
Nenue@6
|
443 -- hide when above a certain number
|
Nenue@6
|
444
|
Nenue@6
|
445 if self.spiral and self.spiral.subCounter then
|
Nenue@6
|
446 if self.valueFull > 6 then
|
Nenue@6
|
447 if self.textValues.subCounter then
|
Nenue@6
|
448 --print('hiding milliseconds')
|
Nenue@6
|
449 self.textRegions.subCounter:Hide()
|
Nenue@6
|
450 self.textRegionsSub = self.textRegions.subCounter
|
Nenue@6
|
451 self.textValuesSub = self.textValues.subCounter
|
Nenue@6
|
452 self.textRegions.subCounter = nil
|
Nenue@6
|
453 self.textValues.subCounter = nil
|
Nenue@6
|
454 end
|
Nenue@6
|
455 else
|
Nenue@6
|
456 if not self.textValues.subCounter then
|
Nenue@6
|
457 --print('showing milliseconds')
|
Nenue@6
|
458 self.textValues.subCounter = self.textValuesSub
|
Nenue@6
|
459 self.textRegions.subCounter = self.textRegionsSub
|
Nenue@6
|
460 self.textRegions.subCounter:Show()
|
Nenue@6
|
461 end
|
Nenue@6
|
462 end
|
Nenue@6
|
463 end
|
Nenue@6
|
464
|
Nenue@6
|
465 for name, region in pairs(self.textRegions) do
|
Nenue@6
|
466 --print(name)
|
Nenue@6
|
467 --print(name, self.timerName, self.textValues[name](self))
|
Nenue@6
|
468 region:SetText(self.textValues[name](self))
|
Nenue@6
|
469 end
|
Nenue@6
|
470 end
|
Nenue@6
|
471
|
Nenue@6
|
472
|
Nenue@6
|
473 -------------------------------------------------------------------------
|
Nenue@6
|
474 --- Second-tier handlers to cut down on the number of Status:Event() polls
|
Nenue@6
|
475
|
Nenue@6
|
476 --- UNIT_SPELLCAST_*** use args to filter out the number of full handler runs
|
Nenue@6
|
477 function mod:UNIT_SPELLCAST_SUCCEEDED (e, unit, spellName, rank, castID, spellID)
|
Nenue@6
|
478 if not mod.frames.unit[unit] then
|
Nenue@6
|
479 return
|
Nenue@6
|
480 end
|
Nenue@6
|
481
|
Nenue@6
|
482 if #mod.frames.spellName[spellName] > 0 then
|
Nenue@6
|
483 print('spellName-ID relation detected:', cWord(spellName), cNum(spellID))
|
Nenue@6
|
484 for i, frame in pairs(mod.frames.spellName[spellName]) do
|
Nenue@6
|
485 if not frame.frames.spellID then
|
Nenue@6
|
486 frame.frames.spellID = {}
|
Nenue@6
|
487 end
|
Nenue@6
|
488 if not frame.frames.spellID[spellID] then
|
Nenue@6
|
489
|
Nenue@6
|
490 tinsert(mod.frames.spellID[spellID], frame)
|
Nenue@6
|
491 frame.frames.spellID[spellID] = #mod.frames.spellID[spellID]
|
Nenue@6
|
492 print(cText(' updating'), cKey(frame.timerName))
|
Nenue@6
|
493 end
|
Nenue@6
|
494 end
|
Nenue@6
|
495 mod.frames.spellName[spellName] = nil
|
Nenue@6
|
496 end
|
Nenue@6
|
497
|
Nenue@6
|
498
|
Nenue@6
|
499
|
Nenue@6
|
500 if mod.frames.spellID[spellID] then
|
Nenue@6
|
501 for i, timer_frame in pairs(mod.frames.spellID[spellID]) do
|
Nenue@6
|
502 print(cText('caught spell'), cWord(spellName), 'for', timer_frame:GetName())
|
Nenue@6
|
503 timer_frame:Event(e, unit, spellName, rank, castID, spellID)
|
Nenue@6
|
504 end
|
Nenue@6
|
505 end
|
Nenue@6
|
506 end
|
Nenue@6
|
507 mod.UNIT_SPELLCAST_CHANNEL_START = mod.UNIT_SPELLCAST_SUCCEEDED
|
Nenue@6
|
508
|
Nenue@6
|
509 --- Fire a dry event to force status updates on units with changing GUID's
|
Nenue@6
|
510 function mod:PLAYER_TARGET_CHANGED(e, unit)
|
Nenue@6
|
511 print('doing a target swap thing')
|
Nenue@6
|
512 for k, v in pairs( self.frames.unit.target) do
|
Nenue@6
|
513 print(k, v)
|
Nenue@6
|
514 v:Event(nil, 'target')
|
Nenue@6
|
515 end
|
Nenue@6
|
516 end
|
Nenue@6
|
517
|
Nenue@6
|
518 --- Same thing but for talent/spec-driven
|
Nenue@6
|
519 function mod:PLAYER_TALENT_UPDATE(e, unit)
|
Nenue@6
|
520 print('')
|
Nenue@6
|
521 print('')
|
Nenue@6
|
522 print(cText(e), T.specPage, T.specName)
|
Nenue@6
|
523
|
Nenue@6
|
524 local update_queue = {}
|
Nenue@6
|
525 for _, k in ipairs({'talentID', 'talentRow', 'specPage'}) do
|
Nenue@6
|
526 for value, frameSet in pairs(mod.frames.talentID) do
|
Nenue@6
|
527 for id, frame in ipairs(frameSet) do
|
Nenue@6
|
528 print(frame.timerID, frame.timerName)
|
Nenue@6
|
529 update_queue[frame.timerID] = frame
|
Nenue@6
|
530 end
|
Nenue@6
|
531 end
|
Nenue@6
|
532 end
|
Nenue@6
|
533
|
Nenue@6
|
534 for id, frame in pairs(update_queue) do
|
Nenue@6
|
535 print('Refreshing spec-related frames', id, frame.timerName)
|
Nenue@6
|
536 frame.disable = nil
|
Nenue@6
|
537 table.wipe(frame.debug_info)
|
Nenue@6
|
538 local res, msg = mod:EnableTimer(id, frame.dvars)
|
Nenue@6
|
539 end
|
Nenue@6
|
540
|
Nenue@6
|
541 end
|
Nenue@6
|
542
|
Nenue@6
|
543 function mod:PLAYER_EQUIPMENT_CHANGED(e, slot, hasItem)
|
Nenue@6
|
544 print(e, slot, hasItem)
|
Nenue@6
|
545 local itemCheckList
|
Nenue@6
|
546 if mod.frames.inventoryID and mod.frames.inventoryID[slot] then
|
Nenue@6
|
547 print(' Inventory Frames:')
|
Nenue@6
|
548 itemCheckList = GetInventoryItemsForSlot(slot, {}, false)
|
Nenue@6
|
549 for id, slotFrame in pairs(mod.frames.inventoryID[slot]) do
|
Nenue@6
|
550 print(' * Updating', cNum(id), cWord(slotFrame.timerName))
|
Nenue@6
|
551 local res, msg = mod:EnableTimer(slotFrame.timerID, slotFrame.dvars)
|
Nenue@6
|
552 print(' ', cBool(res), cText(msg))
|
Nenue@6
|
553 end
|
Nenue@6
|
554 end
|
Nenue@6
|
555 if itemCheckList then
|
Nenue@6
|
556 print(unpack(itemCheckList))
|
Nenue@6
|
557 end
|
Nenue@6
|
558 local itemID = GetInventoryItemID('player', slot)
|
Nenue@6
|
559 if itemID and mod.frames.itemID[itemID] then
|
Nenue@6
|
560 print(' Item ID Frames:')
|
Nenue@6
|
561 for id, itemFrame in pairs(mod.frames.itemID[itemID]) do
|
Nenue@6
|
562 print(' * Updating', cNum(id), cWord(itemFrame.timerName))
|
Nenue@6
|
563
|
Nenue@6
|
564 local res, msg = mod:EnableTimer(itemFrame.timerID, itemFrame.dvars)
|
Nenue@6
|
565 print(' ', cBool(res), cText(msg))
|
Nenue@6
|
566 end
|
Nenue@6
|
567 end
|
Nenue@6
|
568 end
|
Nenue@6
|
569 function mod:PET_BATTLE_OPENING_START ()
|
Nenue@6
|
570 for i, v in pairs(mod.timers) do
|
Nenue@6
|
571 if not v.disable then
|
Nenue@6
|
572 print('suppressing', v:GetName())
|
Nenue@6
|
573 v.disable = true
|
Nenue@6
|
574 v:Hide()
|
Nenue@6
|
575 pb_suppressed[i] = true
|
Nenue@6
|
576 end
|
Nenue@6
|
577 end
|
Nenue@6
|
578 end
|
Nenue@6
|
579 function mod:PET_BATTLE_CLOSE()
|
Nenue@6
|
580 for id, v in pairs(mod.timers) do
|
Nenue@6
|
581 if pb_suppressed[id] then
|
Nenue@6
|
582 print('restoring', v:GetName())
|
Nenue@6
|
583 mod:EnableTimer(id)
|
Nenue@6
|
584 pb_suppressed[id] = nil
|
Nenue@6
|
585 end
|
Nenue@6
|
586 end
|
Nenue@6
|
587 end |