· 6 years ago · Jan 22, 2020, 07:38 AM
1--[[
2 ****************************************************************
3 EavesDrop
4
5 Author: Grayhoof. Original idea by Bant. Coding help/samples
6 from Andalia`s SideCombatLog and CombatChat.
7
8 Notes: Code comments coming at a later time.
9 ****************************************************************]]
10
11EavesDrop = LibStub("AceAddon-3.0"):NewAddon("EavesDrop", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0")
12local EavesDrop = EavesDrop
13local db
14
15local L = LibStub("AceLocale-3.0"):GetLocale("EavesDrop", true)
16local media = LibStub("LibSharedMedia-3.0")
17
18local OUTGOING = 1
19local INCOMING = -1
20local MISC = 3
21
22local critchar = "*"
23local deathchar = "†"
24local crushchar = "^"
25local glancechar = "~"
26local newhigh = "|cffffff00!|r"
27
28local arrEventData = {}
29local arrEventFrames = {}
30local frameSize = 21
31local arrSize = 10
32local arrDisplaySize = 20
33local arrMaxSize = 128
34local scroll = 0
35local allShown = false
36local totDamageIn = 0
37local totDamageOut = 0
38local totHealingIn = 0
39local totHealingOut = 0
40local timeStart = 0
41local curTime = 0
42local lastTime = 0
43
44--LUA calls
45local _G = _G
46local tonumber = tonumber
47local strsub = strsub
48local string_format = string.format
49local string_match = string.match
50local gsub = gsub
51local tremove = tremove
52local tinsert = tinsert
53local function string_nil(val)
54 if val then
55 return val
56 else
57 return UNKNOWN
58 end
59end
60
61--API calls
62local UnitName = UnitName
63local UnitXP = UnitXP
64local GetSpellInfo = GetSpellInfo
65local GetTime = GetTime
66local InCombatLockdown = InCombatLockdown
67
68--Combat log locals
69local pxp = UnitXP("player")
70local skillmsg = gsub(gsub(gsub(SKILL_RANK_UP, '%d%$', ''), '%%s', '(.+)'), '%%d', '(%%d+)')
71local CombatLog_Object_IsA = CombatLog_Object_IsA
72local Blizzard_CombatLog_CurrentSettings
73
74local COMBATLOG_OBJECT_NONE = COMBATLOG_OBJECT_NONE
75local COMBATLOG_FILTER_MINE = COMBATLOG_FILTER_MINE
76local COMBATLOG_FILTER_MY_PET = COMBATLOG_FILTER_MY_PET
77local COMBATLOG_FILTER_HOSTILE = bit.bor(
78 COMBATLOG_FILTER_HOSTILE_PLAYERS,
79 COMBATLOG_FILTER_HOSTILE_UNITS)
80
81local COMBAT_EVENTS = {
82 ["SWING_DAMAGE"] = "DAMAGE",
83 ["RANGE_DAMAGE"] = "DAMAGE",
84 ["SPELL_DAMAGE"] = "DAMAGE",
85 ["SPELL_PERIODIC_DAMAGE"] = "DAMAGE",
86 ["ENVIRONMENTAL_DAMAGE"] = "DAMAGE",
87 ["DAMAGE_SHIELD"] = "DAMAGE",
88 ["DAMAGE_SPLIT"] = "DAMAGE",
89 ["SPELL_HEAL"] = "HEAL",
90 ["SPELL_PERIODIC_HEAL"] = "HEAL",
91 ["SWING_MISSED"] = "MISS",
92 ["RANGE_MISSED"] = "MISS",
93 ["SPELL_MISSED"] = "MISS",
94 ["SPELL_PERIODIC_MISSED"] = "MISS",
95 ["DAMAGE_SHIELD_MISSED"] = "MISS",
96 ["SPELL_DRAIN"] = "DRAIN",
97 ["SPELL_LEECH"] = "DRAIN",
98 ["SPELL_PERIODIC_DRAIN"] = "DRAIN",
99 ["SPELL_PERIODIC_LEECH"] = "DRAIN",
100 ["SPELL_ENERGIZE"] = "POWER",
101 ["SPELL_PERIODIC_ENERGIZE"] = "POWER",
102 ["PARTY_KILL"] = "DEATH",
103 ["UNIT_DIED"] = "DEATH",
104 ["UNIT_DESTROYED"] = "DEATH",
105}
106
107local SCHOOL_STRINGS = {
108 [SCHOOL_MASK_PHYSICAL] = SPELL_SCHOOL0_CAP,
109 [SCHOOL_MASK_HOLY] = SPELL_SCHOOL1_CAP,
110 [SCHOOL_MASK_FIRE] = SPELL_SCHOOL2_CAP,
111 [SCHOOL_MASK_NATURE] = SPELL_SCHOOL3_CAP,
112 [SCHOOL_MASK_FROST] = SPELL_SCHOOL4_CAP,
113 [SCHOOL_MASK_SHADOW] = SPELL_SCHOOL5_CAP,
114 [SCHOOL_MASK_ARCANE] = SPELL_SCHOOL6_CAP,
115}
116
117--[[local POWER_STRINGS = {
118 [SPELL_POWER_MANA] = MANA,
119 [SPELL_POWER_RAGE] = RAGE,
120 [SPELL_POWER_FOCUS] = FOCUS,
121 [SPELL_POWER_ENERGY] = ENERGY,
122 [SPELL_POWER_RUNES] = RUNES,
123 [SPELL_POWER_RUNIC_POWER] = RUNIC_POWER,
124 [SPELL_POWER_SOUL_SHARDS] = SHARDS,
125 [SPELL_POWER_LUNAR_POWER] = LUNAR_POWER,
126 [SPELL_POWER_HOLY_POWER] = HOLY_POWER,
127 [SPELL_POWER_ALTERNATE_POWER] = ALTERNATE_RESOURCE_TEXT,
128 [SPELL_POWER_MAELSTROM] = MAELSTROM_POWER,
129 [SPELL_POWER_CHI] = CHI_POWER,
130 [SPELL_POWER_INSANITY] = INSANITY_POWER,
131 --[SPELL_POWER_OBSOLETE] = 14;
132 --[SPELL_POWER_OBSOLETE2] = 15;
133 [SPELL_POWER_ARCANE_CHARGES] = ARCANE_CHARGES_POWER,
134 [SPELL_POWER_FURY] = FURY,
135 [SPELL_POWER_PAIN] = PAIN,
136}]]
137
138--set table default size sense table.insert no longer does
139for i=1, arrMaxSize do
140 arrEventData[i] = {}
141end
142
143local function convertRGBtoHEXString(color, text)
144 return string_format("|cFF%02x%02x%02x%s|r", ceil(color.r * 255), ceil(color.g * 255), ceil(color.b * 255), text)
145end
146
147local function shortenValue(value)
148 if value >= 10000000 then
149 value = string_format("%.1fm", value / 1000000)
150 elseif value >= 1000000 then
151 value = string_format("%.2fm",value / 1000000)
152 elseif value >= 100000 then
153 value = string_format("%.0fk",value / 1000)
154 elseif value >= 10000 then
155 value = string_format("%.1fk",value / 1000)
156 end
157 return value
158end
159
160local function round(num, idp)
161 return tonumber(string_format("%." .. (idp or 0) .. "f", num))
162end
163
164local function cleanstring(s)
165 s = gsub(s, "|r", "")
166 s = gsub(s, "|c........", "")
167 s = gsub(s, "|Hunit:%a+%-[^|]+|h", "")
168 s = gsub(s, "|Haction:([%w_*]*)|h", "")
169 s = gsub(s, "|Hitem:(%d+)|h", "")
170 s = gsub(s, "|Hicon:%d+:dest|h", "")
171 s = gsub(s, "|Hicon:%d+:source|h", "")
172 s = gsub(s, "|Hspell:%d+:%d+:([%w_*]*)|h", "")
173 s = gsub(s, "|TInterface.TargetingFrame.UI.RaidTargetingIcon.%d.blp:0|t", "")
174 s = gsub(s, "|h", "")
175 s = gsub(s, "\n", ", ")
176 s = gsub(s, "\124", "\124\124")
177 s=s:gsub("[\r\n]+"," ")
178 return s
179end
180
181local function clearSummary()
182 totDamageIn = 0
183 totDamageOut = 0
184 totHealingIn = 0
185 totHealingOut = 0
186end
187
188--Main Functions
189function EavesDrop:OnInitialize()
190
191 --setup table for display frame objects
192 for i=1, arrDisplaySize do
193 arrEventFrames[i] = {}
194 arrEventFrames[i].frame = _G[string_format("EavesDropEvent%d", i)]
195 arrEventFrames[i].text = _G[string_format("EavesDropEvent%dEventText", i)]
196 arrEventFrames[i].intexture = _G[string_format("EavesDropEvent%dIncomingTexture", i)]
197 arrEventFrames[i].intextureframe = _G[string_format("EavesDropEvent%dIncoming", i)]
198 arrEventFrames[i].outtexture = _G[string_format("EavesDropEvent%dOutgoingTexture", i)]
199 arrEventFrames[i].outtextureframe = _G[string_format("EavesDropEvent%dOutgoing", i)]
200 end
201
202 self.db = LibStub("AceDB-3.0"):New("EavesDropDB", self:GetDefaultConfig())
203 self.chardb = LibStub("AceDB-3.0"):New("EavesDropStatsDB", {profile = {[OUTGOING] = {},[INCOMING] = {}}})
204
205 self:SetupOptions()
206
207 --callbacks for profile changes
208 self.db.RegisterCallback(self, "OnProfileChanged", "UpdateFrame")
209 self.db.RegisterCallback(self, "OnProfileCopied", "UpdateFrame")
210 self.db.RegisterCallback(self, "OnProfileReset", "UpdateFrame")
211
212 --local the profile table
213 db = self.db.profile
214
215 self:PerformDisplayOptions()
216
217
218 self:RegisterEvent("ADDON_LOADED", self.SetFonts)
219end
220
221function EavesDrop:OnEnable()
222 self:RegisterEvent("PLAYER_DEAD")
223 self:UpdateExpEvents()
224 self:UpdateRepHonorEvents()
225 self:UpdateCombatEvents()
226 self:UpdateBuffEvents()
227 self:UpdateBuffFadeEvents()
228 self:UpdateSkillEvents()
229
230 self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED","CombatEvent")
231
232 --show frame
233 EavesDropFrame:Show()
234 if (db["FADEFRAME"]) then
235 self:HideFrame()
236 end
237
238end
239
240function EavesDrop:OnDisable()
241 self:UnregisterAllEvents()
242 EavesDropFrame:Hide()
243end
244
245function EavesDrop:UpdateCombatEvents()
246 if (db["COMBAT"] == true) then
247 self:RegisterEvent("PLAYER_REGEN_DISABLED")
248 self:RegisterEvent("PLAYER_REGEN_ENABLED")
249 else
250 self:UnregisterEvent("PLAYER_REGEN_DISABLED")
251 self:UnregisterEvent("PLAYER_REGEN_ENABLED")
252 end
253end
254
255function EavesDrop:UpdateExpEvents()
256 if (db["EXP"] == true) then
257 self:RegisterEvent("PLAYER_XP_UPDATE")
258 else
259 self:UnregisterEvent("PLAYER_XP_UPDATE")
260 end
261end
262
263function EavesDrop:UpdateRepHonorEvents()
264 if (db["REP"] or db["HONOR"]) then
265 self:RegisterEvent("COMBAT_TEXT_UPDATE")
266 else
267 self:UnregisterEvent("COMBAT_TEXT_UPDATE")
268 end
269end
270
271function EavesDrop:UpdateBuffEvents()
272 if (db["DEBUFF"] == true or db["BUFF"] == true) then
273 COMBAT_EVENTS["SPELL_AURA_APPLIED"] = "BUFF"
274 COMBAT_EVENTS["SPELL_PERIODIC_AURA_APPLIED"] = "BUFF"
275 COMBAT_EVENTS["SPELL_AURA_APPLIED_DOSE"] = "BUFF"
276 COMBAT_EVENTS["SPELL_PERIODIC_AURA_APPLIED_DOSE"] = "BUFF"
277 COMBAT_EVENTS["ENCHANT_APPLIED"] = "ENCHANT_APPLIED"
278 else
279 COMBAT_EVENTS["SPELL_AURA_APPLIED"] = nil
280 COMBAT_EVENTS["SPELL_PERIODIC_AURA_APPLIED"] = nil
281 COMBAT_EVENTS["SPELL_AURA_APPLIED_DOSE"] = nil
282 COMBAT_EVENTS["SPELL_PERIODIC_AURA_APPLIED_DOSE"] = nil
283 COMBAT_EVENTS["ENCHANT_APPLIED"] = nil
284 end
285end
286
287function EavesDrop:UpdateBuffFadeEvents()
288 if (db["DEBUFFFADE"] == true or db["BUFFFADE"] == true) then
289 COMBAT_EVENTS["SPELL_AURA_REMOVED"] = "FADE"
290 COMBAT_EVENTS["SPELL_PERIODIC_AURA_REMOVED"] = "FADE"
291 COMBAT_EVENTS["SPELL_AURA_REMOVED_DOSE"] = "FADE"
292 COMBAT_EVENTS["SPELL_PERIODIC_AURA_REMOVED_DOSE"] = "FADE"
293 COMBAT_EVENTS["ENCHANT_REMOVED"] = "ENCHANT_REMOVED"
294 else
295 COMBAT_EVENTS["SPELL_AURA_REMOVED"] = nil
296 COMBAT_EVENTS["SPELL_PERIODIC_AURA_REMOVED"] = nil
297 COMBAT_EVENTS["SPELL_AURA_REMOVED_DOSE"] = nil
298 COMBAT_EVENTS["SPELL_PERIODIC_AURA_REMOVED_DOSE"] = nil
299 COMBAT_EVENTS["ENCHANT_REMOVED"] = nil
300 end
301end
302
303function EavesDrop:UpdateSkillEvents()
304 if (db["SKILL"] == true) then
305 self:RegisterEvent("CHAT_MSG_SKILL")
306 else
307 self:UnregisterEvent("CHAT_MSG_SKILL")
308 end
309end
310
311----------------------
312--Reset everything to default
313function EavesDrop:UpdateFrame()
314 --local the profile table
315 db = self.db.profile
316 self:UpdateExpEvents()
317 self:UpdateRepHonorEvents()
318 self:UpdateCombatEvents()
319 self:UpdateBuffEvents()
320 self:UpdateBuffFadeEvents()
321 self:UpdateSkillEvents()
322 self:PerformDisplayOptions()
323 self:UpdateEvents()
324end
325
326function EavesDrop:PerformDisplayOptions()
327 --set size
328 arrSize = db["NUMLINES"]
329 frameSize = db["LINEHEIGHT"] + 1
330 local totalh = (frameSize * arrSize) + 50
331 local totalw = (db["LINEHEIGHT"] * 2) + db["LINEWIDTH"]
332 EavesDropFrame:SetHeight(totalh)
333 EavesDropFrame:SetWidth(totalw)
334 --update look of frame
335 local r,g,b,a = db["FRAME"].r, db["FRAME"].g, db["FRAME"].b, db["FRAME"].a
336 --main frame
337 EavesDropFrame:SetBackdropColor(r, g, b, a)
338 EavesDropTopBar:SetGradientAlpha("VERTICAL", r*.1, g*.1, b*.1, 0, r*.2, g*.2, b*.2, a)
339 EavesDropBottomBar:SetGradientAlpha("VERTICAL", r*.2, g*.2, b*.2, a, r*.1, g*.1, b*.1, 0)
340 EavesDropTopBar:SetWidth(totalw-10)
341 EavesDropBottomBar:SetWidth(totalw-10)
342 r,g,b,a = db["BORDER"].r, db["BORDER"].g, db["BORDER"].b, db["BORDER"].a
343 EavesDropFrame:SetBackdropBorderColor(r, g, b, a)
344 EavesDropFrame:EnableMouse(not db["LOCKED"])
345 --tooltips
346 EavesDropTab.tooltipText = L["TabTip"]
347 if (db["SCROLLBUTTON"]) then
348 EavesDropFrameDownButton:Hide()
349 EavesDropFrameUpButton:Hide()
350 else
351 EavesDropFrameDownButton.tooltipText = L["DownTip"]
352 EavesDropFrameUpButton.tooltipText = L["UpTip"]
353 self:UpdateScrollButtons()
354 end
355 self.ToolTipAnchor = "ANCHOR_"..strupper(db["TOOLTIPSANCHOR"])
356 --labels
357 r,g,b,a = db["LABELC"].r, db["LABELC"].g, db["LABELC"].b, db["LABELC"].a
358 if (db["FLIP"] == true) then
359 EavesDropFramePlayerText:SetText(L["TargetLabel"])
360 EavesDropFrameTargetText:SetText(L["PlayerLabel"])
361 else
362 EavesDropFramePlayerText:SetText(L["PlayerLabel"])
363 EavesDropFrameTargetText:SetText(L["TargetLabel"])
364 end
365 EavesDropFramePlayerText:SetTextColor(r,g,b,a)
366 EavesDropFrameTargetText:SetTextColor(r,g,b,a)
367 --fonts
368 self:SetFonts()
369 --tab
370 if (db["HIDETAB"] == true) then
371 EavesDropTab:Hide()
372 else
373 EavesDropTab:Show()
374 end
375 --position frame (have to schedule cause UI scale is still 1 for some reason during init)
376 self:ScheduleTimer("PlaceFrame", .1, self)
377
378 self:ResetEvents()
379 self:SetupHistory()
380
381 if (db["FADEFRAME"]) then
382 self:HideFrame()
383 else
384 self:ShowFrame()
385 end
386end
387
388function EavesDrop:SetFonts()
389 EavesDropFontNormal:SetFont(media:Fetch("font", db["FONT"]), db["TEXTSIZE"])
390 EavesDropFontNormalSmall:SetFont(media:Fetch("font", db["FONT"]), db["TEXTSIZE"])
391end
392
393function EavesDrop:PlaceFrame()
394 local frame, x, y = EavesDropFrame, db.x, db.y
395 frame:ClearAllPoints()
396 if x==0 and y==0 then
397 frame:SetPoint("CENTER", UIParent, "CENTER")
398 else
399 local es = frame:GetEffectiveScale()
400 frame:SetPoint("TOPLEFT", UIParent, "CENTER", x/es, y/es)
401 end
402end
403
404function EavesDrop:HideFrame()
405 EavesDropFrame:SetAlpha(0)
406end
407
408function EavesDrop:ShowFrame()
409 EavesDropFrame:SetAlpha(1)
410 EavesDropTab:SetAlpha(0)
411end
412
413function EavesDrop:CombatEvent()
414 local timestamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceFlags2, destGUID, destName, destFlags, destFlags2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 = CombatLogGetCurrentEventInfo()
415 local etype = COMBAT_EVENTS[event]
416 if not etype then return end
417
418 if not Blizzard_CombatLog_CurrentSettings then
419 Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[Blizzard_CombatLog_Filters.currentFilter]
420 end
421
422 --check for reflect damage
423 if event == "SPELL_DAMAGE" and sourceName == destName and CombatLog_Object_IsA(destFlags, COMBATLOG_FILTER_HOSTILE) then
424 self:ParseReflect(timestamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceFlags2, destGUID, destName, destFlags, destFlags2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
425 return
426 end
427
428 local toPlayer, fromPlayer, toPet, fromPet
429 if (sourceName and not CombatLog_Object_IsA(sourceFlags, COMBATLOG_OBJECT_NONE) ) then
430 fromPlayer = CombatLog_Object_IsA(sourceFlags, COMBATLOG_FILTER_MINE)
431 fromPet = CombatLog_Object_IsA(sourceFlags, COMBATLOG_FILTER_MY_PET)
432 end
433 if (destName and not CombatLog_Object_IsA(destFlags, COMBATLOG_OBJECT_NONE) ) then
434 toPlayer = CombatLog_Object_IsA(destFlags, COMBATLOG_FILTER_MINE)
435 toPet = CombatLog_Object_IsA(destFlags, COMBATLOG_FILTER_MY_PET)
436 end
437
438 if not fromPlayer and not toPlayer and not fromPet and not toPet then return end
439 if (not fromPlayer and not toPlayer) and (toPet or fromPet) and not db["PET"] then return end
440
441 local amount, overDamage, school, resisted, blocked, absorbed, critical, glancing, crushing
442 local spellId, spellName, spellSchool, missType, powerType, extraAmount, environmentalType, overHeal
443 local text, texture, message, inout, color
444
445 --defaults
446 if toPet or fromPet then texture = "pet" end
447 if toPlayer or toPet then inout = INCOMING end
448 if fromPlayer or fromPet then inout = OUTGOING end
449 if toPet then color = db["PETI"] end
450 if fromPet then color = db["PETO"] end
451
452 --get combat log message (for tooltip)
453 message = CombatLog_OnEvent(Blizzard_CombatLog_CurrentSettings, timestamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceFlags2, destGUID, destName, destFlags, destFlags2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
454
455
456 ------------damage----------------
457 if etype == "DAMAGE" then
458 local intype, outtype
459 if event == "SWING_DAMAGE" then
460 amount, overDamage, school, resisted, blocked, absorbed, critical, glancing, crushing = a1, a2, a3, a4, a5, a6, a7, a8, a9
461 if school == SCHOOL_MASK_PHYSICAL then
462 outtype, intype = "TMELEE", "PHIT"
463 else
464 outtype, intype = "TSPELL", "PSPELL"
465 end
466 elseif event == "RANGE_DAMAGE" then
467 spellId, spellName, spellSchool, amount, overDamage, school, resisted, blocked, absorbed, critical, glancing, crushing = a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12
468 if school == SCHOOL_MASK_PHYSICAL then
469 outtype, intype = "TMELEE", "PHIT"
470 else
471 outtype, intype = "TSPELL", "PSPELL"
472 end
473 elseif event == "ENVIRONMENTAL_DAMAGE" then
474 environmentalType, amount, overDamage, school, resisted, blocked, absorbed, critical, glancing, crushing = a1, a2, a3, a4, a5, a6, a7, a8, a9, a10
475 outtype, intype = "TSPELL", "PSPELL"
476 else
477 spellId, spellName, spellSchool, amount, overDamage, school, resisted, blocked, absorbed, critical, glancing, crushing = a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12
478 texture = select(3, GetSpellInfo(spellName))
479 outtype, intype = "TSPELL", "PSPELL"
480 end
481 text = tostring(shortenValue(amount))
482
483 if (critical) then text = critchar..text..critchar end
484 if (crushing) then text = crushchar..text..crushchar end
485 if (glancing) then text = glancechar..text..glancechar end
486 if (resisted) then text = string_format("%s (%d)", text, shortenValue(resisted)) end
487 if (blocked) then text = string_format("%s (%d)", text, shortenValue(blocked)) end
488 if (absorbed) then text = string_format("%s (%d)", text, shortenValue(absorbed))end
489
490 if fromPlayer then
491 if (self:TrackStat(inout, "hit", spellName, texture, SCHOOL_STRINGS[school], amount, critical, message)) then
492 text = newhigh..text..newhigh
493 end
494 --fix colors for self physical
495 if school == SCHOOL_MASK_PHYSICAL then school = 0 end
496 color = self:SpellColor(db[outtype], SCHOOL_STRINGS[school])
497 totDamageOut = totDamageOut + amount
498 elseif toPlayer then
499 if (self:TrackStat(inout, "hit", spellName, texture, SCHOOL_STRINGS[school], amount, critical, message)) then
500 text = newhigh..text..newhigh
501 end
502 color = self:SpellColor(db[intype], SCHOOL_STRINGS[school])
503 text = "-"..text
504 totDamageIn = totDamageIn + amount
505 elseif toPet then
506 text = "-"..text
507 end
508 self:DisplayEvent(inout, text, texture, color, message)
509 ------------buff/debuff gain----------------
510 elseif etype == "BUFF" then
511 spellId, spellName, spellSchool, auraType, amount = a1, a2, a3, a4, a5
512 texture = select(3, GetSpellInfo(spellName))
513 if toPlayer and db[auraType] then
514 self:DisplayEvent(INCOMING, self:ShortenString(spellName), texture, db["P"..auraType], message)
515 else return
516 end
517 ------------buff/debuff lose----------------
518 elseif etype == "FADE" then
519 spellId, spellName, spellSchool, auraType, amount = a1, a2, a3, a4, a5
520 texture = select(3, GetSpellInfo(spellName))
521 if toPlayer and db[auraType.."FADE"] then
522 self:DisplayEvent(INCOMING, self:ShortenString(spellName).." "..L["Fades"], texture, db["P"..auraType], message)
523 else return
524 end
525 ------------heals----------------
526 elseif etype == "HEAL" then
527 spellId, spellName, spellSchool, amount, overHeal, absorbed, critical = a1, a2, a3, a4, a5, a6, a7
528 text = tostring(shortenValue(amount))
529 texture = select(3, GetSpellInfo(spellName))
530
531 if toPlayer then
532 totHealingIn = totHealingIn + amount
533 if (amount < db["HFILTER"]) then return end
534 if (db["OVERHEAL"]) and overHeal > 0 then text = string_format("%d {%d}", shortenValue(amount-overHeal), shortenValue(overHeal)) end
535 if (critical) then text = critchar..text..critchar end
536 if (db["HEALERID"] == true and not fromPlayer) then text = text.." ("..sourceName..")" end
537 color = db["PHEAL"]
538 if (self:TrackStat(inout, "heal", spellName, texture, SCHOOL_STRINGS[spellSchool], amount, critical, message)) then
539 text = newhigh..text..newhigh
540 end
541 text = "+"..text
542 elseif fromPlayer then
543 totHealingOut = totHealingOut + amount
544 if (amount < db["HFILTER"]) then return end
545 if (db["OVERHEAL"]) and overHeal > 0 then text = string_format("%d {%d}", shortenValue(amount-overHeal), shortenValue(overHeal)) end
546 if (critical) then text = critchar..text..critchar end
547 color = db["THEAL"]
548 if (self:TrackStat(inout, "heal", spellName, texture, SCHOOL_STRINGS[spellSchool], amount, critical, message)) then
549 text = newhigh..text..newhigh
550 end
551 text = "+"..text
552 if (db["HEALERID"] == true) then text = destName..": "..text end
553 end
554 self:DisplayEvent(inout, text, texture, color, message)
555 ------------misses----------------
556 elseif etype == "MISS" then
557 local tcolor
558 if event == "SWING_MISSED" or event == "RANGE_MISSED" then
559 missType = a1
560 tcolor = "TMELEE"
561 else
562 spellId, spellName, spellSchool, missType = a1, a2, a3, a4
563 texture = select(3, GetSpellInfo(spellName))
564 tcolor = "TSPELL"
565 end
566 text = _G[missType]
567 if fromPlayer then
568 color = db[tcolor]
569 elseif toPlayer then
570 if missType == "REFLECT" then
571 self:SetReflect(sourceName, spellName)
572 end
573 color = db["PMISS"]
574 end
575 self:DisplayEvent(inout, text, texture, color, message)
576 ------------leech and drains----------------
577 elseif etype == "DRAIN" then
578 if (db["GAINS"]) then
579 spellId, spellName, spellSchool, amount, powerType, extraAmount = a1, a2, a3, a4, a5, a6
580 texture = select(3, GetSpellInfo(spellName))
581 if toPlayer then
582 text = string_format("-%d %s", amount, string_nil(""))
583 color = db["PGAIN"]
584 elseif fromPlayer and extraAmount then
585 if (extraAmount < db["MFILTER"]) then return end
586 text = string_format("+%d %s", extraAmount, string_nil(""))
587 color = db["PGAIN"]
588 elseif fromPlayer then
589 return
590 --for showing your drain damage
591 --text = string_format("%d %s", amount, string_nil(""))
592 --color = db["TSPELL"]
593 end
594 self:DisplayEvent(inout, text, texture, color, message)
595 end
596 ------------power gains----------------
597 elseif etype == "POWER" then
598 if (db["GAINS"]) then
599 spellId, spellName, spellSchool, amount, powerType = a1, a2, a3, a4, a5
600 texture = select(3, GetSpellInfo(spellName))
601 if toPlayer then
602 if (amount < db["MFILTER"]) then return end
603 color = db["PGAIN"]
604 elseif not toPet then
605 return
606 end
607 text = string_format("+%d %s", amount, string_nil(""))
608 self:DisplayEvent(inout, text, texture, color, message)
609 end
610 ------------deaths----------------
611 elseif etype == "DEATH" then
612 if fromPlayer then
613 text = deathchar..destName..deathchar
614 self:DisplayEvent(MISC, text, texture, db["DEATH"], message)
615 else return
616 end
617 ------------enchants----------------
618 elseif etype == "ENCHANT_APPLIED" then
619 spellName = a1
620 self:DisplayEvent(INCOMING, self:ShortenString(spellName), texture, db["PBUFF"], message)
621 elseif etype == "ENCHANT_REMOVED" then
622 spellName = a1
623 self:DisplayEvent(INCOMING, self:ShortenString(spellName).." "..L["Fades"], texture, db["PBUFF"], message)
624 -------------anything else-------------
625 --else
626 --self:Print(event, sourceName, destName)
627 end
628end
629
630function EavesDrop:PLAYER_XP_UPDATE()
631 local xp = UnitXP("player")
632 local xpgained = xp - pxp
633 self:DisplayEvent(MISC, string_format("+%d (%s)", shortenValue(xpgained), XP), nil, db["EXPC"], nil)
634 pxp = xp
635end
636
637function EavesDrop:COMBAT_TEXT_UPDATE(event, larg1, larg2, larg3)
638 if larg1=="FACTION" then
639 local sign = "+"
640 if larg2 == nil then
641 larg2 = 0
642 end
643 if larg3 == nil then
644 larg3 = 0
645 sign = ""
646 end
647 if (tonumber(larg3) < 0) then sign = "" end
648 self:DisplayEvent(MISC, string_format("%s%d (%s)", sign, larg3, larg2), nil, db["REPC"], nil)
649 elseif larg1=="HONOR_GAINED" then
650 self:DisplayEvent(MISC, string_format("+%d (%s)", larg2, HONOR) , nil, db["HONORC"], nil)
651 end
652end
653
654function EavesDrop:PLAYER_REGEN_DISABLED()
655 pxp = UnitXP("player")
656 timeStart = GetTime()
657 clearSummary()
658 self:DisplayEvent(MISC, L["StartCombat"], nil, db["MISC"])
659 --stop on update, since in combat
660 self:StopOnUpdate()
661 --show frame, if its hidden
662 self:ShowFrame()
663 --flag all as being shown, so buttons appear
664 allShown = true
665end
666
667function EavesDrop:PLAYER_REGEN_ENABLED()
668 self:DisplayEvent(MISC, L["EndCombat"], nil, db["MISC"])
669 if (db["SUMMARY"] == true) then
670 local duration = round(GetTime() - timeStart, 1)
671 local DPS = round(totDamageOut/duration,1) or 0
672 local HPS = round(totHealingOut/duration,1) or 0
673 local IDPS = round(totDamageIn/duration,1) or 0
674 local IHPS = round(totHealingIn/duration,1) or 0
675 local strSummary = convertRGBtoHEXString(db["MISC"], duration.." "..L["IncombatSummary"]).."\n"..
676 convertRGBtoHEXString(db["PHIT"], L["IncomingDamge"]..": "..totDamageIn.." ("..IDPS..")").."\n"..
677 convertRGBtoHEXString(db["PHEAL"], L["IncomingHeals"]..": "..totHealingIn.." ("..IHPS..")").."\n"..
678 convertRGBtoHEXString(db["THEAL"], L["OutgoingHeals"]..": "..totHealingOut.." ("..HPS..")").."\n"..
679 convertRGBtoHEXString(db["TSPELL"], L["OutgoingDamage"]..": "..totDamageOut.." ("..DPS..")")
680
681 self:DisplayEvent(MISC,
682 convertRGBtoHEXString(db["PHIT"], shortenValue(totDamageIn)).." | "..
683 convertRGBtoHEXString(db["PHEAL"], shortenValue(totHealingIn)).." | "..
684 convertRGBtoHEXString(db["THEAL"], shortenValue(totHealingOut)).." | "..
685 convertRGBtoHEXString(db["TSPELL"], shortenValue(totDamageOut)),
686 nil, db["MISC"], strSummary)
687 end
688 clearSummary()
689 --since out of combat, try and start onupdate to count down frames
690 self:StartOnUpdate()
691end
692
693function EavesDrop:PLAYER_DEAD()
694 self:DisplayEvent(MISC, deathchar..UnitName("player")..deathchar, nil, db["DEATH"])
695end
696
697function EavesDrop:CHAT_MSG_SKILL(event, larg1)
698 local skill, rank = string_match(larg1, skillmsg)
699 if skill then
700 self:DisplayEvent(MISC, string_format("%s: %d", skill, rank), nil, db["SKILLC"], larg1)
701 end
702end
703
704local tempcolor = {r = 1, g = 1, b = 1}
705function EavesDrop:DisplayEvent(type, text, texture, color, message, spellname)
706 --remove oldest table and create new display event
707 local pEvent = tremove(arrEventData, 1)
708 local tooltiptext = message
709 if (db["FLIP"] == true) then type = type * -1 end
710 pEvent.type = type
711 pEvent.text = text
712 pEvent.texture = texture
713 pEvent.color = color or tempcolor
714 if spellname then
715 tooltiptext = spellname
716 end
717 if (db["TIMESTAMP"] == true) then
718 pEvent.tooltipText = string_format('|cffffffff%s|r\n%s', date('%I:%M:%S'), tooltiptext or '')
719 else
720 pEvent.tooltipText = tooltiptext
721 end
722 tinsert(arrEventData, arrMaxSize, pEvent)
723 self:UpdateEvents()
724end
725
726function EavesDrop:UpdateEvents()
727 local key, value
728 local frame, text, intexture, outexture
729 local start, finish
730 local delay = db["FADETIME"] + (4 * arrSize)
731 start = arrMaxSize-scroll
732 finish = arrMaxSize-arrSize+1-scroll
733 for i=start,finish,-1 do
734 value = arrEventData[i]
735 key = i - (arrMaxSize-arrSize) + scroll
736 frame = arrEventFrames[key].frame
737 text = arrEventFrames[key].text
738 intexture = arrEventFrames[key].intexture
739 outtexture = arrEventFrames[key].outtexture
740 if (not value.text) then
741 text:SetText(nil)
742 intexture:SetTexture(nil)
743 outtexture:SetTexture(nil)
744 frame.delay = 0
745 frame.alpha = 0
746 frame.tooltipText = nil
747 frame:Hide()
748 else
749 if (value.type == INCOMING) then
750 text:SetJustifyH("LEFT")
751 text:SetWidth(db["LINEWIDTH"]-20)
752 text:SetPoint("LEFT", intexture, "RIGHT", 5, 0)
753 intexture:SetTexCoord(.1,.9,.1,.9)
754 outtexture:SetTexture(nil)
755 if value.texture == "pet" then
756 SetPortraitTexture(intexture, value.texture)
757 else
758 intexture:SetTexture(value.texture)
759 end
760 elseif (value.type == OUTGOING) then
761 text:SetJustifyH("RIGHT")
762 text:SetWidth(db["LINEWIDTH"]-20)
763 text:SetPoint("LEFT", intexture, "RIGHT", 5, 0)
764 intexture:SetTexture(nil)
765 outtexture:SetTexCoord(.1,.9,.1,.9)
766 if value.texture == "pet" then
767 SetPortraitTexture(outtexture, value.texture)
768 else
769 outtexture:SetTexture(value.texture)
770 end
771 else
772 text:SetJustifyH("CENTER")
773 text:SetWidth((db["LINEHEIGHT"] * 2) + (db["LINEWIDTH"]-10))
774 text:SetPoint("LEFT", intexture, "LEFT", 0, 0)
775 intexture:SetTexture(nil)
776 outtexture:SetTexture(nil)
777 end
778 text:SetText(value.text)
779 text:SetTextColor(value.color.r, value.color.g, value.color.b)
780 frame.delay = delay
781 frame.alpha = 1
782 if (db["TOOLTIPS"] == true) then
783 frame.tooltipText = value.tooltipText
784 else
785 frame.tooltipText = nil
786 end
787 frame:Show()
788 frame:SetAlpha(frame.alpha)
789 end
790 delay = delay - 4
791 --set clickthru
792 if (frame.tooltipText) then
793 frame:EnableMouse(true)
794 else
795 frame:EnableMouse(false)
796 end
797 end
798 --Update scrolls
799 self:UpdateScrollButtons()
800 --try to start up onUpdate. if in combat it won't start.
801 self:StartOnUpdate()
802end
803
804function EavesDrop:StartOnUpdate()
805 --only start on update if not in combat, and not already started.
806 if not InCombatLockdown() and not self.OnUpdateStarted then
807 lastTime = GetTime()
808 self.OnUpdateStarted = self:ScheduleRepeatingTimer("OnUpdate", .2, self)
809 end
810end
811
812function EavesDrop:StopOnUpdate()
813 self:CancelTimer(self.OnUpdateStarted, true)
814 self.OnUpdateStarted = nil
815end
816
817function EavesDrop:ResetEvents()
818 local frame, text, intexture, outexture
819 for i=1,arrDisplaySize do
820 frame = arrEventFrames[i].frame
821 text = arrEventFrames[i].text
822 intexture = arrEventFrames[i].intextureframe
823 outtexture = arrEventFrames[i].outtextureframe
824 frame.delay = 0
825 frame.alpha = 0
826 frame.tooltipText = nil
827 frame:SetHeight(db["LINEHEIGHT"] + 1)
828 frame:SetWidth((db["LINEHEIGHT"] * 2) + db["LINEWIDTH"])
829 frame:Hide()
830 text:SetHeight(db["LINEHEIGHT"])
831 intexture:SetHeight(db["LINEHEIGHT"])
832 intexture:SetWidth(db["LINEHEIGHT"])
833 intexture:SetPoint("LEFT", frame, "RIGHT", 5, 0)
834 outtexture:SetHeight(db["LINEHEIGHT"])
835 outtexture:SetWidth(db["LINEHEIGHT"])
836 end
837end
838
839function EavesDrop:OnUpdate()
840 local frame
841 local count = 0
842 curTime = GetTime()
843 elapsed = curTime - lastTime
844 lastTime = curTime
845 for i=1,arrSize do
846 frame = arrEventFrames[i].frame
847 if (frame:IsShown()) then
848 count = count + 1
849 frame.delay = frame.delay - elapsed
850 if frame.delay <= 0 then
851 frame.alpha = frame.alpha - .2
852 frame:SetAlpha(frame.alpha)
853 end
854 if (frame.alpha <= 0) then
855 frame:Hide()
856 EavesDropFrameUpButton:Hide()
857 count = count - 1
858 end
859 end
860 end
861 if (count == arrSize) then
862 allShown = true
863 else
864 allShown = false
865 end
866 --if none are active, stop onUpdate
867 if (count == 0) then
868 self:StopOnUpdate()
869 end
870 --hide frame when none active
871 if (db["FADEFRAME"]) then
872 if ((count == 0) and (scroll==0)) then
873 self:HideFrame()
874 else
875 self:ShowFrame()
876 end
877 end
878end
879
880function EavesDrop:Scroll(this, dir)
881 local self = EavesDrop
882 if dir > 0 then
883 if IsShiftKeyDown() then
884 self:ScrollToTop()
885 elseif IsControlKeyDown() then
886 self:FindCombatUp()
887 else
888 self:ScrollUp()
889 end
890 elseif dir < 0 then
891 if IsShiftKeyDown() then
892 self:ScrollToBottom()
893 elseif IsControlKeyDown() then
894 self:FindCombatDown()
895 else
896 self:ScrollDown()
897 end
898 end
899end
900
901function EavesDrop:FindCombatUp()
902 for i=arrMaxSize-scroll-arrSize, 1, -1 do
903 if arrEventData[i].text and arrEventData[i].text == L["StartCombat"] then
904 scroll = arrMaxSize-i-arrSize+1
905 self:UpdateScrollButtons()
906 self:UpdateEvents()
907 return
908 end
909 end
910end
911
912function EavesDrop:FindCombatDown()
913 for i=arrMaxSize-scroll+1,arrMaxSize do
914 if arrEventData[i].text and arrEventData[i].text == L["EndCombat"] then
915 scroll = arrMaxSize-i
916 self:UpdateScrollButtons()
917 self:UpdateEvents()
918 return
919 end
920 end
921end
922
923function EavesDrop:ScrollToTop()
924 scroll = arrMaxSize-arrSize
925 self:UpdateScrollButtons()
926 self:UpdateEvents()
927end
928
929function EavesDrop:ScrollToBottom()
930 scroll = 0
931 self:UpdateScrollButtons()
932 self:UpdateEvents()
933end
934
935function EavesDrop:ScrollUp()
936 scroll = scroll + 1
937 if (scroll > (arrMaxSize-arrSize)) then
938 scroll = arrMaxSize-arrSize
939 end
940 self:UpdateScrollButtons()
941 self:UpdateEvents()
942end
943
944function EavesDrop:ScrollDown()
945 scroll = scroll - 1
946 if (scroll < 0) then
947 scroll = 0
948 end
949 self:UpdateScrollButtons()
950 self:UpdateEvents()
951end
952
953function EavesDrop:UpdateScrollButtons()
954 if ( not db["SCROLLBUTTON"]) then
955
956 if (scroll > 0) then
957 EavesDropFrameDownButton:Show()
958 if (scroll == arrMaxSize-arrSize) then
959 EavesDropFrameUpButton:Hide()
960 else
961 EavesDropFrameUpButton:Show()
962 end
963 else
964 EavesDropFrameDownButton:Hide()
965 if (not allShown) then
966 EavesDropFrameUpButton:Hide()
967 else
968 EavesDropFrameUpButton:Show()
969 end
970 end
971 end
972end
973
974function EavesDrop:SpellColor(option, type)
975 if (db["SPELLCOLOR"] == true) then
976 return db[type] or option
977 else
978 return option
979 end
980end
981
982-------------------------
983--Set last reflection
984function EavesDrop:ParseReflect(timestamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceFlags2, destGUID, destName, destFlags, destFlags2, ...)
985 local spellId, spellName, spellSchool, amount, school, resisted, blocked, absorbed, critical, glancing, crushing = ...
986 local texture = select(3, GetSpellInfo(spellName))
987 local text = amount
988 local messsage = CombatLog_OnEvent(Blizzard_CombatLog_CurrentSettings, timestamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceFlags2, destGUID, destName, destFlags, destFlags2, ...)
989
990 --reflected events
991 if (self.ReflectTarget == sourceName and sourceName == destName and self.ReflectSkill == spellName) then
992 local text = string_format("%s: %d", REFLECT, shortenValue(amount))
993 if (critical) then text = critchar..text..critchar end
994 self:DisplayEvent(OUTGOING, text, texture, self:SpellColor(db["TSPELL"], SCHOOL_STRINGS[school]), messsage)
995 self:ClearReflect()
996 end
997end
998
999-------------------------
1000--Set last reflection
1001function EavesDrop:SetReflect(target, skill)
1002 self.ReflectTarget = target
1003 self.ReflectSkill = skill
1004 --clear reflection after 3 seconds.
1005 self:ScheduleTimer(self.ClearReflect, 3, self)
1006end
1007
1008-------------------------
1009--Clear last reflection
1010function EavesDrop:ClearReflect()
1011 self.ReflectTarget = nil
1012 self.ReflectSkill = nil
1013end
1014
1015------------------------------
1016---Shorten a spell/buff
1017function EavesDrop:ShortenString(strString)
1018 if (db["TRUNCATETYPE"] ~= "0") and strlen(strString) > db["TRUNCATESIZE"] then
1019 if (db["TRUNCATETYPE"] == "1") then
1020 return strsub(strString, 1, db["TRUNCATESIZE"]).."..."
1021 elseif (db["TRUNCATETYPE"] == "2") then
1022 return gsub(gsub(gsub(strString," of ","O"),"%s",""), "(%u)%l*", "%1")
1023 end
1024 else
1025 return strString
1026 end
1027end
1028
1029------------------------------
1030---Send Text to the editbox
1031function EavesDrop:SendToChat(text)
1032 local tmptext = cleanstring(text)
1033 if tmptext == "" then return end
1034 local edit_box = _G.ChatEdit_ChooseBoxForSend()
1035 if edit_box:IsShown() then
1036 edit_box:Insert(tmptext)
1037 else
1038 _G.ChatEdit_ActivateChat(edit_box)
1039 edit_box:Insert(tmptext)
1040 end
1041end
1042
1043------------------------------
1044---Show/Hide history frame
1045function EavesDrop:ShowHistory()
1046 if (not EavesDropHistoryFrame:IsShown()) then
1047 EavesDropHistoryFrame:Show()
1048 else
1049 EavesDropHistoryFrame:Hide()
1050 end
1051 PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
1052end