Advertisement
Guest User

Untitled

a guest
Oct 22nd, 2018
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 72.90 KB | None | 0 0
  1. --[[   ____    ______
  2.       /\  _`\ /\__  _\   __
  3.  __  _\ \ \/\_\/_/\ \/ /_\ \___
  4. /\ \/'\\ \ \/_/_ \ \ \/\___  __\
  5. \/>  </ \ \ \L\ \ \ \ \/__/\_\_/
  6.  /\_/\_\ \ \____/  \ \_\  \/_/
  7.  \//\/_/  \/___/    \/_/
  8.  
  9.  [=====================================]
  10.  [  Author: Dandraffbal-Stormreaver US ]
  11.  [  xCT+ Version 4.x.x                 ]
  12.  [  ⓒ2018. All Rights Reserved.        ]
  13.  [====================================]]
  14.  
  15. local ADDON_NAME, addon = ...
  16.  
  17. -- Shorten my handle
  18. local x = addon.engine
  19.  
  20. -- up values
  21. local _, _G, sformat, mfloor, mabs, ssub, smatch, sgsub, s_upper, s_lower, string, tinsert, tremove, ipairs, pairs, print, tostring, tonumber, select, unpack =
  22.   nil, _G, string.format, math.floor, math.abs, string.sub, string.match, string.gsub, string.upper, string.lower, string, table.insert, table.remove, ipairs, pairs, print, tostring, tonumber, select, unpack
  23.  
  24. --UTF8 Functions
  25. local utf8 = {
  26.   len = string.utf8len,
  27.   sub = string.utf8sub,
  28.   reverse = string.utf8reverse,
  29.   upper = string.utf8upper,
  30.   lower = string.utf8lower
  31. }
  32.  
  33. local xCP = LibStub and LibStub("xCombatParser-1.0", true)
  34. if not xCP then print("Something went wrong when xCT+ tried to load. Please reinstall and inform the author.") end
  35.  
  36.  
  37. --[=====================================================[
  38.  Holds cached spells, buffs, and debuffs
  39. --]=====================================================]
  40. x.spellCache = {
  41.   buffs = { },
  42.   debuffs = { },
  43.   spells = { },
  44.   procs = { },
  45.   items = { },
  46.   damage = { },
  47.   healing = { },
  48. }
  49.  
  50. --[=====================================================[
  51.  A Simple Managed Table Pool
  52. --]=====================================================]
  53. local tpool = { }
  54. local function tnew( )
  55.   if #tpool > 0 then
  56.     local t = tpool[1]
  57.     tremove( tpool, 1 )
  58.     return t
  59.   else
  60.     return { }
  61.   end
  62. end
  63. local function tdel( t )
  64.   tinsert( tpool, t )
  65. end
  66.  
  67. --[=====================================================[
  68.  Power Type Definitions
  69. --]=====================================================]
  70. x.POWER_LOOKUP = {
  71.     [0] = "MANA",
  72.     [1] = "RAGE",
  73.     [2] = "FOCUS",
  74.     [3] = "ENERGY",
  75.     [4] = "COMBO_POINTS",
  76.     [5] = "RUNES",
  77.     [6] = "RUNIC_POWER",
  78.     [7] = "SOUL_SHARDS",
  79.     [8] = "LUNAR_POWER",
  80.     [9] = "HOLY_POWER",
  81.     [10] = "ALTERNATE_POWER_INDEX",
  82.     [11] = "MAELSTROM",
  83.     [12] = "CHI",
  84.     [13] = "INSANITY",
  85.     [14] = "BURNING_EMBERS",
  86.     [15] = "DEMONIC_FURY",
  87.     [16] = "ARCANE_CHARGES",
  88.     [17] = "FURY",
  89.     [18] = "PAIN",
  90. }
  91.  
  92.  
  93. --[=====================================================[
  94.  Holds player info; use AddOn:UpdatePlayer()
  95. --]=====================================================]
  96. x.player = {
  97.   unit = "player",
  98.   guid = nil, -- dont get the guid until we load
  99.   class = "unknown",
  100.   name = "unknown",
  101.   spec = -1,
  102. }
  103.  
  104. --[=====================================================[
  105.  AddOn:UpdatePlayer()
  106.     Updates important information about the player we
  107.   need inorder to correctly show combat text events.
  108. --]=====================================================]
  109. function x:UpdatePlayer()
  110.   -- Set the Player's Current Playing Unit
  111.   if x.player.unit == "custom" then
  112.     --CombatTextSetActiveUnit(x.player.customUnit)
  113.   else
  114.     if UnitHasVehicleUI("player") then
  115.       x.player.unit = "vehicle"
  116.     else
  117.       x.player.unit = "player"
  118.     end
  119.     CombatTextSetActiveUnit(x.player.unit)
  120.   end
  121.  
  122.   -- Set Player's Information
  123.   x.player.name   = UnitName("player")
  124.   x.player.class  = select(2, UnitClass("player"))
  125.   x.player.guid   = UnitGUID("player")
  126.  
  127.   local activeTalentGroup = GetActiveSpecGroup(false, false)
  128.   x.player.spec = GetSpecialization(false, false, activeTalentGroup)
  129. end
  130.  
  131. --[=====================================================[
  132.  AddOn:UpdateCombatTextEvents(
  133.     enable,     [BOOL] - True tp enable the events, false to disable them
  134.   )
  135.     Registers or updates the combat text event frame
  136. --]=====================================================]
  137. function x:UpdateCombatTextEvents(enable)
  138.   local f = nil
  139.   if x.combatEvents then
  140.     x.combatEvents:UnregisterAllEvents()
  141.     f = x.combatEvents
  142.   else
  143.     f = CreateFrame("FRAME")
  144.   end
  145.  
  146.   if enable then
  147.     -- Enabled Combat Text
  148.     f:RegisterEvent("COMBAT_TEXT_UPDATE")
  149.     f:RegisterEvent("UNIT_HEALTH")
  150.     f:RegisterEvent("UNIT_POWER_UPDATE")
  151.     f:RegisterEvent("PLAYER_REGEN_DISABLED")
  152.     f:RegisterEvent("PLAYER_REGEN_ENABLED")
  153.     f:RegisterEvent("UNIT_ENTERED_VEHICLE")
  154.     f:RegisterEvent("UNIT_EXITING_VEHICLE")
  155.     f:RegisterEvent("PLAYER_ENTERING_WORLD")
  156.     f:RegisterEvent("UNIT_PET")
  157.     f:RegisterEvent("PLAYER_TARGET_CHANGED")
  158.     f:RegisterEvent("SPELL_ACTIVATION_OVERLAY_GLOW_SHOW")
  159.  
  160.     -- if runes
  161.     f:RegisterEvent("RUNE_POWER_UPDATE")
  162.  
  163.     -- if loot
  164.     f:RegisterEvent("CHAT_MSG_LOOT")
  165.     f:RegisterEvent("CHAT_MSG_CURRENCY")
  166.     f:RegisterEvent("CHAT_MSG_MONEY")
  167.  
  168.     -- damage and healing
  169.     --f:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
  170.  
  171.     -- Class combo points
  172.     f:RegisterEvent("UNIT_AURA")
  173.     f:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
  174.     --f:RegisterEvent("UNIT_COMBO_POINTS")
  175.     f:RegisterEvent("PLAYER_TARGET_CHANGED")
  176.  
  177.     x.combatEvents = f
  178.     f:SetScript("OnEvent", x.OnCombatTextEvent)
  179.  
  180.     xCP:RegisterCombat(x.CombatLogEvent)
  181.   else
  182.     -- Disabled Combat Text
  183.     f:SetScript("OnEvent", nil)
  184.     xCP:UnregisterCombat(x.CombatLogEvent)
  185.   end
  186. end
  187.  
  188. --[=====================================================[
  189.  Fast Boolean Lookups
  190. --]=====================================================]
  191. local function ShowMissTypes() return x.db.profile.frames.damage.showDodgeParryMiss end
  192. local function ShowResistances() return x.db.profile.frames.damage.showDamageReduction end
  193. local function ShowHonor() return x.db.profile.frames.damage.showHonorGains end
  194. local function ShowFaction() return x.db.profile.frames.general.showRepChanges end
  195. local function ShowReactives() return x.db.profile.frames.procs.enabledFrame end
  196. local function ShowLowResources() return x.db.profile.frames.general.showLowManaHealth end
  197. local function ShowCombatState() return x.db.profile.frames.general.showCombatState end
  198. local function ShowFriendlyNames() return x.db.profile.frames["healing"].showFriendlyHealers end
  199. local function ShowColoredFriendlyNames() return x.db.profile.frames["healing"].enableClassNames end
  200. local function ShowHealingRealmNames() return x.db.profile.frames["healing"].enableRealmNames end
  201. local function ShowOnlyMyHeals() return x.db.profile.frames.healing.showOnlyMyHeals end
  202. local function ShowOnlyMyPetsHeals() return x.db.profile.frames.healing.showOnlyPetHeals end
  203. local function ShowDamage() return x.db.profile.frames["outgoing"].enableOutDmg end
  204. local function ShowHealing() return x.db.profile.frames["outgoing"].enableOutHeal end
  205. local function ShowAbsorbs() return x.db.profile.frames["outgoing"].enableOutAbsorbs end
  206. local function ShowPetDamage() return x.db.profile.frames["outgoing"].enablePetDmg end
  207. local function ShowPetAutoAttack() return x.db.profile.frames["outgoing"].enablePetAutoAttack end
  208. local function ShowVehicleDamage() return x.db.profile.frames["outgoing"].enableVehicleDmg end
  209. local function ShowKillCommand() return x.db.profile.frames["outgoing"].enableKillCommand end
  210. local function ShowAutoAttack() return x.db.profile.frames["outgoing"].enableAutoAttack end -- Also see ShowSwingCrit
  211. local function ShowDots() return x.db.profile.frames["outgoing"].enableDotDmg end
  212. local function ShowHots() return x.db.profile.frames["outgoing"].enableHots end
  213. local function ShowImmunes() return x.db.profile.frames["outgoing"].enableImmunes end -- outgoing immunes
  214. local function ShowMisses() return x.db.profile.frames["outgoing"].enableMisses end -- outgoing misses
  215. local function ShowPartialMisses() return x.db.profile.frames["outgoing"].enablePartialMisses end
  216. local function ShowSwingCrit() return x.db.profile.frames["critical"].showSwing end
  217. local function ShowSwingCritPrefix() return x.db.profile.frames["critical"].prefixSwing end
  218. local function ShowPetCrits() return x.db.profile.frames["critical"].petCrits end
  219. local function ShowLootItems() return x.db.profile.frames["loot"].showItems end
  220. local function ShowLootItemTypes() return x.db.profile.frames["loot"].showItemTypes end
  221. local function ShowLootMoney() return x.db.profile.frames["loot"].showMoney end
  222. local function ShowLootCurrency() return x.db.profile.frames["loot"].showCurrency end
  223. local function ShowTotalItems() return x.db.profile.frames["loot"].showItemTotal end
  224. local function ShowLootCrafted() return x.db.profile.frames["loot"].showCrafted end
  225. local function ShowLootQuest() return x.db.profile.frames["loot"].showQuest end
  226. local function ShowColorBlindMoney() return x.db.profile.frames["loot"].colorBlindMoney end
  227. local function GetLootQuality() return x.db.profile.frames["loot"].filterItemQuality end
  228. local function ShowLootIcons() return x.db.profile.frames["loot"].iconsEnabled end
  229. local function GetLootIconSize() return x.db.profile.frames["loot"].iconsSize end
  230. local function ShowInterrupts() return x.db.profile.frames["general"].showInterrupts end
  231. local function ShowDispells() return x.db.profile.frames["general"].showDispells end
  232. local function ShowPartyKill() return x.db.profile.frames["general"].showPartyKills end
  233. local function ShowBuffs() return x.db.profile.frames["general"].showBuffs end
  234. local function ShowDebuffs() return x.db.profile.frames["general"].showDebuffs end
  235. local function ShowOverHealing() return x.db.profile.frames["healing"].enableOverHeal end
  236. local function HideAbsorbedHealing() return x.db.profile.frames["healing"].hideAbsorbedHeals end
  237. local function ShowEnergyGains() return x.db.profile.frames["power"].showEnergyGains end
  238. local function ShowPeriodicEnergyGains() return x.db.profile.frames["power"].showPeriodicEnergyGains end
  239. local function ShowEnergyTypes() return x.db.profile.frames["power"].showEnergyType end
  240. local function ShowIncomingAutoAttackIcons() return x.db.profile.frames["damage"].iconsEnabledAutoAttack end
  241.  
  242. -- These settings are for the overhealing that the player does
  243. local function ShowOutgoingOverHealing() return x.db.profile.frames["outgoing"].enableOverhealing end
  244. local function IsOutgoingOverHealingFormatted() return x.db.profile.frames["outgoing"].enableOverhealingFormat end
  245. local function FormatOutgoingOverhealing(amount) return x.db.profile.frames["outgoing"].overhealingPrefix .. amount .. x.db.profile.frames["outgoing"].overhealingPostfix end
  246.  
  247. -- TODO: Add Combo Point Support
  248. local function ShowRogueComboPoints() return false end -- x.db.profile.spells.combo["ROGUE"][COMBAT_TEXT_SHOW_COMBO_POINTS_TEXT] and x.player.class == "ROGUE" end
  249. local function ShowFeralComboPoints() return false end -- x.db.profile.spells.combo["DRUID"][2][COMBAT_TEXT_SHOW_COMBO_POINTS_TEXT] and x.player.class == "DRUID" and x.player.spec == 2 end
  250. local function ShowMonkChi() return false end -- return x.db.profile.spells.combo["MONK"][CHI] and x.player.class == "MONK" end
  251. local function ShowPaladinHolyPower() return false end -- return x.db.profile.spells.combo["PALADIN"][HOLY_POWER] and x.player.class == "PALADIN" end
  252. local function ShowPriestShadowOrbs() return false end -- return x.db.profile.spells.combo["PRIEST"][3][SHADOW_ORBS] and x.player.class == "PRIEST" and x.player.spec == 3 end
  253. local function ShowWarlockSoulShards() return false end -- return x.db.profile.spells.combo["WARLOCK"][1][SOUL_SHARDS] and x.player.class == "WARLOCK" and x.player.spec == 1 end
  254. local function ShowWarlockDemonicFury() return false end -- return x.db.profile.spells.combo["WARLOCK"][2][DEMONIC_FURY] and x.player.class == "WARLOCK" and x.player.spec == 2 end
  255. local function ShowWarlockBurningEmbers() return false end -- return x.db.profile.spells.combo["WARLOCK"][3][BURNING_EMBERS] and x.player.class == "WARLOCK" and x.player.spec == 3 end
  256.  
  257. local function ClearWhenLeavingCombat() return x.db.profile.frameSettings.clearLeavingCombat end
  258.  
  259. local function MergeIncomingHealing() return x.db.profile.spells.mergeHealing end
  260. local function MergeMeleeSwings() return x.db.profile.spells.mergeSwings end
  261. local function MergeRangedAttacks() return x.db.profile.spells.mergeRanged end
  262. local function MergePetAttacks() return x.db.profile.spells.mergePet end
  263. local function MergeCriticalsWithOutgoing() return x.db.profile.spells.mergeCriticalsWithOutgoing end
  264. local function MergeCriticalsByThemselves() return x.db.profile.spells.mergeCriticalsByThemselves end
  265. local function MergeDontMergeCriticals() return x.db.profile.spells.mergeDontMergeCriticals end
  266. local function MergeHideMergedCriticals() return x.db.profile.spells.mergeHideMergedCriticals end
  267. local function MergeDispells() return x.db.profile.spells.mergeDispells end
  268.  
  269. local function FilterPlayerPower(value) return x.db.profile.spellFilter.filterPowerValue > value end
  270. local function FilterOutgoingDamage(value, critical)
  271.     if critical and x.db.profile.spellFilter.filterOutgoingDamageCritEnabled then
  272.         return x.db.profile.spellFilter.filterOutgoingDamageCritValue > value
  273.     else
  274.         return x.db.profile.spellFilter.filterOutgoingDamageValue > value
  275.     end
  276. end
  277. local function FilterOutgoingHealing(value, critical)
  278.     if critical and x.db.profile.spellFilter.filterOutgoingHealingCritEnabled then
  279.         return x.db.profile.spellFilter.filterOutgoingHealingCritValue > value
  280.     else
  281.         return x.db.profile.spellFilter.filterOutgoingHealingValue > value
  282.     end
  283. end
  284. local function FilterIncomingDamage(value, critical)
  285.     if critical and x.db.profile.spellFilter.filterIncomingDamageCritEnabled then
  286.         return x.db.profile.spellFilter.filterIncomingDamageCritValue > value
  287.     else
  288.         return x.db.profile.spellFilter.filterIncomingDamageValue > value
  289.     end
  290. end
  291. local function FilterIncomingHealing(value, critical)
  292.     if critical and x.db.profile.spellFilter.filterIncomingHealingCritEnabled then
  293.         return x.db.profile.spellFilter.filterIncomingHealingCritValue > value
  294.     else
  295.         return x.db.profile.spellFilter.filterIncomingHealingValue > value
  296.     end
  297. end
  298. local function TrackSpells() return x.db.profile.spellFilter.trackSpells end
  299.  
  300. local function IsResourceDisabled( resource, amount )
  301.     if resource == "ECLIPSE" then
  302.         if amount > 0 then
  303.             return x.db.profile.frames["power"].disableResource_ECLIPSE_positive
  304.         elseif amount < 0 then
  305.             return x.db.profile.frames["power"].disableResource_ECLIPSE_negative
  306.         end
  307.     end
  308.     if x.db.profile.frames["power"]["disableResource_"..resource] ~= nil then
  309.         return x.db.profile.frames["power"]["disableResource_"..resource]
  310.     end
  311.     return true
  312. end
  313.  
  314. local function IsBearForm() return GetShapeshiftForm() == 1 and x.player.class == "DRUID" end
  315. local function IsSpellFiltered(spellID)
  316.   local spell = x.db.profile.spellFilter.listSpells[tostring(spellID)]
  317.   if x.db.profile.spellFilter.whitelistSpells then
  318.     return not spell
  319.   end
  320.   return spell
  321. end
  322. local function IsBuffFiltered(name)
  323.   local spell = x.db.profile.spellFilter.listBuffs[name]
  324.   if x.db.profile.spellFilter.whitelistBuffs then
  325.     return not spell
  326.   end
  327.   return spell
  328. end
  329. local function IsDebuffFiltered(name)
  330.   local spell = x.db.profile.spellFilter.listDebuffs[name]
  331.   if x.db.profile.spellFilter.whitelistDebuffs then
  332.     return not spell
  333.   end
  334.   return spell
  335. end
  336. local function IsProcFiltered(name)
  337.   local spell = x.db.profile.spellFilter.listProcs[name]
  338.   if x.db.profile.spellFilter.whitelistProcs then
  339.     return not spell
  340.   end
  341.   return spell
  342. end
  343. local function IsItemFiltered(name)
  344.   local spell = x.db.profile.spellFilter.listItems[tostring(name)]
  345.   if x.db.profile.spellFilter.whitelistItems then
  346.     return not spell
  347.   end
  348.   return spell
  349. end
  350.  
  351. local function IsDamageFiltered(name)
  352.   local spell = x.db.profile.spellFilter.listDamage[tostring(name)]
  353.   if x.db.profile.spellFilter.whitelistDamage then
  354.     return not spell
  355.   end
  356.   return spell
  357. end
  358.  
  359. local function IsHealingFiltered(name)
  360.   local spell = x.db.profile.spellFilter.listHealing[tostring(name)]
  361.   if x.db.profile.spellFilter.whitelistHealing then
  362.     return not spell
  363.   end
  364.   return spell
  365. end
  366.  
  367. local function IsMerged(spellID)
  368.     local merged = false
  369.     if x.db.profile.spells.enableMerger then
  370.         spellID = addon.merge2h[spellID] or spellID
  371.         local db = x.db.profile.spells.merge[spellID] or addon.defaults.profile.spells.merge[spellID]
  372.         if db and db.enabled then merged = true end
  373.     end
  374.     return merged
  375. end
  376.  
  377. local function UseStandardSpellColors() return not x.db.profile.frames["outgoing"].standardSpellColor end
  378.  
  379. --[=====================================================[
  380.  String Formatters
  381. --]=====================================================]
  382. local format_getItemString = "([^|]+)|cff(%x+)|H([^|]+)|h%[([^%]]+)%]|h|r[^%d]*(%d*)"
  383. local format_getCraftedItemString
  384. if GetLocale() == "koKR" then
  385.   format_getCraftedItemString = "|cff(%x+)|H([^|]+)|h%[([^%]]+)%]|h|r.+ (.+)"
  386. end
  387. local format_pet  = sformat("|cff798BDD[%s]:|r %%s (%%s)", sgsub(BATTLE_PET_CAGE_ITEM_NAME,"%s?%%s","")) -- [Caged]: Pet Name (Pet Family)
  388.  
  389. -- TODO: Remove old loot pattern
  390. --local format_loot = "([^|]*)|cff(%x*)|H([^:]*):(%d+):%d+:(%d+):[-?%d+:]+|h%[?([^%]]*)%]|h|r?%s?x?(%d*)%.?"
  391. -- "You create: |cffa335ee|Hitem:124515::::::::100:254:4:3::530:::|h[Talisman of the Master Tracker]|h|r"
  392. --local msg = "|cff1eff00|Hitem:108840:0:0:0:0:0:0:443688319:90:0:0:0|h[Warlords Intro Zone PH Mail Helm]|h|r"
  393. --local format_loot = "([^|]*)|cff(%x*)|H([^:]*):(%d+):[-?%d+:]+|h%[?([^%]]*)%]|h|r?%s?x?(%d*)%.?"
  394.  
  395. local format_fade               = "-%s"
  396. local format_gain               = "+%s"
  397. local format_gain_rune          = "%s +%s %s"
  398. local format_resist             = "-%s |c%s(%s %s)|r"
  399. local format_energy             = "+%s %s"
  400. local format_honor              = sgsub(COMBAT_TEXT_HONOR_GAINED, "%%s", "+%%s")
  401. local format_faction_add        = "%s +%s"
  402. local format_faction_sub        = "%s %s"
  403. local format_crit               = "%s%s%s"
  404. local format_dispell            = "%s: %s"
  405. local format_quality            = "ITEM_QUALITY%s_DESC"
  406. local format_remove_realm       = "(.*)-.*"
  407.  
  408. local format_spell_icon         = " |T%s:%d:%d:0:0:64:64:5:59:5:59|t"
  409. local format_msspell_icon_right = "%s |cff%sx%d|r |T%s:%d:%d:0:0:64:64:5:59:5:59|t"
  410. local format_msspell_icon_left  = " |T%s:%d:%d:0:0:64:64:5:59:5:59|t %s |cff%sx%d|r"
  411. local format_loot_icon          = "|T%s:%d:%d:0:0:64:64:5:59:5:59|t"
  412. local format_lewtz              = "%s%s: %s [%s]%s%%s"
  413. local format_lewtz_amount       = " |cff798BDDx%s|r"
  414. local format_lewtz_total        = " |cffFFFF00(%s)|r"
  415. local format_lewtz_blind        = "(%s)"
  416. local format_crafted            = (LOOT_ITEM_CREATED_SELF:gsub("%%.*", ""))       -- "You create: "
  417. if GetLocale() == "koKR" then
  418.   format_crafted = (LOOT_ITEM_CREATED_SELF:gsub("%%.+ ", ""))
  419. end
  420. local format_looted             = (LOOT_ITEM_SELF:gsub("%%.*", ""))               -- "You receive loot: "
  421. local format_pushed             = (LOOT_ITEM_PUSHED_SELF:gsub("%%.*", ""))        -- "You receive item: "
  422. local format_strcolor_white     = "ffffff"
  423. local format_currency_single    = (CURRENCY_GAINED:gsub("%%s", "(.+)"))                                 -- "You receive currency: (.+)."
  424. local format_currency_multiple  = (CURRENCY_GAINED_MULTIPLE:gsub("%%s", "(.+)"):gsub("%%d", "(%%d+)"))  -- "You receive currency: (.+) x(%d+)."
  425. local format_currency           = "%s: %s [%s] |cff798BDDx%s|r |cffFFFF00(%s)|r"
  426.  
  427. --[=====================================================[
  428.  Message Formatters
  429. --]=====================================================]
  430. local xCTFormat = { }
  431.  
  432. function xCTFormat:SPELL_HEAL( outputFrame, spellID, amount, critical, merged, overheal)
  433.   local outputColor, message = "healingOut"
  434.  
  435.   -- Format Criticals and also abbreviate values
  436.   if critical then
  437.     outputColor = "healingOutCritical"
  438.     amount = x:Abbreviate( amount, "critical")
  439.     if IsOutgoingOverHealingFormatted and overheal > 0 then
  440.         amount = amount .. FormatOutgoingOverhealing( x:Abbreviate( overheal, outputFrame ) )
  441.     end
  442.     message = sformat( format_crit, x.db.profile.frames["critical"].critPrefix,
  443.                                     amount,
  444.                                     x.db.profile.frames["critical"].critPostfix )
  445.   else
  446.     message = x:Abbreviate( amount, outputFrame )
  447.     if IsOutgoingOverHealingFormatted and overheal > 0 then
  448.         message = message .. FormatOutgoingOverhealing( x:Abbreviate( overheal, outputFrame ) )
  449.     end
  450.   end
  451.  
  452.   -- Add Icons
  453.   message = x:GetSpellTextureFormatted( spellID,
  454.                                         message,
  455.        x.db.profile.frames[outputFrame].iconsEnabled and x.db.profile.frames[outputFrame].iconsSize or -1,
  456.        x.db.profile.frames[outputFrame].fontJustify )
  457.  
  458.   x:AddMessage(outputFrame, message, outputColor)
  459. end
  460.  
  461. function xCTFormat:SPELL_PERIODIC_HEAL( outputFrame, spellID, amount, critical, merged )
  462.   local outputColor, message = "healingOutPeriodic"
  463.  
  464.   -- Format Criticals and also abbreviate values
  465.   if critical then
  466.     message = sformat( format_crit, x.db.profile.frames["critical"].critPrefix,
  467.                                     x:Abbreviate( amount, "critical" ),
  468.                                     x.db.profile.frames["critical"].critPostfix )
  469.   else
  470.     message = x:Abbreviate( amount, outputFrame )
  471.   end
  472.  
  473.   -- Add Icons
  474.   message = x:GetSpellTextureFormatted( spellID,
  475.                                         message,
  476.        x.db.profile.frames[outputFrame].iconsEnabled and x.db.profile.frames[outputFrame].iconsSize or -1,
  477.        x.db.profile.frames[outputFrame].fontJustify )
  478.  
  479.   x:AddMessage(outputFrame, message, outputColor)
  480. end
  481.  
  482.  
  483.  
  484. --[=====================================================[
  485.  Capitalize Locales
  486. --]=====================================================]
  487. local unsupportedLocales = { zhCN = true, koKR = true, zhTW = true }
  488.  
  489. local XCT_STOLE
  490. local XCT_KILLED
  491. local XCT_DISPELLED
  492.  
  493. if unsupportedLocales[GetLocale()] then
  494.   XCT_STOLE = ACTION_SPELL_STOLEN
  495.   XCT_KILLED = ACTION_PARTY_KILL
  496.   XCT_DISPELLED = ACTION_SPELL_DISPEL
  497. else
  498.   XCT_STOLE = utf8.upper(utf8.sub(ACTION_SPELL_STOLEN, 1, 1))..utf8.sub(ACTION_SPELL_STOLEN, 2)
  499.   XCT_KILLED = utf8.upper(utf8.sub(ACTION_PARTY_KILL, 1, 1))..utf8.sub(ACTION_PARTY_KILL, 2)
  500.   XCT_DISPELLED = utf8.upper(utf8.sub(ACTION_SPELL_DISPEL, 1, 1))..utf8.sub(ACTION_SPELL_DISPEL, 2)
  501. end
  502.  
  503. --[=====================================================[
  504.  Flag value for special pets and vehicles
  505. --]=====================================================]
  506. local COMBATLOG_FILTER_MY_VEHICLE = bit.bor( COMBATLOG_OBJECT_AFFILIATION_MINE,
  507.   COMBATLOG_OBJECT_REACTION_FRIENDLY, COMBATLOG_OBJECT_CONTROL_PLAYER, COMBATLOG_OBJECT_TYPE_GUARDIAN )
  508.  
  509. --[=====================================================[
  510.  AddOn:OnCombatTextEvent(
  511.     event,     [string] - Name of the event
  512.     ...,       [multiple] - args from the combat event
  513.   )
  514.     This is the event handler and will act like a
  515.   switchboard the send the events to where they need
  516.   to go.
  517. --]=====================================================]
  518. function x.OnCombatTextEvent(self, event, ...)
  519.   if event == "COMBAT_LOG_EVENT_UNFILTERED" then
  520.     local timestamp, eventType, hideCaster, sourceGUID, sourceName, sourceFlags, srcFlags2, destGUID, destName, destFlags, destFlags2 = CombatLogGetCurrentEventInfo()
  521.     --local timestamp, eventType, hideCaster, sourceGUID, sourceName, sourceFlags, srcFlags2, destGUID, destName, destFlags, destFlags2 = select(1, ...)
  522.  
  523.     if sourceGUID == x.player.guid or ( sourceGUID == UnitGUID("pet") and ShowPetDamage() ) or sourceFlags == COMBATLOG_FILTER_MY_VEHICLE then
  524.       if x.outgoing_events[eventType] then
  525.         x.outgoing_events[eventType](...)
  526.       end
  527.     end
  528.   elseif event == "COMBAT_TEXT_UPDATE" then
  529.     local subevent, arg2, arg3 = ...
  530.     if x.combat_events[subevent] then
  531.       x.combat_events[subevent](arg2, arg3)
  532.     end
  533.   else
  534.     if x.events[event] then
  535.       x.events[event](...)
  536.     end
  537.   end
  538. end
  539.  
  540. --[=====================================================[
  541.  AddOn:GetSpellTextureFormatted(
  542.     spellID,     [number] - The spell ID you want the icon for
  543.     message,     [string] - The message that will be used (usually the amount)
  544.     iconSize,    [number] - The format size of the icon
  545.     justify,     [string] - Can be 'LEFT' or 'RIGHT'
  546.     strColor,    [string] - the color to be used or defaults white
  547.     mergeOverride, [bool] - If enable, will format like: "Messsage x12" where 12 is entries
  548.     entries      [number] - The number of entries to use
  549.   )
  550.   Returns:
  551.     message,     [string] - the message contains the formatted icon
  552.  
  553.     Formats an icon quickly for use when outputing to a combat text frame.
  554. --]=====================================================]
  555. function x:GetSpellTextureFormatted( spellID, message, iconSize, justify, strColor, mergeOverride, entries )
  556.   local icon = x.BLANK_ICON
  557.   strColor = strColor or format_strcolor_white
  558.   if spellID == 0 then
  559.     icon = PET_ATTACK_TEXTURE
  560.   elseif type(spellID) == 'string' then
  561.     icon = spellID
  562.   else
  563.     icon = GetSpellTexture( addon.merge2h[spellID] or spellID ) or x.BLANK_ICON
  564.   end
  565.  
  566.   if iconSize < 1 then
  567.     icon = x.BLANK_ICON
  568.   end
  569.  
  570.   if mergeOverride then
  571.     if entries > 1 then
  572.       if justify == "LEFT" then
  573.         message = sformat( format_msspell_icon_left, icon, iconSize, iconSize, message, strColor, entries )
  574.       else
  575.         message = sformat( format_msspell_icon_right, message, strColor, entries, icon, iconSize, iconSize )
  576.       end
  577.     else
  578.       if justify == "LEFT" then
  579.         message = sformat( "%s %s", sformat( format_spell_icon, icon, iconSize, iconSize ), message )
  580.       else
  581.         message = sformat( "%s%s", message, sformat( format_spell_icon, icon, iconSize, iconSize ) )
  582.       end
  583.     end
  584.   else
  585.  
  586.     if justify == "LEFT" then
  587.       message = sformat( "%s %s", sformat( format_spell_icon, icon, iconSize, iconSize ), message )
  588.     else
  589.       message = sformat( "%s%s", message, sformat( format_spell_icon, icon, iconSize, iconSize ) )
  590.     end
  591.   end
  592.  
  593.   if x.db.profile.spells.enableMergerDebug then
  594.     message = message .. " |cffFFFFFF[|cffFF0000ID:|r|cffFFFF00" .. (spellID or "No ID") .. "|r]|r"
  595.   end
  596.  
  597.   return message
  598. end
  599.  
  600.  
  601. --[=====================================================[
  602.  Combo Points - Rogues / Feral
  603. --]=====================================================]
  604. local function UpdateComboPoints()
  605.   if ShowRogueComboPoints() or ShowFeralComboPoints() then
  606.     local comboPoints, outputColor = GetComboPoints(x.player.unit, "target"), "comboPoints"
  607.     if comboPoints == MAX_COMBO_POINTS then outputColor = "comboPointsMax" end
  608.     if comboPoints > 0 then
  609.       x.cpUpdated = true
  610.       x:AddMessage("class", comboPoints, outputColor)
  611.     elseif x.cpUpdated then
  612.       x.cpUpdated = false
  613.       x:AddMessage("class", " ", outputColor)
  614.     end
  615.   end
  616. end
  617.  
  618. --[=====================================================[
  619.   Combo Points - Class Power Types
  620. --]=====================================================]
  621. local function UpdateUnitPower(unit, powertype)
  622.   if unit == x.player.unit then
  623.     local value
  624.  
  625.     if powertype == "CHI" and ShowMonkChi() then
  626.       value = UnitPower(x.player.unit, SPELL_POWER_CHI)
  627.     elseif powertype == "HOLY_POWER" and ShowPaladinHolyPower() then
  628.       value = UnitPower(x.player.unit, SPELL_POWER_HOLY_POWER)
  629.     elseif powertype == "SHADOW_ORBS" and ShowPriestShadowOrbs() then
  630.       value = UnitPower(x.player.unit, SPELL_POWER_SHADOW_ORBS)
  631.     elseif powertype == "SOUL_SHARDS" and ShowWarlockSoulShards() then
  632.       value = UnitPower(x.player.unit, SPELL_POWER_SOUL_SHARDS) / 100
  633.     elseif powertype == "DEMONIC_FURY" and ShowWarlockDemonicFury() then
  634.       value = UnitPower(x.player.unit, SPELL_POWER_DEMONIC_FURY) / 100
  635.     elseif powertype == "BURNING_EMBERS" and ShowWarlockBurningEmbers() then
  636.       value = UnitPower(x.player.unit, SPELL_POWER_BURNING_EMBERS)
  637.     end
  638.  
  639.     if value then
  640.       if value < 1 then
  641.         if value == 0 then
  642.           x:AddMessage("class", " ", "comboPoints")
  643.         else
  644.           x:AddMessage("class", "0", "comboPoints")
  645.         end
  646.       else
  647.         x:AddMessage("class", mfloor(value), "comboPoints")
  648.       end
  649.     end
  650.   end
  651. end
  652.  
  653. --[=====================================================[
  654.  Combo Points - Class Aura Types
  655. --]=====================================================]
  656. local function UpdateAuraTracking(unit)
  657.   local entry = x.TrackingEntry
  658.  
  659.   if entry then
  660.     if unit == entry.unit then
  661.       local i, name, icon, count, _, _, _, _, _, _, spellId = 1, UnitBuff(entry.unit, 1)
  662.  
  663.       while name do
  664.         if entry.id == spellId then
  665.           break
  666.         end
  667.         i = i + 1;
  668.         name, icon, count, _, _, _, _, _, _, spellId = UnitBuff(entry.unit, i)
  669.       end
  670.  
  671.       if name and count > 0 then
  672.         x:AddMessage("class", count, "comboPoints")
  673.       else
  674.         x:AddMessage("class", " ", "comboPoints")
  675.       end
  676.  
  677.     -- Fix issue of not reseting when unit disapears (e.g. dismiss pet)
  678.     elseif not UnitExists(entry.unit) then
  679.       x:AddMessage("class", " ", "comboPoints")
  680.     end
  681.   end
  682. end
  683.  
  684. function x:QuickClassFrameUpdate()
  685.   local entry = x.TrackingEntry
  686.   if entry and UnitExists(entry.unit) then
  687.     -- Update Buffs
  688.     UpdateAuraTracking(entry.unit)
  689.  
  690.     -- Update Unit's Power
  691.     if ShowMonkChi() then
  692.       UpdateUnitPower(entry.unit, "LIGHT_FORCE")
  693.     elseif ShowPaladinHolyPower() then
  694.       UpdateUnitPower(entry.unit, "HOLY_POWER")
  695.     elseif ShowPriestShadowOrbs() then
  696.       UpdateUnitPower(entry.unit, "SHADOW_ORBS")
  697.     elseif ShowWarlockSoulShards() then
  698.       UpdateUnitPower(entry.unit, "SOUL_SHARDS")
  699.     elseif ShowWarlockDemonicFury() then
  700.       UpdateUnitPower(entry.unit, "DEMONIC_FURY")
  701.     elseif ShowWarlockBurningEmbers() then
  702.       UpdateUnitPower(entry.unit, "BURNING_EMBERS")
  703.     end
  704.   else
  705.     -- Update Combo Points
  706.     UpdateComboPoints()
  707.   end
  708. end
  709.  
  710. --[=====================================================[
  711.  Looted Item - Latency Update Adpation
  712. --]=====================================================]
  713. local function LootFrame_OnUpdate(self, elapsed)
  714.   local removeItems = { }
  715.   for i, item in ipairs(self.items) do
  716.     item.t = item.t + elapsed
  717.  
  718.     -- Time to wait before showing a looted item
  719.     if item.t > 0.5 then
  720.       x:AddMessage("loot", sformat(item.message, sformat(format_lewtz_total, GetItemCount(item.id))), {item.r, item.g, item.b})
  721.       removeItems[i] = true
  722.     end
  723.   end
  724.  
  725.   for k in pairs(removeItems) do
  726.     --self.items[k] = nil
  727.     tremove( self.items, k )
  728.   end
  729.  
  730.   if #removeItems > 1 then
  731.     local index, newList = 1, { }
  732.  
  733.     -- Rebalance the Lua list
  734.     for _, v in pairs(self.items) do
  735.       newList[index] = v
  736.       index = index + 1
  737.     end
  738.  
  739.     self.items = newList
  740.   end
  741.  
  742.   if #self.items < 1 then
  743.     self:SetScript("OnUpdate", nil)
  744.     self.isRunning = false
  745.   end
  746. end
  747.  
  748. --[=====================================================[
  749.  Event handlers - Combat Text Events
  750. --]=====================================================]
  751. x.combat_events = {
  752.  
  753.   ["SPELL_ACTIVE"] = function(spellName)
  754.       if not spellName then return end -- trying to fix table index is nil error
  755.       if TrackSpells() then x.spellCache.procs[spellName] = true end
  756.       if IsProcFiltered(spellName) then return end
  757.  
  758.       local message = spellName
  759.  
  760.       -- Add Stacks
  761.       local icon, spellStacks = select(3, UnitAura("player", spellName))
  762.       if spellStacks and tonumber(spellStacks) > 1 then
  763.         message = spellName .. " |cffFFFFFFx" .. spellStacks .. "|r"
  764.       end
  765.  
  766.       -- Add Icons
  767.       if icon and x.db.profile.frames["procs"].iconsEnabled then
  768.         if x.db.profile.frames["procs"].fontJustify == "LEFT" then
  769.           message = sformat(format_spell_icon, icon, iconSize, iconSize) .. "  " .. message
  770.         else
  771.           message = message .. sformat(format_spell_icon, icon, iconSize, iconSize)
  772.         end
  773.       end
  774.  
  775.       x:AddMessage("procs", message, "spellProc")
  776.     end,
  777.  
  778.   ["SPELL_CAST"] = function(spellName) if ShowReactives() then x:AddMessage("procs", spellName, "spellReactive") end end,
  779.  
  780.   -- REMOVING PERIODIC_ENERGIZE, AS IT'S NOW COVERED BY SPELLENERGIZE Event
  781.  
  782.   -- TODO: Create a merger for faction and honor xp
  783.     ["HONOR_GAINED"] = function() -- UNTESTED
  784.         local amount = GetCurrentCombatTextEventInfo()
  785.         local num = mfloor(tonumber(amount) or 0)
  786.         if num > 0 and ShowHonor() then
  787.             x:AddMessage('general', sformat(format_honor, HONOR, x:Abbreviate(amount,"general")), 'honorGains')
  788.         end
  789.     end,
  790.  
  791.     ["FACTION"] = function() -- TESTED
  792.         local faction, amount = GetCurrentCombatTextEventInfo()
  793.         local num = mfloor(tonumber(amount) or 0)
  794.         if num > 0 and ShowFaction() then
  795.             x:AddMessage('general', sformat(format_faction_add, faction, x:Abbreviate(amount,'general')), 'reputationGain')
  796.         elseif num < 0 and ShowFaction() then
  797.             x:AddMessage('general', sformat(format_faction_sub, faction, x:Abbreviate(amount,'general')), 'reputationLoss')
  798.         end
  799.     end,
  800. }
  801.  
  802. --[=====================================================[
  803.  Event handlers - General Events
  804. --]=====================================================]
  805. x.events = {
  806.   ["UNIT_HEALTH"] = function()
  807.       if ShowLowResources() and UnitHealth(x.player.unit) / UnitHealthMax(x.player.unit) <= COMBAT_TEXT_LOW_HEALTH_THRESHOLD then
  808.         if not x.lowHealth then
  809.           x:AddMessage('general', HEALTH_LOW, 'lowResourcesHealth')
  810.           x.lowHealth = true
  811.         end
  812.       else
  813.         x.lowHealth = false
  814.       end
  815.     end,
  816.   ["UNIT_POWER_UPDATE"] = function(unit, powerType)
  817.       -- Update for Class Combo Points
  818.       UpdateUnitPower(unit, powerType)
  819.  
  820.       if select(2, UnitPowerType(x.player.unit)) == "MANA" and ShowLowResources() and UnitPower(x.player.unit) / UnitPowerMax(x.player.unit) <= COMBAT_TEXT_LOW_MANA_THRESHOLD then
  821.         if not x.lowMana then
  822.           x:AddMessage('general', MANA_LOW, 'lowResourcesMana')
  823.           x.lowMana = true
  824.         end
  825.       else
  826.         x.lowMana = false
  827.       end
  828.     end,
  829.   ["RUNE_POWER_UPDATE"] = function(slot)
  830.       if GetRuneCooldown(slot) ~= 0 then return end
  831.       local message = sformat(format_gain_rune, x.runeIcons[4], COMBAT_TEXT_RUNE_DEATH, x.runeIcons[4])
  832.       x:AddSpamMessage("power", RUNES, message, x.runecolors[4], 1)
  833.     end,
  834.   ["PLAYER_REGEN_ENABLED"] = function()
  835.       x.inCombat = false
  836.       x:CombatStateChanged()
  837.       if ClearWhenLeavingCombat() then
  838.         -- only clear frames with icons
  839.         x:Clear('outgoing')
  840.         x:Clear('critical')
  841.         x:Clear('loot')
  842.         x:Clear('power')
  843.       end
  844.       if ShowCombatState() then
  845.         x:AddMessage('general', sformat(format_fade, LEAVING_COMBAT), 'combatLeaving')
  846.       end
  847.     end,
  848.   ["PLAYER_REGEN_DISABLED"] = function()
  849.       x.inCombat = true
  850.       x:CombatStateChanged()
  851.       if ShowCombatState() then
  852.         x:AddMessage('general', sformat(format_gain, ENTERING_COMBAT), 'combatEntering')
  853.       end
  854.     end,
  855.   ["UNIT_COMBO_POINTS"] = function() UpdateComboPoints() end,
  856.  
  857.   ["PLAYER_TARGET_CHANGED"] = function() UpdateComboPoints() end,
  858.   ["UNIT_AURA"] = function(unit) UpdateAuraTracking(unit) end,
  859.  
  860.   ["UNIT_ENTERED_VEHICLE"] = function(unit) if unit == "player" then x:UpdatePlayer() end end,
  861.   ["UNIT_EXITING_VEHICLE"] = function(unit) if unit == "player" then x:UpdatePlayer() end end,
  862.   ["PLAYER_ENTERING_WORLD"] = function()
  863.       x:UpdatePlayer()
  864.       x:UpdateComboPointOptions()
  865.       x:Clear()
  866.  
  867.       -- Lazy Coding (Clear up messy libraries... yuck!)
  868.       collectgarbage()
  869.     end,
  870.  
  871.   ["UNIT_PET"] = function()
  872.       x:UpdatePlayer()
  873.     end,
  874.  
  875.   ["ACTIVE_TALENT_GROUP_CHANGED"] = function() x:UpdatePlayer(); x:UpdateComboTracker() end,    -- x:UpdateComboPointOptions(true) end,
  876.  
  877.   ["CHAT_MSG_LOOT"] = function(msg)
  878.       -- Fixing Loot for Legion
  879.       local preMessage, linkColor, itemString, itemName, amount = string.match(msg, format_getItemString)
  880.       if not preMessage or preMessage == "" then
  881.         linkColor, itemString, itemName, preMessage = string.match(msg, format_getCraftedItemString)
  882.       end
  883.  
  884.       -- Decode item string: (linkQuality for pets only)
  885.       local linkType, linkID, _, linkQuality = strsplit(':', itemString)
  886.  
  887.       -- TODO: Clean up this debug scratch stuff
  888.       --"([^|]*)|cff(%x*)|H([^:]*):(%d+):%d+:(%d+):[-?%d+:]+|h%[?([^%]]*)%]|h|r?%s?x?(%d*)%.?"
  889.       -- "|cff0070dd|Hbattlepet:1343:1:3:158:10:12:BattlePet-0-000002C398CB|h[Bonkers]|h|r" - C_PetJournal.GetPetInfoBySpeciesID(1343)
  890.       -- "|cff9d9d9d|Hbattlepet:467:1:0:140:9:9:BattlePet-0-000002C398C4|h[Dung Beetle]|h|r" - C_PetJournal.GetPetInfoBySpeciesID(467)
  891.       -- GetItemQualityColor(3)
  892.  
  893.       -- local format_getItemString = "([^|]+)|cff(%x+)|H([^|]+)|h%[([^%]]+)%]|h|r[^%d]*(%d*)"
  894.       -- "|cffffffff|Hitem:119299::::::::100:252::::::|h[드레노어 기계공학의 비밀]|h|r을 만들었습니다."
  895.  
  896.       if TrackSpells() then
  897.         x.spellCache.items[linkID] = true
  898.       end
  899.  
  900.       if IsItemFiltered( linkID ) then return end
  901.  
  902.       -- Check to see if this is a battle pet
  903.       if linkType == "battlepet" then
  904.         -- TODO: Add pet icons!
  905.         local speciesName, speciesIcon, petType = C_PetJournal.GetPetInfoBySpeciesID(linkID)
  906.         local petTypeName = PET_TYPE_SUFFIX[petType]
  907.         local message = sformat(format_pet, speciesName, petTypeName)
  908.  
  909.         local r, g, b = GetItemQualityColor(linkQuality or 0)
  910.  
  911.         -- Add the message
  912.         x:AddMessage("loot", message, { r, g, b } )
  913.         return
  914.       end
  915.  
  916.       -- Check to see if this is a item
  917.       if linkType == "item" then
  918.         local crafted, looted, pushed = (preMessage == format_crafted), (preMessage == format_looted), (preMessage == format_pushed)
  919.  
  920.         -- Item Quality, See "GetAuctionItemClasses()" For Type and Subtype, Item Icon Texture Location
  921.         local itemQuality, _, _, itemType, itemSubtype, _, _, itemTexture = select(3, GetItemInfo(linkID))
  922.  
  923.         -- Item White-List Filter
  924.         local listed = x.db.profile.spells.items[itemType] and (x.db.profile.spells.items[itemType][itemSubtype] == true)
  925.  
  926.         -- Fix the Amount of a item looted
  927.         amount = tonumber(amount) or 1
  928.  
  929.         -- Only let self looted items go through the "Always Show" filter
  930.         if (listed and looted) or (ShowLootItems() and looted and itemQuality >= GetLootQuality()) or (itemType == "Quest" and ShowLootQuest() and looted) or (crafted and ShowLootCrafted()) then
  931.           local r, g, b = GetItemQualityColor(itemQuality)
  932.           -- "%s%s: %s [%s]%s %%s"
  933.           local message = sformat(format_lewtz,
  934.               ShowLootItemTypes() and itemType or "Item",       -- Item Type
  935.               ShowColorBlindMoney()                     -- Item Quality (Color Blind)
  936.                 and sformat(format_lewtz_blind,
  937.                               _G[sformat(format_quality,
  938.                                          itemQuality)]
  939.                            )
  940.                 or "",
  941.               ShowLootIcons()                           -- Icon
  942.                 and sformat(format_loot_icon,
  943.                             itemTexture,
  944.                             GetLootIconSize(),
  945.                             GetLootIconSize())
  946.                 or "",
  947.               itemName,                                 -- Item Name
  948.               sformat(format_lewtz_amount, amount)      -- Amount Looted
  949.             )
  950.  
  951.           -- Purchased/quest items seem to get to your bags faster than looted items
  952.           if ShowTotalItems() then
  953.  
  954.             -- This frame was created to make sure I always display the correct number of an item in your bag
  955.             if not x.lootUpdater then
  956.               x.lootUpdater = CreateFrame("FRAME")
  957.               x.lootUpdater.isRunning = false
  958.               x.lootUpdater.items = { }
  959.             end
  960.  
  961.             -- Enqueue the item to wait 1 second before showing
  962.             tinsert(x.lootUpdater.items, { id=linkID, message=message, t=0, r=r, g=g, b=b, })
  963.  
  964.             if not x.lootUpdater.isRunning then
  965.               x.lootUpdater:SetScript("OnUpdate", LootFrame_OnUpdate)
  966.               x.lootUpdater.isRunning = true
  967.             end
  968.           else
  969.  
  970.             -- Add the message
  971.             x:AddMessage("loot", sformat(message, ""), {r, g, b})
  972.           end
  973.         end
  974.       end
  975.     end,
  976.   ["CHAT_MSG_CURRENCY"] = function(msg)
  977.       if not ShowLootCurrency() then return end
  978.       -- get currency from chat
  979.       local currencyLink, amountGained = msg:match(format_currency_multiple)
  980.       if not currencyLink then
  981.         amountGained, currencyLink = 1, msg:match(format_currency_single)
  982.  
  983.         if not currencyLink then
  984.           return
  985.         end
  986.       end
  987.  
  988.       -- get currency info
  989.       local name, amountOwned, texturePath = _G.GetCurrencyInfo(tonumber(currencyLink:match("currency:(%d+)")))
  990.  
  991.       -- format curency
  992.       -- "%s: %s [%s] |cff798BDDx%s|r |cffFFFF00(%s)|r"
  993.       local message = sformat(format_currency,
  994.         _G.CURRENCY,
  995.         ShowLootIcons()
  996.           and sformat(format_loot_icon,
  997.             texturePath,
  998.             GetLootIconSize(),
  999.             GetLootIconSize())
  1000.           or "",
  1001.         name,
  1002.         amountGained,
  1003.         amountOwned
  1004.       )
  1005.  
  1006.       -- Add the message
  1007.       x:AddMessage("loot", message, {1, 1, 1})
  1008.     end,
  1009.   ["CHAT_MSG_MONEY"] = function(msg)
  1010.       if not ShowLootMoney() then return end
  1011.       local g, s, c = tonumber(msg:match(GOLD_AMOUNT:gsub("%%d", "(%%d+)"))), tonumber(msg:match(SILVER_AMOUNT:gsub("%%d", "(%%d+)"))), tonumber(msg:match(COPPER_AMOUNT:gsub("%%d", "(%%d+)")))
  1012.       local money, o = (g and g * 10000 or 0) + (s and s * 100 or 0) + (c or 0), MONEY .. ": "
  1013.  
  1014.       -- TODO: Add a minimum amount of money
  1015.  
  1016.       if ShowColorBlindMoney() then
  1017.         o = o..(g and g.." G " or "")..(s and s.." S " or "")..(c and c.." C " or "")
  1018.       else
  1019.         o = o..GetCoinTextureString(money).." "
  1020.       end
  1021.  
  1022.       -- This only works on english clients :\
  1023.       if msg:find("share") then o = o.."(split)" end
  1024.  
  1025.       x:AddMessage("loot", o, {1, 1, 0}) -- yellow
  1026.     end,
  1027.  
  1028.   ["SPELL_ACTIVATION_OVERLAY_GLOW_SHOW"] = function(spellID)
  1029.       if spellID == 32379 then  -- Shadow Word: Death
  1030.         local name = GetSpellInfo(spellID)
  1031.         --x:AddMessage("procs", name, "spellProc")
  1032.       end
  1033.     end,
  1034. }
  1035.  
  1036. -- =====================================================
  1037. --                  Format Name Things
  1038. -- =====================================================
  1039.  
  1040. -- Changes a color table into a hex string
  1041.  
  1042. local function hexNameColor(t)
  1043.     if type(t) == "string" then
  1044.         return "ff"..t
  1045.     elseif not t then
  1046.         return "ffFFFFFF"
  1047.     elseif t.colorStr then -- Support Blizzard's raid colors
  1048.         return t.colorStr
  1049.     end
  1050.     return sformat("ff%2X%2X%2X", mfloor(t[1]*255+.5), mfloor(t[2]*255+.5), mfloor(t[3]*255+.5))
  1051. end
  1052.  
  1053. -- Checks the options you provide and outputs the correctly formated name
  1054. local function formatNameHelper(name, enableColor, color, enableCustomColor, customColor)
  1055.     if enableColor then
  1056.         if enableCustomColor then
  1057.             return "|c"..hexNameColor(customColor)..name.."|r"
  1058.         end
  1059.         return "|c"..hexNameColor(color)..name.."|r"
  1060.     end
  1061.     return "|cffFFFFFF"..name.."|r"
  1062. end
  1063.  
  1064. -- Format Handlers for name
  1065. local CLASS_LOOKUP = {
  1066.     [1] = "DEATHKNIGHT",
  1067.     [2] = "DEMONHUNTER",
  1068.     [4] = "DRUID",
  1069.     [8] = "HUNTER",
  1070.     [16] = "MAGE",
  1071.     [32] = "MONK",
  1072.     [64] = "PALADIN",
  1073.     [128] = "PRIEST",
  1074.     [256] = "ROGUE",
  1075.     [512] = "SHAMAN",
  1076.     [1024] = "WARLOCK",
  1077.     [2048] = "WARRIOR"
  1078. }
  1079.  
  1080. local formatNameTypes
  1081. formatNameTypes = {
  1082.     function (args, settings, isSource) -- [1] = Source/Destination Name
  1083.         local guid, name, color = isSource and args.sourceGUID or args.destGUID, isSource and args.sourceName or args.destName
  1084.  
  1085.         if settings.removeRealmName then
  1086.             name = smatch(name, format_remove_realm) or name
  1087.         end
  1088.  
  1089.         if settings.enableNameColor and not settings.enableCustomNameColor then
  1090.             if args.prefix == "ENVIRONMENTAL" then
  1091.                 color = x.spellColors[args.school or args.spellSchool or 1]
  1092.             else
  1093.                 if smatch(guid, "^Player") then
  1094.                     local _, class = GetPlayerInfoByGUID(guid)
  1095.                     color = RAID_CLASS_COLORS[class or 0]
  1096.                 end
  1097.             end
  1098.         end
  1099.  
  1100.         return formatNameHelper(name,
  1101.                        settings.enableNameColor,
  1102.                                 color,
  1103.                        settings.enableCustomNameColor,
  1104.                        settings.customNameColor)
  1105.     end,
  1106.  
  1107.     function (args, settings, isSource) -- [2] = Spell Name
  1108.         local color
  1109.             if settings.enableNameColor and not settings.enableCustomNameColor then
  1110.  
  1111.             -- NOTE: I don't think we want the spell school of the spell
  1112.             --       being cast. We want the spell school of the damage
  1113.             --       being done. That said, if you want to change it so
  1114.             --       that the spell name matches the type of spell it
  1115.             --       is, and not the type of damage it does, change
  1116.             --       "args.school" to "args.spellSchool".
  1117.             color = x.GetSpellSchoolColor(args.school or args.spellSchool)
  1118.         end
  1119.  
  1120.         return formatNameHelper(args.spellName,
  1121.                             settings.enableSpellColor,
  1122.                                      color,
  1123.                             settings.enableCustomSpellColor,
  1124.                             settings.customSpellColor)
  1125.     end,
  1126.  
  1127.     function (args, settings, isSource) -- [3] = Source Name - Spell Name
  1128.         if args.hideCaster then
  1129.             return formatNameTypes[2](args, settings, isSource)
  1130.         end
  1131.  
  1132.         return formatNameTypes[1](args, settings, isSource) .. " - " .. formatNameTypes[2](args, settings, isSource)
  1133.     end,
  1134.  
  1135.     function (args, settings, isSource) -- [4] = Spell Name - Source Name
  1136.         if args.hideCaster then
  1137.             return formatNameTypes[2](args, settings, isSource)
  1138.         end
  1139.  
  1140.         return formatNameTypes[2](args, settings, isSource) .. " - " .. formatNameTypes[1](args, settings, isSource)
  1141.     end
  1142. }
  1143.  
  1144. -- Check to see if the name needs for be formated, if so, handle all the logistics
  1145. function x.formatName(args, settings, isSource)
  1146.     -- Event Type helper
  1147.     local eventType = settings[isSource and args:GetSourceController() or args:GetDestinationController()]
  1148.  
  1149.     -- If we have a valid event type that we can handle
  1150.     if eventType and eventType.nameType > 0 then
  1151.         return settings.namePrefix .. formatNameTypes[eventType.nameType](args, eventType, isSource) .. settings.namePostfix
  1152.     end
  1153.     return "" -- Names not supported
  1154. end
  1155.  
  1156. -- =====================================================
  1157. --           Quick Partial Name Formatter
  1158. -- =====================================================
  1159.  
  1160. local missTypeColorLookup = {
  1161.     ['MISS'] = 'missTypeMiss',
  1162.     ['DODGE'] = 'missTypeDodge',
  1163.     ['PARRY'] = 'missTypeParry',
  1164.     ['EVADE'] = 'missTypeEvade',
  1165.     ['IMMUNE'] = 'missTypeImmune',
  1166.     ['DEFLECT'] = 'missTypeDeflect',
  1167.     ['REFLECT'] = 'missTypeReflect'
  1168. }
  1169.  
  1170. local PARTIAL_MISS_FORMATTERS = {
  1171.     ['absorbed'] = " |c%s"..(TEXT_MODE_A_STRING_RESULT_ABSORB:gsub("%%d","%%s")).."|r", -- |c%s(%s Absorbed)|r
  1172.     ['blocked']  = " |c%s"..( TEXT_MODE_A_STRING_RESULT_BLOCK:gsub("%%d","%%s")).."|r", -- |c%s(%s Blocked)|r
  1173.     ['resisted'] = " |c%s"..(TEXT_MODE_A_STRING_RESULT_RESIST:gsub("%%d","%%s")).."|r", -- |c%s(%s Resisted)|r
  1174. }
  1175.  
  1176. local PARTIAL_MISS_COLORS = {
  1177.     ['absorbed'] = 'missTypeAbsorbPartial',
  1178.     ['blocked']  = 'missTypeBlockPartial',
  1179.     ['resisted'] = 'missTypeResistPartial',
  1180. }
  1181.  
  1182. local FULL_MISS_COLORS = {
  1183.     ['absorbed'] = 'missTypeAbsorb',
  1184.     ['blocked']  = 'missTypeBlock',
  1185.     ['resisted'] = 'missTypeResist',
  1186. }
  1187.  
  1188.  
  1189. local function GetPartialMiss(args, settings, outgoingFrame)
  1190.     local blocked, absorbed, resisted = args.blocked or 0, args.absorbed or 0, args.resisted or 0
  1191.     if blocked > 0 or absorbed > 0 or resisted > 0 then
  1192.  
  1193.         -- Show only the highest partial miss
  1194.         if settings.showHighestPartialMiss then
  1195.             local maxType, color
  1196.             if blocked > absorbed then
  1197.                 if blocked > resisted then maxType = 'blocked' else maxType = 'resisted' end
  1198.             else
  1199.                 if absorbed > resisted then maxType = 'absorbed' else maxType = 'resisted' end
  1200.             end
  1201.  
  1202.             color = hexNameColor(x.LookupColorByName(args.amount > 0 and PARTIAL_MISS_COLORS[maxType] or FULL_MISS_COLORS[maxType]))
  1203.             return true, sformat(PARTIAL_MISS_FORMATTERS[maxType], color, x:Abbreviate(args[maxType], outgoingFrame))
  1204.         end
  1205.  
  1206.         -- Show All the partial misses that exsist
  1207.         local message, color = ""
  1208.         if absorbed > 0 then
  1209.             color = hexNameColor(x.LookupColorByName(args.amount > 0 and PARTIAL_MISS_COLORS.absorbed or FULL_MISS_COLORS.absorbed))
  1210.             message = message .. sformat(PARTIAL_MISS_FORMATTERS.absorbed, color, x:Abbreviate(absorbed, outgoingFrame))
  1211.         end
  1212.  
  1213.         if blocked > 0 then
  1214.             color = hexNameColor(x.LookupColorByName(args.amount > 0 and PARTIAL_MISS_COLORS.blocked or FULL_MISS_COLORS.blocked))
  1215.             message = message .. sformat(PARTIAL_MISS_FORMATTERS.blocked, color, x:Abbreviate(blocked, outgoingFrame))
  1216.         end
  1217.  
  1218.         if resisted > 0 then
  1219.             color = hexNameColor(x.LookupColorByName(args.amount > 0 and PARTIAL_MISS_COLORS.resisted or FULL_MISS_COLORS.resisted))
  1220.             message = message .. sformat(PARTIAL_MISS_FORMATTERS.resisted, color, x:Abbreviate(resisted, outgoingFrame))
  1221.         end
  1222.  
  1223.         return true, message
  1224.     else
  1225.         return false, ""
  1226.     end
  1227. end
  1228.  
  1229.  
  1230.  
  1231. -- =====================================================
  1232. --               The New Combat Handlers
  1233. -- =====================================================
  1234. local CombatEventHandlers = {
  1235.     ["ShieldOutgoing"] = function (args)
  1236.         local buffIndex = x.findBuffIndex(args.destName, args.spellName)
  1237.         if not buffindex then return end
  1238.         local settings, value = x.db.profile.frames['outgoing'], select(16, UnitBuff(args.destName, buffIndex))
  1239.         if not value or value <= 0 then return end
  1240.  
  1241.         -- Keep track of spells that go by
  1242.         if TrackSpells() then x.spellCache.spells[args.spellId] = true end
  1243.  
  1244.         if not ShowAbsorbs() then return end
  1245.  
  1246.         -- Filter Ougoing Healing Spell or Amount
  1247.         if IsSpellFiltered(args.spellId) or FilterOutgoingHealing(args.amount) then return end
  1248.  
  1249.         -- Create the message
  1250.         local message = x:Abbreviate(value, 'outgoing')
  1251.  
  1252.         message = x:GetSpellTextureFormatted(args.spellId,
  1253.                                                message,
  1254.                 x.db.profile.frames['outgoing'].iconsEnabled and x.db.profile.frames['outgoing'].iconsSize or -1,
  1255.                 x.db.profile.frames['outgoing'].fontJustify)
  1256.  
  1257.         -- Add names
  1258.         message = message .. x.formatName(args, settings.names, true)
  1259.  
  1260.         x:AddMessage('outgoing', message, 'shieldOut')
  1261.     end,
  1262.  
  1263.     ["HealingOutgoing"] = function (args)
  1264.         local spellID, isHoT, amount, merged = args.spellId, args.prefix == "SPELL_PERIODIC", args.amount
  1265.  
  1266.         -- Keep track of spells that go by
  1267.         if TrackSpells() then x.spellCache.spells[spellID] = true end
  1268.  
  1269.         if not ShowHealing() then return end
  1270.  
  1271.         -- Check to see if this is a HoT
  1272.         if isHoT and not ShowHots() then return end
  1273.  
  1274.         -- Filter Ougoing Healing Spell or Amount
  1275.         if IsSpellFiltered(spellID) or FilterOutgoingHealing(amount) then return end
  1276.  
  1277.         -- Filter Overhealing
  1278.         --if not ShowOutgoingOverHealing() then
  1279.         amount = amount - args.overhealing
  1280.         --  if amount < 1 then
  1281.         --      return
  1282.         --  end
  1283.         --end
  1284.  
  1285.         -- Figure out which frame and color to output
  1286.         local outputFrame, outputColor, critical = "outgoing", "healingOut", args.critical
  1287.         if critical then
  1288.             outputFrame = "critical"
  1289.             outputColor = "healingOutCritical"
  1290.         end
  1291.  
  1292.         -- HoTs only have one color
  1293.         if isHoT then outputColor = "healingOutPeriodic"end
  1294.  
  1295.         -- Condensed Critical Merge
  1296.         if IsMerged(spellID) then
  1297.             merged = true
  1298.             if critical then
  1299.                 if MergeCriticalsByThemselves() then
  1300.                     x:AddSpamMessage(outputFrame, spellID, amount, outputColor)
  1301.                     return
  1302.                 elseif MergeCriticalsWithOutgoing() then
  1303.                     x:AddSpamMessage("outgoing", spellID, amount, outputColor)
  1304.                 elseif MergeHideMergedCriticals() then
  1305.                     x:AddSpamMessage("outgoing", spellID, amount, outputColor)
  1306.                     return
  1307.                 end
  1308.             else
  1309.                 x:AddSpamMessage(outputFrame, spellID, amount, outputColor)
  1310.                 return
  1311.             end
  1312.         end
  1313.  
  1314.         if args.event == "SPELL_PERIODIC_HEAL" then
  1315.             xCTFormat:SPELL_PERIODIC_HEAL(outputFrame, spellID, amount, critical, merged, args.overhealing)
  1316.         elseif args.event == "SPELL_HEAL" then
  1317.             xCTFormat:SPELL_HEAL(outputFrame, spellID, amount, critical, merged, args.overhealing)
  1318.         else
  1319.             if UnitName('player') == "Dandraffbal" then
  1320.                 print("xCT Needs Some Help: unhandled _HEAL event", args.event)
  1321.             end
  1322.         end
  1323.     end,
  1324.  
  1325.     ["DamageOutgoing"] = function (args)
  1326.         local message
  1327.         local critical, spellID, amount, merged = args.critical, args.spellId, args.amount
  1328.         local isEnvironmental, isSwing, isAutoShot, isDoT = args.prefix == "ENVIRONMENTAL", args.prefix == "SWING", spellID == 75, args.prefix == "SPELL_PERIODIC"
  1329.         local outputFrame, outputColorType = "outgoing"
  1330.  
  1331.         -- Keep track of spells that go by (Don't track Swings or Environmental damage)
  1332.         if not isEnvironmental and not isSwing and TrackSpells() then x.spellCache.spells[spellID] = true end
  1333.  
  1334.         if not ShowDamage() then return end
  1335.         if isSwing and not args:IsSourceMyPet() and not args:IsSourceMyVehicle() and not ShowAutoAttack() then return end
  1336.  
  1337.         -- Filter Ougoing Damage Spell or Amount
  1338.         if IsSpellFiltered(spellID) or FilterOutgoingDamage(amount) then return end
  1339.  
  1340.         -- Check to see if my pet is doing things
  1341.         if args:IsSourceMyPet() and (not ShowKillCommand() or spellID ~= 34026) then
  1342.             if not ShowPetDamage() then return end
  1343.             if isSwing and not ShowPetAutoAttack() then return end
  1344.             if MergePetAttacks() then
  1345.                 local icon = x.GetPetTexture() or ""
  1346.                 x:AddSpamMessage(outputFrame, icon, amount, x.db.profile.spells.mergePetColor, 6)
  1347.                 return
  1348.             end
  1349.             if not ShowPetCrits() then
  1350.                 critical = nil -- stupid spam fix for hunter pets
  1351.             end
  1352.             if isSwing then
  1353.                 spellID = 0 -- this will get fixed later
  1354.             end
  1355.         end
  1356.  
  1357.         if args:IsSourceMyVehicle() then
  1358.             if not ShowVehicleDamage() then return end
  1359.             if isSwing and not ShowPetAutoAttack() then return end
  1360.             if not ShowPetCrits() then
  1361.                 critical = nil -- stupid spam fix for hunter pets
  1362.             end
  1363.             if isSwing then
  1364.                 spellID = 0 -- this will get fixed later
  1365.             end
  1366.         end
  1367.  
  1368.         -- Check for Critical Swings
  1369.         if critical then
  1370.             if (isSwing or isAutoShot) and ShowSwingCrit() then
  1371.                 outputFrame = 'critical'
  1372.             elseif not isSwing and not isAutoShot then
  1373.                 outputFrame = 'critical'
  1374.             end
  1375.         end
  1376.  
  1377.         -- Lookup the color
  1378.         if isSwing or isAutoShot then
  1379.             outputColorType = critical and 'meleeCrit' or 'melee'
  1380.         end
  1381.  
  1382.         local outputColor = x.GetSpellSchoolColor(args.spellSchool, outputColorType)
  1383.  
  1384.         if (isSwing or isAutoShot) and MergeMeleeSwings() then
  1385.             merged = true
  1386.             if outputFrame == "critical" then
  1387.                 if MergeCriticalsByThemselves() then
  1388.                     x:AddSpamMessage(outputFrame, spellID, amount, outputColor, 6)
  1389.                     return
  1390.                 elseif MergeCriticalsWithOutgoing() then
  1391.                     x:AddSpamMessage("outgoing", spellID, amount, outputColor, 6)
  1392.                 elseif MergeHideMergedCriticals() then
  1393.                     x:AddSpamMessage("outgoing", spellID, amount, outputColor, 6)
  1394.                     return
  1395.                 end
  1396.             else
  1397.                 x:AddSpamMessage(outputFrame, spellID, amount, outputColor, 6)
  1398.                 return
  1399.             end
  1400.         elseif not isSwing and not isAutoShot and IsMerged(spellID) then
  1401.             merged = true
  1402.             if critical then
  1403.                 if MergeCriticalsByThemselves() then
  1404.                     x:AddSpamMessage(outputFrame, spellID, amount, outputColor)
  1405.                     return
  1406.                 elseif MergeCriticalsWithOutgoing() then
  1407.                     x:AddSpamMessage("outgoing", spellID, amount, outputColor)
  1408.                 elseif MergeHideMergedCriticals() then
  1409.                     x:AddSpamMessage("outgoing", spellID, amount, outputColor)
  1410.                     return
  1411.                 end
  1412.             else
  1413.                 x:AddSpamMessage(outputFrame, spellID, amount, outputColor)
  1414.                 return
  1415.             end
  1416.         end
  1417.  
  1418.         if critical and ShowSwingCrit() then
  1419.             settings = x.db.profile.frames['critical']
  1420.             if ShowSwingCritPrefix() then
  1421.                 message = sformat(format_crit, x.db.profile.frames['critical'].critPrefix,
  1422.                                                x:Abbreviate(amount,'critical'),
  1423.                                                x.db.profile.frames['critical'].critPostfix)
  1424.             else
  1425.                 message = x:Abbreviate(amount, 'critical')
  1426.             end
  1427.         else
  1428.             settings = x.db.profile.frames['outgoing']
  1429.             message = x:Abbreviate(amount, 'outgoing')
  1430.         end
  1431.  
  1432.         -- Add the Partial Miss Types
  1433.         if ShowPartialMisses() then
  1434.             local hasPartialMiss, formattedMessage = GetPartialMiss(args, settings, critical and 'critical' or 'outgoing')
  1435.             if hasPartialMiss then
  1436.                 message = message .. formattedMessage
  1437.             end
  1438.         end
  1439.  
  1440.         -- Add names
  1441.         message = message .. x.formatName(args, settings.names)
  1442.  
  1443.         -- Add Icons
  1444.         message = x:GetSpellTextureFormatted( spellID,
  1445.                                               message,
  1446.              x.db.profile.frames[outputFrame].iconsEnabled and x.db.profile.frames[outputFrame].iconsSize or -1,
  1447.              x.db.profile.frames[outputFrame].fontJustify )
  1448.  
  1449.         x:AddMessage(outputFrame, message, outputColor)
  1450.  
  1451.     end,
  1452.  
  1453.     ["DamageIncoming"] = function (args)
  1454.         local message
  1455.         local settings = x.db.profile.frames["damage"]
  1456.  
  1457.         -- Keep track of spells that go by
  1458.         if args.spellId and TrackSpells() then x.spellCache.damage[args.spellId] = true end
  1459.  
  1460.  
  1461.         if IsDamageFiltered(args.spellId or false) then return end
  1462.  
  1463.         -- Check for resists
  1464.         if ShowResistances() then
  1465.             if FilterIncomingDamage(args.amount + (args.resisted or 0) + (args.blocked or 0) + (args.absorbed or 0)) then return end
  1466.  
  1467.             local resistedAmount, resistType, color
  1468.  
  1469.             -- Check for resists (full and partials)
  1470.             if (args.resisted or 0) > 0 then
  1471.                 resistType, resistedAmount = RESIST, args.amount > 0 and args.resisted
  1472.                 color = resistedAmount and 'missTypeResist' or 'missTypeResistPartial'
  1473.             elseif (args.blocked or 0) > 0 then
  1474.                 resistType, resistedAmount = BLOCK, args.amount > 0 and args.blocked
  1475.                 color = resistedAmount and 'missTypeBlock' or 'missTypeBlockPartial'
  1476.             elseif (args.absorbed or 0) > 0 then
  1477.                 resistType, resistedAmount = ABSORB, args.amount > 0 and args.absorbed
  1478.                 color = resistedAmount and 'missTypeAbsorb' or 'missTypeAbsorbPartial'
  1479.             end
  1480.  
  1481.             if resistType then
  1482.                 -- Craft the new message (if is partial)
  1483.                 if resistedAmount then
  1484.                     -- format_resist: "-%s |c%s(%s %s)|r"
  1485.                     color = hexNameColor(x.LookupColorByName(color))
  1486.                     message = sformat(format_resist, x:Abbreviate(args.amount, 'damage'), color, resistType, x:Abbreviate(resistedAmount, 'damage'))
  1487.                 else
  1488.                     -- It was a full resist
  1489.                     message = resistType    -- TODO: Add an option to still see how much was reisted on a full resist
  1490.                 end
  1491.             end
  1492.         else
  1493.             if FilterIncomingDamage(args.amount) then return end
  1494.         end
  1495.  
  1496.         -- If this is not a resist, then lets format it as normal
  1497.         if not message then
  1498.             -- Format Criticals and also abbreviate values
  1499.             if args.critical then
  1500.                 message = sformat(format_crit, x.db.profile.frames['damage'].critPrefix,
  1501.                                                x:Abbreviate(-args.amount, 'damage'),
  1502.                                                x.db.profile.frames['damage'].critPostfix)
  1503.             else
  1504.                 message = x:Abbreviate(-args.amount, 'damage')
  1505.             end
  1506.         end
  1507.  
  1508.         -- TODO: Add merge settings
  1509.  
  1510.         -- Add names
  1511.         message = message .. x.formatName(args, settings.names, true)
  1512.  
  1513.         -- Add Icons (Hide Auto Attack icons)
  1514.         if args.prefix ~= "SWING" or ShowIncomingAutoAttackIcons() then
  1515.             message = x:GetSpellTextureFormatted(args.spellId,
  1516.                                                  message,
  1517.                    x.db.profile.frames['damage'].iconsEnabled and x.db.profile.frames['damage'].iconsSize or -1,
  1518.                    x.db.profile.frames['damage'].fontJustify)
  1519.         else
  1520.             message = x:GetSpellTextureFormatted(nil,
  1521.                                                  message,
  1522.                    x.db.profile.frames['damage'].iconsEnabled and x.db.profile.frames['damage'].iconsSize or -1,
  1523.                    x.db.profile.frames['damage'].fontJustify)
  1524.         end
  1525.  
  1526.         local colorOverride
  1527.         if args.spellSchool == 1 then
  1528.             colorOverride = args.critical and 'damageTakenCritical' or 'damageTaken'
  1529.         else
  1530.             colorOverride = args.critical and 'spellDamageTakenCritical' or 'spellDamageTaken'
  1531.         end
  1532.  
  1533.         -- Output message
  1534.         x:AddMessage('damage', message, x.GetSpellSchoolColor(args.spellSchool, colorOverride))
  1535.     end,
  1536.  
  1537.     ["ShieldIncoming"] = function (args)
  1538.         local buffIndex = x.findBuffIndex("player", args.spellName)
  1539.         if not buffIndex then return end
  1540.         local settings, value = x.db.profile.frames['healing'], select(16, UnitBuff("player", buffIndex))
  1541.         if not value or value <= 0 then return end
  1542.  
  1543.         if TrackSpells() then x.spellCache.healing[args.spellId] = true end
  1544.  
  1545.         if IsHealingFiltered(args.spellId) then return end
  1546.  
  1547.         -- Create the message
  1548.         local message = sformat(format_gain, x:Abbreviate(value, "healing"))
  1549.  
  1550.         message = x:GetSpellTextureFormatted(args.spellId,
  1551.                                                message,
  1552.                 x.db.profile.frames['healing'].iconsEnabled and x.db.profile.frames['healing'].iconsSize or -1,
  1553.                 x.db.profile.frames['healing'].fontJustify)
  1554.  
  1555.         -- Add names
  1556.         message = message .. x.formatName(args, settings.names, true)
  1557.  
  1558.         x:AddMessage('healing', message, 'shieldTaken')
  1559.     end,
  1560.  
  1561.     ["HealingIncoming"] = function (args)
  1562.         local amount, isHoT, spellID = args.amount, args.prefix == "SPELL_PERIODIC", args.spellId
  1563.         local color = isHoT and "healingTakenPeriodic" or args.critical and "healingTakenCritical" or "healingTaken"
  1564.         local settings = x.db.profile.frames["healing"]
  1565.  
  1566.         if TrackSpells() then x.spellCache.healing[args.spellId] = true end
  1567.  
  1568.         if IsHealingFiltered(args.spellId) then return end
  1569.  
  1570.         -- Adjust the amount if the user doesnt want over healing
  1571.         if not ShowOverHealing() then
  1572.             amount = amount - args.overhealing
  1573.         end
  1574.  
  1575.         -- Don't show healing that gets absorbed by a debuff or mechanic
  1576.         if HideAbsorbedHealing() then
  1577.             amount = amount - args.absorbed
  1578.         end
  1579.  
  1580.         -- Filter out small amounts
  1581.         if amount <= 0 or FilterIncomingHealing(amount) then return end
  1582.  
  1583.         if ShowOnlyMyHeals() and not args.isPlayer then
  1584.             if ShowOnlyMyPetsHeals() and args:IsSourceMyPet() then
  1585.                 -- If its the pet, then continue
  1586.             else
  1587.                 return
  1588.             end
  1589.         end
  1590.  
  1591.         -- format_gain = "+%s"
  1592.         local healer_name, message = args.sourceName, sformat(format_gain, x:Abbreviate(amount,"healing"))
  1593.  
  1594.         if MergeIncomingHealing() then
  1595.             x:AddSpamMessage("healing", x.formatName(args, settings.names, true), amount, "healingTaken", 5)
  1596.         else
  1597.             -- Add names
  1598.             message = message .. x.formatName(args, settings.names, true)
  1599.  
  1600.             -- Add the icon
  1601.             message = x:GetSpellTextureFormatted(args.spellId,
  1602.                                                       message,
  1603.                        x.db.profile.frames['healing'].iconsEnabled and x.db.profile.frames['healing'].iconsSize or -1,
  1604.                        x.db.profile.frames['healing'].fontJustify)
  1605.  
  1606.             x:AddMessage("healing", message, color)
  1607.         end
  1608.     end,
  1609.  
  1610.     ["AuraIncoming"] = function (args)
  1611.  
  1612.         -- Some useful information about the event
  1613.         local isBuff, isGaining = args.auraType == "BUFF", args.suffix == "_AURA_APPLIED" or args.suffix == "_AURA_APPLIED_DOSE"
  1614.  
  1615.         -- Track the aura
  1616.         if TrackSpells() then x.spellCache[isBuff and 'buffs' or 'debuffs'][args.spellName]=true end
  1617.  
  1618.         -- Check to see if we are filtering this spell's name
  1619.         if IsBuffFiltered(args.spellName) then return end
  1620.  
  1621.         -- See if we are showing that type of aura
  1622.         if (isBuff and not ShowBuffs()) or (not isBuff and not ShowDebuffs()) then return end
  1623.  
  1624.         -- Begin constructing the event message and color
  1625.         local color, message
  1626.         if isGaining then
  1627.             message = sformat(format_gain, args.spellName)
  1628.             color = isBuff and 'buffsGained' or 'debuffsGained'
  1629.         else
  1630.             message = sformat(format_fade, args.spellName)
  1631.             color = isBuff and 'buffsFaded' or 'debuffsFaded'
  1632.         end
  1633.  
  1634.         -- Add the icon
  1635.         message = x:GetSpellTextureFormatted(args.spellId,
  1636.                                                   message,
  1637.                    x.db.profile.frames['general'].iconsEnabled and x.db.profile.frames['general'].iconsSize or -1,
  1638.                    x.db.profile.frames['general'].fontJustify)
  1639.  
  1640.         x:AddMessage('general', message, color)
  1641.     end,
  1642.  
  1643.     ["KilledUnit"] = function (args)
  1644.         if not ShowPartyKill() then return end
  1645.  
  1646.         local color = 'killingBlow'
  1647.         if args.destGUID then
  1648.             local class = select(2, GetPlayerInfoByGUID(args.destGUID))
  1649.             if RAID_CLASS_COLORS[class] then
  1650.                 color = RAID_CLASS_COLORS[class]
  1651.             end
  1652.         end
  1653.  
  1654.         x:AddMessage('general', sformat(format_dispell, XCT_KILLED, args.destName), color)
  1655.     end,
  1656.  
  1657.     ["InterruptedUnit"] = function (args)
  1658.         if not ShowInterrupts() then return end
  1659.  
  1660.         -- Create and format the message
  1661.         local message = sformat(format_dispell, INTERRUPTED, args.extraSpellName)
  1662.  
  1663.         -- Add the icon
  1664.         message = x:GetSpellTextureFormatted(args.extraSpellId,
  1665.                                                   message,
  1666.                    x.db.profile.frames['general'].iconsEnabled and x.db.profile.frames['general'].iconsSize or -1,
  1667.                    x.db.profile.frames['general'].fontJustify)
  1668.  
  1669.         x:AddMessage('general', message, 'interrupts')
  1670.     end,
  1671.  
  1672.     ["OutgoingMiss"] = function (args)
  1673.         local message, spellId = _G["COMBAT_TEXT_"..args.missType], args.spellId
  1674.  
  1675.         -- If this is a melee swing, it could also be our pets
  1676.         if args.prefix == 'SWING' then
  1677.             if not ShowAutoAttack() then return end
  1678.             if args:IsSourceMyPet() then
  1679.                 spellId = PET_ATTACK_TEXTURE
  1680.             else
  1681.                 spellId = 6603
  1682.             end
  1683.         end
  1684.  
  1685.         -- Check for filtered immunes
  1686.         if args.missType == "IMMUNE" and not ShowImmunes() then return end
  1687.         if args.missType ~= "IMMUNE" and not ShowMisses() then return end
  1688.  
  1689.         -- Add Icons
  1690.         message = x:GetSpellTextureFormatted(spellId,
  1691.                                              message,
  1692.              x.db.profile.frames['outgoing'].iconsEnabled and x.db.profile.frames['outgoing'].iconsSize or -1,
  1693.              x.db.profile.frames['outgoing'].fontJustify)
  1694.  
  1695.         x:AddMessage('outgoing', message, 'misstypesOut')
  1696.     end,
  1697.  
  1698.     ["IncomingMiss"] = function (args)
  1699.         if not ShowMissTypes() then return end
  1700.  
  1701.         local message = _G["COMBAT_TEXT_"..args.missType]
  1702.  
  1703.         -- Add Icons
  1704.         message = x:GetSpellTextureFormatted(args.extraSpellId,
  1705.                                                   message,
  1706.                   x.db.profile.frames['damage'].iconsEnabled and x.db.profile.frames['damage'].iconsSize or -1,
  1707.                   x.db.profile.frames['damage'].fontJustify)
  1708.  
  1709.         x:AddMessage('damage', message, missTypeColorLookup[args.missType] or 'misstypesOut')
  1710.     end,
  1711.  
  1712.     ["SpellDispel"] = function (args)
  1713.         if not ShowDispells() then return end
  1714.  
  1715.         local color = args.auraType == 'BUFF' and 'dispellBuffs' or 'dispellDebuffs'
  1716.         local message = sformat(format_dispell, XCT_DISPELLED, args.extraSpellName)
  1717.  
  1718.         -- Add Icons
  1719.         message = x:GetSpellTextureFormatted(args.extraSpellId,
  1720.                                                   message,
  1721.                    x.db.profile.frames['general'].iconsEnabled and x.db.profile.frames['general'].iconsSize or -1,
  1722.                    x.db.profile.frames['general'].fontJustify)
  1723.  
  1724.         if MergeDispells() then
  1725.             x:AddSpamMessage('general', args.extraSpellName, message, color, 0.5)
  1726.         else
  1727.             x:AddMessage('general', message, color)
  1728.         end
  1729.     end,
  1730.  
  1731.     ["SpellStolen"] = function (args)
  1732.         if not ShowDispells() then return end
  1733.         local message = sformat(format_dispell, XCT_STOLE, args.extraSpellName)
  1734.  
  1735.         -- Add Icons
  1736.         message = x:GetSpellTextureFormatted(args.extraSpellId,
  1737.                                                   message,
  1738.                    x.db.profile.frames['general'].iconsEnabled and x.db.profile.frames['general'].iconsSize or -1,
  1739.                    x.db.profile.frames['general'].fontJustify)
  1740.  
  1741.         x:AddMessage('general', message, 'dispellStolen')
  1742.     end,
  1743.  
  1744.     ["SpellEnergize"] = function (args)
  1745.         local amount, energy_type = args.amount, x.POWER_LOOKUP[args.powerType]
  1746.         if not ShowEnergyGains() then return end
  1747.         if FilterPlayerPower(mabs(tonumber(amount))) then return end
  1748.         if IsResourceDisabled( energy_type, amount ) then return end
  1749.  
  1750.         local color, message = nil, x:Abbreviate( amount, "power" )
  1751.         if energy_type == "ECLIPSE" then
  1752.             if amount > 0 then
  1753.                 color = x.LookupColorByName("color_ECLIPSE_positive")
  1754.             elseif amount < 0 then
  1755.                 color = x.LookupColorByName("color_ECLIPSE_negative")
  1756.             end
  1757.         else
  1758.             color = x.LookupColorByName("color_" .. energy_type )
  1759.         end
  1760.  
  1761.         -- Default Color will be white
  1762.         if not color then
  1763.             color = {1,1,1}
  1764.         end
  1765.         x:AddMessage("power", sformat(format_energy, message, ShowEnergyTypes() and _G[energy_type] or ""), color)
  1766.     end,
  1767. }
  1768.  
  1769. local BuffsOrDebuffs = {
  1770.     ["_AURA_APPLIED"] = true,
  1771.     ["_AURA_REMOVED"] = true,
  1772.     ["_AURA_APPLIED_DOSE"] = true,
  1773.     ["_AURA_REMOVED_DOSE"] = true,
  1774.     --["_AURA_REFRESH"] = true, -- I dont know how we should support this
  1775. }
  1776.  
  1777. -- List from: http://www.tukui.org/addons/index.php?act=view&id=236
  1778. local AbsorbList = {
  1779.     -- All
  1780.     [187805] = true, -- Etheralus (WoD Legendary Ring)
  1781.     [173260] = true, -- Shield Tronic (Like a health potion from WoD)
  1782.     [64413]  = true, -- Val'anyr, Hammer of Ancient Kings (WotLK Legendary Mace)
  1783.     [82626]  = true, -- Grounded Plasma Shield (Engineer's Belt Enchant)
  1784.     [207472] = true, -- Prydaz, Xavaric's Magnum Opus (Legendary Neck)
  1785.  
  1786.     -- Coming Soon (Delicious Cake!) Trinket
  1787.     --[231290] = true, -- TODO: Figure out which one is correct
  1788.     [225723] = true, -- Both are Delicious Cake! from item:140793
  1789.  
  1790.     -- Coming Soon (Royal Dagger Haft, item:140791)
  1791.     -- Sooooo I dont think this one is going to be trackable... we will see when i can get some logs!
  1792.     --[225720] = true, -- TODO: Figure out which is the real one
  1793.     --[229457] = true, -- Sands of Time (From the Royal Dagger Haft tinket) (Its probably this one)
  1794.     --[229333] = true, -- Sands of Time (From the Royal Dagger Haft tinket)
  1795.     --[225124] = true, -- Sands of Time (From the Royal Dagger Haft tinket)
  1796.  
  1797.     -- Coming Soon -- Animated Exoskeleton (Trinket, Item: 140789)
  1798.     [225033] = true, -- Living Carapace (Needs to be verified)
  1799.  
  1800.     -- Coming Soon -- Infernal Contract (Trinket, Item: 140807)
  1801.     [225140] = true, -- Infernal Contract (Needs to be verified)
  1802.  
  1803.  
  1804.  
  1805.     -- Legion Trinkets
  1806.     [221878] = true, -- Buff: Spirit Fragment        - Trinket[138222]: Vial of Nightmare Fog
  1807.     [215248] = true, -- Buff: Shroud of the Naglfar  - Trinket[133645]: Naglfar Fare
  1808.     [214366] = true, -- Buff: Crystalline Body       - Trinket[137338]: Shard of Rokmora
  1809.     [214423] = true, -- Buff: Stance of the Mountain - Trinket[137344]: Talisman of the Cragshaper
  1810.     [214971] = true, -- Buff: Gaseous Bubble         - Trinket[137369]: Giant Ornamental Pearl
  1811.     [222479] = true, -- Buff: Shadowy Reflection     - Trinket[138225]: Phantasmal Echo
  1812.  
  1813.     -- Death Knight
  1814.     [48707] = true,  -- Anti-Magic Shield
  1815.     [77535] = true,  -- Blood Shield
  1816.     [116888] = true, -- Purgatory
  1817.     [219809] = true, -- Tombstone
  1818.  
  1819.     -- Demon Hunter
  1820.     [227225] = true, -- Soul Barrier
  1821.  
  1822.     -- Mage
  1823.     [11426] = true,  -- Ice Barrier
  1824.  
  1825.     -- Monk
  1826.     [116849] = true, -- Life Cocoon
  1827.  
  1828.     -- Paladin
  1829.     [203538] = true, -- Greater Blessing of Kings
  1830.     [185676] = true, -- Protection Paladin T18 - 2 piece
  1831.     [184662] = true, -- Shield of Vengeance
  1832.  
  1833.     --Priest
  1834.     [152118] = true, -- Clarity of Will
  1835.     [17] = true,     -- Power Word: Shield
  1836.  
  1837.     -- Shaman
  1838.     [145378] = true, -- Shaman T16 - 2 piece
  1839.     [114893] = true, -- Stone Bulwark
  1840.  
  1841.     -- Warlock
  1842.     [108416] = true, -- Dark Pact
  1843.     [108366] = true, -- Soul Leech
  1844.  
  1845.     -- Warrior
  1846.     [190456] = true, -- Ignore Pain
  1847.     [112048] = true, -- Shield Barrier
  1848. }
  1849.  
  1850. function x.CombatLogEvent (args)
  1851.     -- Is the source someone we care about?
  1852.     if args.isPlayer or args:IsSourceMyVehicle() or ShowPetDamage() and args:IsSourceMyPet() then
  1853.         if args.suffix == "_HEAL" then
  1854.             CombatEventHandlers.HealingOutgoing(args)
  1855.  
  1856.         elseif args.suffix == "_DAMAGE" then
  1857.             CombatEventHandlers.DamageOutgoing(args)
  1858.  
  1859.         elseif args.suffix == '_MISSED' then
  1860.             CombatEventHandlers.OutgoingMiss(args)
  1861.  
  1862.         elseif args.event == 'PARTY_KILL' then
  1863.             CombatEventHandlers.KilledUnit(args)
  1864.  
  1865.         elseif args.event == 'SPELL_INTERRUPT' then
  1866.             CombatEventHandlers.InterruptedUnit(args)
  1867.  
  1868.         elseif args.event == 'SPELL_DISPEL' then
  1869.             CombatEventHandlers.SpellDispel(args)
  1870.  
  1871.         elseif args.event == 'SPELL_STOLEN' then
  1872.             CombatEventHandlers.SpellStolen(args)
  1873.  
  1874.         elseif (args.suffix == "_AURA_APPLIED" or args.suffix == "_AURA_REFRESH") and AbsorbList[args.spellId] then
  1875.             CombatEventHandlers.ShieldOutgoing(args)
  1876.  
  1877.         elseif args.suffix == "_ENERGIZE" then
  1878.             CombatEventHandlers.SpellEnergize(args)
  1879.  
  1880.         end
  1881.     end
  1882.  
  1883.     -- Is the destination someone we care about?
  1884.     if args.atPlayer or args:IsDestinationMyVehicle() then
  1885.         if args.suffix == "_HEAL" then
  1886.             CombatEventHandlers.HealingIncoming(args)
  1887.  
  1888.         elseif args.suffix == "_DAMAGE" then
  1889.             CombatEventHandlers.DamageIncoming(args)
  1890.  
  1891.         elseif args.suffix == "_MISSED" then
  1892.             CombatEventHandlers.IncomingMiss(args)
  1893.  
  1894.         elseif args.event == 'SPELL_DISPEL' then
  1895.             local message = args.sourceName .. " dispelled:"
  1896.  
  1897.             if GetLocale() == "koKR" then message = args.sourceName .. " 무효화:" end
  1898.  
  1899.             message = x:GetSpellTextureFormatted(args.extraSpellId,
  1900.                                                  message,
  1901.                   x.db.profile.frames['general'].iconsEnabled and x.db.profile.frames['general'].iconsSize or -1,
  1902.                   x.db.profile.frames['general'].fontJustify)
  1903.  
  1904.             x:AddMessage('general', message, "dispellDebuffs")
  1905.  
  1906.         elseif (args.suffix == "_AURA_APPLIED" or args.suffix == "_AURA_REFRESH") and AbsorbList[args.spellId] then
  1907.             CombatEventHandlers.ShieldIncoming(args)
  1908.         end
  1909.     end
  1910.  
  1911.     -- Player Auras
  1912.     if args.atPlayer and BuffsOrDebuffs[args.suffix] then
  1913.         CombatEventHandlers.AuraIncoming(args)
  1914.  
  1915.     end
  1916. end
  1917.  
  1918. function x.findBuffIndex(unitName, spellName)
  1919.     for i = 1, 40 do
  1920.  
  1921.         -- TODO: Keep if we want to change this to find SpellID index
  1922.         -- buffName, _, _, _, _, _, _, _, _ , spellId = UnitBuff(unitName, i)
  1923.  
  1924.         if UnitBuff(unitName, i) == spellName then
  1925.             return i
  1926.         end
  1927.     end
  1928.     return false
  1929. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement