Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

Event Horizon Continued (MoP Beta)

By: a guest on Jul 5th, 2012  |  syntax: Lua  |  size: 101.48 KB  |  views: 50  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. --local DEBUG = true
  2. local EHN,ns = ...
  3. EventHorizon = ns
  4.  
  5. local class = select(2,UnitClass('player'))
  6. local playername = UnitName('player')..' - '..GetRealmName('player')
  7. local Cataclysm = select(4,GetBuildInfo()) >= 40000
  8. local Mop       = select(4,GetBuildInfo()) >= 50000
  9.  
  10. ns.defaultDB = {
  11.         point = {'CENTER', 'UIParent', 'CENTER'},
  12.         isActive = true,
  13.         version = 4,
  14. }
  15.  
  16. ns.defaultDBG = {
  17.         profiles = {
  18.                 default = {},
  19.         },
  20.         itemInfo = {},
  21.         profilePerChar = {},
  22.         defaultProfile = 'default',
  23.         version = 4,
  24. }
  25.  
  26. ns.db = {
  27.         point = {'CENTER', 'UIParent', 'CENTER'},
  28.         isActive = true,
  29.         version = 4,
  30. }
  31.  
  32. ns.frames = {
  33.         config = {},    -- validated barframe config entries - format = ns.frames.config[i] = {barconfig}
  34.         frames = {},    -- all loaded barframes
  35.         active = {},    -- refs to barframes currently collecting information (matches talent spec)
  36.         shown = {},             -- refs to barframes currently visible to the player (matches stance)
  37.         mouseover = {}, -- refs to barframes requiring mouseover target information
  38. }
  39. ns.defaultconfig = {
  40.         showTrinketBars = {
  41.                 default = true,
  42.                 boolean = true,
  43.                 name = 'Show Trinket Bars',
  44.                 desc = 'When enabled, displays trinkets in addition to spells and abilities.',
  45.         },
  46.         castLine = {
  47.                 default = true,
  48.                 boolean = true,
  49.                 number = true,
  50.                 name = 'End-of-Cast Line',
  51.                 desc = 'When enabled, adds a vertical line which marks the end of any spellcast in progress.',
  52.         },
  53.         gcdStyle = {
  54.                 default = 'line',
  55.                 valid = {'line','bar',false},
  56.                 name = 'Global Cooldown Style',
  57.                 desc = 'When set to Line, a vertical line will mark the end of the current GCD. \n When set to Bar, a textured bar is used instead. \n Can also be disabled to neither track or display the GCD.',
  58.         },
  59.  
  60.         enableRedshift = {
  61.                 default = false,
  62.                 boolean = true,
  63.                 name = 'Enable Redshift',
  64.                 desc = 'An optional module which hides Axis untless certain conditions, such as combat or targeting, are met.',
  65.         },
  66.         Redshift = {
  67.                 name = 'Redshift States',
  68.                 desc = 'Conditions for the Redshift Module to show Axis.',
  69.                 sub = {
  70.                         showCombat = {
  71.                                 default = true,
  72.                                 boolean = true,
  73.                                 name = 'Show in Combat',
  74.                                 desc = 'When enabled, displays Axis when in combat.',
  75.                         },
  76.                         showHarm = {
  77.                                 default = true,
  78.                                 boolean = true,
  79.                                 name = 'Show Harmful Units',
  80.                                 desc = 'When enabled, displays Axis when an attackable unit is targeted.',
  81.                         },
  82.                         showHelp = {
  83.                                 default = false,
  84.                                 boolean = true,
  85.                                 name = 'Show Helpful Units',
  86.                                 desc = 'When enabled, displays Axis when a friendly unit is targeted.',
  87.                         },
  88.                         showBoss = {
  89.                                 default = true,
  90.                                 boolean = true,
  91.                                 name = 'Show on Boss',
  92.                                 desc = 'When enabled, displays Axis when a boss-level unit is targeted.',
  93.                         },
  94.                         showFocus = {
  95.                                 default = false,
  96.                                 boolean = true,
  97.                                 name = 'Show on Focus',
  98.                                 desc = 'When enabled, displays Axis when you have a focus target.'
  99.                         },
  100.                         hideVehicle = {
  101.                                 default = true,
  102.                                 boolean = true,
  103.                                 name = 'Hide in Vehicle',
  104.                                 desc = 'When enabled, HIDES Axis when using a vehicle with its own actionbar.',
  105.                         },
  106.                         hideVitals = {
  107.                                 default = true,
  108.                                 boolean = true,
  109.                                 name = 'Hide Vitals',
  110.                                 desc = 'When enabled, the Vitals display is hidden whenever Axis is hidden.',
  111.                         },
  112.                 },
  113.         },
  114.  
  115. --      Pulse = 0.5,
  116. --      PulseIntensity = 0.5,
  117. --      PulseFPS = 30,
  118.  
  119.         Lines = {
  120.                 default = false,
  121.                 boolean = true,
  122.                 table = true,
  123.                 name = 'Static Lines',
  124.                 desc = 'When enabled, enables the Lines Module.',
  125.         },
  126.         LinesColor = {
  127.                 default = {1,1,1,0.5},
  128.                 table = true,
  129.                 name = 'Static Line Colors',
  130.                 desc = 'The color of any static lines being displayed by the Lines Axis Module.'
  131.         },
  132.  
  133.         anchor = {
  134.                 default = {"TOPRIGHT", "EventHorizonHandle", "BOTTOMRIGHT"},
  135.                 table = true,
  136.                 name = 'Anchor Position',
  137.                 desc = "Axis' Handle Information",
  138.         },
  139.         width = {
  140.                 default = 150,
  141.                 number = true,
  142.                 name = 'Bar Width',
  143.                 desc = 'Set the width of shown bars. Icons add to the actual width of the window.'
  144.         },
  145.         height = {
  146.                 default = 18,
  147.                 number = true,
  148.                 name = 'Bar Height',
  149.                 desc = 'Set the height of each individual bar. Also sets the width of icons.',
  150.         },
  151.         spacing = {
  152.                 default = 0,
  153.                 number = true,
  154.                 name = 'Bar Spacing',
  155.                 desc = 'Set the spacing between each shown bar.',
  156.         },
  157.         staticheight = {
  158.                 default = false,
  159.                 number = true,
  160.                 boolean = true,
  161.                 name = 'Static Height',
  162.                 desc = 'When set, Axis will resize its bars to fit this height. \n When disabled, Axis will grow or shrink depending on the number of shown bars.'
  163.         },
  164.         hideIcons = {
  165.                 default = false,
  166.                 boolean = true,
  167.                 name = 'Hide Bar Icons',
  168.                 desc = 'When enabled, Icons are not shown, however stack-text is still shown.',
  169.         },
  170.  
  171.         past = {
  172.                 default = -3,
  173.                 number = true,
  174.                 name = 'Past Time',
  175.                 desc = 'How many seconds in the past for Axis to display.',
  176.         },
  177.         future = {
  178.                 default = 12,
  179.                 number = true,
  180.                 name = 'Future Time',
  181.                 desc = 'How many seconds in the future for Axis to display.'
  182.         },
  183.  
  184.         texturedbars = {
  185.                 default = true,
  186.                 boolean = true,
  187.                 name = 'Textured Bars',
  188.                 desc = 'When enabled, Axis displays textured bars according to the Bar Texture option. \n When disabled, Axis displays the bars as a solid color.',
  189.         },
  190.        
  191.         bartexture = {
  192.                 default = "Interface\\Addons\\EventHorizon\\Smooth",
  193.                 string = true,
  194.                 name = 'Bar Texture',
  195.                 desc = 'Set the texture to use for each bar.',
  196.         },
  197.         texturealphamultiplier = {
  198.                 default = 2,
  199.                 number = true,
  200.                 name = 'Texture Alpha-Multiplier',
  201.                 desc = 'This option directly influences the opacity of textured bars to account for varying degrees of visibility.'
  202.         },
  203.  
  204.         backdrop = {
  205.                 default = true,
  206.                 boolean = true,
  207.                 name = 'Show Backdrop',
  208.                 desc = 'When enabled, Axis displays the backdrop.',
  209.         },
  210.         padding = {
  211.                 default = 3,
  212.                 number = true,
  213.                 name = 'Backdrop Padding',
  214.                 desc = 'Set the padding between the backdrop and bar edges.'
  215.         },
  216.         bg = {
  217.                 default = "Interface\\ChatFrame\\ChatFrameBackground",
  218.                 string = true,
  219.                 name = 'Backdrop Texture',
  220.                 desc = 'Set the texture to use for the backdrop.',
  221.         },
  222.         border = {
  223.                 default = "Interface\\Tooltips\\UI-Tooltip-Border",
  224.                 string = true,
  225.                 name = 'Backdrop Border Texture',
  226.                 desc = 'Set the texture to use for the backdrop border.',
  227.         },
  228.         edgesize = {
  229.                 default = 8,
  230.                 number = true,
  231.                 name = 'Backdrop Edge Size',
  232.                 desc = 'Set the thickness of the backdrop border.',
  233.         },
  234.         inset = {
  235.                 default = {top = 2, bottom = 2, left = 2, right = 2},
  236.                 table = true,
  237.                 name = 'Backdrop Insets',
  238.                 desc = 'Trim the backdrop texture to account for its border.',
  239.         },
  240.  
  241.         stackFont = {
  242.                 default = false,
  243.                 boolean = true,
  244.                 string = true,
  245.                 name = 'Stack Text Font',
  246.                 desc = 'Sets the font of the stack text shown on bar icons.',
  247.         },
  248.         stackFontSize = {
  249.                 default = false,
  250.                 boolean = true,
  251.                 number = true,
  252.                 name = 'Stack Text Size',
  253.                 desc = 'Set the size of the stack text shown on bar icons.',
  254.         },
  255.         stackFontOutline = {
  256.                 default = false,
  257.                 valid = {'OUTLINE','THICKOUTLINE','MONOCHROME',false},
  258.                 name = 'Stack Text Outline',
  259.                 desc = 'Set the outline of the stack text shown on bar icons.',
  260.         },
  261.         stackFontColor = {
  262.                 default = false,
  263.                 table = true,
  264.                 name = 'Stack Text Color',
  265.                 desc = 'Sets the color of the stack text shown on bar icons.',
  266.         },
  267.         stackFontShadow = {
  268.                 default = false,
  269.                 table = true,
  270.                 boolean = true,
  271.                 name = 'Stack Text Shadow',
  272.                 desc = 'Apply a shadow effect to the stack text shown on bar icons. \n This option adjusts the shadow color and can be left at default for black.',
  273.         },
  274.         stackFontShadowOffset = {
  275.                 default = false,
  276.                 table = true,
  277.                 boolean = true,
  278.                 name = 'Stack Text Shadow Offset',
  279.                 desc = 'Set the offset of the stack text shadow.',
  280.         },
  281.         stackOnRight = {
  282.                 default = false,
  283.                 boolean = true,
  284.                 name = 'Stack Text on Right',
  285.                 desc = 'When enabled the stack text is displayed on the right-hand side of the bars. \n When disabled, stack text is shown on the left side, as default.',
  286.         },
  287. }
  288.  
  289. ns.defaultcolors = {
  290.         sent = {true,class == 'PRIEST' and 0.7 or 1,1},
  291.         tick = {true,class == 'PRIEST' and 0.7 or 1,1},
  292.         casting = {0,1,0.2,0.25},
  293.         castLine = {0,1,0.2,0.3},
  294.         cooldown = {0.6,0.8,1,0.3},
  295.         debuffmine = {true,class == 'PRIEST' and 0.7 or 1,0.3},
  296.         debuff = {true,0.5,0.3},
  297.         playerbuff = {true,class == 'PRIEST' and 0.7 or 1,0.3},
  298.         nowLine = {1,1,1,0.3},
  299.         bgcolor = {0,0,0,0.6},
  300.         bordercolor = {1,1,1,1},
  301.         gcdColor = {1,1,1,0.5},
  302. }
  303.  
  304. ns.defaultlayouts = {
  305.         tick = {
  306.                 top = 0,
  307.                 bottom = 0.2,
  308.         },
  309.         smalldebuff = {
  310.                 top = 0.2,
  311.                 bottom = 0.35,
  312.         },
  313.         cantcast = {
  314.                 top = 0.35,
  315.                 bottom = 1,
  316.         },
  317.         default = {
  318.                 top = 0.2,
  319.                 bottom = 1,
  320.         },
  321. }
  322.  
  323. ns.config = {Redshift = {}, blendModes = {}}
  324. ns.layouts = {}
  325. ns.colors = {}
  326.  
  327. ns.glyphs = {}                  -- currently active glyph storage. format = ns.glyphs[i] = glyphID
  328. ns.otherIDs = {}                -- combatlog events either not directly tied to bars, or using spells other than bar.spellID
  329. ns.modules = {}                 -- storage for loaded modules - format = module = ns.modules[string.lower(moduleName)] = {namespace}
  330.  
  331.  
  332. ns.vars = {                             -- storage for widely used vars/math/etc - format = ns.vars[var] = val
  333.         config = {},
  334.         onepixelwide = 1,
  335.         visibleFrame = true,
  336.         numframes = 0,
  337.         buff = {},
  338.         debuff = {},
  339. }
  340. local vars = ns.vars
  341.  
  342. local UnitDebuff = UnitDebuff
  343. local UnitBuff = UnitBuff
  344.  
  345. local SpellFrame = {}
  346.  
  347. local EventHorizonFrame = CreateFrame('Frame','EventHorizonFrame',UIParent)
  348. local mainframe = CreateFrame('Frame',nil,EventHorizonFrame)
  349. local frame = CreateFrame('Frame')
  350. local frame2 = CreateFrame('Frame')
  351. local frame3 = CreateFrame('Frame')
  352. ns.mainframe = mainframe
  353.  
  354. -- Frames to be created on demand
  355. local handle
  356.  
  357.  
  358. local function printhelp(...) if select('#',...)>0 then return tostring((select(1,...))), printhelp(select(2,...)) end end
  359. local function debug(...)
  360.         print(...)
  361. end
  362. local function print(...)
  363.         ChatFrame1:AddMessage('EventHorizon: '..strjoin(',',printhelp(...)))
  364. end
  365.  
  366. local draworder = {
  367.         default = -8,
  368.         cooldown = -7,
  369.         debuff = -6,
  370.         playerbuff = -5,
  371.         debuffmine = -4,
  372.         casting = -3,
  373.         sent = -2,
  374.         tick = -1,
  375.         channeltick = 0,
  376.         now = 1,
  377.         gcd = 2,
  378.         nowI = 7,
  379. }
  380.  
  381. local auraids = {
  382.         tick = true,
  383.         cantcast = true,
  384.         debuff = true,
  385.         playerbuff = true,
  386.         debuffmine = true,
  387. }
  388.  
  389. local customColors = {
  390.         debuff = true,
  391.         debuffmine = true,
  392.         playerbuff = true,
  393. }
  394.  
  395. local exemptColors = {
  396.         default = true,
  397.         sent = true,
  398.         tick = true,
  399.         channeltick = true,
  400.         castLine = true,
  401.         nowLine = true,
  402.         bgcolor = true,
  403.         bordercolor = true,
  404.         gcdColor = true,
  405. }
  406.  
  407. local equipSlots = {
  408.         ["ChestSlot"] = 5,
  409.         ["FeetSlot"] = 8,
  410.         ["Finger0Slot"] = 11,
  411.         ["Finger1Slot"] = 12,
  412.         ["HandsSlot"] = 10,
  413.         ["HeadSlot"] = 1,
  414.         ["LegsSlot"] = 7,
  415.         ["MainHandSlot"] = 16,
  416.         ["NeckSlot"] = 2,
  417.         ["RangedSlot"] = 18,
  418.         ["SecondaryHandSlot"] = 17,
  419.         ["ShirtSlot"] = 4,
  420.         ["ShoulderSlot"] = 3,
  421.         ["TabardSlot"] = 19,
  422.         ["Trinket0Slot"] = 13,
  423.         ["Trinket1Slot"] = 14,
  424.         ["WaistSlot"] = 6,
  425.         ["WristSlot"] = 9,
  426. }
  427.  
  428. local mainframeEvents = {
  429.         ['COMBAT_LOG_EVENT_UNFILTERED'] = true,
  430.         ['PLAYER_TALENT_UPDATE'] = true,
  431.         ['UPDATE_SHAPESHIFT_FORM'] = true,
  432.         ['UPDATE_SHAPESHIFT_FORMS'] = true,
  433.         ['SPELL_UPDATE_COOLDOWN'] = true,
  434.         ['PLAYER_LEVEL_UP'] = true,
  435.         ['PLAYER_TARGET_CHANGED'] = true,
  436.         ['UNIT_AURA'] = true,
  437. }
  438.  
  439. local reloadEvents = {
  440.         ['GLYPH_ADDED'] = true,
  441.         ['GLYPH_ENABLED'] = true,
  442.         ['GLYPH_REMOVED'] = true,
  443.         ['GLYPH_UPDATED'] = true,
  444.         ['GLYPH_DISABLED'] = true,
  445.         ['PLAYER_REGEN_DISABLED'] = true,
  446.         ['PLAYER_REGEN_ENABLED'] = true,
  447.         ['ZONE_CHANGED_NEW_AREA'] = true,
  448.         ['ZONE_CHANGED_INDOORS'] = true,
  449.         ['LFG_LOCK_INFO_RECEIVED'] = true,
  450. }
  451.  
  452. local tickevents = {
  453.         ['SPELL_PERIODIC_DAMAGE'] = true,
  454.         ['SPELL_PERIODIC_HEAL'] = true,
  455.         ['SPELL_PERIODIC_ENERGIZE'] = true,
  456.         ['SPELL_PERIODIC_DRAIN'] = true,
  457.         ['SPELL_PERIODIC_LEACH'] = true,       
  458.         ['SPELL_DAMAGE'] = true,
  459.         ['SPELL_HEAL'] = true,
  460.         --['SPELL_AURA_APPLIED'] = true,
  461. }
  462.  
  463. -- Dispatch event to method of the event's name.
  464. local EventHandler = function (self, event, ...)
  465.         local f = self[event]
  466.         if f then
  467.                 --if event ~= 'COMBAT_LOG_EVENT_UNFILTERED' then print(event) end
  468.                 f(self,...)
  469.                 if event ~= 'COMBAT_LOG_EVENT_UNFILTERED' then
  470.                         ns:ModuleEvent(event,...)
  471.                 end
  472.         end
  473. end
  474.  
  475. local Clone = function (t)
  476.         local new = {}
  477.         local i, v = next(t, nil)       -- i is an index of t, v = t[i]
  478.         while i do
  479.                 new[i] = v
  480.                 i, v = next(t, i)
  481.         end
  482.         return new
  483. end
  484.  
  485. -- pairs(t) for metatable usage. Doesn't return numeric index unless value is keyless.
  486. function mpairs(t)
  487.         local visited = {}
  488.         local f
  489.         f = function(_, k)
  490.                 if not t then
  491.                         return
  492.                 end
  493.                 while true do
  494.                         local k2, v2 = next(t, k)
  495.                         if k2 == nil then
  496.                                 break
  497.                         end
  498.                         if not visited[k2] then
  499.                                 visited[k2] = true
  500.                                 return k2, v2
  501.                         end
  502.                         k = k2
  503.                 end
  504.                 local mt = getmetatable(t)
  505.                 if mt then
  506.                         local indextable = mt.__index
  507.                         if type(indextable) == "table" then
  508.                                 t = indextable
  509.                                 return f()
  510.                         end
  511.                 end
  512.                 t = nil
  513.         end
  514.         return f
  515. end
  516.  
  517. -- Since Blizzard doesn't provide the ability to look up a slot name from a slotID...
  518. local GetSlotName = function (slot)
  519.         for k,v in pairs(equipSlots) do
  520.                 if v == slot then return k end
  521.         end
  522. end
  523.  
  524. local mainframe_UNIT_AURA = function (self,unit)
  525.         if vars.buff[unit] then
  526.                 table.wipe(vars.buff[unit])
  527.                 for i = 1,50 do
  528.                         local name, _, icon, count, _, duration, expirationTime, source, _, _, spellID = UnitBuff(unit,i)
  529.                         --print(name,icon,count,duration,expirationTime,source,spellID)
  530.                         if not (name and spellID) then break end
  531.                         table.insert(vars.buff[unit],{
  532.                                 name = name,
  533.                                 icon = icon,
  534.                                 count = count,
  535.                                 duration = duration,
  536.                                 expirationTime = expirationTime,
  537.                                 source = source,
  538.                                 spellID = spellID,
  539.                         })
  540.                 end
  541.         end
  542.         if vars.debuff[unit] then
  543.                 table.wipe(vars.debuff[unit])
  544.                 for i = 1,100 do
  545.                         local name, _, icon, count, _, duration, expirationTime, source, _, _, spellID = UnitDebuff(unit,i)
  546.                         if not (name and spellID) then break end
  547.                         table.insert(vars.debuff[unit], {
  548.                                 name = name,
  549.                                 icon = icon,
  550.                                 count = count,
  551.                                 duration = duration,
  552.                                 expirationTime = expirationTime,
  553.                                 source = source,
  554.                                 spellID = spellID,
  555.                         })
  556.                 end
  557.         end    
  558.         for i,spellframe in pairs(ns.frames.frames) do
  559.                 if (spellframe.auraunit and spellframe.auraunit == unit) then
  560.                         spellframe:UNIT_AURA(unit)
  561.                 end
  562.         end
  563. end
  564.  
  565. local GetAura = function (self)
  566.         local s = self.isType == 'playerbuff' and 'buff' or 'debuff'
  567.         local a = vars[s][self.auraunit]
  568.         if not a then return end
  569.         if type(self.auraname) == 'table' then
  570.                 for k,aura in pairs(a) do
  571.                         for i = 1,#self.auraname do
  572.                                 if (aura.name == self.auraname[i]) and (aura.source == 'player' or self.unique) and (not(self.uniqueID) or self.uniqueID == aura.spellID) then
  573.                                         return aura.name, aura.icon, aura.count, aura.duration, aura.expirationTime, aura.source, aura.spellID
  574.                                 end
  575.                         end
  576.                 end
  577.         else
  578.                 for k,aura in pairs(a) do
  579.                         if (aura.name == self.auraname) and (aura.source == 'player' or self.unique) and (not(self.uniqueID) or self.uniqueID == aura.spellID) then
  580.                                 return aura.name, aura.icon, aura.count, aura.duration, aura.expirationTime, aura.source, aura.spellID
  581.                         end
  582.                 end
  583.         end
  584. end
  585.  
  586. ns.GetAura = function (self,auralist,auratype,unit)
  587.         if not auratype and unit then return error('Invalid arg in EventHorizon:GetAura(self,auralist,auratype,unit)') end
  588.         local a = vars[auratype][unit]
  589.         if not a then return end
  590.         if type(auralist) == 'table' then
  591.                 for k,aura in pairs(a) do
  592.                         for i = 1,#auralist do
  593.                                 local t = type(auralist[i])
  594.                                 if (t == 'string' and aura.name or t == 'number' and aura.spellID) == auralist[i] then
  595.                                         return aura.name, aura.icon, aura.count, aura.duration, aura.expirationTime, aura.source, aura.spellID
  596.                                 end
  597.                         end
  598.                 end
  599.         else
  600.                 for k,aura in pairs(a) do
  601.                         local t = type(auralist)
  602.                         if (t == 'string' and aura.name or t == 'number' and aura.spellID) == auralist then
  603.                                 return aura.name, aura.icon, aura.count, aura.duration, aura.expirationTime, aura.source, aura.spellID
  604.                         end
  605.                 end
  606.         end
  607. end
  608.  
  609. -- SpellFrame - All spell bar frames inherit from this class.
  610.  
  611. --Indicators represent a point or range of time. There are different types. The type determines the color and position.
  612. local typeparent = {}
  613.  
  614. local SetStacks = function (self,count)
  615.         if count>1 then
  616.                 self.stacks:SetFormattedText('%d',count)
  617.         elseif self.glyphstacks then
  618.                 if self.glyphstacks[guid] and (self.glyphstacks[guid] > 0) then
  619.                         self.stacks:SetText(self.glyphstacks[guid])
  620.                 else
  621.                         self.stacks:SetText()
  622.                 end
  623.         else
  624.                 self.stacks:SetText()
  625.         end
  626. end
  627.  
  628. local SpellFrame_NotInteresting = function (self, unitid, spellname)
  629.         return unitid ~= 'player' or spellname ~= self.spellname
  630. end
  631.  
  632. -- FindItemInfo:
  633. local SpellFrame_FindItemInfo = function (self,slotID)
  634.         local itemID = self.itemID or GetInventoryItemID('player',slotID or self.slotID)
  635.         if itemID then
  636.                 local dbI = EventHorizonDBG.itemInfo[itemID]
  637.                 if dbI and (dbI.name and dbI.tex) then
  638.                         return itemID,dbI.name,dbI.tex
  639.                 else
  640.                         local name,_,_,_,_,_,_,_,_,tex = GetItemInfo(itemID)
  641.                         if (name and tex) then
  642.                                 EventHorizonDBG.itemInfo[itemID] = {name = name, tex = tex}
  643.                                 return itemID,name,tex
  644.                         end
  645.                 end
  646.         end
  647. end
  648.  
  649. local SpellFrame_AddIndicator = function (self, typeid, layoutid, time, usetexture)
  650.         local indicator
  651.         local parent = typeparent[typeid]
  652.         local ndtex, ndcol
  653.         if usetexture and self.bartexture then ndtex = self.bartexture end
  654.         if typeid and customColors[typeid] then
  655.                 if self.barcolorunique and typeid == 'debuff' then
  656.                         ndcol = self.barcolorunique
  657.                 elseif self.barcolor then
  658.                         ndcol = self.barcolor
  659.                 end                    
  660.         end
  661.        
  662.         if not parent then
  663.                 --print'creating indicator parent'
  664.                 parent = {}
  665.                 parent.unused = {}
  666.                 typeparent[typeid] = parent
  667.                 --if DEBUG and typeid=='tick'  then parent.numchildren=0 end--]]
  668.         end
  669.         if #parent.unused>0 then
  670.                 indicator = tremove(parent.unused)
  671.                 indicator:ClearAllPoints()
  672.                 indicator.time = nil
  673.                 indicator.start = nil
  674.                 indicator.stop = nil
  675.                 indicator.happened = nil
  676.                 --if DEBUG and typeid=='tick'  then debug('reusing indicator',indicator.frameindex) end--]]
  677.         else
  678.                 indicator = mainframe:CreateTexture(nil, 'ARTWORK', nil, draworder[typeid])
  679.                 indicator.parent = parent
  680.                 --if DEBUG and typeid=='tick' then parent.numchildren=parent.numchildren+1 indicator.frameindex=parent.numchildren debug('adding indicator',indicator.frameindex) end--]]
  681.         end
  682.         -- Layout
  683.         local layouts = ns.layouts
  684.         local layout = layouts[layoutid] or layouts.default
  685.         local color = ndcol or ns.colors[typeid] or ns.colors.default
  686.         if layoutid == 'frameline' then
  687.                 color = typeid == 'sent' and ns.colors.castLine or ns.colors[typeid]
  688.                 indicator:SetPoint('TOP',ns.mainframe)
  689.                 indicator:SetPoint('BOTTOM',ns.mainframe)
  690.         else
  691.                 indicator:SetPoint('TOP',self, 'TOP', 0, -layout.top*vars.barheight)
  692.                 indicator:SetPoint('BOTTOM',self, 'TOP', 0, -layout.bottom*vars.barheight)
  693.         end
  694.        
  695.         if usetexture then
  696.                 indicator:SetTexture(ndtex or vars.bartexture)
  697.                 indicator:SetTexCoord(unpack(layout.texcoords))
  698.         else
  699.                 indicator:SetTexture(1,1,1,1)
  700.         end
  701.         indicator:SetVertexColor(unpack(ndcol or color))
  702.         if ns.config.blendModes[typeid] and type(ns.config.blendModes[typeid]) == 'string' then
  703.                 indicator:SetBlendMode(ns.config.blendModes[typeid])
  704.         end
  705.  
  706.         indicator:Hide()
  707.         indicator:SetWidth(vars.onepixelwide)
  708.         indicator.time = time
  709.         indicator.typeid = typeid
  710.         indicator.layoutid = layoutid
  711.         if indicator then
  712.                 tinsert(self.indicators, indicator)
  713.         end
  714.         return indicator
  715. end
  716.  
  717. local SpellFrame_AddSegment = function (self, typeid, layoutid, start, stop, start2)
  718.         if stop<start then return end
  719.         local indicator = self:AddIndicator(typeid, layoutid, start, vars.texturedbars)
  720.         indicator.time = nil
  721.         indicator.start = start
  722.         indicator.stop = stop
  723.         --debug(start,stop)
  724.         return indicator
  725. end
  726.  
  727. local SpellFrame_Remove = function (self,indicator)
  728.         if type(indicator)=='number' then
  729.                 local index, indicator = indicator, self.indicators[indicator]
  730.                 indicator:Hide()
  731.                 --if DEBUG and indicator.typeid=='tick' then debug('deleting',indicator.frameindex) end--]]
  732.                 tinsert(indicator.parent.unused, tremove(self.indicators, index))
  733.         else
  734.                 for index=1,#self.indicators do
  735.                         if self.indicators[index]==indicator then
  736.                                 indicator:Hide()
  737.                                 --if DEBUG and indicator.typeid=='tick' then debug('deleting',indicator.frameindex) end--]]
  738.                                 tinsert(indicator.parent.unused, tremove(self.indicators,index))
  739.                                 break
  740.                         end
  741.                 end
  742.         end
  743. end
  744.  
  745. local SpellFrame_OnUpdate = function (self,elapsed)
  746.         local now = GetTime()
  747.         local diff = now+vars.past
  748.  
  749.         -- spellframe.nexttick is used to schedule the creation of predicted ticks as soon as they scroll past now+future.
  750.         local nexttick = self.nexttick
  751.         if nexttick and nexttick <= now+vars.future then
  752.                 if nexttick<=self.lasttick then
  753.                         self:AddIndicator('tick', 'tick', nexttick)
  754.                         self.latesttick = nexttick
  755.                         self.nexttick = nexttick + (self.dotMod or self.dot)
  756.                 else
  757.                         self.nexttick = nil
  758.                 end
  759.         end
  760.         for k=#self.indicators,1,-1 do
  761.                 local indicator = self.indicators[k]
  762.                 local time = indicator.time
  763.                 if time then
  764.                         -- Example:
  765.                         -- [-------|------->--------]
  766.                         -- past    now     time     future
  767.                         -- now=795, time=800, past=-3, then time is time-now-past after past.
  768.                         local p = (time-diff)*vars.scale
  769.                         local remove = p<0 or (time<=now and indicator.typeid=='tick' and not indicator.happened)
  770.                         if remove then
  771.                                 indicator:Hide()
  772.                                 --if DEBUG and indicator.typeid=='tick' then debug('deleting',indicator.frameindex) end--]]
  773.                                 tinsert(indicator.parent.unused, tremove(self.indicators,k))
  774.                         elseif p<=1 then
  775.                                 indicator:SetPoint('LEFT', self, 'LEFT', p*vars.barwidth, 0)
  776.                                 indicator:Show()
  777.                         end
  778.                 else
  779.                         local start, stop = indicator.start, indicator.stop
  780.                         local p1 = (start-diff)*vars.scale
  781.                         local p2 = (stop-diff)*vars.scale
  782.                         if p2<0 then
  783.                                 indicator:Hide()
  784.                                 --if DEBUG and indicator.typeid=='tick' then debug('deleting',indicator.frameindex) end--]]
  785.                                 tinsert(indicator.parent.unused, tremove(self.indicators,k))
  786.                         elseif 1<p1 then
  787.                                 indicator:Hide()
  788.                         else
  789.                                 indicator:Show()
  790.                                 indicator:SetPoint('LEFT', self, 'LEFT', 0<=p1 and p1*vars.barwidth or 0, 0)
  791.                                 indicator:SetPoint('RIGHT', self, 'LEFT', p2<=1 and p2*vars.barwidth+1 or vars.barwidth, 0)
  792.                         end
  793.                 end
  794.         end
  795. end
  796.  
  797. local SpellFrame_UNIT_SPELLCAST_SENT = function (self, unitid, spellname, spellrank, spelltarget)
  798.         if ((self.cast and not(self.cast[spellname])) or (spellname ~= self.spellname)) or unitid ~= 'player' then return end
  799.         local now = GetTime()
  800.         self:AddIndicator('sent', 'default', now)
  801. end
  802.  
  803. local Cast_Start = function (self, unitid, spellname, spellrank)
  804.         if not(self.cast[spellname]) or unitid ~= 'player' then return end
  805.         local _,_,_,_,startTime,endTime,_ = self.cast[spellname].func(unitid)
  806.         if not(startTime and endTime) then return end
  807.        
  808.         startTime, endTime = startTime/1000, endTime/1000
  809.         self.casting = self:AddSegment('casting', 'default', startTime, endTime)
  810.        
  811.         local name,_,icon = GetSpellInfo(self.cast[spellname].id)
  812.         self.lastcast = name
  813.         if not(self.keepIcon) then
  814.                 self.icon:SetTexture(icon)
  815.         end
  816.        
  817.         if vars.castLine and (endTime - startTime > vars.castLine) then
  818.                 self.castLine = self:AddIndicator('sent', 'frameline', endTime)
  819.         end
  820.        
  821.         local numhits = self.cast[spellname].numhits and self.cast[spellname].numhits ~= true and self.cast[spellname].numhits
  822.         if numhits then
  823.                 local casttime = endTime - startTime
  824.                 local tick = casttime/numhits
  825.                 if numhits and numhits ~= true then
  826.                         for i=1,numhits do
  827.                                 self:AddIndicator('channeltick', 'channeltick', startTime + i*tick)
  828.                         end
  829.                 end
  830.         end
  831. end
  832.  
  833. local Cast_Update = function (self, unitid, spellname, spellrank)
  834.         --debug('UNIT_SPELLCAST_CHANNEL_UPDATE',unitid, spellname, spellrank)
  835.         if not(self.cast[spellname]) or unitid ~= 'player' then return end
  836.         local _,_,_,_,startTime,endTime,_ = self.cast[spellname].func(unitid)
  837.         if not (startTime and endTime) then return end
  838.         startTime, endTime = startTime/1000, endTime/1000
  839.         if self.casting then
  840.                 self.casting.stop = endTime
  841.                 if vars.castLine and self.castLine then
  842.                         self.castLine.time = endTime
  843.                 end
  844.         end
  845.         self:RemoveChannelTicksAfter(endTime)
  846. end
  847.  
  848. local Cast_Stop = function (self, unitid, spellname, spellrank)
  849.         if not(self.cast[spellname]) or unitid ~= 'player' then return end
  850.         local now = GetTime()
  851.         if self.casting then
  852.                 self.casting.stop = now
  853.                 if vars.castLine and self.castLine then
  854.                         self.castLine.time = now
  855.                 end
  856.                 self.casting = nil
  857.         end
  858.         self:RemoveChannelTicksAfter(now)
  859. end
  860.  
  861. local SpellFrame_UNIT_AURA = function (self, unitid)
  862.         if unitid~=self.auraunit then return end
  863.         if not (self.spellname and self.auraname) then return end      
  864.        
  865.         local name, icon, count, duration, expirationTime, source, spellID = GetAura(self,unitid)
  866.         --print(name, icon, count, duration, expirationTime, source, spellID)
  867.         local afflicted = name and (self.unique or source=='player') and (not self.minstacks or count>=self.minstacks)
  868.         local addnew
  869.         local now = GetTime()
  870.         local start
  871.         local targ = UnitName(self.auraunit)
  872.        
  873.         if self.uniqueID and self.uniqueID ~= spellID then
  874.                 return
  875.         end
  876.        
  877.         if self.aurasegment and expirationTime == 0 and duration == 0 then      -- Timeless aura, bar exists (Overkill)
  878.                 for i = #self.indicators,1,-1 do
  879.                         self:Remove(i)
  880.                 end
  881.                 self.aurasegment = nil
  882.                 self.nexttick = nil
  883.                 self.stacks:SetText()
  884.                 return
  885.         end
  886.        
  887.         if expirationTime == 0 then
  888.                 return
  889.         end
  890.        
  891.         if afflicted then
  892.                 start = expirationTime-duration
  893.                 if icon and not(self.cast or self.slotID or self.keepIcon) then self.icon:SetTexture(icon) end
  894.                 if self.aurasegment and (self.aurasegment.lastunit == targ) then
  895.                         -- The aura is currently displayed
  896.                         if expirationTime~=self.aurasegment.stop then
  897.                                 if self.alwaysrefresh and not self.cast then -- alwaysrefresh = buff. Cast + buff - HoT = BAD. Buffs with cast time and no HoT component are treated much differently.
  898.                                         if self.dot then -- ...check to see if it's a HoT. If so, it's treated as a DoT.
  899.                                                 self.aurasegment.stop = start-0.2
  900.                                                 if self.cast and self.useSmalldebuff then
  901.                                                         self.cantcast.stop = start-0.2
  902.                                                 end
  903.                                                 self:RemoveTicksAfter(start)
  904.                                                 addnew = true
  905.                                         else
  906.                                                 -- If it's a buff with no cast time or HoT component, no special handling needed, move along.
  907.                                                 self.aurasegment.stop = expirationTime
  908.                                         end
  909.                                 else
  910.                                         -- The aura was replaced.
  911.                                         self.aurasegment.stop = start-0.2
  912.                                         if self.cast and self.useSmalldebuff then
  913.                                                 self.cantcast.stop = start-0.2
  914.                                         end
  915.                                         self:RemoveTicksAfter(start)
  916.                                         addnew = true
  917.                                 end
  918.                                 if self.internalcooldown and type(self.internalcooldown) == 'number' then
  919.                                         local stop = now + self.internalcooldown
  920.                                         if start > stop then
  921.                                                 start = now
  922.                                         end
  923.                                         self:AddSegment('cooldown', 'cooldown', start, stop)
  924.                                 end
  925.                         end
  926.                 else
  927.                         addnew = true
  928.                         if self.internalcooldown and type(self.internalcooldown) == 'number' then
  929.                                 local stop = now + self.internalcooldown
  930.                                 if start > stop then
  931.                                         start = now
  932.                                 end
  933.                                 self:AddSegment('cooldown', 'cooldown', start, stop)
  934.                         end
  935.                 end
  936.                 SetStacks(self,count)
  937.         else
  938.                 if self.aurasegment then
  939.                         if math.abs(self.aurasegment.stop - now)>0.3 then
  940.                                 self.aurasegment.stop = now
  941.                                 if self.cast and self.useSmalldebuff then
  942.                                         self.cantcast.stop = now-0.2
  943.                                 end
  944.                         end
  945.                         self:RemoveTicksAfter(now)
  946.                         self.aurasegment = nil
  947.                         self.stacks:SetText()
  948.                 end
  949.         end
  950.         self:UpdateDoT(addnew, source, now, start, expirationTime, duration, name)
  951. end
  952.  
  953. local mainframe_PLAYER_TARGET_CHANGED = function (self)
  954.         local exists = UnitExists('target')
  955.         local dead
  956.         if exists then
  957.                 dead = UnitIsDead('target')
  958.         end
  959.         for i,spellframe in pairs(ns.frames.frames) do
  960.                 if spellframe.auraunit == 'target' then
  961.                         if spellframe.aurasegment then
  962.                                 for i = #spellframe.indicators,1,-1 do
  963.                                         local ind = spellframe.indicators[i]
  964.                                         if auraids[ind.typeid] then
  965.                                                 spellframe:Remove(i)
  966.                                         end
  967.                                 end
  968.                                 spellframe.aurasegment = nil
  969.                                 spellframe.targetdebuff = nil
  970.                                 spellframe.nexttick = nil
  971.                                 spellframe.recenttick = nil
  972.                                 spellframe.stacks:SetText()
  973.                         end
  974.                        
  975.                         if spellframe.refreshable then
  976.                                 if exists then
  977.                                         if dead then
  978.                                                 spellframe.debuffs[UnitGUID('target')] = nil
  979.                                         else
  980.                                                 spellframe.targetdebuff = spellframe.debuffs[UnitGUID('target')]
  981.                                         end
  982.                                 end
  983.                         end            
  984.                 end
  985.         end
  986.        
  987.         if UnitExists('target') then
  988.                 self:UNIT_AURA('target')
  989.         end
  990. end
  991.  
  992. local SpellFrame_RemoveTicksAfter = function (self, min)
  993.         local indicators = self.indicators
  994.         for i = #indicators,1,-1 do
  995.                 local ind = indicators[i]
  996.                 if (ind.typeid == 'tick') and ind.time>min then
  997.                         self:Remove(i)
  998.                 end
  999.         end
  1000.         --print('removing ticks after',min)
  1001.         self.nexttick = nil
  1002. end
  1003.  
  1004. local SpellFrame_RemoveChannelTicksAfter = function (self, min)
  1005.         local indicators = self.indicators
  1006.         for i = #indicators,1,-1 do
  1007.                 local ind = indicators[i]
  1008.                 if ind.typeid == 'channeltick' and ind.time>min then
  1009.                         self:Remove(i)
  1010.                 end
  1011.         end
  1012.         self.nextchanneltick = nil
  1013. end
  1014.  
  1015. local mainframe_CLEU_OtherInterestingSpell = function (self, time, event, hideCaster, srcguid, srcname, srcflags, destguid, destname, destflags, spellid, spellname)
  1016.         local now = GetTime()
  1017.  
  1018.         if ns.otherIDs[spellname] then
  1019.                 local id = ns.otherIDs[spellname]
  1020.                 local bf = ns.frames.frames
  1021.                 if event == 'SPELL_DAMAGE' and id.isChannel then
  1022.                         for i in pairs(bf) do
  1023.                                 if bf[i].cast and bf[i].cast[spellname] then
  1024.                                         local tick = bf[i]:AddIndicator('tick', 'tick', now)
  1025.                                         tick.happened = true
  1026.                                         break
  1027.                                 end
  1028.                         end
  1029.                 elseif event == 'SPELL_CAST_SUCCESS' or event == 'SPELL_DAMAGE' and id.isGlyph then             -- Glyph refresh
  1030.                         if id.last and (now < (id.last + 0.9)) then             -- Throttle heavily, don't want stacks getting blown
  1031.                                 --debug("Ignoring "..event.." from "..spellname.." at "..now)
  1032.                                 return
  1033.                         else
  1034.                                 --debug("Interesting spell potentially not in frame detected! Spell: "..spellname,event)
  1035.                                 id.last = now
  1036.                                 for i in pairs(bf) do
  1037.                                         local gr = bf[i].glyphrefresh or nil
  1038.                                         local gs = bf[i].glyphstacks or nil
  1039.                                         if gr and (gr[3] == spellname) then
  1040.                                                 if gs[destguid] then
  1041.                                                         gs[destguid] = gs[destguid] - 1
  1042.                                                         bf[i].stacks:SetText(gs[destguid] > 0 and gs[destguid] or nil)
  1043.                                                 end
  1044.                                                 --debug("SUCCESS! "..gr[3].." has triggered "..frame[i].auraname)
  1045.                                         end
  1046.                                 end
  1047.                         end
  1048.                 end
  1049.         end
  1050. end
  1051.  
  1052. local AddTicks = {}
  1053. AddTicks.stop = function (self,now,fresh)
  1054.         local nexttick = self.start
  1055.         while nexttick<=self.stop+0.1 do
  1056.                 if now+vars.future<nexttick then
  1057.                         self.nexttick = nexttick
  1058.                         self.lasttick = self.stop
  1059.                         break
  1060.                 end
  1061.                 if now+vars.past<=nexttick then
  1062.                         self:AddIndicator('tick', 'tick', nexttick)
  1063.                         self.latesttick = nexttick
  1064.                 end
  1065.                 nexttick = nexttick+(self.dotMod or self.dot)
  1066.         end
  1067. end
  1068.  
  1069. AddTicks.start = function (self,now)
  1070.        
  1071.         local nexttick = now+(self.dotMod or self.dot)
  1072.         while nexttick<=(self.stop+0.2) do
  1073.                 if now+vars.future<nexttick then
  1074.                         -- The next tick is not visible yet.
  1075.                         self.nexttick = nexttick
  1076.                         self.lasttick = self.stop
  1077.                         break
  1078.                 end
  1079.                 if now+vars.past<=nexttick then
  1080.                         local tick = self:AddIndicator('tick', 'tick', nexttick)
  1081.                         self.latesttick = nexttick
  1082.                 end
  1083.                 nexttick = nexttick+(self.dotMod or self.dot)
  1084.         end
  1085. end
  1086.  
  1087. local SpellFrame_COMBAT_LOG_EVENT_UNFILTERED = function (self, timestamp, event, hideCaster, srcguid,srcname,srcflags, destguid,destname,destflags, spellid,spellname)
  1088.         local now = GetTime()
  1089.         if event == 'SPELL_AURA_REMOVED' then
  1090.                 if self.glyphrefresh then
  1091.                         self.glyphstacks[destguid] = 0
  1092.                 end
  1093.         end
  1094.        
  1095.         if event == 'SPELL_CAST_SUCCESS' then
  1096.                 --debug('SPELL_CAST_SUCCESS',destguid)
  1097.                 self.castsuccess[destguid] = now
  1098.  
  1099.                 if self.glyphrefresh then
  1100.                         for i = 1,6 do
  1101.                                 if ns.glyphs[i] == self.glyphrefresh[2] then
  1102.                                         self.glyphstacks[destguid] = self.glyphrefresh[1]
  1103.                                         SetStacks()
  1104.                                 end
  1105.                         end
  1106.                 end
  1107.         elseif tickevents[event] then
  1108.                                 local isInvalid = not(self.dot) and (self.cast and self.cast[spellname] and not(self.cast[spellname].numhits))  -- filter out cast+channel bars
  1109.                 if isInvalid then return end
  1110.                 if UnitGUID(self.auraunit or 'target')==destguid then
  1111.                         local tick = self:AddIndicator('tick', 'tick', now)
  1112.                         tick.happened = true
  1113.                         if (self.dot and (self.stop and self.stop ~= nil)) then
  1114.                                 if self.isHasted and self.ticks then
  1115.                                         self.dotMod = self.ticks.last and (now - self.ticks.last) or self.dot
  1116.                                         self.dotMod = self.dotMod > self.dot and self.dot or self.dotMod
  1117.                                         self.ticks.last = now
  1118.                                 end
  1119.                                 self:RemoveTicksAfter(now) -- Reconstruct ticks from spellframe info
  1120.                                 local nexttick = now+(self.dotMod or self.dot)
  1121.                                 self.nexttick = nil
  1122.                                 self.recenttick = now
  1123.                                 while nexttick<=(self.stop+0.2) do -- Account for lag
  1124.                                         if now+vars.future<nexttick then
  1125.                                                 -- The next tick is not visible yet.
  1126.                                                 self.nexttick = nexttick
  1127.                                                 self.lasttick = self.stop
  1128.                                                 break
  1129.                                         end
  1130.                                         if now+vars.past<=nexttick then
  1131.                                                 -- The next tick is visible.
  1132.                                                 local tick = self:AddIndicator('tick', 'tick', nexttick)
  1133.                                                 if nexttick<=now then
  1134.                                                         tick.happened = true
  1135.                                                 end
  1136.                                                 self.latesttick = nexttick
  1137.                                         end
  1138.                                         nexttick=nexttick+(self.dotMod or self.dot)
  1139.                                 end    
  1140.                         end
  1141.                 end
  1142.         end
  1143. end
  1144.  
  1145. local SpellFrame_UNIT_AURA_refreshable = function (self, unitid)
  1146.         if unitid~=self.auraunit then return end
  1147.         if not(self.auraname and self.spellname) then return end
  1148.         local name, icon, count, duration, expirationTime, source, spellID = GetAura(self,unitid)
  1149.         local afflicted = name and (self.unique or source=='player') and (not self.minstacks or count>=self.minstacks)
  1150.         local addnew, refresh
  1151.         local now = GetTime()
  1152.         local guid = UnitGUID(self.auraunit or 'target')
  1153.         --print(name,source,self.spellname,self.auraname)
  1154.         -- First find out if the debuff was refreshed.
  1155.        
  1156.         if self.aurasegment and expirationTime == 0 and duration == 0 then      -- Timeless aura, bar exists (Overkill)
  1157.                 for i = #self.indicators,1,-1 do
  1158.                         self:Remove(i)
  1159.                 end
  1160.                 self.aurasegment = nil
  1161.                 self.nexttick = nil
  1162.                 self.stacks:SetText()
  1163.                 return
  1164.         end
  1165.        
  1166.         if expirationTime == 0 then
  1167.                 return
  1168.         end
  1169.        
  1170.         if afflicted then
  1171.                 start = expirationTime-duration
  1172.                 if icon and not(self.cast or self.slotID or self.keepIcon) then self.icon:SetTexture(icon) end
  1173.                 if self.targetdebuff then
  1174.                         if self.targetdebuff.stop == expirationTime then
  1175.                                 start = self.targetdebuff.start
  1176.                         else
  1177.                                 -- Check for refresh.
  1178.                                 if start < self.targetdebuff.stop then
  1179.                                         local totalduration = self.targetdebuff.stop - self.targetdebuff.start
  1180.                                         local lasttick = self.targetdebuff.stop - math.fmod(totalduration, self.dotMod or self.dot)
  1181.                                         local success = self.castsuccess[guid]
  1182.                                         local not_recast = true -- Poisons are never actually recast, so we default to true here, because success will always be nil.
  1183.                                         if success then
  1184.                                                 not_recast = math.abs(success-start)>0.5
  1185.                                         end
  1186.                                         if not_recast and start < lasttick then
  1187.                                                 -- The current debuff was refreshed.
  1188.                                                 start = self.targetdebuff.start
  1189.                                                 refresh = true
  1190.                                         end
  1191.                                 end
  1192.                         end
  1193.                 end
  1194.                 if self.aurasegment then
  1195.                         if expirationTime~=self.aurasegment.stop and not refresh then
  1196.                                 -- The current debuff was replaced.
  1197.                                 self.aurasegment.stop = start-0.2
  1198.                                 self:RemoveTicksAfter(start)
  1199.  
  1200.                                 --debug('replaced')
  1201.                                 addnew = true
  1202.                         end
  1203.                 else
  1204.                         addnew = true
  1205.                 end
  1206.                 SetStacks(self,count)
  1207.         else
  1208.                 if self.aurasegment then
  1209.                         if math.abs(self.aurasegment.stop - now)>0.3 then
  1210.                                 -- The current debuff ended.
  1211.                                 self.aurasegment.stop = now
  1212.                                 if self.cantcast then
  1213.                                         self.cantcast.stop = now
  1214.                                 end
  1215.                         end
  1216.                         self:RemoveTicksAfter(now)
  1217.                         self.aurasegment = nil
  1218.                         self.cantcast = nil
  1219.                         self.targetdebuff = nil
  1220.                         self.recenttick = nil
  1221.                         self.stacks:SetText()
  1222.                 end
  1223.         end
  1224.         self:UpdateDoT(addnew, source, now, start, expirationTime, duration, name, refresh, guid)
  1225. end
  1226.  
  1227. local SpellFrame_UpdateDoT = function (self, addnew, source, now, start, expirationTime, duration, name, refresh, guid)
  1228.         local addticks
  1229.         local isHasted
  1230.         local checkDoT = self.auranamePrimary or name
  1231.         local isPrimary = checkDoT == name or nil
  1232.         self.start, self.stop, self.duration = start, expirationTime, duration
  1233.        
  1234.         local targ = UnitName(self.auraunit)
  1235.         if addnew then
  1236.                 --debug('addnew', start, expirationTime)
  1237.                 local typeid = (source=='player' and self.isType) or (source~='player' and 'debuff')
  1238.                 if self.cast and self.useSmalldebuff then
  1239.                         self.aurasegment = self:AddSegment(typeid, 'smalldebuff', start, expirationTime)
  1240.                         local hastedcasttime = select(7, GetSpellInfo(self.lastcast or self.spellname))/1000
  1241.                         self.cantcast = self:AddSegment(typeid, 'cantcast', start, expirationTime-hastedcasttime)
  1242.                         self.aurasegment.lastunit = targ
  1243.                 else
  1244.                         self.aurasegment = self:AddSegment(typeid, 'default', start, expirationTime)
  1245.                         self.aurasegment.lastunit = targ
  1246.                 end
  1247.                 -- Add visible ticks.
  1248.                 if self.dot and isPrimary then
  1249.                         addticks = start
  1250.                 end
  1251.                 if self.debuffs then
  1252.                         -- Refreshable only.
  1253.                         self.targetdebuff = {start=start, stop=expirationTime}
  1254.                         self.debuffs[guid] = self.targetdebuff
  1255.                 end
  1256.                 self.recenttick = now
  1257.         elseif refresh then
  1258.                 -- debug('refresh', start, expirationTime)
  1259.                 -- Note: refresh requires afflicted and self.targetdebuff. Also, afflicted and not self.debuff implies addnew.
  1260.                 -- So we can get here only if afflicted and self.debuff and self.targetdebuff.
  1261.                 self.aurasegment.stop = expirationTime
  1262.                 self.targetdebuff.stop = expirationTime
  1263.                 if self.cantcast then
  1264.                         self.cantcast.start = start
  1265.                         self.cantcast.stop = expirationTime-(select(7, GetSpellInfo(self.lastcast or self.spellname))/1000)
  1266.                 end
  1267.                 if self.latesttick then
  1268.                         addticks = self.latesttick
  1269.                 end
  1270.         end
  1271.         if addticks then
  1272.                 addticks = self.recenttick or addticks
  1273.                 local nexttick = addticks+(self.dotMod or self.dot)
  1274.                 self.nexttick = nil
  1275.                
  1276.                 if self.hasted then
  1277.                         if type(self.hasted) == 'number' then
  1278.                                 for i = 1,6 do
  1279.                                         if ns.glyphs[i] == self.hasted then isHasted = true end
  1280.                                 end
  1281.                         elseif self.hasted == true then
  1282.                                 isHasted = true
  1283.                         end
  1284.                 end
  1285.                
  1286.                 if isHasted and self.expectedTicks then         -- Using expectedTicks
  1287.                         self.dotMod = (expirationTime - start)/self.expectedTicks
  1288.                         local magearmor = UnitBuff(self.auraunit, "Mage Armor")
  1289.                         if self.dot and magearmor and self.dotMod <= 1.5 then self.dotMod = self.dotMod * 2 end         -- Adjust for mage armor rank 5+ 50% duration reduction, use number comparison to make sure we're not changing something that shouldn't be.
  1290.                 elseif isHasted then
  1291.                         local bct = ns.config.hastedSpellID[2]
  1292.                         local hct = select(7, GetSpellInfo(ns.config.hastedSpellID[1]))/1000
  1293.                         self.dotMod = self.dot*(hct/bct)
  1294. --[[            if ns.config.nonAffectingHaste then
  1295.                                 for i,nah in ipairs(ns.config.nonAffectingHaste) do
  1296.                                         local name,_,_,_,_,source = ns:GetAura(nah[1],'buff','player')
  1297.                                         if name and (source == 'player') then
  1298.                                                 self.dotMod = self.dotMod * nah[2]
  1299.                                         end
  1300.                                 end
  1301.                         end--]]
  1302.                 end
  1303.                 self:RemoveTicksAfter(now)
  1304.                 --self:AddTicks(now)
  1305.                
  1306.                 if self.hasted then
  1307.                         if type(self.hasted) == 'number' then
  1308.                                 for i = 1,6 do
  1309.                                         if ns.glyphs[i] == self.hasted then isHasted = true end
  1310.                                 end
  1311.                         elseif self.hasted == true then
  1312.                                 isHasted = true
  1313.                         end
  1314.                 end
  1315.                
  1316.                 if isHasted and self.ticks then                                 -- Tick-process haste handling
  1317.                         self.ticks.last = self.ticks.last or now
  1318.                         self.dotMod = self.dotMod and self.dotMod or self.dot
  1319.                         if (self.dotMod > self.dot) or (self.dotMod < 1.5) then self.dotMod = self.dot end
  1320.                         self.isHasted = true
  1321.                 elseif isHasted and self.expectedTicks then             -- Using expectedTicks
  1322.                         self.dotMod = (expirationTime - start)/self.expectedTicks
  1323.                 end
  1324.                
  1325.                 while nexttick<=(self.stop+0.2) do -- Account for lag
  1326.                         if now+vars.future<nexttick then
  1327.                                 -- The next tick is not visible yet.
  1328.                                 self.nexttick = nexttick
  1329.                                 self.lasttick = self.stop
  1330.                                 break
  1331.                         end
  1332.                         if now+vars.past<=nexttick then
  1333.                                 -- The next tick is visible.
  1334.                                 local tick = self:AddIndicator('tick', 'tick', nexttick)
  1335.                                 if nexttick<=now then
  1336.                                         tick.happened = true
  1337.                                 end
  1338.                                 self.latesttick = nexttick
  1339.                         end
  1340.                         nexttick=nexttick+(self.dotMod or self.dot)
  1341.                 end
  1342.                
  1343.         end
  1344. end
  1345.  
  1346. local SpellFrame_PLAYER_REGEN_ENABLED = function (self)
  1347.         local thresh = GetTime() - 10
  1348.         local remove = {}
  1349.         for guid,data in pairs(self.debuffs) do
  1350.                 if data.stop < thresh then
  1351.                         tinsert(remove, guid)
  1352.                 end
  1353.         end
  1354.         for _,guid in ipairs(remove) do
  1355.                 --debug('removing',guid,self.spellname)
  1356.                 self.debuffs[guid]=nil
  1357.         end
  1358. end
  1359.  
  1360. local SpellFrame_SPELL_UPDATE_COOLDOWN = function (self)
  1361. --      print(self.spellname,self.cooldownID,'SPELL_UPDATE_COOLDOWN')
  1362.         if self.slotID and self.cooldownID and not(self.spellname) then -- item is equipped but has none of the needed info, so rescan it.
  1363.                 return self:PLAYER_EQUIPMENT_CHANGED(self.slotID)
  1364.         end
  1365.         if not(self.cooldownID or self.spellname) then return end
  1366.        
  1367.         local start
  1368.         local duration
  1369.         local enabled
  1370.         local ready
  1371.        
  1372.         -- if type(self.cooldown) == "table" then -- we choose the one with the longer CD (This is mostly for sfiend/mindbender bar)
  1373.                 -- print("test")
  1374.                 -- for i,cooldown in pairs(self.cooldown) do
  1375.                         -- start2, duration2, enabled2 = self.CooldownFunction(cooldown)
  1376.                         --print(start2, duration2, enabled2, ready2)
  1377.                         -- if start2+duration2 > start+duration then
  1378.                                 -- start = start2
  1379.                                 -- duration = duration2
  1380.                                 -- enabled = enabled2
  1381.                                 -- ready = (enabled==1 and start~=0 and duration) and start+duration
  1382.                         -- end
  1383.                         --print(start, duration, enabled, ready)
  1384.                 -- end
  1385.                 --print(start, duration, enabled, ready)
  1386.         -- else
  1387.                 start, duration, enabled = self.CooldownFunction(self.cooldownID or self.spellname)
  1388.                 ready = enabled==1 and start~=0 and duration and start+duration
  1389.         -- end
  1390.         --print(start, duration, enabled, ready)
  1391.         if ready and duration>1.5 then
  1392.                 -- The spell is on cooldown, but not just because of the GCD.
  1393.                 if self.cooldownID then
  1394.                        
  1395.                 end
  1396.                 if self.cooldown ~= ready then          -- The CD has changed since last check
  1397.                         if not(self.coolingdown) then   -- No CD bar exists.
  1398.                                 self.coolingdown = self:AddSegment('cooldown', self.smallCooldown and 'smallCooldown' or 'cooldown', start, ready)
  1399.                         elseif self.coolingdown.stop and self.coolingdown.stop ~= ready then    -- cd exists but has changed
  1400.                                 self.coolingdown.start = start
  1401.                                 self.coolingdown.stop = ready
  1402.                         end
  1403.                         self.cooldown = ready
  1404.                 end
  1405.         else
  1406.                 if self.coolingdown then
  1407.                         -- Spell is off cooldown or cd expires during GCD window
  1408.                         local now = GetTime()
  1409.                         -- See when the cooldown is ready. If the spell is currently on GCD, check the GCD end; otherwise check now.
  1410.                         if self.cooldown > (ready or now) then
  1411.                                 -- The cooldown ended earlier.
  1412.                                 self.coolingdown.stop = now
  1413.                         end
  1414.                         self.coolingdown = nil
  1415.                 end
  1416.                 self.cooldown = nil
  1417.         end
  1418. end
  1419.  
  1420. local SpellFrame_PLAYER_EQUIPMENT_CHANGED = function (self,slot,equipped)
  1421.         if not (slot or self.slotID) or (self.slotID ~= slot) then return end
  1422.        
  1423.         for i = #self.indicators,1,-1 do
  1424.                 self:Remove(i)
  1425.         end
  1426.        
  1427.         self.aurasegment = nil
  1428.         self.nexttick = nil
  1429.         self.stacks:SetText()
  1430.        
  1431.         self.cooldown = nil
  1432.         self.coolingdown = nil
  1433.         self.playerbuff = nil
  1434.         self.spellname = nil
  1435.         self.auraname = nil
  1436.         self.internalcooldown = true
  1437.        
  1438.         local itemID,name,tex = self:FindItemInfo()
  1439.         self.cooldownID = itemID
  1440.        
  1441.         if (itemID and name and tex) and not(ns.trinkets.blacklist[name]) then
  1442.                 self.spellname = name
  1443.                 self.icon:SetTexture(tex)
  1444.                
  1445.                 self.stance = true -- Always show
  1446.                
  1447.                 if ns.trinkets[name] then
  1448.                         if type(ns.trinkets[name]) == 'number' then
  1449.                                 self.playerbuff = ns.trinkets[name]
  1450.                         elseif type(ns.trinkets[name]) == 'table' then
  1451.                                 self.playerbuff = ns.trinkets[name][1]
  1452.                                 self.internalcooldown = ns.trinkets[name][2]
  1453.                         end
  1454.                 elseif self.slotID == 10 then
  1455.                         self.playerbuff = 54758         -- Engy gloves
  1456.                 elseif self.slotID == 8 then
  1457.                         self.playerbuff = 54861         -- Nitro Boosts
  1458.                 end
  1459.                
  1460.                 if type(self.playerbuff)=='number' then
  1461.                         self.auraname = (GetSpellInfo(self.playerbuff))
  1462.                 elseif type(self.playerbuff)=='table' then
  1463.                         self.auraname = {}
  1464.                         self.auranamePrimary = (GetSpellInfo(self.playerbuff[1]))
  1465.                         for i,id in ipairs(self.playerbuff) do
  1466.                                 tinsert(self.auraname, (GetSpellInfo(id)))
  1467.                         end
  1468.                         self.AuraFunction = UnitBuffUnique
  1469.                 else
  1470.                         self.auraname = self.spellname
  1471.                 end
  1472.                 self:SPELL_UPDATE_COOLDOWN()
  1473.         else
  1474.                 self.stance = 50 -- More efficient than other methods of hiding the bar.
  1475.                 self.icon:SetTexture(0,0,0,0)
  1476.         end
  1477.        
  1478.         -- Throttle equipment checks to every 2 seconds. This should decrease overall cpu load while making equipment checks more reliable on beta/ptr.
  1479. --      vars.EQCframes = vars.EQCframes or {}
  1480. --      table.insert(vars.EQCframes,self)
  1481.         --print('equipment update - slot '..self.slotID)
  1482.         if not(vars.currentEQcheck) then
  1483.                 frame2.elapsed = 0
  1484.                 vars.currentEQcheck = true
  1485.                 frame2:SetScript('OnUpdate', function (self,elapsed)
  1486.                         self.elapsed = self.elapsed + elapsed
  1487.                         if self.elapsed >= 2 then
  1488.                                 mainframe:UPDATE_SHAPESHIFT_FORM()
  1489.                 --[[    for i,v in ipairs(vars.EQCframes) do
  1490.                                         v:SPELL_UPDATE_COOLDOWN()
  1491.                                 end     ]]--
  1492.                                 vars.currentEQcheck = nil
  1493.                 --              vars.EQCframes = nil
  1494.                                 --print('equipment check onupdate complete and cleared')
  1495.                                 self:SetScript('OnUpdate',nil)
  1496.                         end
  1497.                 end)
  1498.         end
  1499. end
  1500.  
  1501. --[[
  1502. Things get ugly again here.
  1503. UNIT_AURA does not fire for mouseover units, so we need to emulate it.
  1504. UPDATE_MOUSEOVER_UNIT does not fire when a mouseover unit is cleared, so we need to emulate that as well.
  1505. The UMU check is unthrottled by necessity. UNIT_AURA doesn't really need to be run more than 10 times per second, so it gets throttled to save cycles.
  1506. ]]--
  1507. local TTL,TSLU = 0.15,0
  1508. local UpdateMouseover = function (self,elapsed)
  1509.         TSLU = TSLU+elapsed
  1510.         if not(UnitExists('mouseover')) then
  1511.                 ns:CheckMouseover()
  1512.                 frame:SetScript('OnUpdate',nil)
  1513.         else
  1514.                 if (TSLU >= TTL) then
  1515.                         mainframe:UNIT_AURA('mouseover')
  1516.                         TSLU = 0
  1517.                 end
  1518.         end
  1519. end
  1520.  
  1521. local SpellFrame_UPDATE_MOUSEOVER_UNIT = function (self)
  1522.         --print("UPDATE_MOUSEOVER_UNIT")
  1523.         if UnitExists('mouseover') then
  1524.                 vars.isMouseover = true
  1525.                 self.auraunit = 'mouseover'
  1526.         else
  1527.                 vars.isMouseover = nil
  1528.                 self.auraunit = self.baseunit
  1529.         end
  1530.         frame:SetScript('OnUpdate',UpdateMouseover)
  1531.        
  1532.         if self.aurasegment then
  1533.                 for i = #self.indicators,1,-1 do
  1534.                         local ind = self.indicators[i]
  1535.                         if auraids[ind.typeid] then
  1536.                                 self:Remove(i)
  1537.                         end
  1538.                 end
  1539.                 self.aurasegment = nil
  1540.                 self.nexttick = nil
  1541.                 self.stacks:SetText()
  1542.         end
  1543.        
  1544.         if self.refreshable then
  1545.                 if UnitExists(self.auraunit) then
  1546.                         local guid = UnitGUID(self.auraunit)
  1547.                         if UnitIsDead(self.auraunit) then
  1548.                                 self.debuffs[guid] = nil
  1549.                         else
  1550.                                 self.targetdebuff = self.debuffs[guid]
  1551.                                 --if self.targetdebuff then debug(self.spellname, 'have old') end
  1552.                                 mainframe:UNIT_AURA(self.auraunit)
  1553.                                 --if self.aurasegment then debug(self.spellname, 'added new') end
  1554.                                 if self.glyphstacks and self.aurasegment then
  1555.                                        
  1556.                                         local count = self.glyphstacks[guid]
  1557.                                         if self.glyphstacks[guid] and ( count > 0) then
  1558.                                                 self.stacks:SetText(self.glyphstacks[UnitGUID(self.auraunit)])
  1559.                                         end
  1560.                                 end
  1561.                         end
  1562.                 end
  1563.         elseif UnitExists(self.auraunit) then
  1564.                 mainframe:UNIT_AURA(self.auraunit)
  1565.         end
  1566. end
  1567.  
  1568. -- A SpellFrame is active (i.e. listening to events) iff the talent requirements are met.
  1569. -- The table EventHorizon.frames.active contains all the active frames.
  1570. -- If the stance requirement is not met, the frame is hidden, but still active.
  1571. local SpellFrame_Deactivate = function (self)
  1572.         if not self.isActive then return end
  1573.         --debug('unregistering events for', self.spellname)
  1574.         self:UnregisterAllEvents()
  1575.         if self.interestingCLEU then
  1576.                 mainframe.framebyspell[self.spellname] = nil
  1577.         end
  1578.         self:Hide()
  1579.         for index=#self.indicators,1,-1 do
  1580.                 self:Remove(index)
  1581.         end
  1582.         self.isActive = nil
  1583. end
  1584.  
  1585. local SpellFrame_Activate = function (self)
  1586.         if self.isActive then return end
  1587.         --debug('registering events for', self.spellname)
  1588.         for event in pairs(self.interestingEvent) do
  1589.                 self:RegisterEvent(event)
  1590.         end
  1591.         if self.interestingCLEU then
  1592.                 mainframe.framebyspell[self.spellname] = self
  1593.         end
  1594.  
  1595.         self:Show()
  1596.         self.isActive = true
  1597. end
  1598.  
  1599. local timer = 0
  1600. local checkInProgress
  1601. function ns:CheckTalents()
  1602.         if checkInProgress then return end
  1603.         checkInProgress = true
  1604.         frame3:SetScript('OnUpdate', function (f,elapsed)
  1605.                 timer = timer + elapsed
  1606.                 if timer >= 2 then
  1607.                         timer = 0
  1608.                         checkInProgress = nil
  1609.                         ns:CheckRequirements()
  1610.                         f:SetScript('OnUpdate',nil)
  1611.                 end
  1612.         end)
  1613. end
  1614.  
  1615. function ns:SetFrameDimensions()
  1616.         local left,right,top,bottom = 0.07, 0.93, 0.07, 0.93
  1617.         local barheight2 = self.config.height
  1618.         local modHeight = self.config.height
  1619.        
  1620.         local sfn = type(self.config.staticframes) == 'number' and self.config.staticframes or 0
  1621.         local sfi = self.config.hideIcons == true
  1622.         if (#ns.frames.shown >= sfn) and type(self.config.staticheight) == 'number' then
  1623.                 mainframe:SetHeight(self.config.staticheight)
  1624.                 vars.barheight = (self.config.staticheight - (vars.barspacing*(vars.numframes - 1)))/vars.numframes
  1625.                 modHeight = vars.barheight
  1626.                 local ratio = vars.barheight/barheight2
  1627.                 ratio = math.abs( (1-(1/ratio))/2 )     -- Yes, this was a bitch to figure out.
  1628.                 if vars.barheight > barheight2 then     -- icon is taller than it is wide
  1629.                         left = left + ratio
  1630.                         right = right - ratio
  1631.                 else
  1632.                         top = top + ratio
  1633.                         bottom = bottom - ratio
  1634.                 end
  1635.         else
  1636.                 vars.barheight = barheight2
  1637.                 mainframe:SetHeight(vars.numframes * (vars.barheight+vars.barspacing) - vars.barspacing)
  1638.         end
  1639.        
  1640.         vars.nowleft = -vars.past/(vars.future-vars.past)*vars.barwidth-0.5 + (ns.config.hideIcons and 0 or ns.config.height)
  1641.         if ns.frames.nowIndicator then
  1642.                 ns.frames.nowIndicator:SetPoint('BOTTOM',mainframe,'BOTTOM')
  1643.                 ns.frames.nowIndicator:SetPoint('TOPLEFT',mainframe,'TOPLEFT', vars.nowleft, 0)
  1644.                 ns.frames.nowIndicator:SetWidth(vars.onepixelwide)
  1645.                 ns.frames.nowIndicator:SetTexture(unpack(self.colors.nowLine))
  1646.         end
  1647.        
  1648.         local shownframes = #ns.frames.shown > 0
  1649.         if shownframes then
  1650.                 for i = 1,#ns.frames.shown do
  1651.                         local spellframe = ns.frames.shown[i]
  1652.                         if spellframe then
  1653.                                 --spellframe:ClearAllPoints()
  1654.                                 spellframe:SetHeight(vars.barheight)
  1655.                                 spellframe:SetWidth(vars.barwidth)
  1656.                                
  1657.                                 spellframe.icon:ClearAllPoints()
  1658.                                 spellframe:SetPoint('RIGHT', mainframe, 'RIGHT')
  1659.                                 if i == 1 then
  1660.                                         spellframe:SetPoint('TOPLEFT', mainframe, 'TOPLEFT', sfi and 0 or barheight2, 0)
  1661.                                 else
  1662.                                         spellframe:SetPoint('TOPLEFT', ns.frames.shown[i-1], 'BOTTOMLEFT', 0, -vars.barspacing)
  1663.                                 end
  1664.                                 if not(sfi) then
  1665.                                         spellframe.icon:SetPoint('TOPRIGHT',spellframe,'TOPLEFT')
  1666.                                         spellframe.icon:SetWidth(barheight2)
  1667.                                         spellframe.icon:SetHeight(modHeight)
  1668.                                         spellframe.icon:SetTexCoord(left,right,top,bottom)
  1669.                                 end
  1670.                                
  1671.                                 local indicators = #spellframe.indicators > 0
  1672.                                 if indicators then
  1673.                                         for i=1,#spellframe.indicators do
  1674.                                                 local indicator = spellframe.indicators[i]
  1675.                                                 if indicator then
  1676.                                                         local ndtex, ndcol
  1677.                                                         local typeid = indicator.typeid
  1678.                                                         local layoutid = indicator.layoutid
  1679.                                                         local usetexture
  1680.                                                        
  1681.                                                         if not(exemptColors[typeid]) and self.bartexture then ndtex = self.bartexture end
  1682.                                                         if typeid and customColors[typeid] then
  1683.                                                                 usetexture = true
  1684.                                                                 if spellframe.barcolorunique and typeid == 'debuff' then
  1685.                                                                         ndcol = spellframe.barcolorunique
  1686.                                                                 elseif spellframe.barcolor then
  1687.                                                                         ndcol = spellframe.barcolor
  1688.                                                                 end
  1689.                                                         elseif typeid == 'cooldown' then
  1690.                                                                 usetexture = true
  1691.                                                         end
  1692.                                                         usetexture = usetexture and vars.texturedbars
  1693.                                                        
  1694.                                                         -- Layout
  1695.                                                         local layouts = ns.layouts
  1696.                                                         local layout = layouts[layoutid] or layouts.default
  1697.                                                         local color = ndcol or ns.colors[typeid] or ns.colors.default
  1698.                                                        
  1699.                                                         if layoutid == 'frameline' then
  1700.                                                                 color = typeid == 'sent' and ns.colors.castLine or ns.colors[typeid]
  1701.                                                                 indicator:SetPoint('TOP',ns.mainframe)
  1702.                                                                 indicator:SetPoint('BOTTOM',ns.mainframe)
  1703.                                                         else
  1704.                                                                 indicator:SetPoint('TOP',spellframe, 'TOP', 0, -layout.top*vars.barheight)
  1705.                                                                 indicator:SetPoint('BOTTOM',spellframe, 'TOP', 0, -layout.bottom*vars.barheight)
  1706.                                                         end
  1707.                                                        
  1708.                                                         if usetexture then
  1709.                                                                 indicator:SetTexture(ndtex or vars.bartexture)
  1710.                                                                 indicator:SetTexCoord(unpack(layout.texcoords))
  1711.                                                         else
  1712.                                                                 indicator:SetTexture(1,1,1,1)
  1713.                                                         end
  1714.                                                         indicator:SetVertexColor(unpack(ndcol or color))
  1715.                                                         --if typeid == 'casting' then print(unpack(ndcol or color)) end
  1716.                                                 end
  1717.                                         end
  1718.                                 end
  1719.                        
  1720.                         end
  1721.                 end
  1722.         end
  1723. end
  1724. --[[
  1725. function ns:AddCheckedTalent(tab,index)
  1726.         local required = true
  1727.         for k,v in ipairs(self.talents) do
  1728.                 if (v[1] == tab) and (v[2] == index) then
  1729.                         required = nil
  1730.                 end
  1731.         end
  1732.         if required then
  1733.                 table.insert(self.talents,{tab,index})
  1734.         end
  1735. end
  1736. ]]
  1737. function ns:CheckRequirements()
  1738.         --print('CheckTalents')
  1739.         table.wipe(self.frames.active)
  1740.         table.wipe(self.frames.mouseover)
  1741.         --print('checkrequirements')
  1742.         --print(GetTime())
  1743.        
  1744.         EventHorizonDB.charInfo = EventHorizonDB.charInfo or {}
  1745.         local cc = EventHorizonDB.charInfo
  1746.        
  1747.         vars.activeTree = GetSpecialization()
  1748.         vars.activeTalentGroup = GetActiveSpecGroup('player')
  1749.         vars.currentLevel = UnitLevel('player')
  1750.        
  1751.  
  1752.         self.glyphs = {}
  1753.         for i = 1,6 do
  1754.                 local enabled,_,gsID,_ = GetGlyphSocketInfo(i)
  1755.                 if enabled and gsID then
  1756.                         self.glyphs[i] = gsID
  1757.                 else
  1758.                         self.glyphs[i] = nil
  1759.                 end
  1760.         end
  1761.        
  1762.        
  1763.         for i,config in ipairs(self.frames.config) do
  1764.                 local rG = config.requiredGlyph
  1765.                 local rS = config.requiredTree
  1766.                 local rL = config.requiredLevel or 1
  1767.                
  1768.                 local haveGlyphReq = true
  1769.                 local haveSpecReq = true
  1770.                 local haveLevelReq = rL <= vars.currentLevel
  1771.                
  1772.                                
  1773.                 if rG then
  1774.                         haveGlyphReq = nil
  1775.                         for i,glyph in ipairs(self.glyphs) do
  1776.                                 if rG == glyph then haveGlyphReq = true end
  1777.                         end
  1778.                 end
  1779.                
  1780.                 if rS then
  1781.                         haveSpecReq = nil
  1782.                         if type(rS) == 'number' then
  1783.                                 rS = {rS}
  1784.                         end
  1785.                         --print(config.spellID,rS)
  1786.                         for i,spec in ipairs(rS) do
  1787.                                 if spec == vars.activeTree then
  1788.                                         haveSpecReq = true
  1789.                                 end
  1790.                         end
  1791.                 end
  1792.                                
  1793.                 -- Check if there already is a frame
  1794.                 local spellframe = self.frames.frames[i]
  1795.                 local frameExists = spellframe~=nil
  1796.                
  1797.                
  1798.                 if haveGlyphReq and haveSpecReq and haveLevelReq then
  1799.                         if frameExists then
  1800.                                 spellframe:Activate()
  1801.                         else
  1802.                                 spellframe = self:CreateSpellBar(config)
  1803.                                 self.frames.frames[i] = spellframe
  1804.                         end
  1805.                         table.insert(self.frames.active, spellframe)
  1806.                         if spellframe.usemouseover then
  1807.                                 table.insert(self.frames.mouseover, spellframe)
  1808.                         end
  1809.                        
  1810.                         if spellframe.cooldownTable then -- We need to update the spellID again
  1811.                                 spellframe.cooldownID = IsUsableSpell(config.cooldown[2]) and config.cooldown[2] or config.cooldown[1]
  1812.                                 spellframe.cooldown = true
  1813.                         end
  1814.                 else
  1815.                         if frameExists then
  1816.                                 spellframe:Deactivate()
  1817.                         end
  1818.                 end
  1819.         end
  1820.  
  1821.         local activate = #self.frames.active > 0
  1822.         self:Activate(activate)
  1823.         if activate then
  1824.                 mainframe:UPDATE_SHAPESHIFT_FORM()
  1825.         end
  1826.        
  1827.         ns:ModuleEvent('CheckTalents')
  1828. end
  1829.  
  1830. local mainframe_UPDATE_SHAPESHIFT_FORM = function (self)
  1831.         local stance = GetShapeshiftForm()
  1832.         -- On PLAYER_LOGIN, GetShapeshiftForm() sometimes returns a bogus value (2 on a priest with 1 form). Ignored for Warlocks and cached information.
  1833.         if not(stance) or (GetNumShapeshiftForms() and class ~= 'WARLOCK' and stance>GetNumShapeshiftForms()) then return end
  1834.         mainframe:SetHeight(1)
  1835.         table.wipe(ns.frames.shown)
  1836.        
  1837.         EventHorizonDB.charInfo.stance = stance
  1838.         vars.numframes = 0
  1839.        
  1840.         for i,spellframe in ipairs(ns.frames.active) do
  1841.                 local shown = spellframe:IsShown()
  1842.                
  1843.                 if spellframe.stance then
  1844.                         shown = false
  1845.                         if type(spellframe.stance) == 'table' then
  1846.                                 shown = false
  1847.                                 for i in ipairs(spellframe.stance) do
  1848.                                         if spellframe.stance[i] == stance then
  1849.                                                 shown = true
  1850.                                         end
  1851.                                 end
  1852.                         elseif spellframe.stance == true then
  1853.                                 shown = true
  1854.                         elseif spellframe.stance == stance and not shown then
  1855.                                 shown = true
  1856.                         elseif spellframe.stance and spellframe.stance ~= stance and shown then
  1857.                                 shown = false
  1858.                         end
  1859.                 end
  1860.                
  1861.                 if spellframe.notstance then
  1862.                         shown = true
  1863.                         if spellframe.notstance and type(spellframe.notstance) == 'table' then
  1864.                                 for i in ipairs(spellframe.notstance) do
  1865.                                         if spellframe.notstance[i] == stance then
  1866.                                                 shown = false
  1867.                                         end
  1868.                                 end
  1869.                         elseif spellframe.notstance == stance then
  1870.                                 shown = false
  1871.                         end
  1872.                 end
  1873.  
  1874.                 if shown then
  1875.                         spellframe:Show()
  1876.                         vars.numframes = vars.numframes+1
  1877.                         table.insert(ns.frames.shown,spellframe)
  1878.                 else
  1879.                         spellframe:Hide()
  1880.                         for i,indicator in ipairs(spellframe.indicators) do
  1881.                                 indicator:Hide()
  1882.                         end
  1883.                 end    
  1884.         end
  1885.        
  1886.         if vars.numframes>0 then
  1887.                 ns:SetFrameDimensions()
  1888.                 if (EventHorizonDB.redshift) and (ns.modules.redshift.isReady and EventHorizonDB.redshift.isActive == true) then
  1889.                         ns.modules.redshift:Check()
  1890.                 elseif ns.isActive and vars.visibleFrame then
  1891.                         mainframe:Show()
  1892.                 end
  1893.         else
  1894.                 mainframe:Hide()
  1895.         end
  1896.        
  1897.         return true
  1898. end
  1899.  
  1900. function ns:CheckMouseover()
  1901.         for i,spellframe in ipairs(self.frames.mouseover) do
  1902.                 spellframe:UPDATE_MOUSEOVER_UNIT()
  1903.         end
  1904. end
  1905.  
  1906. -- GCD indicator
  1907. local mainframe_SPELL_UPDATE_COOLDOWN = function (self)
  1908.         if ns.frames.gcd then
  1909.                 local start, duration = GetSpellCooldown(vars.gcdSpellName)
  1910.                 local sfi = ns.config.hideIcons
  1911.                 --print(start,duration)
  1912.                 if start and duration and duration>0 then
  1913.                         vars.gcdend = start+duration
  1914.                         mainframe:SetScript('OnUpdate', function (self, elapsed)
  1915.                                 if vars.gcdend then
  1916.                                         local now = GetTime()
  1917.                                         if vars.gcdend<=now then
  1918.                                                 vars.gcdend = nil
  1919.                                                 ns.frames.gcd:Hide()
  1920.                                         else
  1921.                                                 local diff = now+vars.past
  1922.                                                 local p = (vars.gcdend-diff)*vars.scale
  1923.                                                 if p<=1 then
  1924.                                                         ns.frames.gcd:SetPoint('RIGHT', self, 'RIGHT',(p-1)*vars.barwidth+vars.onepixelwide, 0)
  1925.                                                         ns.frames.gcd:Show()
  1926.                                                 end
  1927.                                         end
  1928.                                 end
  1929.                         end)
  1930.                 else
  1931.                         vars.gcdend = nil
  1932.                         ns.frames.gcd:Hide()
  1933.                         mainframe:SetScript('OnUpdate', nil)
  1934.                 end
  1935.         end
  1936. end
  1937.  
  1938. -- Dispatch the CLEU.
  1939. local mainframe_COMBAT_LOG_EVENT_UNFILTERED = function (self,time, event, hideCaster, srcguid,srcname,srcflags, destguid,destname,destflags, spellid,spellname)
  1940.         if srcguid~=vars.playerguid or event:sub(1,5)~='SPELL' then return end
  1941.         local spellframe = self.framebyspell[spellname]
  1942.         if ns.otherIDs[spellname] then
  1943.                 mainframe:CLEU_OtherInterestingSpell(time, event, hideCaster, srcguid,srcname,srcflags, destguid,destname,destflags, spellid,spellname)
  1944.         end
  1945.         if spellframe then
  1946.                 if spellframe.interestingCLEU[event] then
  1947.                         spellframe:COMBAT_LOG_EVENT_UNFILTERED(time, event, hideCaster, srcguid,srcname,srcflags, destguid,destname,destflags, spellid,spellname)
  1948.                 end
  1949.         end
  1950. end
  1951.  
  1952. function ns:LoadClassModule()
  1953.         local class = select(2,UnitClass('player'))
  1954.        
  1955.         class = class:sub(1,1)..class:sub(2):lower() -- 'WARLOCK' -> 'Warlock'
  1956.        
  1957.         local name, _, _, enabled, loadable = GetAddOnInfo('EventHorizon_'..class)
  1958.  
  1959.         DisableAddOn('EventHorizon_Redshift')
  1960.         DisableAddOn('EventHorizon_Lines')
  1961.        
  1962.         if not enabled or not loadable then
  1963.                 return
  1964.         end
  1965.         local loaded, reason = LoadAddOn(name)
  1966.         if loaded and self.InitializeClass then
  1967.                 return true
  1968.         end
  1969. end
  1970.  
  1971. --[[
  1972. spellid: number, rank doesn't matter
  1973. abbrev: string
  1974. config: table
  1975. {
  1976.         cast = <boolean>,
  1977.         channeled = <boolean>,
  1978.         numhits = <number of hits per channel>,
  1979.         cooldown = <boolean>,
  1980.         debuff = <boolean>,
  1981.         dot = <tick interval in s, requires debuff>,
  1982.         refreshable = <boolean>,
  1983. }
  1984. --]]
  1985. function ns:NewSpell(config)
  1986.         local spellid = config.spellID or config.itemID or config.slotID
  1987.         if type(spellid)~='number' then
  1988.                 return
  1989.         end
  1990.  
  1991.         table.insert(self.frames.config, config)
  1992. end
  1993.  
  1994. --Set spellframe attributes separately from bar creation. Helps keep things tidy and all, y'know?
  1995. local function SetSpellAttributes(spellframe,config)
  1996.         local interestingEvent = {}
  1997.         local interestingCLEU = {}
  1998.         local config = config
  1999.         local otherids = ns.otherIDs
  2000.         local spellname = spellframe.spellname
  2001.         interestingEvent['UNIT_SPELLCAST_SENT'] = true
  2002.        
  2003.         if config.itemID or config.slotID then
  2004.                 spellframe.cooldown = true      -- Not getting out of this one. It's an item, what else do you watch?
  2005.                 spellframe.cooldownID = config.itemID
  2006.                 spellframe.CooldownFunction = GetItemCooldown
  2007.                 interestingEvent['SPELL_UPDATE_COOLDOWN'] = true
  2008.                 interestingEvent['BAG_UPDATE_COOLDOWN'] = true
  2009.                 if config.slotID then
  2010.                         config.playerbuff = true
  2011.                         config.internalcooldown = true  -- Failsafe
  2012.                         interestingEvent['PLAYER_EQUIPMENT_CHANGED'] = true
  2013.                 end
  2014.         end
  2015.        
  2016.         if config.cast or config.channeled then
  2017.                 spellframe.cast = {}
  2018.                 if config.channeled then
  2019.                         -- Register for the CLEU tick event.
  2020.                         interestingCLEU.SPELL_DAMAGE = true
  2021.                         -- Register event functions
  2022.                         interestingEvent['UNIT_SPELLCAST_CHANNEL_START'] = true
  2023.                         interestingEvent['UNIT_SPELLCAST_CHANNEL_STOP'] = true
  2024.                         interestingEvent['UNIT_SPELLCAST_CHANNEL_UPDATE'] = true
  2025.                         local tcc = type(config.channeled)
  2026.                         if config.channeled == true then        -- defaults
  2027.                                 spellframe.cast[spellname] = {
  2028.                                         numhits = config.numhits or true,       -- use numhits as an indicator that the cast is channeled and not to change smalldebuff, or something.
  2029.                                         func = UnitChannelInfo,
  2030.                                         id = config.spellID,
  2031.                                 }
  2032.                         elseif tcc == 'number' then
  2033.                                 local sn = GetSpellInfo(config.channeled)
  2034.                                 spellframe.cast[sn] = {
  2035.                                         numhits = config.numhits or true,       -- use numhits as an indicator that the cast is channeled and not to change smalldebuff, or something.
  2036.                                         func = UnitChannelInfo,
  2037.                                         id = config.channeled,
  2038.                                 }
  2039.                                 otherids[sn] = {isChannel = true}
  2040.                         elseif tcc == 'table' then
  2041.                                 local channel = type(config.channeled[1]) == 'table' and config.channeled or {config.channeled}
  2042.                                 for _,v in ipairs(channel) do
  2043.                                         local sn = GetSpellInfo(v[1])
  2044.                                         spellframe.cast[sn] = {
  2045.                                                 numhits = v[2] or config.numhits or true,
  2046.                                                 func = UnitChannelInfo,
  2047.                                                 id = v[1],
  2048.                                         }
  2049.                                         otherids[sn] = {isChannel = true}
  2050.                                 end
  2051.                         end
  2052.                 end
  2053.                 if config.cast then
  2054.                         interestingEvent['UNIT_SPELLCAST_START'] = true
  2055.                         interestingEvent['UNIT_SPELLCAST_STOP'] = true
  2056.                         interestingEvent['UNIT_SPELLCAST_DELAYED'] = true
  2057.                         spellframe.useSmalldebuff = config.recast
  2058.                         if ((config.debuff or config.playerbuff) and type(config.debuff or config.playerbuff) == 'boolean') then
  2059.                                 spellframe.useSmalldebuff = true
  2060.                         end
  2061.                         if config.cast == true then
  2062.                                 spellframe.cast[spellname] = {
  2063.                                         func = UnitCastingInfo,
  2064.                                         id = config.spellID
  2065.                                 }
  2066.                         else
  2067.                                 config.cast = type(config.cast) == 'table' and config.cast or {config.cast}
  2068.                                 for _,id in ipairs(config.cast) do
  2069.                                         spellframe.cast[GetSpellInfo(id)] = {
  2070.                                                 func = UnitCastingInfo,
  2071.                                                 id = id
  2072.                                         }
  2073.                                 end
  2074.                         end
  2075.                 end
  2076.         end
  2077.  
  2078.         if config.cooldown then
  2079.                 if type(config.cooldown) == 'number' then
  2080.                         spellframe.cooldownID = config.cooldown
  2081.                         spellframe.cooldown = true
  2082.                 elseif type(config.cooldown) == 'table' then -- If the second spellID entered is actually usable, then use that otherwise use the other
  2083.                         spellframe.cooldownID = IsUsableSpell(config.cooldown[2]) and config.cooldown[2] or config.cooldown[1]
  2084.                         spellframe.cooldownTable = true
  2085.                         spellframe.cooldown = true
  2086.                 end
  2087.                 spellframe.CooldownFunction = GetSpellCooldown
  2088.                 interestingEvent['SPELL_UPDATE_COOLDOWN'] = true
  2089.         end
  2090.  
  2091.         if config.debuff then
  2092.                 spellframe.isType = 'debuffmine'
  2093.                 spellframe.AuraFunction = UnitDebuff
  2094.                 spellframe.auraunit = config.auraunit or 'target'
  2095.                 vars.debuff[spellframe.auraunit] = {}
  2096.                 if spellframe.auraunit == 'mouseover' then
  2097.                         interestingEvent['UPDATE_MOUSEOVER_UNIT'] = true
  2098.                         spellframe.usemouseover = true
  2099.                         spellframe.baseunit = config.baseunit or 'target'
  2100.                 end
  2101.                 local tcd = type(config.debuff)
  2102.                 if tcd == 'number' then
  2103.                         spellframe.auraname = (GetSpellInfo(config.debuff))
  2104.                 elseif tcd == 'table' then
  2105.                         spellframe.auranamePrimary = (GetSpellInfo(config.spellID))
  2106.                         spellframe.auraname = {}
  2107.                         for i,id in ipairs(config.debuff) do
  2108.                                 tinsert(spellframe.auraname, (GetSpellInfo(id)))
  2109.                         end
  2110.                         spellframe.AuraFunction = UnitDebuffUnique
  2111.                 else
  2112.                         spellframe.auraname = spellname
  2113.                 end
  2114. --              interestingEvent['UNIT_AURA'] = true
  2115. --              interestingEvent['PLAYER_TARGET_CHANGED'] = true
  2116.                 if config.dot then
  2117.                         spellframe.dot = config.dot
  2118.                         interestingCLEU.SPELL_PERIODIC_DAMAGE = true
  2119.                         spellframe.AddTicks = AddTicks.stop
  2120.                         if config.refreshable then
  2121.                                 spellframe.refreshable = true
  2122.                                 spellframe.UNIT_AURA = SpellFrame.UNIT_AURA_refreshable
  2123. --                              spellframe.PLAYER_TARGET_CHANGED = SpellFrame.PLAYER_TARGET_CHANGED_refreshable
  2124.                                 interestingEvent['PLAYER_REGEN_ENABLED'] = true
  2125.                                 interestingCLEU.SPELL_CAST_SUCCESS=true
  2126.                                 spellframe.debuffs = {}
  2127.                                 spellframe.castsuccess = {}
  2128.                         end
  2129.                 end
  2130.         elseif config.playerbuff then
  2131.                 spellframe.isType = 'playerbuff'
  2132.                 spellframe.AuraFunction = UnitBuff
  2133.                 spellframe.auraunit = config.auraunit or 'player'
  2134.                 vars.buff[spellframe.auraunit] = {}
  2135.                 if config.auraunit then
  2136. --                      interestingEvent['PLAYER_TARGET_CHANGED'] = true
  2137.                 end
  2138.                 if spellframe.auraunit == 'mouseover' then
  2139.                         interestingEvent['UPDATE_MOUSEOVER_UNIT'] = true
  2140.                         spellframe.usemouseover = true
  2141.                         spellframe.baseunit = config.baseunit or 'target'
  2142.                 end
  2143.                 spellframe.alwaysrefresh = true
  2144. --              interestingEvent['UNIT_AURA'] = true
  2145.                 local tcp = type(config.playerbuff)
  2146.                 if tcp == 'number' then
  2147.                         spellframe.auraname = (GetSpellInfo(config.playerbuff))
  2148.                 elseif tcp == 'table' then
  2149.                         spellframe.auraname = {}
  2150.                         spellframe.auranamePrimary = (GetSpellInfo(config.spellID))
  2151.                         for i,id in ipairs(config.playerbuff) do
  2152.                                 tinsert(spellframe.auraname, (GetSpellInfo(id)))
  2153.                         end
  2154.                         spellframe.AuraFunction = UnitBuffUnique
  2155.                 else
  2156.                         spellframe.auraname = spellname
  2157.                 end
  2158.                
  2159.                 if config.dot then              -- Register for periodic effect intervals.
  2160.                         spellframe.dot = config.dot
  2161.                         spellframe.AddTicks = AddTicks.stop
  2162.                         interestingCLEU.SPELL_PERIODIC_HEAL = true
  2163.                         if config.refreshable then
  2164.                                 spellframe.refreshable = true
  2165.                                 spellframe.UNIT_AURA = SpellFrame.UNIT_AURA_refreshable
  2166. --                              spellframe.PLAYER_TARGET_CHANGED = SpellFrame.PLAYER_TARGET_CHANGED_refreshable
  2167.                                 interestingEvent['PLAYER_REGEN_ENABLED'] = true
  2168.                                 interestingCLEU.SPELL_CAST_SUCCESS=true
  2169.                                 spellframe.debuffs = {}
  2170.                                 spellframe.castsuccess = {}
  2171.                         end
  2172.                 end
  2173.         end
  2174.        
  2175.         if config.cleu or config.event then -- Register custom CLEU events.
  2176.                 if config.event then -- Optional alias for the forgetful.
  2177.                         config.cleu = config.event
  2178.                 end
  2179.                 local cleu = type(config.cleu)
  2180.                 if cleu == 'string' then -- Single event
  2181.                         interestingCLEU[config.cleu] = true
  2182.                 elseif cleu == 'table' then
  2183.                         for i in pairs(config.cleu) do -- Multiple events
  2184.                                 interestingCLEU[ config.cleu[i] ] = true
  2185.                         end
  2186.                 end
  2187.         end    
  2188.        
  2189.         if type(config.glyphrefresh) == 'table' then
  2190.                 spellframe.glyphrefresh = config.glyphrefresh
  2191.                 spellframe.glyphstacks = {}
  2192.                 if not otherids[config.glyphrefresh[3]] then
  2193.                         otherids[config.glyphrefresh[3]] = {}
  2194.                 end
  2195.                 otherids[config.glyphrefresh[3]][spellname] = true
  2196.                 otherids[config.glyphrefresh[3]].isGlyph = true
  2197.                 interestingCLEU.SPELL_AURA_REMOVED = true
  2198.         end
  2199.        
  2200.         spellframe.hasted = config.hasted
  2201.         spellframe.minstacks = config.minstacks
  2202.         spellframe.stance = config.stance
  2203.         spellframe.notstance = config.notstance
  2204.         spellframe.internalcooldown = config.internalcooldown
  2205.         spellframe.bartexture = config.bartexture
  2206.         spellframe.barcolor = config.barcolor
  2207.         spellframe.barcolorunique = config.barcolorunique
  2208.         spellframe.unique = config.unique
  2209.         spellframe.uniqueID = config.uniqueID
  2210.         spellframe.keepIcon = config.keepIcon
  2211.         spellframe.smallCooldown = config.smallCooldown
  2212.        
  2213.         spellframe.interestingCLEU = interestingCLEU
  2214.         return interestingEvent
  2215. end
  2216.  
  2217.  
  2218. function ns:CreateSpellBar(config)
  2219.         local spellid = config.spellID
  2220.         local invid = config.itemID
  2221.         local csid = config.slotID
  2222.         local slotname, spellname, tex, _
  2223.        
  2224.         local spellframe = CreateFrame('Frame', nil, mainframe)
  2225.         mainframe.numframes = mainframe.numframes+1
  2226.        
  2227.         if spellid then
  2228.                 spellname, _, tex = GetSpellInfo(spellid)
  2229.         elseif invid then
  2230.                 spellname,_,_,_,_,_,_,_,_,tex,_ = GetItemInfo(invid)
  2231.         elseif csid then
  2232.                 slotname = GetSlotName(csid)
  2233.                 spellframe.slotID = csid
  2234.                 spellframe.slotName = slotname
  2235.                 local itemID = GetInventoryItemID('player',csid)
  2236.                 if itemID then
  2237.                         spellname,_,_,_,_,_,_,_,_,tex,_ = GetItemInfo(itemID)
  2238.                 else
  2239.                         spellname = slotName
  2240.                         tex = nil
  2241.                 end
  2242.         end
  2243.         local basename = slotname or spellname
  2244.         --debug('creating frame for ',spellname)
  2245.         spellframe.spellname = spellname
  2246.  
  2247.         -- Create the bar.
  2248.         spellframe.indicators = {}
  2249.         if ns.config.barbg then
  2250.                 spellframe:SetBackdrop{bgFile = vars.bartexture}
  2251.                 spellframe:SetBackdropColor(unpack(ns.colors.barbgcolor))
  2252.         end
  2253.  
  2254.         -- Create and set the spell icon.
  2255.         if config.icon then
  2256.                 local t = type(config.icon)
  2257.                 if t == 'number' then
  2258.                         if spellid then
  2259.                                 _,_,tex = GetSpellInfo(config.icon)
  2260.                         elseif invid then
  2261.                                 tex = select(10,GetItemInfo(config.icon))
  2262.                         end
  2263.                 elseif t == 'string' then
  2264.                         tex = config.icon
  2265.                 end
  2266.                 config.keepIcon = true
  2267.         end
  2268.         spellframe.icon = spellframe:CreateTexture(nil, 'BORDER')
  2269.         spellframe.icon:SetTexture(tex)
  2270.  
  2271.         spellframe.stacks = spellframe:CreateFontString(nil, 'OVERLAY')
  2272.         if vars.stackFont then
  2273.                 spellframe.stacks:SetFont(vars.stackFont,vars.stackFontSize)
  2274.                 if vars.stackFontShadow then
  2275.                         spellframe.stacks:SetShadowColor(unpack(vars.stackFontShadow))
  2276.                         spellframe.stacks:SetShadowOffset(unpack(vars.stackFontShadowOffset))
  2277.                 end
  2278.         else
  2279.                 spellframe.stacks:SetFontObject('NumberFontNormalSmall')
  2280.         end
  2281.         spellframe.stacks:SetVertexColor(unpack(vars.stackFontColor))
  2282.  
  2283.         for k,v in pairs(SpellFrame) do
  2284.                 if not spellframe[k] then spellframe[k] = v end
  2285.         end
  2286.        
  2287.         spellframe.interestingEvent = SetSpellAttributes(spellframe,config)
  2288.        
  2289.         spellframe:SetScript('OnEvent', EventHandler)
  2290.         spellframe:SetScript('OnUpdate', spellframe.OnUpdate)
  2291.        
  2292.         local sfi = self.config.hideIcons
  2293.         local sor = self.config.stackOnRight
  2294.         -- Layout
  2295.         spellframe.stacks:SetPoint((sfi and not(sor)) and 'BOTTOMLEFT' or 'BOTTOMRIGHT', (sfi or sor) and spellframe or spellframe.icon, (sfi and not(sor)) and 'BOTTOMLEFT' or 'BOTTOMRIGHT')
  2296.         spellframe.stacks:SetJustifyH(sor and 'LEFT' or 'RIGHT')
  2297.  
  2298.         spellframe:Activate()
  2299.        
  2300.         if config.slotID then
  2301.                 spellframe:PLAYER_EQUIPMENT_CHANGED(config.slotID)      -- Initialize trinkets and such if needed.
  2302.         end
  2303.        
  2304.         return spellframe
  2305. end
  2306.  
  2307. function ns:LoadModules()
  2308.         for i,module in pairs(self.modules) do
  2309.                 if not EventHorizonDB[i] then EventHorizonDB[i] = { isActive = true } end
  2310.                 if (EventHorizonDB[i] and EventHorizonDB[i].isActive == true) or module.alwaysLoad then
  2311.                         if not(self.modules[i].Enable) then self.modules[i].Enable = function () end end
  2312.                         if not(self.modules[i].Disable) then self.modules[i].Disable = function () end end
  2313.                         self.modules[i]:Init()
  2314.                         self.modules[i]:Enable()
  2315.                         vars.modulesLoaded = true
  2316.                 end
  2317.         end
  2318. end
  2319.  
  2320. function ns:ActivateModule(module,slash)
  2321.         if EventHorizonDB[module].isActive ~= true then
  2322.                 self.modules[module].isActive = true
  2323.                 EventHorizonDB[module].isActive = true
  2324.                 if not(self.modules[module].isReady == true) then self.modules[module].Init() end
  2325.                 self.modules[module].Enable(slash)
  2326.         end
  2327. end
  2328.  
  2329. function ns:DeactivateModule(module,slash)
  2330.         if EventHorizonDB[module].isActive == true then
  2331.                 self.modules[module].isActive = false
  2332.                 EventHorizonDB[module].isActive = false
  2333.                 if not(self.modules[module].isReady == true) then self.modules[module].Init() end
  2334.                 self.modules[module].Disable(slash)
  2335.         end
  2336. end
  2337.  
  2338. function ns:ToggleModule(module,slash)
  2339.         if EventHorizonDB[module].isActive ~= true then
  2340.                 self:ActivateModule(module,slash)
  2341.         else
  2342.                 self:DeactivateModule(module,slash)
  2343.         end
  2344. end
  2345.  
  2346. -- External event handler for modules, same rules as EH's event handler (passes self, extra args, event is presumed known)
  2347. function ns:ModuleEvent(event, ...)
  2348.         for i,module in pairs(self.modules) do
  2349.                 local f = module[event]
  2350.                 if f then
  2351.                         f(module,...)
  2352.                 end
  2353.         end
  2354. end
  2355.  
  2356. function ns:Activate(...)
  2357.         local activate = select('#',...) == 0 or ...
  2358.         --debug('Activate',activate, ...)
  2359.         if not activate then
  2360.                 return self:Deactivate()
  2361.         end
  2362.         for k,v in pairs(mainframeEvents) do
  2363.                 mainframe:RegisterEvent(k)
  2364.         end
  2365.        
  2366.         self.isActive = true
  2367.         vars.visibleFrame = true
  2368.        
  2369.         if (self.modules.redshift.isReady and EventHorizonDB.redshift.isActive == true) then
  2370.                 self.modules.redshift:Check()
  2371.         else
  2372.                 mainframe:Show()
  2373.         end
  2374. end
  2375.  
  2376. function ns:Deactivate()
  2377.         if self.isActive==false then
  2378.                 return
  2379.         end
  2380.         mainframe:UnregisterAllEvents()
  2381.         mainframe:RegisterEvent('PLAYER_TALENT_UPDATE')
  2382.  
  2383.         mainframe:Hide()
  2384.        
  2385.         self.isActive = false
  2386. end
  2387.  
  2388. function ns:InitDB()
  2389.         if not EventHorizonDB then EventHorizonDB = self.defaultDB end
  2390. --      print('initdb')
  2391.         local reset
  2392.                 -- Upgrade DB.
  2393.         if EventHorizonDB and not EventHorizonDB.version then
  2394.                 EventHorizonDB.version = 0
  2395.         end
  2396.         if EventHorizonDB.version ~= EventHorizon.defaultDB.version then
  2397.                 reset = true
  2398.                 table.wipe(EventHorizonDB)
  2399.                 EventHorizonDB = Clone(ns.defaultDB)
  2400.         end
  2401.  
  2402.         if not EventHorizonDBG then EventHorizonDBG = self.defaultDBG end
  2403.                 -- Upgrade DB.
  2404.         if EventHorizonDBG and not EventHorizonDBG.version then
  2405.                 EventHorizonDBG.version = 0
  2406.         end
  2407.         if EventHorizonDBG.version ~= EventHorizon.defaultDBG.version then
  2408.                 reset = true
  2409.                 table.wipe(EventHorizonDBG)
  2410.                 EventHorizonDBG = Clone(ns.defaultDBG)
  2411.         end
  2412.        
  2413.         -- If profile doesn't exist, set it to the default.
  2414.         EventHorizonDBG.profilePerChar[playername] = EventHorizonDBG.profilePerChar[playername] or EventHorizonDBG.defaultProfile
  2415.         local ppc = EventHorizonDBG.profilePerChar[playername]
  2416.        
  2417.         if not EventHorizonDBG.profiles[ppc] then
  2418.                 EventHorizonDBG.profiles[ppc] = {}
  2419.         end
  2420.         self.vars.currentProfile = EventHorizonDBG.profiles[ppc]
  2421.        
  2422.         if reset then
  2423.                 print('Your savedvariables have been reset due to potential conflicts with older versions.')
  2424.         end
  2425.        
  2426.         self.db = EventHorizonDB
  2427.         self.dbg = EventHorizonDBG
  2428. end
  2429.  
  2430. --[[
  2431. Should only be called after the DB is loaded and spell and talent information is available.
  2432. --]]
  2433. function ns:Initialize()
  2434.         -- Make sure this function is called only once.
  2435.         --self.Initialize = nil
  2436.         --print('initialize')
  2437.         self:InitDB()
  2438.        
  2439.         --debug('GetTalentInfo(1,1)',GetTalentInfo(1,1))
  2440.         vars.playerguid = UnitGUID('player')
  2441.        
  2442.         -- Create the main and spell frames.
  2443.         mainframe:SetHeight(1)
  2444.         mainframe.numframes = 0
  2445.         mainframe.framebyspell= {}
  2446.         mainframe:SetScript('OnEvent', EventHandler)
  2447.         mainframe:SetScale(self.config.scale or 1)
  2448.        
  2449.         vars.buff.player = {}
  2450.        
  2451.         if not self:LoadClassModule() then
  2452.                 return
  2453.         end
  2454.  
  2455.         self:ApplyConfig()
  2456.  
  2457.         self:InitializeClass()
  2458.         if self.config.showTrinketBars and self.config.showTrinketBars == true then
  2459.                 self:NewSpell({slotID = 13})
  2460.                 self:NewSpell({slotID = 14})
  2461.         end
  2462.        
  2463.         local sfi = self.config.hideIcons
  2464.         mainframe:SetWidth(vars.barwidth + (sfi and 0 or self.config.height))
  2465.        
  2466.         self:SetupStyleFrame()          -- Spawn backdrop frame.
  2467.                
  2468.         -- Create the indicator for the current time.
  2469.         -- Bugfix: When the UI scale is at a very low setting, textures with a width of 1
  2470.         -- were not visible in some resolutions.
  2471.         local effectiveScale = mainframe:GetEffectiveScale()
  2472.         if effectiveScale then
  2473.                 vars.onepixelwide = 1/effectiveScale
  2474.         end
  2475.         --nowI = CreateFrame('Frame',nil,mainframe)
  2476.         --nowI:SetFrameLevel(20)
  2477.         ns.frames.nowIndicator = mainframe:CreateTexture(nil, 'ARTWORK', nil, draworder.nowI)
  2478.        
  2479.         ns.frames.nowIndicator:SetPoint('BOTTOM',mainframe,'BOTTOM')
  2480.         ns.frames.nowIndicator:SetPoint('TOPLEFT',mainframe,'TOPLEFT', vars.nowleft, 0)
  2481.         ns.frames.nowIndicator:SetWidth(vars.onepixelwide)
  2482.         ns.frames.nowIndicator:SetTexture(unpack(self.colors.nowLine))
  2483.         if self.config.blendModes.nowLine and type(self.config.blendModes.nowLine) == 'string' then
  2484.                 ns.frames.nowIndicator:SetBlendMode(self.config.blendModes.nowLine)
  2485.         end
  2486.  
  2487.         local anchor = self.config.anchor or {'TOPRIGHT', 'EventHorizonHandle', 'BOTTOMRIGHT'}
  2488.         if anchor[2]=='EventHorizonHandle' then
  2489.                 -- Create the handle to reposition the frame.
  2490.                 handle = CreateFrame('Frame', 'EventHorizonHandle', mainframe)
  2491.                 handle:SetFrameStrata('HIGH')
  2492.                 handle:SetWidth(10)
  2493.                 handle:SetHeight(5)
  2494.                 handle:EnableMouse(true)
  2495.                 handle:SetClampedToScreen(1)
  2496.                 handle:RegisterForDrag('LeftButton')
  2497.                 handle:SetScript('OnDragStart', function(handle, button) handle:StartMoving() end)
  2498.                 handle:SetScript('OnDragStop', function(handle)
  2499.                         handle:StopMovingOrSizing()
  2500.                         local a,b,c,d,e = handle:GetPoint(1)
  2501.                         if type(b)=='frame' then
  2502.                                 b=b:GetName()
  2503.                         end
  2504.                         EventHorizonDB.point = {a,b,c,d,e}
  2505.                 end)
  2506.                 handle:SetMovable(true)
  2507.  
  2508.                 mainframe:SetPoint(unpack(anchor))
  2509.                 handle:SetPoint(unpack(EventHorizonDB.point))
  2510.  
  2511.                 handle.tex = handle:CreateTexture(nil, 'ARTWORK', nil, 7)
  2512.                 handle.tex:SetAllPoints()
  2513.                 handle:SetScript('OnEnter',function(frame) frame.tex:SetTexture(1,1,1,1) end)
  2514.                 handle:SetScript('OnLeave',function(frame) frame.tex:SetTexture(1,1,1,0.1) end)
  2515.                 handle.tex:SetTexture(1,1,1,0.1)
  2516.                
  2517.                 if EventHorizonDB.isLocked then
  2518.                         handle:Hide()
  2519.                 end
  2520.         end
  2521.  
  2522.         vars.gcdSpellName = self.config.gcdSpellID and (GetSpellInfo(self.config.gcdSpellID))
  2523.         if vars.gcdSpellName and self.config.gcdStyle then
  2524.                 -- Create the GCD indicator, register cooldown event.
  2525.                 ns.frames.gcd = mainframe:CreateTexture(nil, 'ARTWORK',nil,draworder.gcd)
  2526.                 ns.frames.gcd:SetPoint('BOTTOM',mainframe,'BOTTOM')
  2527.                 ns.frames.gcd:SetPoint('TOP',mainframe,'TOP')
  2528.                 ns.frames.gcd:Hide()
  2529.  
  2530.                 if self.config.gcdStyle == 'line' then
  2531.                         ns.frames.gcd:SetWidth(vars.onepixelwide)
  2532.                 else
  2533.                         ns.frames.gcd:SetPoint('LEFT',mainframe,'LEFT', vars.nowleft, 0)
  2534.                 end
  2535.  
  2536.                 local gcdColor = self.colors.gcdColor or {.5,.5,.5,.3}
  2537.                 ns.frames.gcd:SetTexture(unpack(gcdColor))
  2538.                 if self.config.blendModes.gcdColor and type(self.config.blendModes.gcdColor) == 'string' then
  2539.                         ns.frames.gcd:SetBlendMode(self.config.blendModes.gcdColor)
  2540.                 end
  2541.         end
  2542.  
  2543.         mainframe:SetPoint(unpack(anchor))
  2544.  
  2545.         SLASH_EVENTHORIZON1 = '/eventhorizon'
  2546.         SLASH_EVENTHORIZON2 = '/ehz'
  2547.         SlashCmdList['EVENTHORIZON'] = function(msg)
  2548.                 local cmd = string.lower(msg)
  2549.                 local toggle = not(msg) or cmd == ''
  2550.                
  2551.                 if cmd == 'help' then
  2552.                         debug'Use "/eventhorizon" or "/ehz" to show or hide EventHorizon.'
  2553.                         debug'To enable or disable a module, use "/ehz ModuleName". For example, "/ehz redshift".'
  2554.                         debug'To see a list of currently installed modules and visible bars, use "/ehz status".'
  2555.                         if anchor[2]=='EventHorizonHandle' then
  2556.                                 debug('  EventHorizon is currently '..(EventHorizonDB.isLocked and 'locked.' or 'movable.'))
  2557.                                 debug('  To '..(EventHorizonDB.isLocked and 'unlock ' or 'lock ')..'EventHorizon, use "/ehz lock".')
  2558.                                 debug'  If you are unable see or move EventHorizon, use "/ehz reset".'
  2559.                         end
  2560.                 elseif cmd == 'status' then
  2561.                         print('Installed plugins:')
  2562.                         for i in pairs(self.modules) do debug('  '..i) end
  2563.                         print('Visible bars:')
  2564.                         for i,v in pairs(self.frames.shown) do debug('  '..v.spellname) end
  2565.                 elseif cmd == 'reset' then
  2566.                         if anchor[2]=='EventHorizonHandle' then
  2567.                                 debug'Resetting EventHorizon\'s position.'
  2568.                                 EventHorizonHandle:SetPoint(unpack(self.defaultDB.point))
  2569.                                 self:CheckTalents()
  2570.                         else
  2571.                                 print"The frame is otherwise anchored. Adjust config.anchor in [my]config.lua to move EventHorizon."
  2572.                         end
  2573.                 elseif cmd == 'lock' then
  2574.                         if anchor[2]=='EventHorizonHandle' then
  2575.                                 if EventHorizonHandle:IsShown() then
  2576.                                         EventHorizonHandle:Hide()
  2577.                                         EventHorizonDB.isLocked = true
  2578.                                 else
  2579.                                         EventHorizonHandle:Show()
  2580.                                         EventHorizonDB.isLocked = nil
  2581.                                 end
  2582.                                 print("The frame is now "..(EventHorizonDB.isLocked and 'locked.' or 'unlocked.'))
  2583.                         else
  2584.                                 print"The frame is otherwise anchored. Adjust config.anchor in [my]config.lua to move EventHorizon."
  2585.                         end
  2586.                 elseif self.modules[cmd] then
  2587.                         self:ToggleModule(string.lower(msg))
  2588.                         print(string.lower(msg)..' has been turned '..((self.modules[string.lower(msg)].isActive == true) and 'ON' or 'OFF')..'.')
  2589.                 elseif toggle then
  2590.                         if self.isActive then
  2591.                                 print('Deactivating EventHorizon. Use "/ehz help" to see what else you can do.')
  2592.                                 self:Deactivate()
  2593.                                 mainframe:UnregisterEvent('PLAYER_TALENT_UPDATE')
  2594.                         else
  2595.                                 print('Activating EventHorizon. Use "/ehz help" to see what else you can do.')
  2596.                                 self:Activate()
  2597.                                 self:CheckTalents()
  2598.                         end
  2599.                 else
  2600.                         print('Invalid command. Use "/ehz" alone to show or hide EventHorizon, or "/ehz help" to see a list of commands.')
  2601.                 end
  2602.                 EventHorizonDB.isActive = self.isActive
  2603.         end
  2604.        
  2605.         ns.isActive = EventHorizonDB.isActive
  2606.         if not EventHorizonDB.isActive then
  2607.                 self:Deactivate()
  2608.                 mainframe:UnregisterEvent('PLAYER_TALENT_UPDATE')
  2609.         end
  2610.        
  2611.         self:CheckRequirements()
  2612.         self:LoadModules()
  2613.        
  2614.         if not(ns.config.hastedSpellID and type(ns.config.hastedSpellID) == 'table') then
  2615.                 vars.useOldHaste = true
  2616.         end
  2617.         if ns.config.nonAffectingHaste then
  2618.                 if type(ns.config.nonAffectingHaste[1]) == 'number' then
  2619.                         ns.config.nonAffectingHaste = {ns.config.nonAffectingHaste}
  2620.                 end
  2621.         end
  2622.        
  2623.         self.isReady = true
  2624. end
  2625.  
  2626. function ns:ApplyConfig()
  2627.         table.wipe(ns.vars.config)
  2628.         local config = {}
  2629.         local ppc = EventHorizonDBG.profilePerChar[playername] -- EventHorizonDBG.profilePerChar[playername] = 'ProfileName'
  2630.         if ppc then
  2631.                 config = EventHorizonDBG.profiles[ppc] -- EventHorizon.profiles[ProfileName] = {overriddenConfig}
  2632.         end
  2633.         setmetatable(config,{__index = ns.config}) -- Set non-overridden values to what is in [my]config.lua
  2634.        
  2635.         vars.past = -math.abs(config.past) or -3        -- We really don't want config.past to be positive, so negative absolute values work great here.
  2636.         vars.future = math.abs(config.future) or 9
  2637.         vars.barheight = config.height or 18
  2638.         vars.barwidth = config.width or 150
  2639.         vars.barspacing = config.spacing or 0
  2640.         vars.scale = 1/(vars.future-vars.past)
  2641.         vars.bartexture = config.bartexture or 'Interface\\Addons\\EventHorizon\\Smooth'
  2642.         vars.texturedbars = config.texturedbars
  2643.         vars.texturealpha = config.texturealphamultiplier or 1
  2644.         vars.classburn = config.classburn or 0.7
  2645.         vars.classalpha = config.classalpha or 0.3
  2646.         vars.castLine = config.castLine and ((type(config.castLine) == 'number' and config.castLine) or config.castLine == true and 0) or nil
  2647.         vars.nowleft = -vars.past/(vars.future-vars.past)*vars.barwidth-0.5 + (config.hideIcons and 0 or config.height)
  2648.        
  2649.         local classcolors = CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS
  2650.         self.classcolor = Clone(classcolors[select(2,UnitClass('player'))])
  2651.        
  2652.         vars.stackFont = config.stackFont
  2653.         vars.stackFontSize = config.stackFontSize
  2654.         vars.stackFontColor = config.stackFontColor == true and {1,1,1,1} or config.stackFontColor or {1,1,1,1}
  2655.         vars.stackFontShadow = config.stackFontShadow == true and {0,0,0,0.5} or config.stackFontShadow or {0,0,0,0.5}
  2656.         vars.stackFontShadowOffset = config.stackFontShadowOffset == true and {1,-1} or config.stackFontShadowOffset or {1,-1}
  2657.  
  2658.         for colorid,color in pairs(self.colors) do
  2659.                 if color[1] == true then
  2660.                         if color[2] then
  2661.                                 self.colors[colorid] = {self.classcolor.r * color[2], self.classcolor.g * color[2], self.classcolor.b * color[2], color[3] or vars.classalpha}          -- For really bad reasons, this took a very long time to get right...
  2662.                         else
  2663.                                 self.colors[colorid] = {self.classcolor.r, self.classcolor.g, self.classcolor.b, vars.classalpha}
  2664.                         end
  2665.                 end
  2666.         end
  2667.        
  2668.         if vars.texturedbars then
  2669.                 for colorid,color in pairs(self.colors) do
  2670.                         if color[4] and not(exemptColors[colorid]) then
  2671.                                 color[4] = vars.texturealpha*color[4]
  2672.                         end
  2673.                 end
  2674.         end
  2675.  
  2676.         local layouts = self.layouts
  2677.         layouts.frameline = {
  2678.                 top = 0,
  2679.                 bottom = 1,
  2680.         }
  2681.         local default = layouts.default
  2682.         for typeid,layout in pairs(layouts) do
  2683.                 if typeid~='default' then
  2684.                         for k,v in pairs(default) do
  2685.                                 if layout[k]==nil then
  2686.                                         layout[k] = v
  2687.                                 end
  2688.                         end
  2689.                 end
  2690.                 layout.texcoords = {0, 1, layout.top, layout.bottom}
  2691.         end
  2692.        
  2693.         ns:ModuleEvent('ApplyConfig')
  2694. end
  2695.  
  2696. function ns:UpdateConfig()
  2697.         if not(self.isReady) then return end
  2698.         self:ApplyConfig()
  2699.  
  2700.         mainframe:SetScale(self.config.scale or 1)
  2701.         local effectiveScale = mainframe:GetEffectiveScale()
  2702.         if effectiveScale then
  2703.                 vars.onepixelwide = 1/effectiveScale
  2704.         end
  2705.        
  2706.         self:SetupStyleFrame()          -- Spawn backdrop frame.
  2707.        
  2708.         vars.nowleft = -vars.past/(vars.future-vars.past)*vars.barwidth-0.5 + (ns.config.hideIcons and 0 or ns.config.height)
  2709.         --nowI:SetFrameLevel(20)
  2710.         ns.frames.nowIndicator:SetPoint('BOTTOM',mainframe,'BOTTOM')
  2711.         ns.frames.nowIndicator:SetPoint('TOPLEFT',mainframe,'TOPLEFT', vars.nowleft, 0)
  2712.         ns.frames.nowIndicator:SetTexture(unpack(self.colors.nowLine))
  2713.  
  2714.         local anchor = self.config.anchor or {'TOPRIGHT', 'EventHorizonHandle', 'BOTTOMRIGHT'}
  2715.         if anchor[2]=='EventHorizonHandle' then
  2716.                 -- Create the handle to reposition the frame.
  2717.                 handle = handle or CreateFrame('Frame', 'EventHorizonHandle', mainframe)
  2718.                 handle:SetFrameStrata('HIGH')
  2719.                 handle:SetWidth(10)
  2720.                 handle:SetHeight(5)
  2721.                 handle:EnableMouse(true)
  2722.                 handle:SetClampedToScreen(1)
  2723.                 handle:RegisterForDrag('LeftButton')
  2724.                 handle:SetScript('OnDragStart', function(handle, button) handle:StartMoving() end)
  2725.                 handle:SetScript('OnDragStop', function(handle)
  2726.                         handle:StopMovingOrSizing()
  2727.                         local a,b,c,d,e = handle:GetPoint(1)
  2728.                         if type(b)=='frame' then
  2729.                                 b=b:GetName()
  2730.                         end
  2731.                         EventHorizonDB.point = {a,b,c,d,e}
  2732.                 end)
  2733.                 handle:SetMovable(true)
  2734.  
  2735.                 mainframe:SetPoint(unpack(anchor))
  2736.                 handle:SetPoint(unpack(EventHorizonDB.point))
  2737.  
  2738.                 handle.tex = handle:CreateTexture(nil, 'BORDER')
  2739.                 handle.tex:SetAllPoints()
  2740.                 handle:SetScript('OnEnter',function(frame) frame.tex:SetTexture(1,1,1,1) end)
  2741.                 handle:SetScript('OnLeave',function(frame) frame.tex:SetTexture(1,1,1,0.1) end)
  2742.                 handle.tex:SetTexture(1,1,1,0.1)
  2743.         end
  2744.  
  2745.         vars.gcdSpellName = self.config.gcdSpellID and (GetSpellInfo(self.config.gcdSpellID))
  2746.         if vars.gcdSpellName and self.config.gcdStyle then
  2747.                 -- Create the GCD indicator, register cooldown event.
  2748.                 ns.frames.gcd = mainframe:CreateTexture('EventHorizonns.frames.gcd', 'BORDER')
  2749.                 ns.frames.gcd:SetPoint('BOTTOM',mainframe,'BOTTOM')
  2750.                 ns.frames.gcd:SetPoint('TOP',mainframe,'TOP')
  2751.                 ns.frames.gcd:Hide()
  2752.  
  2753.                 if self.config.gcdStyle == 'line' then
  2754.                         ns.frames.gcd:SetWidth(vars.onepixelwide)
  2755.                 else
  2756.                         ns.frames.gcd:SetPoint('LEFT',mainframe,'LEFT', vars.nowleft, 0)
  2757.                 end
  2758.  
  2759.                 local gcdColor = self.colors.gcdColor or {.5,.5,.5,.3}
  2760.                 ns.frames.gcd:SetTexture(unpack(gcdColor))
  2761.         end
  2762.        
  2763.         mainframe:SetPoint(unpack(anchor))
  2764.         self:SetFrameDimensions()
  2765. end
  2766.  
  2767. local glyphCheck = function ()
  2768.         if ns.isActive == true then
  2769.                 ns:CheckTalents()
  2770.  
  2771.                 for i,spellframe in pairs(ns.frames.shown) do
  2772.                         if spellframe.slotID then spellframe:PLAYER_EQUIPMENT_CHANGED(spellframe.slotID) end
  2773.                 end
  2774.         end    
  2775. end
  2776.  
  2777. function ns:SetupStyleFrame()
  2778.         local c = self.config.backdrop
  2779.         if c then
  2780.                 if not(self.styleframe) then self.styleframe = CreateFrame('Frame',nil,mainframe) end
  2781.         else
  2782.                 if self.styleframe then self.styleframe:Hide() end
  2783.                 return
  2784.         end
  2785.        
  2786.         local styleframe = self.styleframe
  2787.         local stylebg = self.config.bg or 'Interface\\ChatFrame\\ChatFrameBackground'
  2788.         local styleborder = self.config.border or 'Interface\\Tooltips\\UI-Tooltip-Border'
  2789.         local stylebgcolor = self.colors.bgcolor or {0,0,0,0.6}
  2790.         local stylebordercolor = self.colors.bordercolor or {1,1,1,1}
  2791.         local styleinset = self.config.inset or {top = 2, bottom = 2, left = 2, right = 2}
  2792.         local stylepadding = self.config.padding or 3
  2793.         local styleedge = self.config.edgesize or 8
  2794.  
  2795.         styleframe:SetFrameStrata('BACKGROUND')
  2796.         styleframe:SetPoint('TOPRIGHT', mainframe, 'TOPRIGHT', stylepadding, stylepadding)
  2797.         styleframe:SetPoint('BOTTOMLEFT', mainframe, 'BOTTOMLEFT', -stylepadding, -stylepadding)
  2798.         styleframe:SetBackdrop({
  2799.                 bgFile = stylebg,
  2800.                 edgeFile = styleborder, tileSize = 0, edgeSize = styleedge,
  2801.                 insets = styleinset,
  2802.         })
  2803.         styleframe:SetBackdropColor(unpack(stylebgcolor))
  2804.         styleframe:SetBackdropBorderColor(unpack(stylebordercolor))
  2805. end
  2806.  
  2807. function ns:RegisterModule(module,namespace)
  2808.         if not(module and namespace) then
  2809.                 print("Module registration failed. Usage: EventHorizon:RegisterModule(module,namespace)")
  2810.         end
  2811.         local module = string.lower(module)
  2812.         self.modules[module] = namespace
  2813. end
  2814.  
  2815.  
  2816. frame:SetScript('OnEvent', EventHandler)
  2817. frame:RegisterEvent('PLAYER_LOGIN')
  2818.  
  2819. frame.PLAYER_ALIVE = function (self)
  2820.         self:SetScript('OnUpdate', UpdateMouseover)
  2821.         frame2:SetScript('OnEvent', EventHandler)
  2822.         for k,v in pairs(reloadEvents) do
  2823.                 frame2:RegisterEvent(k)
  2824.                 frame2[k] = glyphCheck
  2825.         end
  2826.         if not(ns.isReady) then
  2827.                 ns:Initialize()
  2828.         else
  2829.                 ns:LoadModules()
  2830.         end
  2831.         self:UnregisterEvent('PLAYER_ALIVE')
  2832. end
  2833.        
  2834. frame.PLAYER_LOGIN = function (self)
  2835.         local talents = GetTalentInfo(1)
  2836.         if talents then
  2837.                 self:UnregisterEvent('PLAYER_LOGIN')
  2838.                 self:SetScript('OnUpdate', UpdateMouseover)
  2839.                 frame2:SetScript('OnEvent', EventHandler)
  2840.                 for k,v in pairs(reloadEvents) do
  2841.                         frame2:RegisterEvent(k)
  2842.                         frame2[k] = glyphCheck
  2843.                 end
  2844.                 if not(ns.isReady) then
  2845.                         ns:Initialize()
  2846.                 else
  2847.                         ns:LoadModules()
  2848.                 end
  2849.         else
  2850.                 self:UnregisterEvent('PLAYER_LOGIN')
  2851.                 self:RegisterEvent('PLAYER_ALIVE')
  2852.         end
  2853. end
  2854.  
  2855. mainframe.CLEU_OtherInterestingSpell = mainframe_CLEU_OtherInterestingSpell
  2856. mainframe.UPDATE_SHAPESHIFT_FORM = mainframe_UPDATE_SHAPESHIFT_FORM
  2857. mainframe.SPELL_UPDATE_COOLDOWN = mainframe_SPELL_UPDATE_COOLDOWN
  2858. mainframe.COMBAT_LOG_EVENT_UNFILTERED = mainframe_COMBAT_LOG_EVENT_UNFILTERED
  2859. mainframe.UPDATE_SHAPESHIFT_FORMS = mainframe_UPDATE_SHAPESHIFT_FORM
  2860. mainframe.PLAYER_TALENT_UPDATE = ns.CheckTalents
  2861. mainframe.PLAYER_LEVEL_UP = ns.CheckTalents
  2862. mainframe.PLAYER_TARGET_CHANGED = mainframe_PLAYER_TARGET_CHANGED
  2863. mainframe.UNIT_AURA = mainframe_UNIT_AURA
  2864.  
  2865. SpellFrame.NotInteresting = SpellFrame_NotInteresting
  2866. SpellFrame.AddSegment = SpellFrame_AddSegment
  2867. SpellFrame.AddIndicator = SpellFrame_AddIndicator
  2868. SpellFrame.Remove = SpellFrame_Remove
  2869. SpellFrame.RemoveTicksAfter = SpellFrame_RemoveTicksAfter
  2870. SpellFrame.RemoveChannelTicksAfter = SpellFrame_RemoveChannelTicksAfter
  2871. SpellFrame.OnUpdate = SpellFrame_OnUpdate
  2872. SpellFrame.UpdateDoT = SpellFrame_UpdateDoT
  2873. SpellFrame.Activate = SpellFrame_Activate
  2874. SpellFrame.Deactivate = SpellFrame_Deactivate
  2875. SpellFrame.FindItemInfo = SpellFrame_FindItemInfo
  2876.  
  2877. SpellFrame.UNIT_AURA = SpellFrame_UNIT_AURA
  2878. SpellFrame.UNIT_AURA_refreshable = SpellFrame_UNIT_AURA_refreshable
  2879. SpellFrame.COMBAT_LOG_EVENT_UNFILTERED = SpellFrame_COMBAT_LOG_EVENT_UNFILTERED
  2880. SpellFrame.UNIT_SPELLCAST_SENT = SpellFrame_UNIT_SPELLCAST_SENT
  2881. SpellFrame.UNIT_SPELLCAST_CHANNEL_START = Cast_Start
  2882. SpellFrame.UNIT_SPELLCAST_CHANNEL_UPDATE = Cast_Update
  2883. SpellFrame.UNIT_SPELLCAST_CHANNEL_STOP = Cast_Stop
  2884. SpellFrame.UNIT_SPELLCAST_START = Cast_Start
  2885. SpellFrame.UNIT_SPELLCAST_STOP = Cast_Stop
  2886. SpellFrame.UNIT_SPELLCAST_DELAYED = Cast_Update
  2887. --SpellFrame.PLAYER_TARGET_CHANGED = SpellFrame_PLAYER_TARGET_CHANGED
  2888. --SpellFrame.PLAYER_TARGET_CHANGED_refreshable = SpellFrame_PLAYER_TARGET_CHANGED_refreshable
  2889. SpellFrame.PLAYER_REGEN_ENABLED = SpellFrame_PLAYER_REGEN_ENABLED
  2890. SpellFrame.SPELL_UPDATE_COOLDOWN = SpellFrame_SPELL_UPDATE_COOLDOWN
  2891. SpellFrame.BAG_UPDATE_COOLDOWN = SpellFrame_SPELL_UPDATE_COOLDOWN
  2892. SpellFrame.PLAYER_EQUIPMENT_CHANGED = SpellFrame_PLAYER_EQUIPMENT_CHANGED
  2893. SpellFrame.UPDATE_MOUSEOVER_UNIT = SpellFrame_UPDATE_MOUSEOVER_UNIT
  2894.  
  2895. local Redshift = {}
  2896. Redshift.Check = function (self)
  2897.         if EventHorizonDB.redshift.isActive ~= true then
  2898.                 return Redshift:Disable()
  2899.         end
  2900.         if not(Redshift.frame) then
  2901.                 Redshift.frame = CreateFrame("FRAME",nil,UIParent)
  2902.                 Redshift.frame:SetScript('OnEvent',EventHandler)
  2903.                 for k,v in pairs(Redshift.Events) do
  2904.                         if v then
  2905.                                 Redshift.frame:RegisterEvent(k)
  2906.                                 Redshift.frame[k] = Redshift.Check
  2907.                         end
  2908.                 end
  2909.         end
  2910.        
  2911.         local s = Redshift.states
  2912.        
  2913.         showState = nil
  2914.        
  2915.         local attackable = UnitCanAttack("player","target")
  2916.         local targeting = UnitExists("target")
  2917.         local focusing = UnitExists("focus")
  2918.         local classify = UnitClassification("target")
  2919.         local dead = UnitIsDeadOrGhost("target")
  2920.         local vehicle = UnitHasVehicleUI("player")
  2921.        
  2922.         if(s.showCombat and UnitAffectingCombat("player")) then
  2923.                 showState = true
  2924.         end
  2925.        
  2926.         if (s.showFocus and UnitExists("focus")) then
  2927.                 showState = true
  2928.         end
  2929.        
  2930.         if targeting then
  2931.                 if(s.showHelp and not attackable) and not dead then
  2932.                         showState = true
  2933.                 end
  2934.                 if(s.showHarm and attackable) and not dead then
  2935.                         showState = true
  2936.                 end
  2937.                 if(s.showBoss and classify == "worldboss") and not dead then
  2938.                         showState = true
  2939.                 end
  2940.         end
  2941.        
  2942.         if (s.hideVehicle and UnitHasVehicleUI("player")) then
  2943.                 showState = nil
  2944.         end
  2945.        
  2946.         if showState then
  2947.                 vars.visibleFrame = true
  2948.                 mainframe:Show()
  2949.                 if EventHorizon_VitalsFrame and s.hideVitals then
  2950.                         EventHorizon_VitalsFrame:Show()
  2951.                 end
  2952.         else
  2953.                 vars.visibleFrame = false
  2954.                 mainframe:Hide()
  2955.                 if EventHorizon_VitalsFrame and s.hideVitals then
  2956.                         EventHorizon_VitalsFrame:Hide()
  2957.                 end
  2958.         end
  2959. end
  2960.  
  2961. Redshift.Init = function ()
  2962.         local settingsChanged = EventHorizonDB.redshift.lastConfig ~= ns.config.enableRedshift
  2963.         EventHorizonDB.redshift.lastConfig = ns.config.enableRedshift
  2964.        
  2965.         if settingsChanged then
  2966.                 local ends = ns.config.enableRedshift and 'enabled' or 'disabled'
  2967.                 local settingsString = "Redshift has been "..ends.." via config.lua. Ingame settings have been adjusted to match. Use /ehz redshift to enable or disable Redshift as needed."
  2968.                 EventHorizonDB.redshift.isActive = ns.config.enableRedshift
  2969.         end
  2970.  
  2971.         local db = EventHorizonDB.redshift.isActive
  2972.         if not (db) then return end
  2973.        
  2974.         Redshift.states = {}
  2975.         Redshift.Events = {
  2976.                 ["PLAYER_REGEN_DISABLED"] = true,
  2977.                 ["PLAYER_REGEN_ENABLED"] = true,
  2978.                 ["PLAYER_TARGET_CHANGED"] = true,
  2979.                 ["PLAYER_GAINS_VEHICLE_DATA"] = true,
  2980.                 ["PLAYER_LOSES_VEHICLE_DATA"] = true,
  2981.                 ["UNIT_ENTERED_VEHICLE"] = true,
  2982.                 ["UNIT_EXITED_VEHICLE"] = true,
  2983.                 ["UNIT_ENTERING_VEHICLE"] = true,
  2984.                 ["UNIT_EXITING_VEHICLE"] = true,
  2985.                 ["VEHICLE_PASSENGERS_CHANGED"] = true,
  2986.         }
  2987.        
  2988.         for k,v in pairs(ns.config.Redshift) do
  2989.                 if v then
  2990.                         Redshift.states[k] = true
  2991.                 end
  2992.         end
  2993.        
  2994.         if (EventHorizonDB.redshift.isActive == true) then Redshift:Check() end
  2995.         Redshift.isReady = true
  2996. end
  2997.  
  2998. Redshift.Enable = function (slash)
  2999.         if EventHorizonDB.redshift.isActive and not(Redshift.isReady) then
  3000.                 Redshift:Init()
  3001.                 Redshift:Check()
  3002.         elseif EventHorizonDB.redshift.isActive then
  3003.                 Redshift:Check()
  3004.         end
  3005.         if Redshift.frame then Redshift.frame:SetScript('OnEvent',EventHandler) end
  3006. end
  3007.  
  3008. Redshift.Disable = function (slash)
  3009.         vars.visibleFrame = true
  3010.         if Redshift.frame then Redshift.frame:SetScript('OnEvent',nil) end
  3011.         if ns.isActive == true then mainframe:Show() end
  3012. end
  3013.  
  3014. local Lines = {}
  3015. Lines.CreateLines = function ()
  3016.         if Lines.frame then return end
  3017.         local c = ns.config.Lines
  3018.         local db = EventHorizonDB.lines.isActive == true
  3019.         if not(c and db) then return
  3020.         elseif type(c) == 'number' then c = {c} -- Turn numbers into delicious tables.
  3021.         elseif type(c) ~= 'table' then return   -- Turn away everything else.
  3022.         end
  3023.        
  3024.         Lines.frame = CreateFrame('Frame',nil,UIParent)
  3025.         Lines.line = {}
  3026.        
  3027.         local multicolor
  3028.         local color = ns.config.LinesColor
  3029.         if color and type(color) == 'table' then
  3030.                 if type(color[1]) == 'table' then
  3031.                         multicolor = true       -- trying not to further complicate things
  3032.                         for i,v in ipairs(c) do
  3033.                                 if not(color[i]) then
  3034.                                         color[i] = color[i-1] -- if we have more lines than colors, we need moar colors
  3035.                                 end
  3036.                         end
  3037.                 end
  3038.         else
  3039.                 color = {1,1,1,0.5}
  3040.         end
  3041.        
  3042.         local now = -vars.past/(vars.future-vars.past)*vars.barwidth-0.5 + vars.barheight
  3043.         local pps = (vars.barwidth+vars.barheight-now)/vars.future
  3044.        
  3045.         for i = 1, #c do
  3046.                 local seconds = c[i]
  3047.                 local position = now+(pps*seconds)
  3048.                 Lines.line[i] = mainframe:CreateTexture(nil,"OVERLAY")
  3049.                 Lines.line[i]:SetPoint('TOPLEFT', mainframe, 'TOPLEFT', position, 0)
  3050.                 if multicolor then
  3051.                         Lines.line[i]:SetTexture(unpack(color[i]))
  3052.                 else
  3053.                         Lines.line[i]:SetTexture(unpack(color))
  3054.                 end
  3055.                 Lines.line[i]:SetWidth(vars.onepixelwide)
  3056.                 Lines.line[i]:SetPoint('BOTTOM', mainframe, 'BOTTOM')
  3057.         end
  3058.        
  3059.         Lines.Enable = function ()
  3060.                 for i = 1,#Lines.line do
  3061.                         Lines.line[i]:Show()
  3062.                 end
  3063.         end
  3064.        
  3065.         Lines.Disable = function ()
  3066.                 for i = 1,#Lines.line do
  3067.                         Lines.line[i]:Hide()
  3068.                 end
  3069.         end
  3070. end
  3071.  
  3072. Lines.Init = function ()
  3073.         Lines.CreateLines()
  3074.         Lines.isReady = true
  3075. end
  3076. --[[
  3077. local Pulse = {
  3078.         cache = {},                                     -- subframe storage
  3079.         frames = {},                            -- framerefs
  3080.         alwaysLoad = true,                      -- Flag EH to load the module even when db.isActive ~= true
  3081. }
  3082.  
  3083. Pulse.Enable = function ()
  3084.         local cv = ns.config.Pulse
  3085.         local sv = ns.db.pulse
  3086.         local int = ns.config.PulseIntensity
  3087.         local fps = ns.config.PulseFPS
  3088.         if not(fps) or (type(fps) ~= 'number' or fps == 0) then
  3089.                 fps = ns.defaultconfig.PulseFPS
  3090.         end
  3091.        
  3092.         if not Pulse.frame then
  3093.                 Pulse.frame = CreateFrame('Frame',nil,mainframe)
  3094.         end
  3095.        
  3096.         Pulse.duration = (cv and sv.isActive) and ((cv == true or type(cv) ~= 'number') and ns.defaultconfig.Pulse or type(cv) == 'number' and cv)
  3097.         Pulse.intensity = int and (type(int) == 'number' and int > 0 and int) or ns.defaultconfig.PulseIntensity
  3098.         Pulse.TTL = (1000/fps)/1000
  3099.        
  3100.         if Pulse.duration and not(Pulse.framesCreated) then
  3101.                 local ehf = EventHorizon.frames.frames
  3102.                 --      for k,v in pairs(ns.frames.frames) do print(k,v) end
  3103.                 for k,bar in pairs(ns.frames.frames) do -- Use frametable since we want actual bar refs. Don't use ipairs here (will need to fix in other places, likely), as it won't fully iterate.
  3104.                 --      local bar = ehf[i]
  3105.                         if bar and bar.cooldown then
  3106.                                 local temp = {
  3107.                                         spellframe = bar,
  3108.                                         ['SPELL_UPDATE_COOLDOWN'] = true,
  3109.                                 }
  3110.                                 table.insert(Pulse.frames,temp)
  3111.                         elseif bar and (bar.slotID or bar.internalcooldown) then        -- Check for slotID first, since it doesn't always use internalcooldown
  3112.                                 local temp = {
  3113.                                         spellframe = bar,
  3114.                                         ['UNIT_AURA'] = true,
  3115.                                 }
  3116.                                 table.insert(Pulse.frames,temp)
  3117.                         end
  3118.                 end
  3119.                 Pulse.framesCreated = true
  3120.         end
  3121.        
  3122.         Pulse.frame:SetScript('OnEvent',Pulse.OnEvent)
  3123.         Pulse.frame:RegisterEvent('UNIT_AURA')
  3124.         Pulse.frame:RegisterEvent('SPELL_UPDATE_COOLDOWN')
  3125. end
  3126.  
  3127. Pulse.Disable = function ()
  3128.         Pulse.duration = nil
  3129. end
  3130.  
  3131. Pulse.OnFlash = function (self,elapsed)
  3132.         self.TSLU = self.TSLU + elapsed
  3133.         while self.TSLU >= Pulse.TTL do
  3134.                 self.current = self.current and (self.current - self.TSLU) or Pulse.duration
  3135.                 self.alpha = self.current >= 0 and self.current/(Pulse.duration*Pulse.intensity) or 0
  3136.                 self.tex:SetAlpha(self.alpha)
  3137.                 self.TSLU = self.TSLU - Pulse.TTL
  3138.                 if self.current <= 0 then
  3139.                         self:SetScript('OnUpdate',nil)
  3140.                         self.current = nil
  3141.                         self.alpha = nil
  3142.                         print('clearing onupdates')
  3143.                 end
  3144.         end
  3145. end
  3146.  
  3147. Pulse.OnAura = function (self,elapsed)
  3148.         self.remaining = self.remaining - elapsed
  3149.        
  3150.         if self.current and self.alpha then             -- finish off any remaining pulse
  3151.                 self.TSLU = self.TSLU + elapsed
  3152.                 while self.TSLU >= Pulse.TTL do
  3153.                         self.current = self.current and (self.current - self.TSLU) or Pulse.duration
  3154.                         self.alpha = self.current >= 0 and self.current/(Pulse.duration*Pulse.intensity) or 0
  3155.                         self.tex:SetAlpha(self.alpha)
  3156.                         self.TSLU = self.TSLU - Pulse.TTL
  3157.                         if self.current <= 0 then
  3158.                                 self.current = nil
  3159.                                 self.alpha = nil
  3160.                         end
  3161.                 end
  3162.         end
  3163.        
  3164.         if self.remaining <= 0 and Pulse.duration then
  3165.                 self.activeCD = nil
  3166.                 self.remaining = nil
  3167.                 self.TSLU = 0
  3168.                 self:SetAllPoints(self.parent)
  3169.                 self.tex:SetAllPoints(self)
  3170.                 print('setting Pulse.OnFlash')
  3171.                 self:SetScript('OnUpdate',Pulse.OnFlash)
  3172.         elseif self.remaining <= 0 then
  3173.                 self.activeCD = nil
  3174.                 self.remaining = nil
  3175.                 self:SetScript('OnUpdate',nil)
  3176.         end
  3177. end
  3178.  
  3179. Pulse.OnEvent = function (self,event,unit)
  3180.         if event == 'UNIT_AURA' and unit ~= 'player' then return end
  3181.         for i = 1,#Pulse.frames do
  3182.                 local frame = Pulse.frames[i]
  3183.                 local f = Pulse.frames[i].spellframe
  3184.                 if f then
  3185.                         local icd = f.internalcooldown
  3186.                         local cdTime
  3187.                         local apply
  3188.                         local now = GetTime()
  3189.                        
  3190.                         if icd and icd == true then
  3191.                                 icd = nil
  3192.                         end
  3193.                        
  3194.                         if icd and event == 'UNIT_AURA' then
  3195.                                 local _,_,_,_,_,_,expirationTime,active = f.AuraFunction('player',f.auraname)
  3196.                                 local activeCD = frame.activeCD
  3197.                                 if active and expirationTime and (frame.flash and not(frame.flash.activeCD) or not(frame.flash)) then
  3198.                                         apply = true
  3199.                                         frame.activeCD = true
  3200.                                         cdTime = f.internalcooldown
  3201.                                         local start = expirationTime
  3202.                                         local stop = now + f.internalcooldown
  3203.                                         if start > stop then
  3204.                                                 start = now
  3205.                                         end
  3206.                                         f:AddSegment('cooldown', 'cooldown', start, stop)
  3207.                                 end
  3208.                         elseif event == 'SPELL_UPDATE_COOLDOWN' and not(icd) then
  3209.                                 local start, duration, enabled = f.CooldownFunction(f.cooldownID or f.spellname)
  3210.                                 local onCooldown = enabled == 1 and start ~= duration and start > 0 and duration > 1.5  -- Check duration against GCD to ensure we're not pulsing every time the char does something
  3211.                                 cdTime = duration
  3212.                                
  3213.                                 if onCooldown and not(frame.activeCD) then
  3214.                                         apply = true
  3215.                                         print(onCooldown,frame.activeCD,start,duration,enabled)
  3216.                                 elseif (frame.flash and frame.flash.remaining) and not(onCooldown) then -- cooldown expired before pulse went off
  3217.                                         frame.flash.remaining = 0       -- flash at next opportunity
  3218.                                         --print'flash'
  3219.                                 elseif (frame.flash and frame.flash.remaining) and (frame.flash.remaining > (start+duration-now+1)) then -- HOPEFULLY this will catch elemental shaman 2t10.
  3220.                                         frame.flash.remaining = start+duration-now
  3221.                                 end
  3222.                                 frame.activeCD = onCooldown
  3223.                         end
  3224.                        
  3225.                         if apply and cdTime and Pulse.duration then     -- check for fresh application, make sure a cooldown time exists, and don't do anything if pulses are disabled
  3226.                                 if not(frame.flash) then
  3227.                                         frame.flash = CreateFrame('Frame',nil,f)
  3228.                                         frame.flash.tex = frame.flash:CreateTexture(nil,'BACKGROUND')
  3229.                                         frame.flash.tex:SetTexture(vars.texturedbars and vars.bartexture or unpack{1,1,1,1})
  3230.                                         frame.flash.tex:SetAlpha(0)
  3231.                                         frame.flash.TSLU = 0
  3232.                                 end
  3233.                                 frame.flash.parent = f
  3234.                                 frame.flash.TSLU = (frame.flash.current and frame.flash.alpha) and frame.flash.TSLU or 0
  3235.                                 frame.flash.remaining = cdTime
  3236.                                 frame.flash.activeCD = true
  3237.                                 frame.flash:SetScript('OnUpdate',Pulse.OnAura)
  3238.                         end
  3239.                 end
  3240.         end
  3241. end
  3242.  
  3243. Pulse.Init = function ()
  3244.         if Pulse.frame then return end
  3245.         Pulse:Enable()
  3246.         Pulse.isReady = true
  3247. end
  3248. ]]--
  3249. ns:RegisterModule('lines',Lines)
  3250. ns:RegisterModule('redshift',Redshift)
  3251. --ns:RegisterModule('pulse',Pulse)