comparison Turok/Turok.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 --- Turok
2 -- @file-author@
3 -- @project-revision@ @project-hash@
4 -- @file-revision@ @file-hash@
5 --- Defines the mechanisms for the storage and dispatch of events data.
6 --@debug@
7 --@end-debug@
8 -- GLOBALS: LibStub, Turok, TurokData, ReloadUI
9 local ADDON, Tk = ...
10 local db, L
11 local MAJOR, MINOR = "Turok", "@project-revision@"
12 local T, LGIST, _G = Tk.Addon, Tk.LGIST, _G
13
14
15 local pcall, type, ipairs, pairs, format, tinsert, match, strpad, error = pcall, type, ipairs, pairs, string.format, table.insert, string.match, string.rep, error
16 local PlaySoundFile, LoadAddOn, IsAddOnLoaded, UnitName, UnitGUID, UnitPowerMax = PlaySoundFile, LoadAddOn, IsAddOnLoaded, UnitName, UnitGUID, UnitPowerMax
17 local GetSpecializationInfo, GetSpecialization, UnitSpellHaste, GetActiveSpecGroup = GetSpecializationInfo, GetSpecialization, UnitSpellHaste, GetActiveSpecGroup
18 local UnitInfo, UnitCastingInfo, UnitChannelInfo = UnitInfo, UnitCastingInfo, UnitChannelInfo
19 local rawset, unpack, tostring, setmetatable, xpcall, unpack = rawset, unpack, tostring, setmetatable, xpcall, unpack
20
21 --@debug@
22 local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool
23 local print = function(...)
24 if _G.Devian and _G.DevianDB.workspace ~= 1 then
25 _G.print('Turok', ...)
26 end
27 end
28 local GetPrint = function(trace)
29 return trace and print or function() end
30 end
31 --@end-debug@
32
33
34
35 --- Pull saved variables and make them sane
36 function T.OnInitialize(T)
37
38 --@debug@
39 local tmpidx
40 if TurokData and TurokData.spirit and TurokData.spirit.timerindex then
41 tmpidx = TurokData.spirit.timerindex
42 end
43 TurokData = Turok.defaults
44 if tmpidx then
45 TurokData.spirit.timerindex = tmpidx
46 end
47 --@end-debug@
48 T.db = _G.TurokData
49 LibStub("LibFog-1.0"):Embed(T)
50 if T.db.queue_for_wipe then
51 T:Print("db reset flag received")
52 local index = _G.TurokData.spirit.timerindex
53 _G.TurokData = T.defaults
54 T.db = _G.TurokData
55 T.db.spirit.timerindex = index
56 end
57
58 T:RegisterChatCommand("tkr", function()
59 T.db.queue_for_wipe = true
60 ReloadUI()
61 end)
62
63 -- db hierarchy
64 for k, v in pairs(T.db) do
65 if type(v) == 'table' then
66 --@debug@
67 --print('|cFF44FF88loading stored db|r: db.|cFF44AAFF'.. k ..'|r')--@end-debug@
68 T.LinkTable(T.db, v, 'db', k)
69 end
70 end
71 setmetatable(T.db,
72 {__newindex = function (t, k, v)
73 rawset(t,k,v)
74 if type(v) == 'table' then
75 --@debug@
76 --print('|cFF44FF88creating new db|r: db.|cFF44AAFF'.. k ..'|r')--@end-debug@
77 T.LinkTable(T.db, v, 'db', k)
78 end
79 end})
80 T.L = setmetatable({}, {__call = function(t, s) return t[s] or s end})
81 end
82
83 --- Get everything rolling
84 function T:OnEnable()
85 db = TurokData
86 L = T.L
87
88 self.dispatchQueue = {}
89 self.sharedTables = {}
90 local skip = {modules = true, db = true, defaultModuleLibraries = true, orderedModules = true, prototype = true, events = true} -- local data that exists before init
91 for id, mod in pairs(self.orderedModules) do
92 mod.ID = id
93 mod.RegisterCallback = self.RegisterCallback
94 print('load', mod:GetName())
95 for k, v in pairs(mod) do
96 if not skip[k] then
97 if match(k, '^[%u_]+$') then
98 if not self.dispatchQueue[k] then
99 self.dispatchQueue[k] = {}
100 end
101 self:RegisterEvent(k, 'Dispatch')
102 self.dispatchQueue[k][id] = mod:GetName()
103 end
104 end
105 end
106 end
107
108 print('events')
109 for k, v in pairs(self.dispatchQueue) do
110 print(' ',k,'->', unpack(v))
111 end
112
113 print('shared')
114 for k, v in pairs(self.sharedTables) do
115 print(' ',k)
116 end
117 --@debug@
118 self:Print(MAJOR, MINOR, 'enabled.')--@end-debug@
119 self:RegisterChatCommand("tkl", function()
120 PlaySoundFile([[Interface\Addons\Turok\Media\sound\wilhelm.ogg]])
121 if not IsAddOnLoaded("Turok_Config") then
122 local loaded, message = LoadAddOn("Turok_Config")
123 if not loaded then
124 return T:Print("|cFFFF0000Load-on-Demand failed!|r Reason: " .. message)
125 end
126 --self.config = LibStub('AceConfigDialog-3.0'):AddToBlizOptions(MAJOR)
127 end
128 InterfaceOptionsFrame_OpenToCategory(MAJOR)
129 InterfaceOptionsFrame_OpenToCategory(MAJOR)
130 end)
131
132 self:RegisterChatCommand("unlock", function()
133 T.unlocked = (not T.unlocked) and true or nil
134 if T.unlocked then
135 self:Print('frames unlocked')
136 else
137 self:Print('frames locked')
138 end
139 for k, v in pairs(self.orderedModules) do
140 if v.UpdateLocked then
141 v:UpdateLocked()
142 end
143 end
144 end)
145
146 self:RegisterChatCommand("lsm", function(input)
147 local a1, n = self:GetArgs(input, 1,0)
148 local a2 = self:GetArgs(input, 1, n)
149 self:Print(self.LSM:Fetch(a1, a2))
150 end)
151
152 local name, realm = UnitFullName('player')
153 LGIST.RegisterCallback(self, "GroupInSpecT_InspectReady", 'GIST_InspectReady')
154 LGIST.RegisterCallback(self, "GroupInSpecT_Update", 'GIST_Update')
155 self:RegisterCharacterInfo(name, realm)
156
157 if InCombatLockdown() then
158 T.inCombat = true
159 end
160
161 T:PLAYER_SPECIALIZATION_CHANGED('PLAYER_SPECIALIZATION_CHANGED','player')
162 for order, event in ipairs(self.events) do
163 self:RegisterEvent(event, 'Dispatch')
164 end
165 end
166
167 do
168 local bucket_events = {['PLAYER_SPECIALIZATION_CHANGED'] = {}, ['PLAYER_TALENT_UPDATE'] = {}}
169 local bucket_start = {}
170 local event_queue = {}
171 local wipe, debugstack = table.wipe, debugstack
172
173 --- Passes event data to the appropriate handlers, and runs any callback returned
174 -- @param e event name
175 -- @param ... event arguments as given by WoW Lua
176 -- @return callback1 runs after its corresponding method has been dispatched to
177 -- @return callback2 runs after all dispatching has completed, in the order that dispatches occurred
178 function T:Dispatch(event, ...)
179 if not (self[event] or self.dispatchQueue[event]) then
180 return
181 end
182
183
184 if bucket_events[event] then
185 local unit = ...
186 if unit and unit ~= 'player' then
187 return
188 end
189
190 print(cText('*** Bucket Event:'), cWord(event))
191 if not bucket_start[event] then
192 self['TKBATCH_'..event] = {}
193 bucket_start[event] = GetTime()
194 T:ScheduleTimer( function()
195 print('*** Firing bucketed event ('..#bucket_events[event]..'):', event, unpack(bucket_events[event][#bucket_events[event]]))
196 T:Dispatch('TKBATCH_'..event, unpack(bucket_events[event][#bucket_events[event]]))
197 bucket_start[event] = nil
198
199 self['TKBATCH_'..event] = nil
200 end,0.1)
201 end
202 tinsert(bucket_events[event], {...})
203 return
204 else
205 event = event:gsub('^TKBATCH_', '')
206 end
207
208
209 if event ~= 'COMBAT_LOG_EVENT_UNFILTERED' then print('|cFFFF0088received|r', event, ...) end
210 local args = {event, ...}
211
212 -- if addon is listening directly
213 if self[event] then
214 print(cWord(event))
215 local reg = function() print(unpack(args)) self[event](self, unpack(args)) end
216 tinsert(event_queue, {self, event, reg})
217
218
219 -- if modules want this event directly
220 end
221 if self.dispatchQueue[event] then
222 for id, name in pairs(self.dispatchQueue[event]) do
223 local mod = self.orderedModules[id]
224 local reg = function() print(unpack(args)) mod[event](mod, unpack(args)) end
225 tinsert(event_queue, {mod, event, reg})
226 end
227 else
228 print("Received", event, "but nothing is listening to it.")
229 end
230
231 for i, entry in ipairs(event_queue) do
232 local handler, event, func = unpack(entry)
233 print('->', cWord(handler:GetName()), cBool(result), cText(message))
234 local result, message = xpcall(func, function(m) print(m, debugstack()) return debugstack() end)
235
236 if bucket_events[event] then
237 wipe(bucket_events[event])
238 bucket_events[event].history = {}
239 end
240 end
241 wipe(event_queue)
242 end
243 end
244 --- Store character data to speed up spec-specific load time
245 function T:RegisterCharacterInfo(name,realm)
246 local classLocalized, classEnglish, classID = UnitClass('player')
247
248 -- set savedvars
249 self.playerName = name
250 self.playerRealm = realm
251 self.playerClass = classEnglish
252 self.playerClassLocalized = classLocalized
253 self.playerClassID = classID
254 self.GUID = UnitGUID('player')
255 local namerealm = name..'-'..realm
256 if not db.char[namerealm] then
257 db.char[namerealm] = {
258 spellBook = {}
259 }
260 end
261 T.spellBook = db.char[namerealm].spellBook
262
263 -- push combat ratings calc
264 self:COMBAT_RATING_UPDATE()
265 end
266
267 --- Polls for specialization info until it's available
268 function T:RegisterSpecEvents()
269 local specPage = GetSpecialization()
270 if specPage then
271
272 local specID, specName, specDesc, specTexture = GetSpecializationInfo(specPage)
273 local specGroup = GetActiveSpecGroup()
274 print('Turok', cText('* Spec Info:'), GetSpecializationInfo(GetSpecialization()))
275 if T.specID and specID ~= T.specID then
276 print('pushing out old spec data')
277 T.previousSpec = {
278 specPage = T.specPage,
279 specGroup = T.specGroup,
280 specID = T.specID,
281 specName = T.specName,
282 specTexture = T.specTexture
283 }
284 elseif not T.previousSpec then
285 print('first run probably')
286 T.previousSpec = {}
287 end
288
289
290 T.specUpdate = (specID ~= T.specID)
291 T.talentsChanged = (T.specGroup ~= specGroup)
292 T.specPage = specPage
293 T.specGroup = specGroup
294 T.specID = specID
295 T.specName = specName
296 T.specTexture = specTexture
297 else
298 print('Turok', cText('* No Spec Info yet, start polling'))
299 -- repeat until we get something to update with
300 T:ScheduleTimer('RegisterSpecEvents', 1)
301 end
302
303 if T.specID and not T.__specevents then
304 T.__specevents = true
305 T:PLAYER_SPECIALIZATION_CHANGED('PLAYER_SPECIALIZATION_CHANGED','player')
306 T:RegisterEvent('PLAYER_TALENT_UPDATE', 'Dispatch')
307 T:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', 'Dispatch')
308 T:RegisterEvent('ACTIVE_TALENT_GROUP_CHANGED', 'Dispatch')
309 T:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', 'Dispatch')
310 end
311 end
312
313 --- Event handler wrapper for the Specialization getter used at load time
314 local GetSpecializationSpells, GetSpellInfo = GetSpecializationSpells, GetSpellInfo
315 function T:PLAYER_SPECIALIZATION_CHANGED(event, unit)
316 -- make sure this was fired for player
317 if (unit ~= 'player') then
318 return
319 end
320
321
322 print('Turok', '|cFF00FF00'.. event)
323 -- Set current spec values and fill out previousSpec table
324 T:RegisterSpecEvents()
325 local ot = T.previousSpec
326
327 -- Is the new spec different?
328 if T.specUpdate then
329 print(cText('Spec changed from'), cWord(ot.specName), cText('to'), cKey(T.specName))
330
331 if ot.specPage and not T.spellBook[ot.specPage] then
332 T.spellBook[ot.specPage] = {}
333 end
334
335 local spellBook = {GetSpecializationSpells(T.specPage)}
336 if not T.spellBook[T.specPage] then
337 T.spellBook[T.specPage] = {}
338 for i = 1, #spellBook, 2 do
339 T.spellBook[T.specPage][spellBook[i]] = GetSpellInfo(spellBook[i])
340 if (not ot.specPage) or (T.spellBook[ot.specPage] and not T.spellBook[ot.specPage][spellBook[i]]) then
341 print(cText('activating for spell'), T.spellBook[T.specPage][spellBook[i]])
342 end
343 end
344 end
345
346
347
348 -- list changed spells for use by spell posession checks
349 local diff = {
350 gained = {},
351 lost = {}
352 }
353
354 --- Check against current for removed spells
355 if T.spellBook[ot.specPage] then
356 for id, spellInfo in pairs(T.spellBook[ot.specPage]) do
357 if not T.spellBook[ot.specPage] then
358 tinsert(diff.lost, spellInfo)
359 print('lost', spellInfo.spellName)
360 else
361 print('keep', spellInfo.spellName)
362 end
363 end
364 end
365
366 T.spellBook.change = diff
367 end
368 end
369
370 local GetInventoryItemID, GetItemSpell, GetSpellInfo, GetItemInfo = GetInventoryItemID, GetItemSpell, GetSpellInfo, GetItemInfo
371 function T:PLAYER_EQUIPMENT_CHANGED(event, slot, hasItem)
372 print('Equip slot #', slot, ' has?', hasItem)
373 if hasItem then
374 local itemID = GetInventoryItemID('player', slot)
375 print('itemID?', itemID)
376 local spellName = GetItemSpell(itemID)
377 print('spell?', spellName)
378 local _, spellID
379 if spellName then
380 _, _, _, _, _, _, spellID = GetSpellInfo(spellName)
381 end
382
383 local name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture, vendorPrice = GetItemInfo(itemID)
384 T.equipped[slot] = {
385 itemID = itemID,
386 spellName = spellName,
387 spellID = spellID,
388 name = name,
389 link = link,
390 equipSlot = equipSlot,
391 texture = texture,
392 }
393 print('equipped', name)
394
395 else
396 self.equipped[slot] = nil
397 end
398 end
399
400 local GetPowerRegen, UnitPowerType = GetPowerRegen, UnitPowerType
401 function T:COMBAT_RATING_UPDATE(t,e)
402 --@debug@
403 print('|cFF00FFFFCOMBAT_RATING_UPDATE')--@end-debug@
404 self.haste = UnitSpellHaste('player')
405 self.powerRegen = GetPowerRegen()
406 self.powerType = UnitPowerType('player')
407 self.castTimeMod = 1+ self.haste/100
408 self.GCD = 1.5 * self.castTimeMod
409
410 L.haste = format('%.2f', self.haste)
411 L.focusregen = format('%.2f', self.powerRegen)
412 L.castingmod = format('%.2f', self.castTimeMod)
413 end
414
415 function T:UNIT_SPELLCAST_INTERRUPTED(e, unit, spellName, rank, target, castID)
416 if not T.isEventUnit[unit] then
417 return
418 end
419 T.spellevent[unit] = {unit, spellName, rank, target, castID, nil }
420 end
421
422 function T:UNIT_SPELLCAST_SENT(e,unit, spellName, rank, target, castID)
423 if not T.isEventUnit[unit] then
424 return
425 end
426 T.unit[unit].spellEventString = e
427 T.unit[unit].spellevent = {unit, spellName, rank, target, castID}
428 end
429
430 function T:UNIT_SPELLCAST (e, unit, spellName, rank, castID, spellID)
431 if not T.isEventUnit[unit] then
432 return
433 end
434 --name, subText, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible
435 local q = {UnitCastingInfo(unit)}
436 T.unit[unit].casting = q[1] and q or false
437 T.unit[unit].spellEventString = e
438 T.unit[unit].spellevent = {unit, spellName, rank, nil,castID, spellID }
439 print(e, unit)
440 end
441
442 function T:UNIT_CHANNEL(e, unit, spellName, rank, castID, spellID)
443 if not T.isEventUnit[unit] then
444 return
445 end
446 --name, subText, text, texture, startTime, endTime, isTradeSkill, notInterruptible
447 local q = {UnitChannelInfo(unit) }
448 T.unit[unit].channeling = q[1] and q or false
449 T.unit[unit].spellEventString = e
450 T.unit[unit].spellevent = {unit, spellName, rank, nil, castID, spellID }
451 print(e, unit)
452 end
453
454 T.UNIT_SPELLCAST_START = T.UNIT_SPELLCAST
455 T.UNIT_SPELLCAST_STOP = T.UNIT_SPELLCAST
456 T.UNIT_SPELLCAST_DELAYED = T.UNIT_SPELLCAST
457 T.UNIT_SPELLCAST_INTERRUPTED = T.UNIT_SPELLCAST
458 T.UNIT_SPELLCAST_FAILED = T.UNIT_SPELLCAST
459 T.UNIT_SPELLCAST_SUCCEEDED = T.UNIT_SPELLCAST
460 T.UNIT_SPELLCAST_CHANNEL_START = T.UNIT_CHANNEL
461 T.UNIT_SPELLCAST_CHANNEL_UPDATE= T.UNIT_CHANNEL
462 T.UNIT_SPELLCAST_CHANNEL_STOP= T.UNIT_CHANNEL
463
464 local UnitExists, GetRealmName, UnitClassification, UnitClass, UnitIsFriend, UnitIsEnemy, UnitIsFeignDeath
465 = UnitExists, GetRealmName, UnitClassification, UnitClass, UnitIsFriend, UnitIsEnemy, UnitIsFeignDeath
466 function T:UnitChanged(e, unit)
467 local u = T.unit[unit]
468 local exists = UnitExists(unit)
469 local realm
470 _G.print('Update', cText(' '..unit..' change:'), cText(unit), cText(exists and UnitName(unit)))
471
472 u.exists = exists
473 u.name, realm = UnitName(unit)
474 u.realm = realm or GetRealmName()
475 u.classification = UnitClassification(unit)
476 u.class = UnitClass(unit)
477 u.isFriendly = UnitIsFriend('player', unit)
478 u.isEnemy = UnitIsEnemy('player', unit)
479 u.isFeign = UnitIsFeignDeath(unit)
480 u.isNeutral = not(u.isHostile or u.isFriendly)
481
482 local castinfo, channelinfo = {UnitCastingInfo(unit)}, {UnitChannelInfo(unit)}
483 u.casting = (u.exists and castinfo[1]) and castinfo or false
484 u.channeling = (u.exists and channelinfo[1]) and channelinfo or false
485 u.isCasting = (u.casting or u.channeling) and true or false
486
487
488 for k,v in pairs(T.unit[unit]) do
489 _G.print('Update', cText(' -'), cText(k),'->', cText(v))
490 end
491 end
492 function T:PLAYER_TARGET_CHANGED(e)
493 T:UnitChanged(e, 'target')
494 end
495 function T:PLAYER_FOCUS_CHANGED(e)
496 T:UnitChanged(e, 'focus')
497 end
498 function T:UNIT_PET(e, unit,...)
499 if unit == 'player' then
500 print(e, unit, ...)
501 T:UnitChanged(e, 'pet')
502 end
503 end
504
505 local Turok_OnCombat = function(inCombat)
506 print(cText('* CombatToggle:'), cBool(inCombat))
507 PlaySoundFile(db['battle_noise'.. (inCombat and '_start' or '_end')])
508
509 for _, region in pairs(Tk.LibFog.animate_regions) do
510 if region.combatFade then
511 print(' |cFFFFFF00+|r', region:GetName())
512 region:UpdateAlpha(inCombat)
513 else
514 print(' |cFFFF4400-|r', region:GetName())
515 end
516 end
517 end
518
519 --- InCombatLockdown() isn't updated immediately, so we have to assume
520 function T:PLAYER_REGEN_DISABLED(e,...)
521 T.inCombat = true
522 Turok_OnCombat(true)
523 end
524 function T:PLAYER_REGEN_ENABLED(e,...)
525 T.inCombat = nil
526 Turok_OnCombat(false)
527 end
528
529 -- GIST datas
530 function T:GIST_InspectReady (event, guid, unit)
531 print('GIST barf', guid, unit)
532 end
533
534 function T:GIST_Update(event, guid, unit, info)
535
536 if info.class_id and info.global_spec_id and info.guid and info.lku then
537 --_G.print('GIST', 'Update', unit)
538 --_G.print('GIST',' class:', info.class_id, 'specid:', info.global_spec_id, 'guid:', info.guid)
539
540 self.units[info.guid] = info
541 self.unitsBySlot[info.lku] = info
542 end
543 end
544
545 -- todo: re-locate these
546
547 T.PLAY_MOVIE = function (e, id)
548 MovieFrame:Hide()
549 T:Print('skipped a shitty movie', e, id)
550 end
551 T.CINEMATIC_START = function(...)
552 CinematicFrame_CancelCinematic()
553 T:Print('skipped a shitty cinematic', ...)
554 end