-- Hekili.lua -- April 2014 local addon, ns = ... Hekili = LibStub("AceAddon-3.0"):NewAddon( "Hekili", "AceConsole-3.0", "AceSerializer-3.0" ) Hekili.Version = GetAddOnMetadata( "Hekili", "Version" ) Hekili.Flavor = GetAddOnMetadata( "Hekili", "X-Flavor" ) or "Retail" local format = string.format local insert, concat = table.insert, table.concat if Hekili.Version == ( "@" .. "project-version" .. "@" ) then Hekili.Version = format( "Dev-%s (%s)", GetBuildInfo(), date( "%Y%m%d" ) ) end Hekili.AllowSimCImports = true Hekili.IsRetail = function() return Hekili.Flavor == "Retail" end Hekili.IsWrath = function() return Hekili.Flavor == "Wrath" end Hekili.IsClassic = function() return Hekili.IsWrath() end Hekili.IsDragonflight = function() return select( 4, GetBuildInfo() ) >= 100000 end ns.PTR = false ns.Patrons = "Abom, Abra, Abuna, Aern, Aggronaught, akh270, Alasha, alcaras, Amera, ApexPlatypus, aphoenix, Archxlock, Aristocles, aro725, Artoo, Ash, av8ordoc, Battle Hermit VIA, Belatar, Borelia, Brangeddon, Bsirk/Kris, Cele, Chimmi, Coan, Cortland, Daz, DB, Der Baron, Dez, Drako, Enemy, Eryx, fuon, Garumako, Graemec, Grayscale, guhbjs, Hambrick, Hexel, Himea, Hollaputt, Hungrypilot, Ifor, Ingrathis, intheyear, Jacii, jawj, Jenkz, Katurn, Kingreboot, Kittykiller, Lagertha, Leorus, Loraniden, Lord Corn, Lovien, Manni, Mirando, mr. jing0, Mr_Hunter, MrBean73, mrminus, Muffin, Mumrikk, Nelix, neurolawl, Nighteyez, nomiss, nqrse, Orcodamus, Parameshvar, Rage, Ramen, Ramirez (Jon), Rebdull, Ridikulus0510, rockschtar, Roodie, Rusah, Samuraiwillz501, sarrge, Sarthol, Scerick, Sebstar, Seniroth, seriallos, Shakeykev, Shuck, Skeletor, Slem, Spaten, Spy, Srata, Stevi, Strozzy, Tekfire, Tevka, Theda99, Thordros, Tic[à]sentence, Tobi, todd, Torsti, tsukari, Tyazrael, Ulti.DTY, Val (Valdrath), Vaxum, Vsmit, Wargus (Shagus), Weedwalker, WhoaIsJustin, Wonder, zab, Zarggg, and zarrin-zuljin" do local cpuProfileDB = {} function Hekili:ProfileCPU( name, func ) cpuProfileDB[ name ] = func end ns.cpuProfile = cpuProfileDB local frameProfileDB = {} function Hekili:ProfileFrame( name, f ) frameProfileDB[ name ] = f end ns.frameProfile = frameProfileDB end ns.lib = { Format = {} } -- 04072017: Let's go ahead and cache aura information to reduce overhead. ns.auras = { target = { buff = {}, debuff = {} }, player = { buff = {}, debuff = {} } } Hekili.Class = { specs = {}, num = 0, file = "NONE", resources = {}, resourceAuras = {}, talents = {}, pvptalents = {}, auras = {}, auraList = {}, powers = {}, gear = {}, setBonuses = {}, knownAuraAttributes = {}, stateExprs = {}, stateFuncs = {}, stateTables = {}, abilities = {}, abilityByName = {}, abilityList = {}, itemList = {}, itemMap = {}, itemPack = { lists = { items = {} } }, packs = {}, pets = {}, totems = {}, potions = {}, potionList = {}, hooks = {}, range = 8, settings = {}, stances = {}, toggles = {}, variables = {}, } Hekili.Scripts = { DB = {}, Channels = {}, PackInfo = {}, } Hekili.State = {} ns.hotkeys = {} ns.keys = {} ns.queue = {} ns.targets = {} ns.TTD = {} ns.UI = { Displays = {}, Buttons = {} } ns.debug = {} ns.snapshots = {} function Hekili:Query( ... ) local output = ns for i = 1, select( '#', ... ) do output = output[ select( i, ... ) ] end return output end function Hekili:Run( ... ) local n = select( "#", ... ) local fn = select( n, ... ) local func = ns for i = 1, fn - 1 do func = func[ select( i, ... ) ] end return func( select( fn, ... ) ) end local debug = ns.debug local active_debug local current_display local lastIndent = 0 function Hekili:SetupDebug( display ) if not self.ActiveDebug then return end if not display then return end current_display = display debug[ current_display ] = debug[ current_display ] or { log = {}, index = 1 } active_debug = debug[ current_display ] active_debug.index = 1 lastIndent = 0 local pack = self.State.system.packName if not pack then return end self:Debug( "New Recommendations for [ %s ] requested at %s ( %.2f ); using %s( %s ) priority.", display, date( "%H:%M:%S"), GetTime(), self.DB.profile.packs[ pack ].builtIn and "built-in " or "", pack ) end function Hekili:Debug( ... ) if not self.ActiveDebug then return end if not active_debug then return end local indent, text = ... local start if type( indent ) ~= "number" then indent = lastIndent text = ... start = 2 else lastIndent = indent start = 3 end local prepend = format( indent > 0 and ( "%" .. ( indent * 4 ) .. "s" ) or "%s", "" ) text = text:gsub("\n", "\n" .. prepend ) active_debug.log[ active_debug.index ] = format( "%" .. ( indent > 0 and ( 4 * indent ) or "" ) .. "s" .. text, "", select( start, ... ) ) active_debug.index = active_debug.index + 1 end local snapshots = ns.snapshots function Hekili:SaveDebugSnapshot( dispName ) local snapped = false local formatKey = ns.formatKey local state = Hekili.State for k, v in pairs( debug ) do if not dispName or dispName == k then for i = #v.log, v.index, -1 do v.log[ i ] = nil end -- Store aura data. local auraString = "\nplayer_buffs:" local now = GetTime() local class = Hekili.Class for i = 1, 40 do local name, _, count, debuffType, duration, expirationTime, source, _, _, spellId, canApplyAura, isBossDebuff, castByPlayer = UnitBuff( "player", i ) if not name then break end local aura = class.auras[ spellId ] local key = aura and aura.key if key and not state.auras.player.buff[ key ] then key = key .. " [MISSING]" end auraString = format( "%s\n %6d - %-40s - %3d - %-6.2f", auraString, spellId, key or ( "*" .. formatKey( name ) ), count > 0 and count or 1, expirationTime > 0 and ( expirationTime - now ) or 3600 ) end auraString = auraString .. "\n\nplayer_debuffs:" for i = 1, 40 do local name, _, count, debuffType, duration, expirationTime, source, _, _, spellId, canApplyAura, isBossDebuff, castByPlayer = UnitDebuff( "player", i ) if not name then break end local aura = class.auras[ spellId ] local key = aura and aura.key if key and not state.auras.player.debuff[ key ] then key = key .. " [MISSING]" end auraString = format( "%s\n %6d - %-40s - %3d - %-6.2f", auraString, spellId, key or ( "*" .. formatKey( name ) ), count > 0 and count or 1, expirationTime > 0 and ( expirationTime - now ) or 3600 ) end if not UnitExists( "target" ) then auraString = auraString .. "\n\ntarget_auras: target does not exist" else auraString = auraString .. "\n\ntarget_buffs:" for i = 1, 40 do local name, _, count, debuffType, duration, expirationTime, source, _, _, spellId, canApplyAura, isBossDebuff, castByPlayer = UnitBuff( "target", i ) if not name then break end local aura = class.auras[ spellId ] local key = aura and aura.key if key and not state.auras.target.buff[ key ] then key = key .. " [MISSING]" end auraString = format( "%s\n %6d - %-40s - %3d - %-6.2f", auraString, spellId, key or ( "*" .. formatKey( name ) ), count > 0 and count or 1, expirationTime > 0 and ( expirationTime - now ) or 3600 ) end auraString = auraString .. "\n\ntarget_debuffs:" for i = 1, 40 do local name, _, count, debuffType, duration, expirationTime, source, _, _, spellId, canApplyAura, isBossDebuff, castByPlayer = UnitDebuff( "target", i, "PLAYER" ) if not name then break end local aura = class.auras[ spellId ] local key = aura and aura.key if key and not state.auras.target.debuff[ key ] then key = key .. " [MISSING]" end auraString = format( "%s\n %6d - %-40s - %3d - %-6.2f", auraString, spellId, key or ( "*" .. formatKey( name ) ), count > 0 and count or 1, expirationTime > 0 and ( expirationTime - now ) or 3600 ) end end auraString = auraString .. "\n\n" insert( v.log, 1, auraString ) if Hekili.TargetDebug and Hekili.TargetDebug:len() > 0 then insert( v.log, 1, "targets:\n" .. Hekili.TargetDebug ) end insert( v.log, 1, self:GenerateProfile() ) local custom = "" local pack = self.DB.profile.packs[ state.system.packName ] if not pack.builtIn then custom = format( " |cFFFFA700(Custom: %s[%d])|r", state.spec.name, state.spec.id ) end local overview = format( "%s%s; %s|r", state.system.packName, custom, dispName ) local recs = Hekili.DisplayPool[ dispName ].Recommendations for i, rec in ipairs( recs ) do if not rec.actionName then if i == 1 then overview = format( "%s - |cFF666666N/A|r", overview ) end break end overview = format( "%s%s%s|cFFFFD100(%0.2f)|r", overview, ( i == 1 and " - " or ", " ), class.abilities[ rec.actionName ].name, rec.time ) end insert( v.log, 1, overview ) local snap = { header = "|cFFFFD100[" .. date( "%H:%M:%S" ) .. "]|r " .. overview, log = concat( v.log, "\n" ), data = ns.tableCopy( v.log ), recs = {} } insert( snapshots, snap ) snapped = true end end if snapped then if Hekili.DB.profile.screenshot then Screenshot() end return true end return false end Hekili.Snapshots = ns.snapshots ns.Tooltip = CreateFrame( "GameTooltip", "HekiliTooltip", UIParent, "GameTooltipTemplate" ) Hekili:ProfileFrame( "HekiliTooltip", ns.Tooltip )