Quantcast

testing changes

failcoder [07-16-15 - 20:29]
testing changes
Filename
SVUI_!Core/libs/_SVUI_Lib/Events.lua
SVUI_!Core/libs/_SVUI_Lib/Parser.lua
SVUI_!Core/system/misc.lua
SVUI_ActionBars/libs/LibActionButton-1.0/LibActionButton-1.0.lua
diff --git a/SVUI_!Core/libs/_SVUI_Lib/Events.lua b/SVUI_!Core/libs/_SVUI_Lib/Events.lua
index 1db6b64..c4e2a58 100644
--- a/SVUI_!Core/libs/_SVUI_Lib/Events.lua
+++ b/SVUI_!Core/libs/_SVUI_Lib/Events.lua
@@ -57,12 +57,249 @@ if not lib then return end -- No upgrade needed

 local CoreName, CoreObject  = ...

+local LOG_EVENT, _R, _T = {},{},{};
+local COMBAT_LOG_EVENTS = {
+  SWING_DAMAGE            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.amount, LOG_EVENT.overkill, LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked,
+                                LOG_EVENT.absorbed, LOG_EVENT.crit, LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.multi = ...;
+                            end,
+  RANGE_DAMAGE            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.ranged = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.offhand, LOG_EVENT.multi = ...;
+                            end,
+  DAMAGE_SPLIT            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.offhand, LOG_EVENT.multi = ...;
+                            end,
+  SPELL_DAMAGE            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.offhand, LOG_EVENT.multi = ...;
+                            end,
+  SPELL_PERIODIC_DAMAGE   = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.dot = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.offhand, LOG_EVENT.multi = ...;
+                            end,
+  SPELL_BUILDING_DAMAGE   = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing = ...;
+                            end,
+  DAMAGE_SHIELD           = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.shield = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing = ...;
+                            end,
+  SWING_MISSED            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.miss, LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  RANGE_MISSED            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.ranged = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.miss,
+                                LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_MISSED            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.miss,
+                                LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_PERIODIC_MISSED   = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.miss,
+                                LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  DAMAGE_SHIELD_MISSED    = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.shield = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.miss,
+                                LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_DISPEL_FAILED     = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.miss = "RESIST";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.spellID2,
+                                LOG_EVENT.spellName2, LOG_EVENT.school2 = ...;
+                            end,
+  SPELL_PERIODIC_ENERGIZE = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.gain = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.powerType = ...;
+                            end,
+  SPELL_PERIODIC_DRAIN    = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.drain = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.powerType, LOG_EVENT.amount2 = ...;
+                            end,
+  SPELL_PERIODIC_LEECH    = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.leech = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.powerType, LOG_EVENT.amount2 = ...;
+                            end,
+  SPELL_ENERGIZE          = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.gain = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.powerType = ...;
+                            end,
+  SPELL_DRAIN             = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.drain = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.powerType, LOG_EVENT.amount2 = ...;
+                            end,
+  SPELL_LEECH             = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.leech = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.powerType, LOG_EVENT.amount2 = ...;
+                            end,
+  SPELL_STOLEN            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "dispel";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.spellID2,
+                                LOG_EVENT.spellName2, LOG_EVENT.school2, LOG_EVENT.aura = ...;
+                            end,
+  SPELL_DISPEL            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "dispel";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.spellID2,
+                                LOG_EVENT.spellName2, LOG_EVENT.school2, LOG_EVENT.aura = ...;
+                            end,
+  SPELL_HEAL              = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "heal";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.overheal, LOG_EVENT.absorbed, LOG_EVENT.crit, LOG_EVENT.multi = ...;
+                            end,
+  SPELL_PERIODIC_HEAL     = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "heal";
+                                LOG_EVENT.hot = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.overheal, LOG_EVENT.absorbed, LOG_EVENT.crit, LOG_EVENT.multi = ...;
+                            end,
+  ENVIRONMENTAL_DAMAGE    = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "environmental";
+                                LOG_EVENT.hazard, LOG_EVENT.amount, LOG_EVENT.overkill, LOG_EVENT.damage,
+                                LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing = ...;
+                            end,
+  SPELL_INTERRUPT         = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "interrupt";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.spellID2,
+                                LOG_EVENT.spellName2, LOG_EVENT.school2 = ...;
+                            end,
+  SPELL_AURA_APPLIED      = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "aura";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.aura, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_AURA_APPLIED_DOSE = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "aura";
+                                LOG_EVENT.dose = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.aura, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_AURA_REMOVED      = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "aura";
+                                LOG_EVENT.faded = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.aura, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_AURA_REMOVED_DOSE = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "aura";
+                                LOG_EVENT.faded = true;
+                                LOG_EVENT.dose = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.aura, LOG_EVENT.amount = ...;
+                            end,
+  ENCHANT_APPLIED         = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "enchant";
+                                LOG_EVENT.spellName, LOG_EVENT.itemID, LOG_EVENT.itemName = ...;
+                            end,
+  ENCHANT_REMOVED         = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "enchant";
+                                LOG_EVENT.faded = true;
+                                LOG_EVENT.spellName, LOG_EVENT.itemID, LOG_EVENT.itemName = ...;
+                            end,
+  SPELL_CAST_START        = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "cast";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school = ...;
+                            end,
+  PARTY_KILL              = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "kill";
+                            end,
+  SPELL_EXTRA_ATTACKS     = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "extraattacks";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount = ...;
+                            end
+};
+local FULL_PARSE = {
+  SPELL_AURA_APPLIED = true,
+  SPELL_AURA_REMOVED = true,
+  SPELL_AURA_APPLIED_DOSE = true,
+  SPELL_AURA_REMOVED_DOSE = true,
+  SPELL_CAST_START = true,
+};
+local PROXY_UNITS = { player = true, pet = true };
+
+local function flagTest(a, b, c)
+  if(c) then
+    if(bit_band(a, b) > 0) then return true end
+  else
+    if(bit_band(a, b) == b) then return true end
+  end
+end
+
 --[[ LIB CALLBACK STORAGE ]]--

 lib.Triggers = {};
 lib.FireOnce = {};
 lib.LockCallback = {};
 lib.UnlockCallback = {};
