comparison Turok/Modules/Combat/CombatLog.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 --- Combat
2 -- @file-author@
3 -- @project-revision@ @project-hash@
4 -- @file-revision@ @file-hash@
5 -- Created: 1/11/2016 4:27 PM
6 --- Data collector for API Combat Log Event
7 local T, _G = Turok, _G
8 local mod = T:NewModule("Combat")
9 local pairs, ipairs, select, concat, format, tinsert, wipe = pairs, ipairs, select, table.concat, string.format, tinsert, table.wipe
10 local GetSpellTexture, CreateFrame, GetTime, unpack, floor = GetSpellTexture, CreateFrame, GetTime, unpack, floor
11 local db
12 local cText, cNum, cKey, cWord, cPink, cType, cBool = cText, cNum, cKey, cWord, cPink, cType, cBool
13 local print = function(...)
14 if _G.Devian and _G.DevianDB.workspace ~= 1 then
15 _G.print('CombatText', ...)
16 end
17 end
18
19
20 --- performance constants
21 local SCT_NAME = 'TurokSCT%s'
22 local SCT_TEMPLATE = 'TurokSCTAnchorTemplate'
23 local SCT_PREGAME = 5
24 local SCT_MESSAGE_TEMPLATE = 'TurokCombatMessageTemplate'
25 local SCT_MESSAGE_NAME = 'CombatString%d'
26 local LOG_TEMPLATE = 'TurokCombatLogAnchorTemplate'
27
28 --- UX structures
29 T.defaults.CombatText = {
30 width = 400, height = 800,
31 parent = 'UIParent',
32 Outgoing = {
33 anchor = 'RIGHT', anchorTo = 'RIGHT',
34 x = -400, y = -200,
35 },
36 Incoming = {
37 anchor = 'LEFT', anchorTo = 'LEFT',parent = 'UIParent',
38 x = 400, y = -200,
39 },
40 DoTTracker = {
41 anchor = 'BOTTOMLEFT', anchorTo = 'BOTTOM', parent = 'UIParent',
42 x = 80, y = 400,
43 },
44 defaultFont = {"Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Regular.ttf", 18, 'OUTLINE'},
45 defaultAnimation = 'slide',
46
47 textFonts = {
48 font1 = {"Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Regular.ttf" , 30, 'OUTLINE'},
49 font2 = {"Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Regular.ttf" , 24, 'OUTLINE'},
50 font3 = {"Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Bold.ttf" , 20, 'OUTLINE'},
51 },
52
53 --- [(string) combatEvent] = {[1] = (string) format [, [2] = fontKey]}
54 --- Substitution values
55 -- %d [1] amount [2] overkill [3] absorbed [4] blocked
56 -- %s [5] spell [6] caster [7] school
57 textFormat = {
58 ['SWING_DAMAGE'] = {'%d'},
59 ['SPELL_DAMAGE'] = {'%d'},
60 ['RANGE_DAMAGE'] = {'%d'},
61 Incoming = {
62 ['SWING_DAMAGE'] = {'-%d'},
63 ['SPELL_DAMAGE'] = {'-%d (%s)'},
64 ['RANGE_DAMAGE'] = {'-%d'},
65 },
66 },
67 textModifiers ={
68 critical = {'%s!', 'pop'},
69 overKill = {'%s |cFF0088FFKilling Blow!|r', 'slide'},
70 multistrike = {'<%s>', 'lateralSlide', 'font3'},
71 absorbed = {'%s (%d)', 'slide'},
72 blocked = {'%s {%d}', 'slide'},
73 pet = {'(%s)', 'lateralSlide'},
74 grouped = {'%s (%d hit)', 'slide'},
75 },
76 --- [AnimationGroup key] = {[XML attrib] = [value], d[x/y] = (number) 0-1 }
77 -- d[x/y] indicates the proportional relevance of each FontString dimension when frames are displaced by a new event
78 -- x/y indicates the ranges of movement made by an animation, and are also considered when calculating displacement
79 animation = {
80 slide = {
81 x = 0, dx = 0,
82 y = 300, dy = 1,
83 duration = 2
84 },
85 lateralSlide = {
86 x = 300, dx = 1,
87 y = 0, dy = 0,
88 duration = 2
89 },
90 pop = {
91 toScale = 1.4,
92 fromScale = 0.1,
93 duration = 0.14,
94 dx = 0, dy = 1,
95 },
96 fadeOut = {change = -1, duration = 0.5},
97 },
98 }
99 --- [1] text wrapper [2] animation type
100 local dotEvents = {
101 SPELL_AURA_APPLIED = true,
102 SPELL_PERIODIC_DAMAGE = true,
103 SPELL_AURA_REMOVED = true,
104 SPELL_AURA_REFRESHED = true,
105 }
106 local petGUID = {}
107
108 ------------- data structures
109 local defaultAnimation, defaultFont
110 local criticalModifier, absorbedModifier, blockedModifier, overKillModifier, multistrikeModifier, groupedModifier
111 local criticalAnimation, absorbedAnimation, blockedAnimation, overKillAnimation, multistrikeAnimation, groupedAnimation
112 local criticalFont, absorbedFont, blockedFont, overKillFont,multistrikeFont, groupedFont
113 local textFonts = {}
114 local textFormat = {}
115 local animation = {}
116 local spellCache = {}
117 local DoTFrames = {}
118
119 local dotTrackingEvents = {
120 ['SPELL_AURA_APPLIED'] = true,
121 ['SPELL_AURA_REMOVED'] = true,
122 ['SPELL_AURA_REFRESHED'] = true,
123 }
124
125 --- multi-hit events data
126 -- [(string) localized name] = {
127 -- [1] = (bool) controlled channel
128 -- [2] = (number) minimum time to wait for next damage tick
129 -- [3] = (number) maximum time to log grouped spell hits
130 -- [4] = (string) combatEvent full string
131 -- [5] = (string) combatEvent short prefix (as opposed to SPELL_PERIODIC)
132 -- [6] = (string) combatEvent short suffix (as opposed to AURA_APPLIED)
133 -- }
134 -- tailing fields are set to reduce the number of arguments passed around
135 local groupedSpells = {
136 global = {false, 1, 'SPELL_PERIODIC_DAMAGE', 'SPELL', 'DAMAGE'},
137 ['Crimson Tempest'] = {false, 0.3, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- shockwave dot
138 ['Mind Sear'] = {false, 1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- scanning aoe
139 ['Searing Insanity'] = {false, 1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- scanning aoe
140 ['Ice Nova'] = {false, 0.4, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- shockwave aoe
141 ['Blizzard'] = {false, 1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- scanning aoe
142 ['Frozen Orb'] = {false, 1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'},
143 ['Ice Bomb'] = {false, 0.4, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- shockwave aoe
144 ['Comet Storm'] = {false, 2.5, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- staggered multi-hit
145 ['Barrage'] = {false, 1.1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- projectile vommit
146 ['Glaive Toss'] = {false, 3, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- path projectile,
147 ['Doom Nova'] = {false, 0.4, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}
148 }
149
150 local dotSpellIndex = {
151 ['Shadow Word: Pain'] = {'HARMFUL|PLAYER'},
152 ['Vampiric Touch'] = {'HARMFUL|PLAYER'}
153 }
154
155 local offhandSpellIndex = {
156 ['Execute'] = {'Execute Off-Hand'},
157 ['Mutilate'] = {'Mutilate Off-Hand'},
158 ['Stormstrike'] = {'Stormstrike Off-Hand'},
159 }
160
161 --- stored as a list of field representations to be concatenated together within a loadstring def
162
163
164
165 --- Tracking tables
166 local groupedQueue = {}
167 local groupedEvents = {}
168 local offhandQueue = {}
169 local sct_format = {}
170
171
172 local function GetGUIDInfo(guid)
173 local unitType, flags1, flags2 = guid:match('(%a+)\-(%x+)\-(%x+)')
174 return concat({unitType, flags1, flags2},'|r::|cFF0088FF')..'|r'
175 end
176
177 local SpellSchoolColors = {
178 [1] = {255, 255,0}, -- physical
179 [2] = {255, 230, 128}, -- holy
180 [3] = {255, 255, 128}, -- holy+phys
181 [4] = {255, 128, 0}, -- fire
182 [8] = {77, 255, 77}, -- nature
183 [16] = {128, 255, 255}, -- frost
184 [20] = {255, 192, 128}, -- frostfire
185 [32] = {128, 128, 255}, -- shadow
186 [48] = {128, 192, 255}, -- shadow+frost
187 [64] = {255, 128, 255}, -- arcane,
188 [72] = {255, 128, 128}, -- spellstorm,
189 }
190
191 local h = '|cFF%02X%02X%02X'
192 local SpellSchoolColor = function (flags, spellName)
193 local i = 64
194 local rA, gA, bA
195 if SpellSchoolColors[flags] then
196 print(flags, 'match')
197 print(format('%02X%02X%02X', unpack(SpellSchoolColors[flags])))
198 return format(h, unpack(SpellSchoolColors[flags]))
199 end
200
201 repeat
202 local rB, gB, bB = unpack(SpellSchoolColors[i])
203 if i <= flags then
204 if not rA then
205 rA = rB
206 gA = gB
207 bA = bB
208 else
209 rA = (rA+rB)/2
210 gA = (gA+gB)/2
211 bA = (bA+bB)/2
212 end
213 print('test:', cWord(i), '<=', cKey(flags), '=', (i <= flags), cPink(rA), cNum(gA), cText(bA))
214 flags = flags - i
215 else
216 print(i, 'skip')
217 end
218 i = i/2
219 until (i == 1)
220 SpellSchoolColors[flags] = {rA, gA, bA }
221 --print(string.format('%02X%02X%02X', unpack(SpellSchoolColors[flags])))
222 return format(h, unpack(SpellSchoolColors[flags]))
223 end
224 local myGUID
225
226 mod.NewCombatMessage = function(frame, index)
227 local ct = CreateFrame('Frame', SCT_MESSAGE_NAME:format(frame.lineID), frame, SCT_MESSAGE_TEMPLATE)
228 index = index and 'active' or 'expired'
229 frame.lineID = frame.lineID + 1
230 frame.active[#frame.active+1] = ct
231 ct.index = #frame.active
232 ct.x = 0
233 ct.y = 0
234 ct.point = 'BOTTOMLEFT'
235 return ct
236 end
237
238 --- frame interaction logic
239 mod.AddCombatMessage = function(frame, text, icon, animationType, fontKey)
240 local line
241 print(fontKey)
242
243 local expired = frame.expired
244 local active = frame.active
245 local a = 1
246 local shiftY, shiftX
247 local lastFrame
248 --- If animation has overlap delta values, find the last active frame of that animation type and check for overlaps.
249 --- Frames are considered overlapping when the last member's ((height - distance traveled) * delta) is over 0.
250 --- This assumes the same string height for the upcoming frame since wordwrap isn't enabled.
251 print(animationType)
252 if animation[animationType].dx or animation[animationType].dy then
253 print('animation has displacement')
254 if frame.last then
255 lastFrame = frame.last
256 local dp = lastFrame[animationType]:GetProgress()
257 if animation[animationType].dx then
258 local dx = dp * animation[animationType].x
259 shiftX = (lastFrame.string:GetStringWidth() - dx) * animation[animationType].dx
260 end
261 if animation[animationType].dy then
262 local dy = dp * animation[animationType].y
263 shiftY = (lastFrame.string:GetStringHeight() - dy) * animation[animationType].dy
264 print(' ', 'h=', floor(lastFrame.string:GetStringHeight()), 'dY=', dy, 'offsetY=', shiftY)
265 end
266 print(cWord('lastFrame hit:'), lastFrame and lastFrame:GetName(), cNum(shiftX), cNum(shiftY))
267 end
268 end
269
270 -- find a usable frame
271 local currentFrame
272 for i, ct in ipairs(frame.active) do
273 if not currentFrame then
274 if ct.discard then
275 ct.discard= nil
276 currentFrame = ct
277 end
278 end
279
280 if lastFrame and ct.animationType == animationType and not ct.discard then
281 --print('lastFrame defined, check for overlap')
282 if shiftY > 0 then
283 print(cWord(' * vertical shift'), cNum('+'..floor(shiftY)))
284 ct.y = ct.y + shiftY
285 end
286 if shiftX > 0 then
287 print(cWord(' * horizontal shift'), cNum('+'..floor(shiftX)))
288 ct.x = ct.x + shiftX
289 end
290 ct:SetPoint(ct.point, frame, ct.point, ct.x, ct.y)
291 end
292 end
293 -- if no expired frames became available, make a new one (should max at 20 or so if groupings are right)
294 if not currentFrame then
295 currentFrame = mod.NewCombatMessage(frame)
296 print(cNum(' creating new string object for the heap'))
297 end
298
299 print(cText(' * Starting'), cPink(animationType), 'on', cKey(currentFrame:GetName()), ' ['..cNum(currentFrame.index)..']')
300
301 if icon then
302 currentFrame.icon:Show()
303 currentFrame.icon:SetTexture(icon)
304 else
305 currentFrame.icon:Hide()
306 end
307 if fontKey then
308 local newFont = fontKey and textFonts[fontKey] or defaultFont
309
310 local path, size, flags = currentFrame.string:GetFont()
311 path = newFont[1] or path
312 size = newFont[2] or size
313 flags = newFont[3] or flags
314 print(cText('font ('..cWord(fontKey)..'):'), path, size, flags)
315 local result = currentFrame.string:SetFont(path, size, flags)
316 print(cNum(' result:'), cNum(result), currentFrame.string:GetFont())
317 --currentFrame.fontKey = fontKey
318 end
319
320 currentFrame.animationType = animationType
321 currentFrame.string:SetText(text)
322 local cHeight = currentFrame.string:GetStringHeight()
323 currentFrame:SetSize(currentFrame.string:GetStringWidth(), cHeight)
324 currentFrame.icon:SetSize(cHeight, cHeight)
325 currentFrame.y = 0
326 currentFrame.x = 0
327 currentFrame:SetPoint(currentFrame.point, frame, currentFrame.point, currentFrame.x, currentFrame.y)
328 currentFrame[animationType]:Play()
329 frame.last = currentFrame
330 end
331
332 local GetTextFormatFunc = function(amount, overKill, absorbed, blocked, multistrike, spellName, sourceName, destName)
333 local sub_text = {
334 ['%d'] = amount,
335 ['%o'] = overKill,
336 ['%a'] = absorbed,
337 ['%b'] = blocked,
338 ['%m'] = multistrike,
339 ['%s'] = spellName,
340 ['%n'] = sourceName,
341 ['%t'] = destName,
342 }
343 local func = function(token)
344 print(cPink('gsub run:'), token)
345 return sub_text[token]
346 end
347 return func
348 end
349
350 --- builds CT messages from combat log event data
351 -- separated from frame interaction for auxiliary events such as combat/loot/etc
352 local CreateDamageText = function(frame, timestamp, combatEvent, sourceName, destName, spellID, spellName, effectSchool, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike, ticks)
353 if combatEvent:match('^SWING') then
354 spellID = 1
355 spellName = 'Attack'
356 elseif combatEvent:match('^RANGE') then
357 spellID = 2
358 spellName = 'Auto Shot'
359 end
360 if not combatEvent:match('DAMAGE') then
361 return
362 end
363
364
365 local fontKey = 'font1'
366 local icon = GetSpellTexture(spellID)
367 local animationType = defaultAnimation
368 local text = amount
369 if textFormat[combatEvent] then
370 local tString, fontKey = unpack(textFormat[combatEvent])
371 if amount > 1000000 then
372 amount = (floor(amount/100000)/10) ..'M'
373 elseif amount > 1000 then
374 amount = (floor(amount/100)/10) ..'k'
375 end
376
377 text = tString:gsub('%%[doabsnt]', GetTextFormatFunc(amount, overKill, absorbed, blocked, multistrike, spellName, sourceName, destName))
378 print("** font override:", '"'..cText(tString)..'",', cPink(font), cNum(size), cWord(outline))
379 end
380
381 print('** getting color data', cText(spellName))
382 if type(effectSchool) == 'number' then
383 text = SpellSchoolColor(effectSchool) ..text..'|r'
384 end
385
386 if overKill > 0 then
387 text = overKillModifier:format(text, overKill)
388 animationType = overKillAnimation
389 fontKey = overKillFont or fontKey
390 end
391 if critical then
392 text = criticalModifier:format(text)
393 animationType = criticalAnimation
394 fontKey = criticalFont or fontKey
395 end
396 if absorbed then
397 text = absorbedModifier:format(text, absorbed)
398 animationType = absorbedAnimation
399 fontKey = absorbedFont or fontKey
400 end
401 if blocked then
402 text = blockedModifier:format(text, blocked)
403 animationType = blockedAnimation
404 fontKey = blockedFont or fontKey
405 end
406 if multistrike then
407 text = multistrikeModifier:format(text, multistrike)
408 animationType = multistrikeAnimation
409 fontKey = multistrikeFont or fontKey
410 end
411
412 print(ticks)
413 if ticks then
414 text = groupedModifier:format(text, ticks)
415 animationType = groupedAnimation
416 fontKey = groupedFont or fontKey
417 end
418
419
420 print('** sending format to SCT:', text, icon, animationType, fontKey)
421
422
423 mod.AddCombatMessage(frame, text .. '|r', icon, animationType, fontKey)
424 end
425
426 local CT_ShowConsolidated = function()
427 for spellName, queuedSpell in pairs(groupedQueue) do
428 local isChannel, minDelay, combatEvent, sourceName, destName, spellID, school, SCT, timestamp = unpack(queuedSpell)
429 for i, v in ipairs(queuedSpell) do
430 print(' ', i, '=', v)
431 end
432
433 print(spellName, 'vars:', spellID, spellName, school, SCT, timestamp)
434 if groupedEvents[spellName] and #groupedEvents[spellName] ~= 0 then
435 local amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, multistrike, hit = 0, -1, 0, 0, 0, 0, 0, 0, 0, 0
436 for i, line in ipairs(groupedEvents[spellName]) do
437 -- extra strike?
438 --{amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, multistrike}
439 local amount_n, overKill_n, resisted_n, blocked_n, absorbed_n, critical_n, glancing_n, crushing_n, multi_n, sourceGUID, destGUID, sourceName, destName = unpack (line)
440
441 amount = amount + amount_n
442 if overKill_n > 0 then overKill = overKill + overKill_n end
443 if blocked_n then blocked = blocked + line[4] end
444 if absorbed_n then absorbed = absorbed + line[5] end
445 if critical_n then critical = critical + 1 end
446 if multi_n then multistrike = multistrike + 1 end
447
448 hit = hit + 1
449 end
450 if overKill == -1 then
451 overKill = overKill + 1
452 end
453 wipe(groupedEvents[spellName])
454 groupedQueue[spellName] = nil
455 print(' expelling', spellName, cText('A:'), cNum(amount), cText('O:'), cNum(overKill), cText('Ticks:'), cNum(hit), cText('Crits:'), cNum(critical), cText(school))
456 print(SCT, timestamp, combatEvent, sourceName, destName, spellID, spellName, school, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, multistrike, hit)
457 CreateDamageText(SCT, timestamp, combatEvent, sourceName, destName, spellID, spellName, school, amount, -1, nil, nil, nil, false, glancing, crushing, false, multistrike, hit)
458 end
459 end
460 end
461
462 local CT_ConsolidateText = function (self, timestamp, sourceGUID, destGUID, sourceName, destName, spellID, spellName, school, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike)
463 local archive = groupedSpells[spellName] and groupedSpells[spellName] or groupedSpells.global
464 local isChannel, minDelay, combatEvent = unpack(archive)
465 if not groupedEvents[spellName] then
466 groupedEvents[spellName] = {}
467 end
468
469 if #groupedEvents[spellName] == 0 then
470 groupedQueue[spellName] = {isChannel, minDelay, combatEvent, sourceName, destName, spellID, school, self, timestamp}
471 T:ScheduleTimer(CT_ShowConsolidated, minDelay)
472 print(' starting archive for', select(7, unpack(archive)))
473 else
474 print(' recording into archive', cText(spellName))
475 end
476 tinsert(groupedEvents[spellName], {amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, multistrike, sourceGUID, destGUID, sourceName, destName, sourceName, destName,})
477 end
478
479 local CT_OnCast = function(self, event, unit, spellName, lineID, spellID)
480 if unit ~= 'player' and unit ~= 'pet' then
481 return
482 end
483
484 if groupedSpells[spellName] then
485 print(cText('** Spell casting info received'))
486 local isChannel, delay = unpack(groupedSpells[spellName])
487 if isChannel and event == 'CHANNEL_STOP' and groupedEvents[spellName] then
488 T:ScheduleTimer(CT_ShowConsolidated, delay)
489 else
490 if not groupedEvents[spellName] then
491 groupedEvents[spellName] = {}
492 end
493 end
494 end
495 end
496
497 local CT_Unlock = function(str)
498 for i, CT in pairs(mod.CombatTextFrames) do
499 local frame = CT.frame
500 frame.configMode = (frame.configMode == nil) and true or nil
501 frame:RegisterForDrag(frame.configMode and 'LeftButton' or nil)
502 frame:EnableMouse(frame.configMode and true or false)
503 print(i, frame.configMode and 'ON' or 'OFF')
504 for _, reg in ipairs(frame.configRegions) do
505 if frame.configMode then
506 reg:Show()
507 else
508 reg:Hide()
509 end
510 end
511
512 if frame.configMode then
513 CT.configTimer = T:ScheduleRepeatingTimer(function()
514 print(i, 'config tick')
515 for i, s in ipairs(CT.sample) do
516 CT.OnEvent(frame, unpack(s))
517 end
518 end, 2)
519 else
520 print(CT.configTimer)
521 T:CancelTimer(CT.configTimer)
522 end
523
524 end
525 end
526
527 --- check for sectors
528 local queue = {}
529 mod.OnDamage = function(self, event, ...)
530 local isVisible
531
532 local timestamp, combatEvent = ...
533 print(cText('* CT'), cKey(combatEvent))
534 if combatEvent == 'UNIT_DIED' then
535 return
536 end
537 local sourceGUID, sourceName, sourceFlags, _, destGUID, destName, destFlags, _, spellID, spellName, spellSchool = select(4, ...)
538 print(' from', cPink(sourceGUID), 'spell', cNum(spellID), cText(spellName), '->', cKey(destGUID))
539
540 -- SWING starts at arg 10, SPELL/RANGE start at arg 13, ENVIRONMENTAL starts at arg 8
541 local offset = 15
542 print(combatEvent:sub(0,3))
543 if combatEvent:sub(0,3) == 'SWI' then
544 offset = 10
545 elseif combatEvent:sub(0,3) == 'ENV' then
546 offset = 8
547 end
548 local amount, overKill, effectSchool, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike = select(offset, ...)
549
550 print(' dmg', amount, overKill)
551
552 local sc = SpellSchoolColors[effectSchool]
553 if groupedSpells[spellName] then
554 print('* ', cText(spellName), 'to consolidator')
555 CT_ConsolidateText(self, timestamp, sourceGUID, destGUID, sourceName, destName, spellID, spellName, effectSchool, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike)
556 return
557 end
558
559 print('displaying on', cWord(self:GetName()))
560 CreateDamageText(self, timestamp, combatEvent, sourceName, destName, spellID, spellName, effectSchool, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike)
561 end
562
563 mod.maxDotFrame = 1
564 mod.OnDotEvent = function (self, event, timestamp, combatEvent, ...)
565 print(cWord('DOT'), combatEvent)
566 local sourceGUID, sourceName, sourceFlags, _, destGUID, destName, destFlags, destExtraFlags, spellID, spellName, castSchool, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike = select(2, ...)
567 print(cText('dot from'), cWord(sourceGUID), 'to', cKey(destGUID))
568 if sourceGUID == T.GUID then
569 local p = mod.PeriodicTable
570 p[destGUID] = p[destGUID] or {}
571 local unit = p[destGUID]
572 if not p[spellID] then
573 if not p.frames[#p.frames] then
574 unit[spellID] = CreateFrame('Frame', 'DotBar'..mod.maxDotFrame, p, 'TkDotBarTemplate')
575 mod.maxDotFrame = mod.maxDotFrame + 1
576 unit[spellID].dotID = mod.maxDotFrame
577
578 print(' create new frame ['..cKey(unit[spellID]:GetID(), '] for'), cWord(spellName), cKey(destGUID))
579 else
580 unit[spellID] = p.frames[#p.frames]
581 p.frames[#p.frames] = nil -- remove that entry
582 print(' recycling frame ['..cKey(unit[spellID].dotID, '] for'), cWord(spellName), cKey(destGUID))
583 end
584
585 unit[spellID]:Show()
586 end
587 local dot = unit[spellID]
588 local time = GetTime()
589 end
590 end
591
592
593
594
595 function mod:OnInitialize()
596 print('This is a thing.')
597 self.UNIT_SPELLCAST_SUCCEEDED = CT_OnCast
598 self.UNIT_SPELLCAST_CHANNEL_START = CT_OnCast
599 self.UNIT_SPELLCAST_CHANNEL_STOP = CT_OnCast
600 end
601
602 function mod:OnInitialize()
603 mod.db = TurokData.CombatText
604 db = TurokData.CombatText
605 myGUID = T.GUID
606 mod.PeriodicTable = mod.PeriodicTable or CreateFrame('Frame', 'TurokPeriodicFrame', UIParent)
607 mod.PeriodicTable.frames = {}
608
609 local m = mod.db.textModifiers
610 --- These values are going to be looked up a lot, so cache as close as possible
611 criticalModifier = m.critical[1] or '%s CRIT'
612 criticalAnimation = m.critical[2] or 'slide'
613 criticalFont = m.critical[3]
614
615 absorbedModifier = m.absorbed[1] or '%s ABS'
616 absorbedAnimation = m.absorbed[2] or 'slide'
617 absorbedFont = m.absorbed[3]
618
619 blockedModifier = m.blocked[1] or '%s BLK'
620 blockedAnimation = m.blocked[2] or 'slide'
621 blockedFont = m.blocked[3]
622
623 overKillModifier = m.overKill[1] or '%s KILL'
624 overKillAnimation = m.overKill[2] or 'slide'
625 overKillFont = m.overKill[3]
626
627 multistrikeModifier = m.multistrike[1] or '%s MS'
628 multistrikeAnimation = m.multistrike[2] or 'slide'
629 multistrikeFont = m.multistrike[3]
630
631 groupedModifier = m.grouped[1] or '%s'
632 groupedAnimation = m.grouped[2] or 'slide'
633 groupedFont = m.grouped[3]
634
635 --- Same as above, but for specific table values, key is determined by the combat event
636 defaultAnimation = mod.db.defaultAnimation
637 defaultFont = mod.db.defaultFont
638 for k,v in pairs(mod.db.textFormat) do
639 textFormat[k] = {v[1], v[2]}
640 print('imported textFormat.'..k, cText(textFormat[k][1]), cNum(textFormat[k][2]))
641 end
642 for k,v in pairs(mod.db.textFonts) do
643 textFonts[k] = {v[1] or defaultFont[1], v[2] or defaultFont[2], v[3] or defaultFont[3]}
644 print('imported font.'..k, cText(textFonts[k][1]), cNum(textFonts[k][2]), cWord(textFonts[k][3]))
645 end
646
647 for k,v in pairs(mod.db.animation) do
648 animation[k] = {}
649 animation[k].x = v.x
650 animation[k].y = v.y
651 animation[k].dx = v.dx
652 animation[k].dy = v.dy
653 animation[k].fromScale = v.fromScale
654 animation[k].toScale = v.toScale
655 animation[k].deviation = v.deviation
656 animation[k].change = v.change
657 animation[k].fromAlpha = v.fromAlpha
658 animation[k].toAlpha = v.toAlpha
659 animation[k].duration = v.duration
660 end
661 end
662
663 function mod:OnEnable()
664 T:RegisterChatCommand('tkc', CT_Unlock)
665
666 --- Populate CT frames
667 for name, CT in pairs(mod.CombatTextFrames) do
668 print('create CT', name)
669 -- make frame
670 CT.frame = CT.frame or CreateFrame('Frame', SCT_NAME:format(name), UIParent, SCT_TEMPLATE)
671
672 -- local vars
673 local db = db[name] or db
674 local frame = CT.frame
675
676 -- script defs
677 frame.IsFrameEvent = CT.trigger
678 frame.name = name
679 frame.lineID = 0
680 frame.expired = {}
681 frame.active = {}
682
683 -- frame defs
684 frame:SetPoint(db.anchor, db.parent, db.anchorTo, db.x, db.y)
685 frame:RegisterEvent('COMBAT_LOG_EVENT_UNFILTERED')
686 print('bound ', name, 'with', CT.OnEvent)
687 db.sample = {}
688 local logged = {}
689 frame:SetScript('OnEvent', function(self, e,...)
690 if CT.trigger(e, ...) then
691 print('event trigger fired', name)
692 if #db.sample < 5 and not logged[select(2,...)] then
693 logged[select(2,...)] = true
694 tinsert(db.sample, {e, ...})
695 end
696
697 CT.OnEvent(frame, e, ...)
698 end
699 end)
700
701 -- configurators
702 frame.configHeader:SetText(name)
703 frame:EnableMouse(false)
704
705 -- pre-pop some text frames
706 for i = (CT.lineID or 1), SCT_PREGAME do
707 print(frame:GetName(), 'pre-pop #'..i)
708 mod.NewCombatMessage(frame)
709 end
710 end
711 end
712
713
714 local damageEvents = {
715 ['SPELL_DAMAGE'] = true,
716 ['SPELL_PERIODIC_DAMAGE'] = true,
717 ['SWING_DAMAGE'] = true,
718 ['RANGE_DAMAGE'] = true,
719 ['SPELL_HEAL'] = true,
720 }
721 mod.CombatTextFrames = {
722 Incoming = {
723 trigger = function(e, _, c, _, _, _, _, _, d) return (d == T.GUID and damageEvents[c]) end,
724 OnEvent = mod.OnDamage,
725 sample = {
726 {"COMBAT_LOG_EVENT_UNFILTERED", 1455887795.271, "SPELL_HEAL", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Player-3684-07235A4E", "Klakyn", 1297, 0, 143924, "Leech", 1, 93, 93, 0, false, false, },
727 }
728 },
729 Outgoing = {
730 trigger = function(e, _,c,_, s) return (s == T.GUID and damageEvents[c]) end,
731 OnEvent = mod.OnDamage,
732 sample = {
733 {
734 "COMBAT_LOG_EVENT_UNFILTERED", 1455887795.006, "SPELL_DAMAGE", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0, 589, "Shadow Word: Pain", 32, 3944, -1, 32, nil, nil, nil, false, false, false, false, false, }, {
735 "COMBAT_LOG_EVENT_UNFILTERED", 1455887795.271, "SPELL_HEAL", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Player-3684-07235A4E", "Klakyn", 1297, 0, 143924, "Leech", 1, 93, 93, 0, false, false, }, {
736 "COMBAT_LOG_EVENT_UNFILTERED", 1455887797.377, "SPELL_PERIODIC_DAMAGE", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0, 589, "Shadow Word: Pain", 32, 3944, -1, 32, nil, nil, nil, false, false, false, false, false, }, {
737 "COMBAT_LOG_EVENT_UNFILTERED", 1455887812.702, "SWING_DAMAGE", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0, 279, -1, 1, nil, 120, nil, false, false, false, false, false, }, -- [4]
738 }
739 },
740 DoTTracker = {
741 trigger = function(e, _, c, _, s) return (s == T.GUID and dotEvents[c]) end,
742 OnEvent = mod.OnDotEvent,
743 sample = {
744 {"COMBAT_LOG_EVENT_UNFILTERED", 1455887795.006, "SPELL_AURA_APPLIED", false,
745 "Player-3684-07235A4E", "Klakyn", 1297, 0,
746 "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0,
747 589, "Shadow Word: Pain", 32, "DEBUFF", },
748 {"COMBAT_LOG_EVENT_UNFILTERED", 1455887797.377, "SPELL_PERIODIC_DAMAGE", false,
749 "Player-3684-07235A4E", "Klakyn", 1297, 0,
750 "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0,
751 589, "Shadow Word: Pain", 32, 3944, -1, 32, nil, nil, nil, false, false, false, false, false, },
752 {"COMBAT_LOG_EVENT_UNFILTERED", 1455887807.199, "SPELL_AURA_REMOVED", false,
753 "Player-3684-07235A4E", "Klakyn", 1297, 0,
754 "Player-3684-07235A4E", "Klakyn", 1297, 0,
755 15473, "Shadowform", 32, "BUFF", },
756 }
757 }
758 }