local addon, ns = ...
Hekili = LibStub("AceAddon-3.0"):NewAddon( "Hekili", "AceConsole-3.0", "AceSerializer-3.0" )
Hekili.Version = C_AddOns.GetAddOnMetadata( "Hekili", "Version" )
Hekili.Flavor = C_AddOns.GetAddOnMetadata( "Hekili", "X-Flavor" ) or "Retail"
local format = string.format
local insert, concat = table.insert, table.concat
local GetBuffDataByIndex, GetDebuffDataByIndex = C_UnitAuras.GetBuffDataByIndex, C_UnitAuras.GetDebuffDataByIndex
local UnpackAuraData = AuraUtil.UnpackAuraData
local buildStr, _, _, buildNum = GetBuildInfo()
Hekili.CurrentBuild = buildNum
if Hekili.Version == ( "@" .. "project-version" .. "@" ) then
Hekili.Version = format( "Dev-%s (%s)", buildStr, date( "%Y%m%d" ) )
Hekili.IsDev = true
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 buildNum >= 100000
end
Hekili.BuiltFor = 110000
Hekili.GameBuild = buildStr
ns.PTR = buildNum > 110000
ns.Patrons = "|cFFFFD100目前的状态|r\n\n"
.. "目前已经支持所有的专精,但治疗专精的优先级是试验性的,只可用于发呆时打DPS。\n\n"
.. "如果你发现奇怪的问题或建议,请前往下方的|cFFFFD100问题报告|r链接提交必要的信息,以便你的问题能够尽快修正。\n\n"
.. "请不要提交默认优先级的问题(来自于SimulationCraft),它们将在发布后同步更新。谢谢!"
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 = {}
}
ns.auras = {
target = {
buff = {},
debuff = {}
},
player = {
buff = {},
debuff = {}
}
}
Hekili.Class = {
specs = {},
num = 0,
file = "NONE",
initialized = false,
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 )
text = format( "%" .. ( indent > 0 and ( 4 * indent ) or "" ) .. "s", "" ) .. text
if select( start, ... ) ~= nil then
active_debug.log[ active_debug.index ] = format( text, select( start, ... ) )
else
active_debug.log[ active_debug.index ] = text
end
active_debug.index = active_debug.index + 1
end
local snapshots = ns.snapshots
local hasScreenshotted = false
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
local prevString = "\nprevious_spells:"
local i, j = ( #state.predictions + 1 ), 1
local spell = state.prev[i].spell or "no_action"
if spell == "no_action" then
prevString = prevString .. " no history available"
else
local numHistory = #state.prev.history
while i <= numHistory and spell ~= "no_action" do
prevString = format( "%s\n %d - %s", prevString, j, spell )
i, j = i + 1, j + 1
spell = state.prev[i].spell or "no_action"
end
end
prevString = prevString .. "\n\n"
insert( v.log, 1, prevString )
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 = UnpackAuraData( GetBuffDataByIndex( "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 0 )
end
insert( v.log, 1, auraString )
snapped = true
end
end
return snapped
end
function Hekili:ExecuteRecommendedAction()
local recs = Hekili.DisplayPool[ Hekili.State.display ].Recommendations
for i, rec in ipairs(recs) do
if rec.actionName then
local action = rec.actionName
local binding = GetBindingKey("ACTIONBUTTON" .. rec.slot)
if binding then
self:Debug("Recommended Action: %s, Keybind: %s", action, binding)
RunMacroText("/click " .. binding)
return
end
end
end
end
function Hekili:OnRecommendation()
self:ExecuteRecommendedAction()
end