+lib.EventCallback = {};

 --[[ EVENT TRIGGERING ]]--

@@ -155,33 +392,129 @@ function lib:OnUnlock(callback)
     end
 end

---[[ COMMON EVENTS ]]--
+function lib:Register(event, obj, callback)
+    local key = obj.Schema
+    if(not self.EventCallback[event]) then
+        self.EventCallback[event] = {}
+    end
+    self.EventCallback[event][key] = callback;
+end;

-lib.EventManager = CreateFrame("Frame", nil)
-local Library_OnEvent = function(self, event, arg, ...)
-    if(event == 'PLAYER_REGEN_DISABLED') then
-        for i=1, #lib.LockCallback do
-            local fn = lib.LockCallback[i]
-            if(fn and type(fn) == "function") then
-                local _, catch = pcall(fn, ...)
-                if(catch) then
-                    CoreObject:HandleError("Librarian:Events:OnLock(" .. event .. "):", "callback", catch)
-                end
-            end
-        end
-    elseif(event == "PLAYER_REGEN_ENABLED") then
-        for i=1, #lib.UnlockCallback do
-            local fn = lib.UnlockCallback[i]
-            if(fn and type(fn) == "function") then
-                local _, catch = pcall(fn, ...)
-                if(catch) then
-                    CoreObject:HandleError("Librarian:Events:OnUnlock(" .. event .. "):", "callback", catch)
-                end
-            end
-        end
+function lib:Unregister(event, obj)
+    local key = obj.Schema
+    if((not self.EventCallback[event]) or (not self.EventCallback[event][key])) then
+        return
     end
+    self.EventCallback[event][key] = nil;
+end;
+
+function lib:BroadCast(event)
+  if(not self.EventCallback[event]) then return end;
+  for key,fn in pairs(self.EventCallback[event]) do
+    local obj = CoreObject[key];
+    local _, catch = pcall(fn, obj, LOG_EVENT)
+    if(catch) then
+        CoreObject:HandleError("Librarian:Events", "BroadCast", catch)
+    end
+  end
+end;
+
+--[[ COMBAT LOG PARSING ]]--
+
+function lib:COMBAT_LOG_EVENT_UNFILTERED(timestamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags, ...)
+  local fn = COMBAT_LOG_EVENTS[event]
+  if (not fn) then return end
+
+  if (sourceGUID == destGUID and _T[destGUID] and event == "SPELL_DAMAGE") then
+    local skillID = ...
+    if (skillID == _R[destGUID]) then
+      _T[destGUID] = nil;
+      _R[destGUID] = nil;
+      sourceGUID = playerGUID;
+      sourceName = playerName;
+      sourceFlags = FLAGS_ME;
+    end
+  end
+
+  local sourceUnit = unitMap[sourceGUID] or petMap[sourceGUID];
+  local destUnit = unitMap[destGUID] or petMap[destGUID];
+  if ((not sourceUnit) and flagTest(sourceFlags, FLAGS_MINE)) then
+    sourceUnit = flagTest(sourceFlags, FLAGS_MY_GUARDIAN) and "pet" or "player";
+  end
+  if ((not destUnit) and flagTest(destFlags, FLAGS_MINE)) then
+    destUnit = flagTest(destFlags, FLAGS_MY_GUARDIAN) and "pet" or "player";
+  end
+  if ((not FULL_PARSE[event]) and (not PROXY_UNITS[sourceUnit]) and (not PROXY_UNITS[destUnit])) then
+    return;
+  end
+
+  fn(...)
+
+  LOG_EVENT.hostile = flagTest(sourceFlags, COMBATLOG_OBJECT_REACTION_HOSTILE)
+  LOG_EVENT.sourceGUID = sourceGUID
+  LOG_EVENT.sourceName = sourceName
+  LOG_EVENT.sourceFlags = sourceFlags
+  LOG_EVENT.sourceUnit = sourceUnit
+  LOG_EVENT.destGUID = destGUID
+  LOG_EVENT.destName = destName
+  LOG_EVENT.destFlags = destFlags
+  LOG_EVENT.destUnit = destUnit
+
+  if (LOG_EVENT.type == "miss" and LOG_EVENT.miss == "REFLECT" and LOG_EVENT.destUnit == "player") then
+    for guid, reflectTime in pairs(_T) do
+      if (timestamp - reflectTime > REFLECT_HOLD_TIME) then
+        _T[guid] = nil
+        _R[guid] = nil
+      end
+    end
+
+    _T[sourceGUID] = timestamp
+    _R[sourceGUID] = LOG_EVENT.spellID
+  end
+
+  self:BroadCast()
 end

+--[[ COMMON EVENTS ]]--
+
+function lib:PLAYER_REGEN_DISABLED(...)
+  for i=1, #self.LockCallback do
+      local fn = self.LockCallback[i]
+      if(fn and type(fn) == "function") then
+          local _, catch = pcall(fn, ...)
+          if(catch) then
+              CoreObject:HandleError("Librarian:Events:OnLock(PLAYER_REGEN_DISABLED):", "callback", catch)
+          end
+      end
+  end
+end
+
+function lib:PLAYER_REGEN_ENABLED(...)
+  for i=1, #self.UnlockCallback do
+      local fn = self.UnlockCallback[i]
+      if(fn and type(fn) == "function") then
+          local _, catch = pcall(fn, ...)
+          if(catch) then
+              CoreObject:HandleError("Librarian:Events:OnLock(PLAYER_REGEN_ENABLED):", "callback", catch)
+          end
+      end
+  end
+end
+
+--[[ EVENT DISTRIBUTION ]]--
+
+local Library_OnEvent = function(self, event, ...)
+  local fn = self[event]
+  if(fn and type(fn) == "function") then
+      local _, catch = pcall(fn, self, ...)
+      if(catch) then
+          CoreObject:HandleError("Librarian:Events:OnEvent", event, catch)
+      end
+  end
+end
+
+lib.EventManager = CreateFrame("Frame", nil)
 lib.EventManager:RegisterEvent("PLAYER_REGEN_DISABLED")
 lib.EventManager:RegisterEvent("PLAYER_REGEN_ENABLED")
+lib.EventManager:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
 lib.EventManager:SetScript("OnEvent", Library_OnEvent)
diff --git a/SVUI_!Core/libs/_SVUI_Lib/Parser.lua b/SVUI_!Core/libs/_SVUI_Lib/Parser.lua
index 9ea5939..ef5bba6 100644
--- a/SVUI_!Core/libs/_SVUI_Lib/Parser.lua
+++ b/SVUI_!Core/libs/_SVUI_Lib/Parser.lua
@@ -103,42 +103,224 @@ lib.Callbacks = {};

 --[[ EVENT HANDLING ]]--

-local _E, _R, _T = {},{},{};
-local SUB_EVENT_HANDLERS = {
-  SWING_DAMAGE            = function (...) wipe(_E); _E.type, _E.amount, _E.overkill, _E.damage, _E.resisted, _E.blocked, _E.absorbed, _E.crit, _E.glancing, _E.crushing, _E.multi = "damage", ... end,
-  RANGE_DAMAGE            = function (...) wipe(_E); _E.type, _E.ranged, _E.spellID, _E.spellName, _E.school, _E.amount, _E.overkill, _E.damage, _E.resisted, _E.blocked, _E.absorbed, _E.crit, _E.glancing, _E.crushing, _E.offhand, _E.multi = "damage", true, ... end,
-  DAMAGE_SPLIT            = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.amount, _E.overkill, _E.damage, _E.resisted, _E.blocked, _E.absorbed, _E.crit, _E.glancing, _E.crushing, _E.offhand, _E.multi = "damage", ... end,
-  SPELL_DAMAGE            = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.amount, _E.overkill, _E.damage, _E.resisted, _E.blocked, _E.absorbed, _E.crit, _E.glancing, _E.crushing, _E.offhand, _E.multi = "damage", ... end,
-  SPELL_PERIODIC_DAMAGE   = function (...) wipe(_E); _E.type, _E.dot, _E.spellID, _E.spellName, _E.school, _E.amount, _E.overkill, _E.damage, _E.resisted, _E.blocked, _E.absorbed, _E.crit, _E.glancing, _E.crushing, _E.offhand, _E.multi = "damage", true, ... end,
-  SPELL_BUILDING_DAMAGE   = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.amount, _E.overkill, _E.damage, _E.resisted, _E.blocked, _E.absorbed, _E.crit, _E.glancing, _E.crushing = "damage", ... end,
-  DAMAGE_SHIELD           = function (...) wipe(_E); _E.type, _E.shield, _E.spellID, _E.spellName, _E.school, _E.amount, _E.overkill, _E.damage, _E.resisted, _E.blocked, _E.absorbed, _E.crit, _E.glancing, _E.crushing = "damage", true, ... end,
-  SWING_MISSED            = function (...) wipe(_E); _E.type, _E.miss, _E.offhand, _E.multi, _E.amount = "miss", ... end,
-  RANGE_MISSED            = function (...) wipe(_E); _E.type, _E.ranged, _E.spellID, _E.spellName, _E.school, _E.miss, _E.offhand, _E.multi, _E.amount = "miss", true, ... end,
-  SPELL_MISSED            = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.miss, _E.offhand, _E.multi, _E.amount = "miss", ... end,
-  SPELL_PERIODIC_MISSED   = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.miss, _E.offhand, _E.multi, _E.amount = "miss", ... end,
-  SPELL_PERIODIC_ENERGIZE = function (...) wipe(_E); _E.type, _E.isGain, _E.spellID, _E.spellName, _E.school, _E.amount, _E.powerType = "power", true, ... end,
-  SPELL_PERIODIC_DRAIN    = function (...) wipe(_E); _E.type, _E.isDrain, _E.spellID, _E.spellName, _E.school, _E.amount, _E.powerType, _E.amount2 = "power", true, ... end,
-  SPELL_PERIODIC_LEECH    = function (...) wipe(_E); _E.type, _E.isLeech, _E.spellID, _E.spellName, _E.school, _E.amount, _E.powerType, _E.amount2 = "power", true, ... end,
-  SPELL_STOLEN            = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.spellID2, _E.spellName2, _E.school2, _E.aura = "dispel", ... end,
-  DAMAGE_SHIELD_MISSED    = function (...) wipe(_E); _E.type, _E.shield, _E.spellID, _E.spellName, _E.school, _E.miss, _E.offhand, _E.multi, _E.amount = "miss", true, ... end,
-  SPELL_DISPEL_FAILED     = function (...) wipe(_E); _E.type, _E.miss, _E.spellID, _E.spellName, _E.school, _E.spellID2, _E.spellName2, _E.school2 = "miss", "RESIST", ... end,
-  SPELL_HEAL              = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.amount, _E.overheal, _E.absorbed, _E.crit, _E.multi = "heal", ... end,
-  SPELL_PERIODIC_HEAL     = function (...) wipe(_E); _E.type, _E.isHoT, _E.spellID, _E.spellName, _E.school, _E.amount, _E.overheal, _E.absorbed, _E.crit, _E.multi = "heal", true, ... end,
-  ENVIRONMENTAL_DAMAGE    = function (...) wipe(_E); _E.type, _E.hazard, _E.amount, _E.overkill, _E.damage, _E.resisted, _E.blocked, _E.absorbed, _E.crit, _E.glancing, _E.crushing = "environmental", ... end,
-  SPELL_ENERGIZE          = function (...) wipe(_E); _E.type, _E.isGain, _E.spellID, _E.spellName, _E.school, _E.amount, _E.powerType = "power", true, ... end,
-  SPELL_DRAIN             = function (...) wipe(_E); _E.type, _E.isDrain, _E.spellID, _E.spellName, _E.school, _E.amount, _E.powerType, _E.amount2 = "power", true, ... end,
-  SPELL_LEECH             = function (...) wipe(_E); _E.type, _E.isLeech, _E.spellID, _E.spellName, _E.school, _E.amount, _E.powerType, _E.amount2 = "power", true, ... end,
-  SPELL_INTERRUPT         = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.spellID2, _E.spellName2, _E.school2 = "interrupt", ... end,
-  SPELL_AURA_APPLIED      = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.aura, _E.amount = "aura", ... end,
-  SPELL_AURA_APPLIED_DOSE = function (...) wipe(_E); _E.type, _E.isDose, _E.spellID, _E.spellName, _E.school, _E.aura, _E.amount = "aura", true, ... end,
-  SPELL_AURA_REMOVED      = function (...) wipe(_E); _E.type, _E.faded, _E.spellID, _E.spellName, _E.school, _E.aura, _E.amount = "aura", true, ... end,
-  SPELL_AURA_REMOVED_DOSE = function (...) wipe(_E); _E.type, _E.faded, _E.isDose, _E.spellID, _E.spellName, _E.school, _E.aura, _E.amount = "aura", true, true, ... end,
-  ENCHANT_APPLIED         = function (...) wipe(_E); _E.type, _E.spellName, _E.itemID, _E.itemName = "enchant", ... end,
-  ENCHANT_REMOVED         = function (...) wipe(_E); _E.type, _E.faded, _E.spellName, _E.itemID, _E.itemName = "enchant", true, ... end,
-  SPELL_DISPEL            = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.spellID2, _E.spellName2, _E.school2, _E.aura = "dispel", ... end,
-  SPELL_CAST_START        = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school = "cast", ... end,
-  PARTY_KILL              = function (...) wipe(_E); _E.type = "kill" end,
-  SPELL_EXTRA_ATTACKS     = function (...) wipe(_E); _E.type, _E.spellID, _E.spellName, _E.school, _E.amount = "extraattacks", ... end
+local LOG_EVENT, _R, _T = {},{},{};
+local COMBAT_EVENT_HANDLERS = {
+  SWING_DAMAGE            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.amount, LOG_EVENT.overkill, LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked,
+                                LOG_EVENT.absorbed, LOG_EVENT.crit, LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.multi = ...;
+                            end,
+  RANGE_DAMAGE            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.ranged = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.offhand, LOG_EVENT.multi = ...;
+                            end,
+  DAMAGE_SPLIT            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.offhand, LOG_EVENT.multi = ...;
+                            end,
+  SPELL_DAMAGE            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.offhand, LOG_EVENT.multi = ...;
+                            end,
+  SPELL_PERIODIC_DAMAGE   = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.dot = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing, LOG_EVENT.offhand, LOG_EVENT.multi = ...;
+                            end,
+  SPELL_BUILDING_DAMAGE   = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing = ...;
+                            end,
+  DAMAGE_SHIELD           = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "damage";
+                                LOG_EVENT.shield = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.overkill,
+                                LOG_EVENT.damage, LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing = ...;
+                            end,
+  SWING_MISSED            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.miss, LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  RANGE_MISSED            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.ranged = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.miss,
+                                LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_MISSED            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.miss,
+                                LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_PERIODIC_MISSED   = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.miss,
+                                LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  DAMAGE_SHIELD_MISSED    = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.shield = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.miss,
+                                LOG_EVENT.offhand, LOG_EVENT.multi, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_DISPEL_FAILED     = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "miss";
+                                LOG_EVENT.miss = "RESIST";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.spellID2,
+                                LOG_EVENT.spellName2, LOG_EVENT.school2 = ...;
+                            end,
+  SPELL_PERIODIC_ENERGIZE = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.gain = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.powerType = ...;
+                            end,
+  SPELL_PERIODIC_DRAIN    = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.drain = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.powerType, LOG_EVENT.amount2 = ...;
+                            end,
+  SPELL_PERIODIC_LEECH    = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.leech = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.powerType, LOG_EVENT.amount2 = ...;
+                            end,
+  SPELL_ENERGIZE          = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.gain = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount, LOG_EVENT.powerType = ...;
+                            end,
+  SPELL_DRAIN             = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.drain = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.powerType, LOG_EVENT.amount2 = ...;
+                            end,
+  SPELL_LEECH             = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "power";
+                                LOG_EVENT.leech = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.powerType, LOG_EVENT.amount2 = ...;
+                            end,
+  SPELL_STOLEN            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "dispel";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.spellID2,
+                                LOG_EVENT.spellName2, LOG_EVENT.school2, LOG_EVENT.aura = ...;
+                            end,
+  SPELL_DISPEL            = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "dispel";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.spellID2,
+                                LOG_EVENT.spellName2, LOG_EVENT.school2, LOG_EVENT.aura = ...;
+                            end,
+  SPELL_HEAL              = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "heal";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.overheal, LOG_EVENT.absorbed, LOG_EVENT.crit, LOG_EVENT.multi = ...;
+                            end,
+  SPELL_PERIODIC_HEAL     = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "heal";
+                                LOG_EVENT.hot = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount,
+                                LOG_EVENT.overheal, LOG_EVENT.absorbed, LOG_EVENT.crit, LOG_EVENT.multi = ...;
+                            end,
+  ENVIRONMENTAL_DAMAGE    = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "environmental";
+                                LOG_EVENT.hazard, LOG_EVENT.amount, LOG_EVENT.overkill, LOG_EVENT.damage,
+                                LOG_EVENT.resisted, LOG_EVENT.blocked, LOG_EVENT.absorbed, LOG_EVENT.crit,
+                                LOG_EVENT.glancing, LOG_EVENT.crushing = ...;
+                            end,
+  SPELL_INTERRUPT         = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "interrupt";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.spellID2,
+                                LOG_EVENT.spellName2, LOG_EVENT.school2 = ...;
+                            end,
+  SPELL_AURA_APPLIED      = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "aura";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.aura, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_AURA_APPLIED_DOSE = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "aura";
+                                LOG_EVENT.dose = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.aura, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_AURA_REMOVED      = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "aura";
+                                LOG_EVENT.faded = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.aura, LOG_EVENT.amount = ...;
+                            end,
+  SPELL_AURA_REMOVED_DOSE = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "aura";
+                                LOG_EVENT.faded = true;
+                                LOG_EVENT.dose = true;
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.aura, LOG_EVENT.amount = ...;
+                            end,
+  ENCHANT_APPLIED         = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "enchant";
+                                LOG_EVENT.spellName, LOG_EVENT.itemID, LOG_EVENT.itemName = ...;
+                            end,
+  ENCHANT_REMOVED         = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "enchant";
+                                LOG_EVENT.faded = true;
+                                LOG_EVENT.spellName, LOG_EVENT.itemID, LOG_EVENT.itemName = ...;
+                            end,
+  SPELL_CAST_START        = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "cast";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school = ...;
+                            end,
+  PARTY_KILL              = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "kill";
+                            end,
+  SPELL_EXTRA_ATTACKS     = function (...)
+                                wipe(LOG_EVENT);
+                                LOG_EVENT.type = "extraattacks";
+                                LOG_EVENT.spellID, LOG_EVENT.spellName, LOG_EVENT.school, LOG_EVENT.amount = ...;
+                            end
 };
 local FULL_PARSE = {
   SPELL_AURA_APPLIED = true,
@@ -170,7 +352,7 @@ end;
 function lib:BroadCast(event)
   for key,fn in pairs(self.Callbacks) do
     local obj = CoreObject[key];
-    local _, catch = pcall(fn, obj, _E)
+    local _, catch = pcall(fn, obj, LOG_EVENT)
     if(catch) then
         CoreObject:HandleError("Parser", "BroadCast", catch)
     end
@@ -180,7 +362,7 @@ end;
 --[[ COMBAT LOG PARSING ]]--

 function lib:COMBAT_LOG_EVENT_UNFILTERED(timestamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags, ...)
-  local fn = SUB_EVENT_HANDLERS[event]
+  local fn = COMBAT_EVENT_HANDLERS[event]
   if (not fn) then return end

   if (sourceGUID == destGUID and _T[destGUID] and event == "SPELL_DAMAGE") then
@@ -207,18 +389,18 @@ function lib:COMBAT_LOG_EVENT_UNFILTERED(timestamp, event, hideCaster, sourceGUI
   end

   fn(...)
-
-  _E.hostile = flagTest(sourceFlags, COMBATLOG_OBJECT_REACTION_HOSTILE)
-  _E.sourceGUID = sourceGUID
-  _E.sourceName = sourceName
-  _E.sourceFlags = sourceFlags
-  _E.sourceUnit = sourceUnit
-  _E.destGUID = destGUID
-  _E.destName = destName
-  _E.destFlags = destFlags
-  _E.destUnit = destUnit
-
-  if (_E.type == "miss" and _E.miss == "REFLECT" and _E.destUnit == "player") then
+
+  LOG_EVENT.hostile = flagTest(sourceFlags, COMBATLOG_OBJECT_REACTION_HOSTILE)
+  LOG_EVENT.sourceGUID = sourceGUID
+  LOG_EVENT.sourceName = sourceName
+  LOG_EVENT.sourceFlags = sourceFlags
+  LOG_EVENT.sourceUnit = sourceUnit
+  LOG_EVENT.destGUID = destGUID
+  LOG_EVENT.destName = destName
+  LOG_EVENT.destFlags = destFlags
+  LOG_EVENT.destUnit = destUnit
+
+  if (LOG_EVENT.type == "miss" and LOG_EVENT.miss == "REFLECT" and LOG_EVENT.destUnit == "player") then
     for guid, reflectTime in pairs(_T) do
       if (timestamp - reflectTime > REFLECT_HOLD_TIME) then
         _T[guid] = nil
@@ -227,7 +409,7 @@ function lib:COMBAT_LOG_EVENT_UNFILTERED(timestamp, event, hideCaster, sourceGUI
     end

     _T[sourceGUID] = timestamp
-    _R[sourceGUID] = _E.spellID
+    _R[sourceGUID] = LOG_EVENT.spellID
   end

   self:BroadCast()
diff --git a/SVUI_!Core/system/misc.lua b/SVUI_!Core/system/misc.lua
index e58ec7b..bff2e6e 100644
--- a/SVUI_!Core/system/misc.lua
+++ b/SVUI_!Core/system/misc.lua
@@ -521,8 +521,145 @@ local function StupidHatEventHandler()
 	end
 end

-local function ChatLogEventHandler(...)
-	local _, subEvent, _, sourceGUID, sourceName, _, _, destGUID, destName, _, _, spellID, _, _, otherSpellID = ...
+-- local function ChatLogEventHandler(...)
+-- 	local _, subEvent, _, sourceGUID, sourceName, _, _, destGUID, destName, _, _, spellID, _, _, otherSpellID = ...
+--
+-- 	if not sourceName then return end
+--
+-- 	if(REACTION_INTERRUPT) then
+-- 		if ((spellID == 6770) and (destName == PlayerName) and (subEvent == "SPELL_AURA_APPLIED" or subEvent == "SPELL_AURA_REFRESH")) then
+-- 			local msg = SAPPED_MESSAGE[random(1,6)]
+-- 			SendChatMessage(msg, "SAY")
+-- 			SV:AddonMessage("Sapped by: "..sourceName)
+-- 			DoEmote("CRACK", sourceName)
+-- 		elseif(subEvent == "SPELL_INTERRUPT" and sourceGUID == UnitGUID("player") and IsInGroup()) then
+-- 			SendChatMessage(INTERRUPTED.." "..destName..": "..GetSpellLink(otherSpellID), MsgTest())
+-- 		end
+-- 	end
+--
+-- 	if(REACTION_WOOT) then
+-- 		for key, value in pairs(Reactions.Woot) do
+-- 			if spellID == key and value == true and destName == PlayerName and sourceName ~= PlayerName and (subEvent == "SPELL_AURA_APPLIED" or subEvent == "SPELL_CAST_SUCCESS") then
+-- 				Thanks_Emote(sourceName)
+-- 				--SendChatMessage(L["Thanks for "]..GetSpellLink(spellID)..", "..sourceName, "WHISPER", nil, sourceName)
+-- 				print(GetSpellLink(spellID)..L[" received from "]..sourceName)
+-- 			end
+-- 		end
+-- 	end
+--
+-- 	if(REACTION_LOOKY) then
+-- 		local outbound;
+-- 		local spells = Reactions.LookWhatICanDo
+-- 		local _, _, difficultyID = GetInstanceInfo()
+--
+-- 		if(difficultyID ~= 0 and subEvent == "SPELL_CAST_SUCCESS") then
+-- 			if(not (sourceGUID == UnitGUID("player") and sourceName == PlayerName)) then
+-- 				for i, spells in pairs(spells) do
+-- 					if(spellID == spells) then
+-- 						if(destName == nil) then
+-- 							outbound = (L["%s used a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 						else
+-- 							outbound = (L["%s used a %s."]):format(sourceName, GetSpellLink(spellID).." -> "..destName)
+-- 						end
+-- 						if(REACTION_CHAT) then
+-- 							SendChatMessage(outbound, MsgTest())
+-- 						else
+-- 							print(outbound)
+-- 						end
+-- 					end
+-- 				end
+-- 			else
+-- 				if(not (sourceGUID == UnitGUID("player") and sourceName == PlayerName)) then return end
+-- 				for i, spells in pairs(spells) do
+-- 					if(spellID == spells) then
+-- 						if(destName == nil) then
+-- 							outbound = (L["%s used a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 						else
+-- 							outbound = GetSpellLink(spellID).." -> "..destName
+-- 						end
+-- 						if(REACTION_CHAT) then
+-- 							SendChatMessage(outbound, MsgTest())
+-- 						else
+-- 							print(outbound)
+-- 						end
+-- 					end
+-- 				end
+-- 			end
+-- 		end
+-- 	end
+--
+-- 	if(REACTION_SHARE) then
+-- 		if not IsInGroup() or InCombatLockdown() or not subEvent or not spellID then return end
+-- 		if not UnitInRaid(sourceName) and not UnitInParty(sourceName) then return end
+--
+-- 		local sourceName = format(sourceName:gsub("%-[^|]+", ""))
+-- 		if(not sourceName) then return end
+-- 		local thanks = false
+-- 		local outbound
+-- 		if subEvent == "SPELL_CAST_SUCCESS" then
+-- 			-- Feasts
+-- 			if (spellID == 126492 or spellID == 126494) then
+-- 				outbound = (L["%s has prepared a %s - [%s]."]):format(sourceName, GetSpellLink(spellID), SPELL_STAT1_NAME)
+-- 			elseif (spellID == 126495 or spellID == 126496) then
+-- 				outbound = (L["%s has prepared a %s - [%s]."]):format(sourceName, GetSpellLink(spellID), SPELL_STAT2_NAME)
+-- 			elseif (spellID == 126501 or spellID == 126502) then
+-- 				outbound = (L["%s has prepared a %s - [%s]."]):format(sourceName, GetSpellLink(spellID), SPELL_STAT3_NAME)
+-- 			elseif (spellID == 126497 or spellID == 126498) then
+-- 				outbound = (L["%s has prepared a %s - [%s]."]):format(sourceName, GetSpellLink(spellID), SPELL_STAT4_NAME)
+-- 			elseif (spellID == 126499 or spellID == 126500) then
+-- 				outbound = (L["%s has prepared a %s - [%s]."]):format(sourceName, GetSpellLink(spellID), SPELL_STAT5_NAME)
+-- 			elseif (spellID == 104958 or spellID == 105193 or spellID == 126503 or spellID == 126504 or spellID == 145166 or spellID == 145169 or spellID == 145196) then
+-- 				outbound = (L["%s has prepared a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 			-- Refreshment Table
+-- 			elseif spellID == 43987 then
+-- 				outbound = (L["%s has prepared a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 			-- Ritual of Summoning
+-- 			elseif spellID == 698 then
+-- 				outbound = (L["%s is casting %s. Click!"]):format(sourceName, GetSpellLink(spellID))
+-- 			-- Piccolo of the Flaming Fire
+-- 			elseif spellID == 18400 then
+-- 				outbound = (L["%s used a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 			end
+-- 			if(outbound) then thanks = true end
+-- 		elseif subEvent == "SPELL_SUMMON" then
+-- 			-- Repair Bots
+-- 			if Reactions.Bots[spellID] then
+-- 				outbound = (L["%s has put down a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 				thanks = true
+-- 			end
+-- 		elseif subEvent == "SPELL_CREATE" then
+-- 			-- Ritual of Souls and MOLL-E
+-- 			if (spellID == 29893 or spellID == 54710) then
+-- 				outbound = (L["%s has put down a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 				thanks = true
+-- 			-- Toys
+-- 			elseif Reactions.Toys[spellID] then
+-- 				outbound = (L["%s has put down a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 			-- Portals
+-- 			elseif Reactions.Portals[spellID] then
+-- 				outbound = (L["%s is casting %s."]):format(sourceName, GetSpellLink(spellID))
+-- 			end
+-- 		elseif subEvent == "SPELL_AURA_APPLIED" then
+-- 			-- Turkey Feathers and Party G.R.E.N.A.D.E.
+-- 			if (spellID == 61781 or ((spellID == 51508 or spellID == 51510) and destName == PlayerName)) then
+-- 				outbound = (L["%s used a %s."]):format(sourceName, GetSpellLink(spellID))
+-- 			end
+-- 		end
+--
+-- 		if(outbound) then
+-- 			if(REACTION_CHAT) then
+-- 				SendChatMessage(outbound, MsgTest(true))
+-- 			else
+-- 				print(outbound)
+-- 			end
+-- 			if(thanks and sourceName) then
+-- 				Thanks_Emote(sourceName)
+-- 			end
+-- 		end
+-- 	end
+-- end
+local ChatLogEventHandler = function(self, EVENT)
+	local subEvent, sourceGUID, sourceName, destGUID, destName, spellID, otherSpellID = EVENT.type, EVENT.sourceGUID, EVENT.sourceName, EVENT.destGUID, EVENT.destName, EVENT.spellID, EVENT.spellID2;

 	if not sourceName then return end

@@ -658,12 +795,40 @@ local function ChatLogEventHandler(...)
 		end
 	end
 end
+-- local ReactionListener_OnEvent = function(self, event, ...)
+-- 	if(event == "ZONE_CHANGED_NEW_AREA") then
+-- 		StupidHatEventHandler()
+-- 	elseif(event == "COMBAT_LOG_EVENT_UNFILTERED") then
+-- 		ChatLogEventHandler(...)
+-- 	end
+-- end
+--
+-- function SV:ToggleReactions()
+-- 	local settings = SV.db.Extras
+--
+-- 	REACTION_INTERRUPT = settings.pvpinterrupt
+-- 	REACTION_WOOT = settings.woot
+-- 	REACTION_LOOKY = settings.lookwhaticando
+-- 	REACTION_SHARE = settings.sharingiscaring
+-- 	REACTION_EMOTE = settings.reactionEmote
+-- 	REACTION_CHAT = settings.reactionChat
+--
+-- 	if(settings.stupidhat) then
+-- 		ReactionListener:RegisterEvent("ZONE_CHANGED_NEW_AREA")
+-- 	else
+-- 		ReactionListener:UnregisterEvent("ZONE_CHANGED_NEW_AREA")
+-- 	end
+--
+-- 	if(not REACTION_SHARE) and (not REACTION_INTERRUPT) and (not REACTION_WOOT) and (not REACTION_LOOKY) then
+-- 		ReactionListener:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+-- 	else
+-- 		ReactionListener:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+-- 	end
+-- end

 local ReactionListener_OnEvent = function(self, event, ...)
 	if(event == "ZONE_CHANGED_NEW_AREA") then
 		StupidHatEventHandler()
-	elseif(event == "COMBAT_LOG_EVENT_UNFILTERED") then
-		ChatLogEventHandler(...)
 	end
 end

@@ -684,9 +849,9 @@ function SV:ToggleReactions()
 	end

 	if(not REACTION_SHARE) and (not REACTION_INTERRUPT) and (not REACTION_WOOT) and (not REACTION_LOOKY) then
-		ReactionListener:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+		SV.Events:Unregister("COMBAT_LOG_EVENT_UNFILTERED", SV)
 	else
-		ReactionListener:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+		SV.Events:Register("COMBAT_LOG_EVENT_UNFILTERED", SV, ChatLogEventHandler)
 	end
 end

diff --git a/SVUI_ActionBars/libs/LibActionButton-1.0/LibActionButton-1.0.lua b/SVUI_ActionBars/libs/LibActionButton-1.0/LibActionButton-1.0.lua
index da6fd9f..23712e8 100644
--- a/SVUI_ActionBars/libs/LibActionButton-1.0/LibActionButton-1.0.lua
+++ b/SVUI_ActionBars/libs/LibActionButton-1.0/LibActionButton-1.0.lua
@@ -3,16 +3,16 @@ Copyright (c) 2010-2014, Hendrik "nevcairiel" Leppkes <h.leppkes@gmail.com>

 All rights reserved.

-Redistribution and use in source and binary forms, with or without
+Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

-    * Redistributions of source code must retain the above copyright notice,
+    * Redistributions of source code must retain the above copyright notice,
       this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright notice,
-      this list of conditions and the following disclaimer in the documentation
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
-    * Neither the name of the developer nor the names of its contributors
-      may be used to endorse or promote products derived from this software without
+    * Neither the name of the developer nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
       specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
@@ -67,6 +67,9 @@ lib.activeButtons = lib.activeButtons or {}
 lib.actionButtons = lib.actionButtons or {}
 lib.nonActionButtons = lib.nonActionButtons or {}

+lib.ChargeCooldowns = lib.ChargeCooldowns or {}
+lib.NumChargeCooldowns = lib.NumChargeCooldowns or 0
+
 lib.unusedOverlayGlows = lib.unusedOverlayGlows or {}
 lib.numOverlays = lib.numOverlays or 0

@@ -1028,6 +1031,9 @@ function Update(self)
 		end
 		self.cooldown:Hide()
 		self:SetChecked(false)
+		if self.chargeCooldown then
+			EndChargeCooldown(self.chargeCooldown)
+		end
 	end

 	-- Add a green border if button is an equipped item
@@ -1193,6 +1199,38 @@ function HookCooldown(button)
 	end
 end

+function EndChargeCooldown(self)
+	self:Hide()
+	self:SetParent(UIParent)
+	self.parent.chargeCooldown = nil
+	self.parent = nil
+	tinsert(lib.ChargeCooldowns, self)
+end
+
+local function StartChargeCooldown(parent, chargeStart, chargeDuration)
+	if not parent.chargeCooldown then
+		local cooldown = tremove(lib.ChargeCooldowns)
+		if not cooldown then
+			lib.NumChargeCooldowns = lib.NumChargeCooldowns + 1
+			cooldown = CreateFrame("Cooldown", "LAB10ChargeCooldown"..lib.NumChargeCooldowns, parent, "CooldownFrameTemplate");
+			cooldown:SetScript("OnCooldownDone", EndChargeCooldown)
+			cooldown:SetHideCountdownNumbers(true)
+			cooldown:SetDrawEdge(true)
+			cooldown:SetDrawSwipe(false)
+		end
+		cooldown:SetParent(parent)
+		cooldown:SetAllPoints(parent)
+		cooldown:SetFrameStrata("TOOLTIP")
+		cooldown:Show()
+		parent.chargeCooldown = cooldown
+		cooldown.parent = parent
+	end
+	parent.chargeCooldown:SetCooldown(chargeStart, chargeDuration)
+	if not chargeStart or chargeStart == 0 then
+		EndChargeCooldown(parent.chargeCooldown)
+	end
+end
+
 function OnCooldownDone(self)
 	self:SetScript("OnCooldownDone", nil)
 	UpdateCooldown(self:GetParent())
@@ -1200,7 +1238,8 @@ end

 function UpdateCooldown(self)
 	local locStart, locDuration = self:GetLossOfControlCooldown()
-	local start, duration, enable, charges, maxCharges = self:GetCooldown()
+	local start, duration, enable = self:GetCooldown()
+	local charges, maxCharges, chargeStart, chargeDuration = self:GetCharges()

 	if (locStart + locDuration) > (start + duration) then
 		if self.cooldown.currentCooldownType ~= COOLDOWN_TYPE_LOSS_OF_CONTROL then
@@ -1220,6 +1259,11 @@ function UpdateCooldown(self)
 		if locStart > 0 then
 			self.cooldown:SetScript("OnCooldownDone", OnCooldownDone)
 		end
+		if charges and maxCharges and maxCharges > 0 and charges < maxCharges then
+			StartChargeCooldown(self, chargeStart, chargeDuration)
+		elseif self.chargeCooldown then
+			EndChargeCooldown(self.chargeCooldown)
+		end
 		CooldownFrame_SetTimer(self.cooldown, start, duration, enable, charges, maxCharges)
 	end
 end