You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5673 lines
139 KiB

-- Classes.lua
-- July 2014
local addon, ns = ...
local Hekili = _G[ addon ]
local class = Hekili.Class
local state = Hekili.State
local CommitKey = ns.commitKey
local FindUnitBuffByID, FindUnitDebuffByID = ns.FindUnitBuffByID, ns.FindUnitDebuffByID
local GetItemInfo = ns.CachedGetItemInfo
local GetResourceInfo, GetResourceKey = ns.GetResourceInfo, ns.GetResourceKey
local RegisterEvent = ns.RegisterEvent
local RegisterUnitEvent = ns.RegisterUnitEvent
local formatKey = ns.formatKey
local getSpecializationKey = ns.getSpecializationKey
local insert, wipe = table.insert, table.wipe
local mt_resource = ns.metatables.mt_resource
local GetSpellDescription, GetSpellTexture = _G.GetSpellDescription, _G.GetSpellTexture
local GetSpecialization, GetSpecializationInfo = _G.GetSpecialization, _G.GetSpecializationInfo
local Casting = _G.SPELL_CASTING or "Casting"
local specTemplate = {
enabled = false,
potion = "prolonged_power",
aoe = 2,
cycle = false,
cycle_min = 6,
gcdSync = true,
enhancedRecheck = false,
buffPadding = 0,
debuffPadding = 0,
nameplates = true,
nameplateRange = 8,
petbased = false,
damage = true,
damageExpiration = 8,
damageDots = false,
damageRange = 0,
damagePets = false,
throttleRefresh = false,
maxRefresh = 10,
throttleTime = false,
maxTime = 33,
-- Toggles
custom1Name = "Custom 1",
custom2Name = "Custom 2",
}
ns.specTemplate = specTemplate -- for options.
local function Aura_DetectSharedAura( t, type )
if not t then return end
local finder = type == "debuff" and FindUnitDebuffByID or FindUnitBuffByID
local aura = class.auras[ t.key ]
local name, _, count, _, duration, expirationTime, caster = finder( aura.shared, aura.id )
if name then
t.count = count > 0 and count or 1
if expirationTime > 0 then
t.applied = expirationTime - duration
t.expires = expirationTime
else
t.applied = state.query_time
t.expires = state.query_time + t.duration
end
t.caster = caster
return
end
t.count = 0
t.applied = 0
t.expires = 0
t.caster = "nobody"
end
local protectedFunctions = {
-- Channels.
start = true,
tick = true,
finish = true,
-- Casts
handler = true, -- Cast finish.
impact = true, -- Projectile impact.
}
local HekiliSpecMixin = {
RegisterResource = function( self, resourceID, regen, model )
local resource = GetResourceKey( resourceID )
if not resource then
Hekili:Error( "Unable to identify resource with PowerType " .. resourceID .. "." )
return
end
local r = self.resources[ resource ] or {}
r.resource = resource
r.type = resourceID
r.state = model or setmetatable( {
resource = resource,
type = resourceID,
forecast = {},
fcount = 0,
times = {},
values = {},
active_regen = 0,
inactive_regen = 0,
last_tick = 0,
add = function( amt, overcap )
-- Bypasses forecast, useful in hooks.
if overcap then r.state.amount = r.state.amount + amt
else r.state.amount = max( 0, min( r.state.amount + amt, r.state.max ) ) end
end,
timeTo = function( x )
return state:TimeToResource( r.state, x )
end,
}, mt_resource )
r.state.regenModel = regen
if model and not model.timeTo then
model.timeTo = function( x )
return state:TimeToResource( r.state, x )
end
end
if r.state.regenModel then
for _, v in pairs( r.state.regenModel ) do
v.resource = v.resource or resource
self.resourceAuras[ v.resource ] = self.resourceAuras[ v.resource ] or {}
if v.aura then
self.resourceAuras[ v.resource ][ v.aura ] = true
end
if v.channel then
self.resourceAuras[ v.resource ].casting = true
end
end
end
self.primaryResource = self.primaryResource or resource
self.resources[ resource ] = r
CommitKey( resource )
end,
RegisterTalents = function( self, talents )
for talent, id in pairs( talents ) do
self.talents[ talent ] = id
CommitKey( talent )
end
end,
RegisterPvpTalents = function( self, pvp )
for talent, spell in pairs( pvp ) do
self.pvptalents[ talent ] = spell
CommitKey( talent )
end
end,
RegisterAura = function( self, aura, data )
CommitKey( aura )
local a = setmetatable( {
funcs = {}
}, {
__index = function( t, k )
if t.funcs[ k ] then return t.funcs[ k ]() end
return
end
} )
a.key = aura
if not data.id then
self.pseudoAuras = self.pseudoAuras + 1
data.id = ( -1000 * self.id ) - self.pseudoAuras
end
-- default values.
data.duration = data.duration or 30
data.max_stack = data.max_stack or 1
-- This is a shared buff that can come from anyone, give it a special generator.
if data.shared then
a.generate = Aura_DetectSharedAura
end
for element, value in pairs( data ) do
if type( value ) == 'function' then
setfenv( value, state )
if element ~= 'generate' then a.funcs[ element ] = value
else a[ element ] = value end
else
a[ element ] = value
end
class.knownAuraAttributes[ element ] = true
end
self.auras[ aura ] = a
if a.id then
if a.id > 0 then
Hekili:ContinueOnSpellLoad( a.id, function( success )
a.name = GetSpellInfo( a.id )
if not success or not a.name then
for k, v in pairs( class.auraList ) do
if v == a then class.auraList[ k ] = nil end
end
for k, v in pairs( self.auras ) do
if v == a then self.auras[ k ] = nil end
end
Hekili.InvalidSpellIDs = Hekili.InvalidSpellIDs or {}
insert( Hekili.InvalidSpellIDs, a.id )
return
end
a.desc = GetSpellDescription( a.id )
local texture = a.texture or GetSpellTexture( a.id )
class.auraList[ a.key ] = "|T" .. texture .. ":0|t " .. a.name
self.auras[ a.name ] = a
if GetSpecializationInfo( GetSpecialization() or 0 ) == self.id then
-- Copy to class table as well.
class.auras[ a.name ] = a
end
if self.pendingItemSpells[ a.name ] then
local items = self.pendingItemSpells[ a.name ]
if type( items ) == 'table' then
for i, item in ipairs( items ) do
local ability = self.abilities[ item ]
ability.itemSpellKey = a.key .. "_" .. ability.itemSpellID
self.abilities[ ability.itemSpellKey ] = a
class.abilities[ ability.itemSpellKey ] = a
end
else
local ability = self.abilities[ items ]
ability.itemSpellKey = a.key .. "_" .. ability.itemSpellID
self.abilities[ ability.itemSpellKey ] = a
class.abilities[ ability.itemSpellKey ] = a
end
self.pendingItemSpells[ a.name ] = nil
self.itemPended = nil
end
end )
end
self.auras[ a.id ] = a
end
if data.meta then
for k, v in pairs( data.meta ) do
if type( v ) == 'function' then data.meta[ k ] = setfenv( v, state ) end
class.knownAuraAttributes[ k ] = true
end
end
if type( data.copy ) == 'string' then
self.auras[ data.copy ] = a
elseif type( data.copy ) == 'table' then
for _, key in ipairs( data.copy ) do
self.auras[ key ] = a
end
end
end,
RegisterAuras = function( self, auras )
for aura, data in pairs( auras ) do
self:RegisterAura( aura, data )
end
end,
RegisterPower = function( self, power, id, aura )
self.powers[ power ] = id
CommitKey( power )
if aura and type( aura ) == "table" then
self:RegisterAura( power, aura )
end
end,
RegisterPowers = function( self, powers )
for k, v in pairs( powers ) do
self.powers[ k ] = v.id
self.powers[ v.id ] = k
for token, ids in pairs( v.triggers ) do
if not self.auras[ token ] then
self:RegisterAura( token, {
id = v.id,
copy = ids
} )
end
end
end
end,
RegisterStateExpr = function( self, key, func )
setfenv( func, state )
self.stateExprs[ key ] = func
class.stateExprs[ key ] = func
end,
RegisterStateFunction = function( self, key, func )
setfenv( func, state )
self.stateFuncs[ key ] = func
class.stateFuncs[ key ] = func
end,
RegisterStateTable = function( self, key, data )
for _, f in pairs( data ) do
if type( f ) == 'function' then
setfenv( f, state )
end
end
local meta = getmetatable( data )
if meta and meta.__index then
setfenv( meta.__index, state )
end
self.stateTables[ key ] = data
class.stateTables[ key ] = data
end,
RegisterGear = function( self, key, ... )
local n = select( "#", ... )
local gear = self.gear[ key ] or {}
for i = 1, n do
local item = select( i, ... )
table.insert( gear, item )
gear[ item ] = true
end
self.gear[ key ] = gear
end,
RegisterPotion = function( self, potion, data )
self.potions[ potion ] = data
data.key = potion
if data.copy then
if type( data.copy ) == "table" then
for _, key in ipairs( data.copy ) do
self.potions[ key ] = data
end
else
self.potions[ data.copy ] = data
end
end
Hekili:ContinueOnItemLoad( data.item, function ()
local name, link = GetItemInfo( data.item )
data.name = name
data.link = link
class.potionList[ potion ] = link
end )
end,
RegisterPotions = function( self, potions )
for k, v in pairs( potions ) do
self:RegisterPotion( k, v )
end
end,
SetPotion = function( self, potion )
-- if not class.potions[ potion ] then return end
self.potion = potion
end,
RegisterRecheck = function( self, func )
self.recheck = func
end,
RegisterHook = function( self, hook, func )
self.hooks[ hook ] = self.hooks[ hook ] or {}
insert( self.hooks[ hook ], setfenv( func, state ) )
end,
RegisterAbility = function( self, ability, data )
CommitKey( ability )
local a = setmetatable( {
funcs = {},
}, {
__index = function( t, k )
if t.funcs[ k ] then return t.funcs[ k ]() end
if k == "lastCast" then return state.history.casts[ t.key ] or t.realCast end
if k == "lastUnit" then return state.history.units[ t.key ] or t.realUnit end
return
end,
} )
a.key = ability
if not data.id then
if data.item then
self.itemAbilities = self.itemAbilities + 1
data.id = -100 - self.itemAbilities
else
self.pseudoAbilities = self.pseudoAbilities + 1
data.id = -1000 * self.id - self.pseudoAbilities
end
end
local item = data.item
if item and type( item ) == 'function' then
setfenv( item, state )
item = item()
end
if item then
local name, link, _, _, _, _, _, _, _, texture = GetItemInfo( item )
a.name = name or ability
a.link = link or ability
class.itemMap[ item ] = ability
Hekili:ContinueOnItemLoad( item, function( success )
if not success then
-- Assume the item is not presently in-game.
for key, entry in pairs( class.abilities ) do
if a == entry then
class.abilities[ key ] = nil
class.abilityList[ key ] = nil
class.abilityByName[ key ] = nil
class.itemList[ key ] = nil
self.abilities[ key ] = nil
end
end
return
end
local name, link, _, _, _, _, _, _, slot, texture = GetItemInfo( item )
if name then
a.name = a.name or name
a.link = a.link or link
a.texture = a.texture or texture
if a.suffix then
a.actualName = name
a.name = a.name .. " " .. a.suffix
end
self.abilities[ ability ] = self.abilities[ ability ] or a
self.abilities[ a.name ] = self.abilities[ a.name ] or a
self.abilities[ a.link ] = self.abilities[ a.link ] or a
self.abilities[ data.id ] = self.abilities[ a.link ] or a
a.itemLoaded = GetTime()
if a.item and a.item ~= 158075 then
a.itemSpellName, a.itemSpellID = GetItemSpell( a.item )
if a.itemSpellID then
a.itemSpellKey = a.key .. "_" .. a.itemSpellID
self.abilities[ a.itemSpellKey ] = a
class.abilities[ a.itemSpellKey ] = a
end
if a.itemSpellName then
local itemAura = self.auras[ a.itemSpellName ]
if itemAura then
a.itemSpellKey = itemAura.key .. "_" .. a.itemSpellID
self.abilities[ a.itemSpellKey ] = a
class.abilities[ a.itemSpellKey ] = a
else
if self.pendingItemSpells[ a.itemSpellName ] then
if type( self.pendingItemSpells[ a.itemSpellName ] ) == 'table' then
table.insert( self.pendingItemSpells[ a.itemSpellName ], ability )
else
local first = self.pendingItemSpells[ a.itemSpellName ]
self.pendingItemSpells[ a.itemSpellName ] = {
first,
ability
}
end
else
self.pendingItemSpells[ a.itemSpellName ] = ability
a.itemPended = GetTime()
end
end
end
end
if not a.unlisted then
class.abilityList[ ability ] = "|T" .. ( a.texture or texture ) .. ":0|t " .. link
class.itemList[ item ] = "|T" .. a.texture .. ":0|t " .. link
class.abilityByName[ a.name ] = a
end
if data.copy then
if type( data.copy ) == 'string' or type( data.copy ) == 'number' then
self.abilities[ data.copy ] = a
elseif type( data.copy ) == 'table' then
for _, key in ipairs( data.copy ) do
self.abilities[ key ] = a
end
end
end
class.abilities[ ability ] = a
class.abilities[ a.name ] = a
class.abilities[ a.link ] = a
class.abilities[ a.id ] = a
if not a.key then Hekili:Error( "Wanted to EmbedItemOption but no key for " .. ( a.id or "UNKNOWN" ) .. "." )
else Hekili:EmbedItemOption( nil, a.key ) end
return true
end
return false
end )
end
if data.meta then
for k, v in pairs( data.meta ) do
if type( v ) == 'function' then data.meta[ k ] = setfenv( v, state ) end
end
end
-- default values.
if not data.cooldown then data.cooldown = 0 end
if not data.recharge then data.recharge = data.cooldown end
if not data.charges then data.charges = 1 end
if data.hasteCD then
if type( data.cooldown ) == "number" and data.cooldown > 0 then data.cooldown = loadstring( "return " .. data.cooldown .. " * haste" ) end
if type( data.recharge ) == "number" and data.recharge > 0 then data.recharge = loadstring( "return " .. data.recharge .. " * haste" ) end
end
if not data.fixedCast and type( data.cast ) == "number" then
data.cast = loadstring( "return " .. data.cast .. " * haste" )
end
if data.toggle == "interrupts" and data.gcd == "off" and data.readyTime == state.timeToInterrupt and data.interrupt == nil then
data.interrupt = true
end
for key, value in pairs( data ) do
if type( value ) == 'function' then
setfenv( value, state )
if not protectedFunctions[ key ] then a.funcs[ key ] = value
else a[ key ] = value end
data[ key ] = nil
else
a[ key ] = value
end
end
if ( a.velocity or a.flightTime ) and a.impact then
a.isProjectile = true
end
a.realCast = 0
if a.id and a.id > 0 then
Hekili:ContinueOnSpellLoad( a.id, function( success )
if not success then
for k, v in pairs( class.abilityList ) do
if v == a then class.abilityList[ k ] = nil end
end
Hekili.InvalidSpellIDs = Hekili.InvalidSpellIDs or {}
table.insert( Hekili.InvalidSpellIDs, a.id )
return
end
a.name = GetSpellInfo( a.id )
if not a.name then Hekili:Error( "Name info not available for " .. a.id .. "." ); return false end
a.desc = GetSpellDescription( a.id ) -- was returning raw tooltip data.
if a.suffix then
a.actualName = a.name
a.name = a.name .. " " .. a.suffix
end
local texture = a.texture or GetSpellTexture( a.id )
self.abilities[ a.name ] = self.abilities[ a.name ] or a
class.abilities[ a.name ] = class.abilities[ a.name ] or a
if not a.unlisted then
class.abilityList[ ability ] = a.listName or ( "|T" .. texture .. ":0|t " .. a.name )
class.abilityByName[ a.name ] = class.abilities[ a.name ] or a
end
Hekili:EmbedAbilityOption( nil, a.key )
end )
end
if a.rangeSpell and type( a.rangeSpell ) == "number" then
Hekili:ContinueOnSpellLoad( a.rangeSpell, function( success )
if success then
a.rangeSpell = GetSpellInfo( a.rangeSpell )
else
a.rangeSpell = nil
end
end )
end
self.abilities[ ability ] = a
self.abilities[ a.id ] = a
if not a.unlisted then class.abilityList[ ability ] = class.abilityList[ ability ] or a.listName or a.name end
if data.copy then
if type( data.copy ) == 'string' or type( data.copy ) == 'number' then
self.abilities[ data.copy ] = a
elseif type( data.copy ) == 'table' then
for _, key in ipairs( data.copy ) do
self.abilities[ key ] = a
end
end
end
if data.items then
for _, itemID in ipairs( data.items ) do
class.itemMap[ itemID ] = ability
end
end
if a.castableWhileCasting or a.funcs.castableWhileCasting then
self.canCastWhileCasting = true
self.castableWhileCasting[ a.key ] = true
end
if a.auras then
self:RegisterAuras( a.auras )
end
end,
RegisterAbilities = function( self, abilities )
for ability, data in pairs( abilities ) do
self:RegisterAbility( ability, data )
end
end,
RegisterPack = function( self, name, version, import )
self.packs[ name ] = {
version = tonumber( version ),
import = import:gsub("([^|])|([^|])", "%1||%2")
}
end,
RegisterOptions = function( self, options )
self.options = options
for k, v in pairs( specTemplate ) do
if options[ k ] == nil then options[ k ] = v end
end
end,
RegisterEvent = function( self, event, func )
RegisterEvent( event, function( ... )
if state.spec.id == self.id then func( ... ) end
end )
end,
RegisterUnitEvent = function( self, event, unit1, unit2, func )
RegisterUnitEvent( event, unit1, unit2, function( ... )
if state.spec.id == self.id then func( ... ) end
end )
end,
RegisterCycle = function( self, func )
self.cycle = setfenv( func, state )
end,
RegisterPet = function( self, token, id, spell, duration )
self.pets[ token ] = {
id = type( id ) == 'function' and setfenv( id, state ) or id,
token = token,
spell = spell,
duration = type( duration ) == 'function' and setfenv( duration, state ) or duration
}
end,
RegisterTotem = function( self, token, id )
self.totems[ token ] = id
self.totems[ id ] = token
end,
GetSetting = function( self, info )
local setting = info[ #info ]
return Hekili.DB.profile.specs[ self.id ].settings[ setting ]
end,
SetSetting = function( self, info, val )
local setting = info[ #info ]
Hekili.DB.profile.specs[ self.id ].settings[ setting ] = val
end,
-- option should be an AceOption table.
RegisterSetting = function( self, key, value, option )
table.insert( self.settings, {
name = key,
default = value,
info = option
} )
option.order = 100 + #self.settings
option.get = option.get or function( info )
local setting = info[ #info ]
local val = Hekili.DB.profile.specs[ self.id ].settings[ setting ]
if val ~= nil then return val end
return value
end
option.set = option.set or function( info, val )
local setting = info[ #info ]
Hekili.DB.profile.specs[ self.id ].settings[ setting ] = val
end
end,
-- For faster variables.
RegisterVariable = function( self, key, func )
self.variables[ key ] = setfenv( func, state )
end,
}
function Hekili:RestoreDefaults()
local p = self.DB.profile
local changed = {}
for k, v in pairs( class.packs ) do
local existing = rawget( p.packs, k )
if not existing or not existing.version or existing.version < v.version then
local data = self:DeserializeActionPack( v.import )
if data and type( data ) == 'table' then
p.packs[ k ] = data.payload
data.payload.version = v.version
data.payload.date = v.version
data.payload.builtIn = true
insert( changed, k )
end
end
end
if #changed > 0 then
self:LoadScripts()
self:RefreshOptions()
if #changed == 1 then
self:Print( "The |cFFFFD100" .. changed[1] .. "|r priority was updated." )
elseif #changed == 2 then
self:Print( "The |cFFFFD100" .. changed[1] .. "|r and |cFFFFD100" .. changed[2] .. "|r priorities were updated." )
else
local report = "|cFFFFD100" .. changed[1] .. "|r"
for i = 2, #changed - 1 do
report = report .. ", |cFFFFD100" .. changed[i] .. "|r"
end
report = "The " .. report .. ", and |cFFFFD100" .. changed[ #changed ] .. "|r priorities were updated."
Hekili:Print( report )
end
end
end
function Hekili:RestoreDefault( name )
local p = self.DB.profile
local default = class.packs[ name ]
if default then
local data = self:DeserializeActionPack( default.import )
if data and type( data ) == 'table' then
p.packs[ name ] = data.payload
data.payload.version = default.version
data.payload.date = default.version
data.payload.builtIn = true
end
end
end
ns.restoreDefaults = function( category, purge )
return
end
ns.isDefault = function( name, category )
if not name or not category then
return false
end
for i, default in ipairs( class.defaults ) do
if default.type == category and default.name == name then
return true, i
end
end
return false
end
-- Trinket APL
-- ns.storeDefault( [[Usable Items]], 'actionLists', 20180208.181753, [[dq0NnaqijvTjPKpjrrJssPtjr1TufQSljzyk0XqjldPQNHsPAAiLsDnukLTHuk5BOunouk5CQcLMNKk3tQSpjfhucAHivEOefMisPYfvfSrvHmsukQtkbwPu4LOuKBkrj7uv6NQcflvI8uvMkQ0vLOuBfLc9vKsH9s6Vsvdw4WGwScEmctgvDzOnlL6ZOy0iLCAIvJuQ61OuWSv0Tb2Ts)wvnCKILJONlA6uDDKSDuX3vfQA8sOZRkA9iLIMVu0(PSYs5QhTdBdPMUsNEVqaQxzNWHjArbocs9kKWL)Mkx9LLYvVhw4We5v607fcq9ODKqkgA5w8BBX9PMPEfS8cb0)K6T)f1ReoryI6l9JSyN1OELW8trsGPYvD9kCqMI)upEsifdT8(F7(8tnt9ocsHgxV6Tir3LLjR4LeomrElAzH1as4chShxeiyArnDwKO7YYKvazfafWIwwynQ1IeDxwMScalkakGfDDwmArZMwajCHd2JlcemTOUols0DzzYkaSOaOawuU66l9kx9EyHdtKxPtVJGuOX1REls0DzzYkEjHdtK3IwwynGeUWb7XfbcMwutNfj6USmzfqwbqbSOLfwJATir3LLjRaWIcGcyrxNfJw0SPfqcx4G94IabtlQRZIeDxwMScalkakGfLRxjm)uKeyQCvxVchKP4p1RnKA6p7j(uRJKaeMuKOEfS8cb0)K6T)f1ReoryI6l9JSyN1OEVqaQ3JGut)PfLXNADKeGWKIevxFz7kx9EyHdtKxPtVJGuOX1REls0DzzYkEjHdtK3IwwynGeUWb7XfbcMwutNfj6USmzfqwbqbSOLfwJATir3LLjRaWIcGcyrxNfJw0SPfqcx4G94IabtlQRZIeDxwMScalkakGfLR3leG69iC(4EmYe5TOGTnsUWPfLfKGwYI6v4Gmf)PETX5xMiFVSTrYfo7bqcAjlQxjm)uKeyQCvxVs4eHjQV0pYIDwJ6vWYleq)tQ3(xuD9L2w5Q3dlCyI8kD69cbOEp6tYGTfC5lZ0IhbhifcO)j1ReMFkscmvUQRxHdYu8N61(tYGTfC5Z(2WbsHa6Fs9ky5fcO)j1B)lQxjCIWe1x6hzXoRr9ocsHgxV6Tir3LLjR4LeomrElAzH1as4chShxeiyArnDwKO7YYKvazfafWIwwynQ1IeDxwMScalkakGfDDwmArZMwajCHd2JlcemTOUols0DzzYkaSOaOawuU66lBt5Q3dlCyI8kD6DeKcnUE1BrIUlltwXljCyI8w0YcRbKWfoypUiqW0IA6Sir3LLjRaYkakGfTSWAuRfj6USmzfawuaual66Sy0IMnTas4chShxeiyArDDwKO7YYKvayrbqbSOC9EHaup28NCT432c2iC(j1RWbzk(t9O1NC7)T75aNFs9kH5NIKatLR66vcNimr9L(rwSZAuVcwEHa6Fs92)IQRV0wkx9EyHdtKxPtVJGuOX1REls0DzzYkEjHdtK3IwwynGeUWb7XfbcMwutNfj6USmzfqwbqbSOLfwJATir3LLjRaWIcGcyrxNfJw0SPfqcx4G94IabtlQRZIeDxwMScalkakGfLRxjm)uKeyQCvxVchKP4p1JnitApe5Xn7hOixzz6F8ssl9ky5fcO)j1B)lQxjCIWe1x6hzXoRr9EHaup2KmltApe5XTmtlOJICLLXcAdjPL66l7kx9EyHdtKxPtVxia1RSegA5w8BBbBI8NuPELW8trsGPYvD9kCqMI)upGWqlV)3UNnq(tQuVcwEHa6Fs92)I6vcNimr9L(rwSZAuVJGuOX1REls0DzzYkEjHdtK3IwwynGeUWb7XfbcMwutNfj6USmzfqwbqbSOLfwJATir3LLjRaWIcGcyrxNfJw0SPfqcx4G94IabtlQRZIeDxwMScalkakGfLRU(Ywkx9EyHdtKxPtVJGuOX1REls0DzzYkEjHdtK3IwwynGeUWb7XfbcMwutNfj6USmzfqwbqbSOLfwJATir3LLjRaWIcGcyrxNfJw0SPfqcx4G94IabtlQRZIeDxwMScalkakGfLR3leG6vswgl(TTOm(ZjKMuwglEeLtrIPEfoitXFQhPSm9)29e)5estkltFBkNIet9kH5NIKatLR66vcNimr9L(rwSZAuVcwEHa6Fs92)IQRVpwLREpSWHjYR0P3rqk046vVfj6USmzfVKWHjYBrllSgqcx4G94IabtlQPZIeDxwMSciRaOaw0YcRrTwKO7YYKvayrbqbSORZIrlA20ciHlCWECrGGPf11zrIUlltwbGffafWIY1ReMFkscmvUQRxHdYu8N6L0Geos2)B3pGoj8jCQxblVqa9pPE7Fr9kHteMO(s)il2znQ3leG6D0GeosAXVTf0Hoj8jCQU(YAu5Q3dlCyI8kD6DeKcnUE1BrIUlltwXljCyI8w0YcRbKWfoypUiqW0IA6Sir3LLjRaYkakGfTSWAuRfj6USmzfawuaual66Sy0IMnTas4chShxeiyArDDwKO7YYKvayrbqbSOC9ky5fcO)j1B)lQxHdYu8N65Fa2)B3tTKqo4uwM(eUI)uVsy(PijWu5QUELWjctuFPFKf7Sg17fcq94(bOf)2wu2ljKdoLLXIdUI)uD9LflLREpSWHjYR0P3rqk046vVfj6USmzfVKWHjYBrllSgqcx4G94IabtlQPZIeDxwMSciRaOaw0YcRrTwKO7YYKvayrbqbSORZIrlA20ciHlCWECrGGPf11zrIUlltwbGffafWIY1ReMFkscmvUQRxHdYu8N6rbgiHZEW)VmtOWbt9ky5fcO)j1B)lQxjCIWe1x6hzXoRr9EHauVYgmqcNwuw))YmHchmvxFzrVYvVhw4We5v607iifAC9Q3IeDxwMSIxs4We5TOLfwdiHlCWECrGGPf10zrIUlltwbKvaualAzH1Owls0DzzYkaSOaOaw01zXOfnBAbKWfoypUiqW0I66Sir3LLjRaWIcGcyr56vcZpfjbMkx11RWbzk(t94iWz)VDpbctCIz27)IYM6vWYleq)tQ3(xuVs4eHjQV0pYIDwJ69cbOESrboT432IYaHjoXmTG7VOSP6QRxjCIWe1x6hzXwJ0pYwvSyNTX(iBP3rqk046PhBw45XvPtVJgKqGtH2e6YF13r1vfa]] )
function Hekili:NewSpecialization( specID, isRanged )
if not specID or specID < 0 then return end
local id, name, _, texture, role, pClass
if specID > 0 then id, name, _, texture, role, pClass = GetSpecializationInfoByID( specID )
else id = specID end
if not id then
Hekili:Error( "Unable to generate specialization DB for spec ID #" .. specID .. "." )
return nil
end
local spec = class.specs[ id ] or {
id = id,
name = name,
texture = texture,
role = role,
class = pClass,
melee = not isRanged,
resources = {},
resourceAuras = {},
primaryResource = nil,
talents = {},
pvptalents = {},
powers = {},
auras = {},
pseudoAuras = 0,
abilities = {},
pseudoAbilities = 0,
itemAbilities = 0,
pendingItemSpells = {},
pets = {},
totems = {},
potions = {},
settings = {},
stateExprs = {}, -- expressions are returned as values and take no args.
stateFuncs = {}, -- functions can take arguments and can be used as helper functions in handlers.
stateTables = {}, -- tables are... tables.
gear = {},
hooks = {},
funcHooks = {},
gearSets = {},
interrupts = {},
castableWhileCasting = {},
packs = {},
options = {},
variables = {}
}
class.num = class.num + 1
for key, func in pairs( HekiliSpecMixin ) do
spec[ key ] = func
end
class.specs[ id ] = spec
return spec
end
class.file = UnitClassBase( "player" )
local all = Hekili:NewSpecialization( 0, "All", "Interface\\Addons\\Hekili\\Textures\\LOGO-WHITE.blp" )
------------------------------
-- SHARED SPELLS/BUFFS/ETC. --
------------------------------
all:RegisterAuras( {
enlisted_a = {
id = 282559,
duration = 3600,
},
enlisted_b = {
id = 289954,
duration = 3600,
},
enlisted_c = {
id = 269083,
duration = 3600,
},
enlisted = {
alias = { "enlisted_c", "enlisted_b", "enlisted_a" },
aliasMode = "first",
aliasType = "buff",
duration = 3600,
},
ancient_hysteria = {
id = 90355,
shared = "player", -- use anyone's buff on the player, not just player's.
duration = 40,
max_stack = 1,
},
heroism = {
id = 32182,
shared = "player", -- use anyone's buff on the player, not just player's.
duration = 40,
max_stack = 1,
},
time_warp = {
id = 80353,
shared = "player", -- use anyone's buff on the player, not just player's.
duration = 40,
max_stack = 1,
},
netherwinds = {
id = 160452,
shared = "player", -- use anyone's buff on the player, not just player's.
duration = 40,
max_stack = 1,
},
primal_rage = {
id = 264667,
shared = "player", -- use anyone's buff on the player, not just player's.
duration = 40,
max_stack = 1,
},
bloodlust = {
id = 2825,
duration = 40,
generate = function ( t )
local bloodlusts = {
[90355] = 'ancient_hysteria',
[32182] = 'heroism',
[80353] = 'time_warp',
[160452] = 'netherwinds',
[264667] = 'primal_rage',
}
for id, key in pairs( bloodlusts ) do
local aura = buff[ key ]
if aura.up then
t.count = aura.count
t.expires = aura.expires
t.applied = aura.applied
t.caster = aura.caster
return
end
end
local name, _, count, _, duration, expires, caster, _, _, spellID = GetPlayerAuraBySpellID( 2825 )
if name then
t.count = max( 1, count )
t.expires = expires
t.applied = expires - duration
t.caster = caster
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = 'nobody'
end,
},
exhaustion = {
id = 57723,
shared = "player",
duration = 600,
max_stack = 1
},
insanity = {
id = 95809,
shared = "player",
duration = 600,
max_stack = 1
},
temporal_displacement = {
id = 80354,
shared = "player",
duration = 600,
max_stack = 1
},
fatigued = {
id = 264689,
shared = "player",
duration = 600,
max_stack = 1
},
sated = {
id = 57724,
duration = 600,
max_stack = 1,
generate = function ( t )
local sateds = {
[57723] = 'exhaustion',
[95809] = 'insanity',
[80354] = 'temporal_displacement',
[264689] = 'fatigued',
}
for id, key in pairs( sateds ) do
local aura = debuff[ key ]
if aura.up then
t.count = aura.count
t.expires = aura.expires
t.applied = aura.applied
t.caster = aura.caster
return
end
end
local name, _, count, _, duration, expires, caster, _, _, spellID = GetPlayerAuraBySpellID( 57724 )
if name then
t.count = max( 1, count )
t.expires = expires
t.applied = expires - duration
t.caster = caster
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = 'nobody'
end,
},
power_infusion = {
id = 10060,
duration = 20,
max_stack = 1
},
old_war = {
id = 188028,
duration = 25,
},
deadly_grace = {
id = 188027,
duration = 25,
},
prolonged_power = {
id = 229206,
duration = 60,
},
dextrous = {
id = 146308,
duration = 20,
},
vicious = {
id = 148903,
duration = 10,
},
-- WoD Legendaries
archmages_incandescence_agi = {
id = 177161,
duration = 10,
},
archmages_incandescence_int = {
id = 177159,
duration = 10,
},
archmages_incandescence_str = {
id = 177160,
duration = 10,
},
archmages_greater_incandescence_agi = {
id = 177172,
duration = 10,
},
archmages_greater_incandescence_int = {
id = 177176,
duration = 10,
},
archmages_greater_incandescence_str = {
id = 177175,
duration = 10,
},
maalus = {
id = 187620,
duration = 15,
},
thorasus = {
id = 187619,
duration = 15,
},
sephuzs_secret = {
id = 208052,
duration = 10,
max_stack = 1,
},
str_agi_int = {
duration = 3600,
},
stamina = {
duration = 3600,
},
attack_power_multiplier = {
duration = 3600,
},
haste = {
duration = 3600,
},
spell_power_multiplier = {
duration = 3600,
},
critical_strike = {
duration = 3600,
},
mastery = {
duration = 3600,
},
versatility = {
duration = 3600,
},
casting = {
name = Casting,
generate = function( t, auraType )
local unit = auraType == "debuff" and "target" or "player"
if unit == "player" or UnitCanAttack( "player", "target" ) then
local spell, _, _, startCast, endCast, _, _, notInterruptible, spellID = UnitCastingInfo( unit )
if spell then
startCast = startCast / 1000
endCast = endCast / 1000
t.name = spell
t.count = 1
t.expires = endCast
t.applied = startCast
t.duration = endCast - startCast
t.v1 = spellID
t.v2 = notInterruptible
t.v3 = false
t.caster = unit
return
end
spell, _, _, startCast, endCast, _, notInterruptible, spellID = UnitChannelInfo( unit )
if spell then
startCast = startCast / 1000
endCast = endCast / 1000
t.name = spell
t.count = 1
t.expires = endCast
t.applied = startCast
t.duration = endCast - startCast
t.v1 = spellID
t.v2 = notInterruptible
t.v3 = true -- channeled.
t.caster = unit
return
end
end
t.name = Casting
t.count = 0
t.expires = 0
t.applied = 0
t.v1 = 0
t.v2 = false
t.v3 = false
t.caster = unit
end,
},
--[[ player_casting = {
name = "Casting",
generate = function ()
local aura = buff.player_casting
local name, _, _, startCast, endCast, _, _, notInterruptible, spell = UnitCastingInfo( "player" )
if name then
aura.name = name
aura.count = 1
aura.expires = endCast / 1000
aura.applied = startCast / 1000
aura.v1 = spell
aura.caster = 'player'
return
end
name, _, _, startCast, endCast, _, _, notInterruptible, spell = UnitChannelInfo( "player" )
if notInterruptible == false then
aura.name = name
aura.count = 1
aura.expires = endCast / 1000
aura.applied = startCast / 1000
aura.v1 = spell
aura.caster = 'player'
return
end
aura.name = "Casting"
aura.count = 0
aura.expires = 0
aura.applied = 0
aura.v1 = 0
aura.caster = 'target'
end,
}, ]]
movement = {
duration = 5,
max_stack = 1,
generate = function ()
local m = buff.movement
if moving then
m.count = 1
m.expires = query_time + 5
m.applied = query_time
m.caster = "player"
return
end
m.count = 0
m.expires = 0
m.applied = 0
m.caster = "nobody"
end,
},
repeat_performance = {
id = 304409,
duration = 30,
max_stack = 1,
},
-- Why do we have this, again?
unknown_buff = {},
berserking = {
id = 26297,
duration = 10,
},
hyper_organic_light_originator = {
id = 312924,
duration = 6,
},
blood_fury = {
id = 20572,
duration = 15,
},
shadowmeld = {
id = 58984,
duration = 3600,
},
ferocity_of_the_frostwolf = {
id = 274741,
duration = 15,
},
might_of_the_blackrock = {
id = 274742,
duration = 15,
},
zeal_of_the_burning_blade = {
id = 274740,
duration = 15,
},
rictus_of_the_laughing_skull = {
id = 274739,
duration = 15,
},
ancestral_call = {
duration = 15,
alias = { "ferocity_of_the_frostwolf", "might_of_the_blackrock", "zeal_of_the_burning_blade", "rictus_of_the_laughing_skull" },
aliasMode = "first",
},
arcane_pulse = {
id = 260369,
duration = 12,
},
fireblood = {
id = 273104,
duration = 8,
},
out_of_range = {
generate = function ()
local oor = buff.out_of_range
if target.distance > 8 then
oor.count = 1
oor.applied = query_time
oor.expires = 3600
oor.caster = "player"
return
end
oor.count = 0
oor.applied = 0
oor.expires = 0
oor.caster = "nobody"
end,
},
loss_of_control = {
duration = 10,
generate = function( t )
local max_events = GetActiveLossOfControlDataCount()
if max_events > 0 then
local spell, start, duration, remains = "none", 0, 0, 0
for i = 1, max_events do
local event = GetActiveLossOfControlData( i )
if event.lockoutSchool == 0 and event.startTime and event.startTime > 0 and event.timeRemaining and event.timeRemaining > 0 and event.startTime > start and event.timeRemaining > remains then
spell = event.spellID
start = event.startTime
duration = event.duration
remains = event.timeRemaining
end
end
if start + duration > query_time then
t.count = 1
t.expires = start + duration
t.applied = start
t.duration = duration
t.caster = "anybody"
t.v1 = spell
return
end
end
t.count = 0
t.expires = 0
t.applied = 0
t.duration = 10
t.caster = "nobody"
t.v1 = 0
end,
},
dispellable_curse = {
generate = function( t )
local i = 1
local name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
while( name ) do
if debuffType == "Curse" then break end
i = i + 1
name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
end
if name then
t.count = count > 0 and count or 1
t.expires = expirationTime > 0 and expirationTime or query_time + 5
t.applied = expirationTime > 0 and ( expirationTime - duration ) or query_time
t.caster = "nobody"
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = "nobody"
end,
},
dispellable_poison = {
generate = function( t )
local i = 1
local name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
while( name ) do
if debuffType == "Poison" then break end
i = i + 1
name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
end
if name then
t.count = count > 0 and count or 1
t.expires = expirationTime > 0 and expirationTime or query_time + 5
t.applied = expirationTime > 0 and ( expirationTime - duration ) or query_time
t.caster = "nobody"
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = "nobody"
end,
},
dispellable_disease = {
generate = function( t )
local i = 1
local name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
while( name ) do
if debuffType == "Disease" then break end
i = i + 1
name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
end
if name then
t.count = count > 0 and count or 1
t.expires = expirationTime > 0 and expirationTime or query_time + 5
t.applied = expirationTime > 0 and ( expirationTime - duration ) or query_time
t.caster = "nobody"
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = "nobody"
end,
},
dispellable_magic = {
generate = function( t, auraType )
if auraType == "buff" then
local i = 1
local name, _, count, debuffType, duration, expirationTime, _, canDispel = UnitBuff( "target", i )
while( name ) do
if debuffType == "Magic" and canDispel then break end
i = i + 1
name, _, count, debuffType, duration, expirationTime, _, canDispel = UnitBuff( "target", i )
end
if canDispel then
t.count = count > 0 and count or 1
t.expires = expirationTime > 0 and expirationTime or query_time + 5
t.applied = expirationTime > 0 and ( expirationTime - duration ) or query_time
t.caster = "nobody"
return
end
else
local i = 1
local name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
while( name ) do
if debuffType == "Magic" then break end
i = i + 1
name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
end
if name then
t.count = count > 0 and count or 1
t.expires = expirationTime > 0 and expirationTime or query_time + 5
t.applied = expirationTime > 0 and ( expirationTime - duration ) or query_time
t.caster = "nobody"
return
end
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = "nobody"
end,
},
stealable_magic = {
generate = function( t )
if UnitCanAttack( "player", "target" ) then
local i = 1
local name, _, count, debuffType, duration, expirationTime, _, canDispel = UnitBuff( "target", i )
while( name ) do
if debuffType == "Magic" and canDispel then break end
i = i + 1
name, _, count, debuffType, duration, expirationTime, _, canDispel = UnitBuff( "target", i )
end
if canDispel then
t.count = count > 0 and count or 1
t.expires = expirationTime > 0 and expirationTime or query_time + 5
t.applied = expirationTime > 0 and ( expirationTime - duration ) or query_time
t.caster = "nobody"
return
end
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = "nobody"
end,
},
reversible_magic = {
generate = function( t )
local i = 1
local name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
while( name ) do
if debuffType == "Magic" then break end
i = i + 1
name, _, count, debuffType, duration, expirationTime = UnitDebuff( "player", i, "RAID" )
end
if name then
t.count = count > 0 and count or 1
t.expires = expirationTime > 0 and expirationTime or query_time + 5
t.applied = expirationTime > 0 and ( expirationTime - duration ) or query_time
t.caster = "nobody"
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = "nobody"
end,
},
dispellable_enrage = {
generate = function( t )
if UnitCanAttack( "player", "target" ) then
local i = 1
local name, _, count, debuffType, duration, expirationTime, _, canDispel = UnitBuff( "target", i )
while( name ) do
if debuffType == "" and canDispel then break end
i = i + 1
name, _, count, debuffType, duration, expirationTime, _, canDispel = UnitBuff( "target", i )
end
if canDispel then
t.count = count > 0 and count or 1
t.expires = expirationTime > 0 and expirationTime or query_time + 5
t.applied = expirationTime > 0 and ( expirationTime - duration ) or query_time
t.caster = "nobody"
return
end
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = "nobody"
end,
}
} )
all:RegisterPotions( {
-- 9.0
potion_of_spectral_strength = {
item = 171275,
buff = "potion_of_spectral_strength",
copy = "spectral_strength",
},
potion_of_spectral_agility = {
item = 171270,
buff = "potion_of_spectral_agility",
copy = "spectral_agility",
},
potion_of_spiritual_clarity = {
item = 171272,
buff = "potion_of_spiritual_clarity",
copy = "spiritual_clarity"
},
potion_of_phantom_fire = {
item = 171349,
buff = "potion_of_phantom_fire",
copy = "phantom_fire",
},
potion_of_spectral_intellect = {
item = 171273,
buff = "potion_of_spectral_intellect",
copy = "spectral_intellect"
},
potion_of_deathly_fixation = {
item = 171351,
buff = "potion_of_deathly_fixation",
copy = "deathly_fixation"
},
strength_of_blood = {
item = 182163,
buff = "strength_of_blood",
},
potion_of_empowered_exorcisms = {
item = 171352,
buff = "potion_of_empowered_exorcisms",
copy = "empowered_exorcisms"
},
potion_of_unusual_strength = {
item = 180771,
buff = "potion_of_unusual_strength",
copy = "unusual_strength"
},
potion_of_spectral_stamina = {
item = 171274,
buff = "potion_of_spectral_stamina",
copy = "spectral_stamina"
},
-- 8.2
potion_of_empowered_proximity = {
item = 168529,
buff = 'potion_of_empowered_proximity',
copy = 'empowered_proximity'
},
potion_of_focused_resolve = {
item = 168506,
buff = 'potion_of_focused_resolve',
copy = 'focused_resolve'
},
potion_of_unbridled_fury = {
item = 169299,
buff = 'potion_of_unbridled_fury',
copy = 'unbridled_fury'
},
superior_battle_potion_of_agility = {
item = 168489,
buff = 'superior_battle_potion_of_agility',
},
superior_battle_potion_of_intellect = {
item = 168498,
buff = 'superior_battle_potion_of_intellect',
},
superior_battle_potion_of_stamina = {
item = 168499,
buff = 'superior_battle_potion_of_stamina',
},
superior_battle_potion_of_strength = {
item = 168500,
buff = 'superior_battle_potion_of_strength',
},
superior_steelskin_potion = {
item = 168501,
buff = 'superior_steelskin_potion',
},
-- 8.0
battle_potion_of_agility = {
item = 163223,
buff = 'battle_potion_of_agility',
},
battle_potion_of_intellect = {
item = 163222,
buff = 'battle_potion_of_intellect',
},
battle_potion_of_stamina = {
item = 163225,
buff = 'battle_potion_of_stamina',
},
battle_potion_of_strength = {
item = 163224,
buff = 'battle_potion_of_strength',
},
bursting_blood = {
item = 152560,
buff = 'potion_of_bursting_blood',
copy = "bursting_blood",
},
potion_of_rising_death = {
item = 152559,
buff = 'potion_of_rising_death',
copy = "rising_death",
},
steelskin_potion = {
item = 152557,
buff = 'steelskin_potion',
},
} )
all:RegisterAuras( {
-- 9.0
potion_of_spectral_strength = {
id = 307164,
duration = 25,
max_stack = 1,
copy = "spectral_strength"
},
potion_of_spectral_agility = {
id = 307159,
duration = 25,
max_stack = 1,
copy = "spectral_agility"
},
potion_of_spiritual_clarity = {
id = 307161,
duration = 10,
max_stack = 1,
copy = "spiritual_clarity"
},
potion_of_phantom_fire = {
id = 307495,
duration = 25,
max_stack = 1,
copy = "phantom_fire",
},
potion_of_spectral_intellect = {
id = 307162,
duration = 25,
max_stack = 1,
copy = "spectral_intellect"
},
potion_of_deathly_fixation = {
id = 307497,
duration = 25,
max_stack = 1,
copy = "deathly_fixation"
},
strength_of_blood = {
id = 338385,
duration = 60,
max_stack = 1
},
potion_of_empowered_exorcisms = {
id = 307494,
duration = 25,
max_stack = 1,
copy = "empowered_exorcisms"
},
potion_of_unusual_strength = {
id = 334436,
duration = 25,
max_stack = 1,
copy = "unusual_strength"
},
potion_of_spectral_stamina = {
id = 307163,
duration = 25,
max_stack = 1,
copy = "spectral_stamina"
},
-- 8.2
potion_of_empowered_proximity = {
id = 298225,
duration = 25,
max_stack = 1
},
potion_of_focused_resolve = {
id = 298317,
duration = 25,
max_stack = 1
},
potion_of_unbridled_fury = {
id = 300714,
duration = 60,
max_stack = 1
},
superior_battle_potion_of_agility = {
id = 298146,
duration = 25,
max_stack = 1
},
superior_battle_potion_of_intellect = {
id = 298152,
duration = 25,
max_stack = 1
},
superior_battle_potion_of_stamina = {
id = 298153,
duration = 25,
max_stack = 1
},
superior_battle_potion_of_strength = {
id = 298154,
duration = 25,
max_stack = 1
},
superior_steelskin_potion = {
id = 298155,
duration = 25,
max_stack = 1
},
-- 8.0
battle_potion_of_agility = {
id = 279152,
duration = 25,
max_stack = 1,
},
battle_potion_of_intellect = {
id = 279151,
duration = 25,
max_stack = 1,
},
battle_potion_of_stamina = {
id = 279154,
duration = 25,
max_stack = 1,
},
battle_potion_of_strength = {
id = 279153,
duration = 25,
max_stack = 1,
},
potion_of_bursting_blood = {
id = 251316,
duration = 25,
max_stack = 1,
},
potion_of_rising_death = {
id = 269853,
duration = 25,
max_stack = 1,
},
steelskin_potion = {
id = 251231,
duration = 25,
max_stack = 1,
}
})
all:SetPotion( "prolonged_power" )
local gotn_classes = {
WARRIOR = 28880,
MONK = 121093,
DEATHKNIGHT = 59545,
SHAMAN = 59547,
HUNTER = 59543,
PRIEST = 59544,
MAGE = 59548,
PALADIN = 59542
}
all:RegisterAura( "gift_of_the_naaru", {
id = gotn_classes[ UnitClassBase( "player" ) or "WARRIOR" ],
duration = 5,
max_stack = 1,
copy = { 28800, 121093, 59545, 59547, 59543, 59544, 59548, 59542 }
} )
all:RegisterAbility( "gift_of_the_naaru", {
id = 59544,
cast = 0,
cooldown = 180,
gcd = "off",
handler = function ()
applyBuff( "gift_of_the_naaru" )
end,
} )
all:RegisterAbilities( {
global_cooldown = {
id = 61304,
cast = 0,
cooldown = 0,
gcd = "spell",
unlisted = true,
known = function () return true end,
},
ancestral_call = {
id = 274738,
cast = 0,
cooldown = 120,
gcd = "off",
toggle = "cooldowns",
-- usable = function () return race.maghar_orc end,
handler = function ()
applyBuff( "ancestral_call" )
end,
},
arcane_pulse = {
id = 260364,
cast = 0,
cooldown = 180,
gcd = "spell",
toggle = "cooldowns",
-- usable = function () return race.nightborne end,
handler = function ()
applyDebuff( "target", "arcane_pulse" )
end,
},
berserking = {
id = 26297,
cast = 0,
cooldown = 180,
gcd = "off",
toggle = "cooldowns",
-- usable = function () return race.troll end,
handler = function ()
applyBuff( 'berserking' )
end,
},
hyper_organic_light_originator = {
id = 312924,
cast = 0,
cooldown = 180,
gcd = "off",
toggle = "defensives",
handler = function ()
applyBuff( "hyper_organic_light_originator" )
end
},
bag_of_tricks = {
id = 312411,
cast = 0,
cooldown = 90,
gcd = "spell",
toggle = "cooldowns",
}
} )
-- Blood Fury spell IDs vary by class (whether you need AP/Int/both).
local bf_classes = {
DEATHKNIGHT = 20572,
HUNTER = 20572,
MAGE = 33702,
MONK = 33697,
ROGUE = 20572,
SHAMAN = 33697,
WARLOCK = 33702,
WARRIOR = 20572,
}
all:RegisterAbilities( {
blood_fury = {
id = function () return bf_classes[ class.file ] or 20572 end,
cast = 0,
cooldown = 120,
gcd = "off",
toggle = "cooldowns",
-- usable = function () return race.orc end,
handler = function ()
applyBuff( "blood_fury", 15 )
end,
copy = { 33702, 20572, 33697 },
},
arcane_torrent = {
id = function ()
if class.file == "PALADIN" then return 155145 end
if class.file == "MONK" then return 129597 end
if class.file == "DEATHKNIGHT" then return 50613 end
if class.file == "WARRIOR" then return 69179 end
if class.file == "ROGUE" then return 25046 end
if class.file == "HUNTER" then return 80483 end
if class.file == "DEMONHUNTER" then return 202719 end
if class.file == "PRIEST" then return 232633 end
return 28730
end,
cast = 0,
cooldown = 120,
gcd = "spell",
startsCombat = true,
-- usable = function () return race.blood_elf end,
toggle = "cooldowns",
handler = function ()
if class.file == "DEATHKNIGHT" then gain( 20, "runic_power" )
elseif class.file == "HUNTER" then gain( 15, "focus" )
elseif class.file == "MONK" then gain( 1, "chi" )
elseif class.file == "PALADIN" then gain( 1, "holy_power" )
elseif class.file == "ROGUE" then gain( 15, "energy" )
elseif class.file == "WARRIOR" then gain( 15, "rage" )
elseif class.file == "DEMONHUNTER" then gain( 15, "fury" )
elseif class.file == "PRIEST" and state.spec.shadow then gain( 15, "insanity" ) end
removeBuff( "dispellable_magic" )
end,
},
will_to_survive = {
id = 59752,
cast = 0,
cooldown = 180,
gcd = "off",
toggle = "defensives",
},
shadowmeld = {
id = 58984,
cast = 0,
cooldown = 120,
gcd = "off",
usable = function ()
if not boss or solo then return false, "requires boss fight or group (to avoid resetting)" end
if moving then return false, "can't shadowmeld while moving" end
return true
end,
handler = function ()
applyBuff( "shadowmeld" )
end,
},
lights_judgment = {
id = 255647,
cast = 0,
cooldown = 150,
gcd = "spell",
-- usable = function () return race.lightforged_draenei end,
toggle = 'cooldowns',
},
stoneform = {
id = 20594,
cast = 0,
cooldown = 120,
gcd = "off",
handler = function ()
removeBuff( "dispellable_poison" )
removeBuff( "dispellable_disease" )
removeBuff( "dispellable_curse" )
removeBuff( "dispellable_magic" )
removeBuff( "dispellable_bleed" )
applyBuff( "stoneform" )
end,
auras = {
stoneform = {
id = 65116,
duration = 8,
max_stack = 1
}
}
},
fireblood = {
id = 265221,
cast = 0,
cooldown = 120,
gcd = "off",
toggle = "cooldowns",
-- usable = function () return race.dark_iron_dwarf end,
handler = function () applyBuff( "fireblood" ) end,
},
-- INTERNAL HANDLERS
call_action_list = {
name = '|cff00ccff[Call Action List]|r',
cast = 0,
cooldown = 0,
gcd = 'off',
essential = true,
},
run_action_list = {
name = '|cff00ccff[Run Action List]|r',
cast = 0,
cooldown = 0,
gcd = 'off',
essential = true,
},
wait = {
name = '|cff00ccff[Wait]|r',
cast = 0,
cooldown = 0,
gcd = 'off',
essential = true,
},
pool_resource = {
name = '|cff00ccff[Pool Resource]|r',
cast = 0,
cooldown = 0,
gcd = 'off',
},
cancel_action = {
name = "|cff00ccff[Cancel Action]|r",
cast = 0,
cooldown = 0,
gcd = "off",
},
variable = {
name = '|cff00ccff[Variable]|r',
cast = 0,
cooldown = 0,
gcd = 'off',
essential = true,
},
potion = {
name = '|cff00ccff[Potion]|r',
cast = 0,
cooldown = function () return time > 0 and 3600 or 60 end,
gcd = 'off',
startsCombat = false,
toggle = "potions",
handler = function ()
local potion = args.potion or args.name
if not potion or potion == "default" then potion = class.potion end
potion = class.potions[ potion ]
if potion then
applyBuff( potion.buff, potion.duration or 25 )
end
end,
usable = function ()
local pName = args.potion or args.name
if not pName or pName == "default" then pName = class.potion end
local potion = class.potions[ pName ]
if not potion or GetItemCount( potion.item ) == 0 then return false, "no potion found" end
return true
end,
},
healthstone = {
name = "|cff00ccff[Healthstone]|r",
cast = 0,
cooldown = function () return time > 0 and 3600 or 60 end,
gcd = "off",
item = 5512,
bagItem = true,
startsCombat = false,
texture = 538745,
usable = function ()
if GetItemCount( 5512 ) == 0 then return false, "requires healthstone in bags"
elseif not IsUsableItem( 5512 ) then return false, "healthstone on CD"
elseif health.current >= health.max then return false, "must be damaged" end
return true
end,
readyTime = function ()
local start, duration = GetItemCooldown( 5512 )
return max( 0, start + duration - query_time )
end,
handler = function ()
gain( 0.25 * health.max, "health" )
end,
},
cancel_buff = {
name = '|cff00ccff[Cancel Buff]|r',
cast = 0,
gcd = 'off',
startsCombat = false,
buff = function () return args.buff_name or nil end,
indicator = "cancel",
texture = function ()
local a = class.auras[ args.buff_name ]
if a.texture then return a.texture end
a = a and a.id
a = a and GetSpellTexture( a )
return a or 134400
end,
usable = function () return args.buff_name ~= nil, "no buff name detected" end,
timeToReady = function () return gcd.remains end,
handler = function ()
removeBuff( args.buff_name )
end,
},
null_cooldown = {
name = "|cff00ccff[Null Cooldown]|r",
cast = 0,
gcd = "off",
startsCombat = false,
unlisted = true
},
trinket1 = {
name = "|cff00ccff[Trinket #1]",
cast = 0,
gcd = "off",
},
trinket2 = {
name = "|cff00ccff[Trinket #2]",
cast = 0,
gcd = "off",
},
} )
-- Use Items
do
-- Should handle trinkets/items internally.
-- 1. Check APLs and don't try to recommend items that have their own APL entries.
-- 2. Respect item preferences registered in spec options.
all:RegisterAbility( "use_items", {
name = "|cff00ccff[Use Items]|r",
cast = 0,
cooldown = 120,
gcd = 'off',
} )
all:RegisterAbility( "heart_essence", {
name = "|cff00ccff[Heart Essence]|r",
cast = 0,
cooldown = 0,
gcd = 'off',
item = 158075,
essence = true,
toggle = "essences",
usable = function () return false, "your equipped major essence is supported elsewhere in the priority or is not an active ability" end
} )
end
-- 8.3 - WORLD
-- Corruption Curse that impacts resource costs.
all:RegisterAura( "hysteria", {
id = 312677,
duration = 30,
max_stack = 99
} )
-- BFA TRINKETS
-- EQUIPPED EFFECTS
all:RegisterAuras( {
-- Darkmoon Deck: Squalls
suffocating_squall = { id = 276132, duration = 26, max_stack = 1 }, -- I made up max duration (assume 13 card types and 2s per card).
-- Construct Overcharger
titanic_overcharge = { id = 278070, duration = 10, max_stack = 8 },
-- Xalzaix's Veiled Eye
xalzaixs_gaze = { id = 278158, duration = 20, max_stack = 1 },
-- Syringe of Bloodborne Infirmity
wasting_infection = { id = 278110, duration = 12, max_stack = 1 },
critical_prowess = { id = 278109, duration = 6, max_stack = 5 },
-- Frenetic Corpuscle
frothing_rage = { id = 278140, duration = 45, max_stack = 4 },
-- Tear of the Void
voidspark = { id = 278831, duration = 14, max_stack = 1 },
-- Prism of Dark Intensity
dark_intensity = { id = 278378, duration = 18, max_stack = 6,
meta = {
-- Stacks every 3 seconds until expiration; should generalize this kind of thing...
stacks = function ( aura )
if aura.up then return 1 + floor( ( query_time - aura.applied ) / 3 ) end
return 0
end
}
},
-- Plume of the Seaborne Avian
seaborne_tempest = { id = 278382, duration = 10, max_stack = 1 },
-- Drust-Runed Icicle
chill_of_the_runes = { id = 278862, duration = 12, max_stack = 1 },
-- Permafrost-Encrusted Heart
coldhearted_instincts = { id = 278388, duration = 15, max_stack = 5, copy = "cold_hearted_instincts",
meta = {
-- Stacks every 3 seconds until expiration; should generalize this kind of thing...
stacks = function ( aura )
if aura.up then return 1 + floor( ( query_time - aura.applied ) / 3 ) end
return 0
end
}
},
-- Spiritbound Voodoo Burl
coalesced_essence = { id = 278224, duration = 12, max_stack = 1 },
-- Wing Bone of the Budding Tempest
avian_tempest = { id = 278253, duration = 10, max_stack = 5 },
-- Razorcrest of the Enraged Matriarch
winged_tempest = { id = 278248, duration = 16, max_stack = 1 },
-- Hurricane Heart
hurricane_within = { id = 161416, duration = 12, max_stack = 6,
meta = {
-- Stacks every 2 seconds until expiration; should generalize this kind of thing...
stacks = function ( aura )
if aura.up then return 1 + floor( ( query_time - aura.applied ) / 2 ) end
return 0
end
}
},
-- Kraulok's Claw
krauloks_strength = { id = 278287, duration = 10, max_stack = 1 },
-- Doom's Hatred
blood_hatred = { id = 278356, duration = 10, max_stack = 1 },
-- Lion's Grace
lions_grace = { id = 278815, duration = 10, max_stack = 1 },
-- Landoi's Scrutiny
landois_scrutiny = { id = 281544, duration = 15, max_stack = 1 },
-- Leyshock's Grand Compilation
precision_module = { id = 281791, duration = 15, max_stack = 3 }, -- Crit.
iteration_capacitor = { id = 281792, duration = 15, max_stack = 3 }, -- Haste.
efficiency_widget = { id = 281794, duration = 15, max_stack = 3 }, -- Mastery.
adaptive_circuit = { id = 281795, duration = 15, max_stack = 3 }, -- Versatility.
leyshocks_grand_compilation = {
alias = { "precision_module", "iteration_capacitor", "efficiency_widget", "adaptive_circuit" },
aliasMode = "longest",
aliasType = "buff",
duration = 15,
},
-- Twitching Tentacle of Xalzaix
lingering_power_of_xalzaix = { id = 278155, duration = 30, max_stack = 5 },
uncontained_power = { id = 278156, duration = 12, max_stack = 1 },
-- Surging Alchemist Stone
-- I believe these buffs are recycled a lot...
agility = { id = 60233, duration = 15, max_stack = 1 },
intellect = { id = 60234, duration = 15, max_stack = 1 },
strength = { id = 60229, duration = 15, max_stack = 1 },
-- Harlan's Loaded Dice
loaded_die_mastery = { id = 267325, duration = 15, max_stack = 1 },
loaded_die_haste = { id = 267327, duration = 15, max_stack = 1 },
loaded_die_critical_strike = { id = 267330, duration = 15, max_stack = 1 },
loaded_die = {
alias = { "loaded_die_mastery", "loaded_die_haste", "loaded_die_critical_strike" },
aliasMode = "longest",
aliasType = "buff",
duration = 15,
},
-- Tiny Electromental in a Jar
phenomenal_power = { id = 267179, duration = 30, max_stack = 12 },
-- Rezan's Gleaming Eye
rezans_gleaming_eye = { id = 271103, duration = 15, max_stack = 1 },
-- Azerokk's Resonating Heart
resonating_elemental_heart = { id = 268441, duration = 15, max_stack = 1 },
-- Gore-Crusted Butcher's Block
butchers_eye = { id = 271104, duration = 15, max_stack = 1 },
-- Briny Barnacle
choking_brine = { id = 268194, duration = 6, max_stack = 1 },
-- Conch of Dark Whispers
conch_of_dark_whispers = { id = 271071, duration = 15, max_stack = 1 },
-- Dead Eye Spyglass
dead_ahead = { id = 268756, duration = 10, max_stack = 1 },
dead_ahead_crit = { id = 268769, duration = 10, max_stack = 5 },
-- Lingering Sporepods
lingering_spore_pods = { id = 268062, duration = 4, max_stack = 1 },
} )
-- BFA TRINKETS/ITEMS
-- Ny'alotha
all:RegisterAbility( "manifesto_of_madness", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 174103,
toggle = "cooldowns",
handler = function ()
applyBuff( "manifesto_of_madness_chapter_one" )
end,
} )
all:RegisterAuras( {
manifesto_of_madness_chapter_one = {
id = 313948,
duration = 10,
max_stack = 1
},
manifesto_of_madness_chapter_two = {
id = 314040,
duration = 10,
max_stack = 1
}
} )
all:RegisterAbility( "forbidden_obsidian_claw", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 173944,
toggle = "cooldowns",
handler = function ()
applyDebuff( "target", "obsidian_claw" )
end,
} )
all:RegisterAura( "obsidian_claw", {
id = 313148,
duration = 8.5,
max_stack = 1
} )
all:RegisterAbility( "sigil_of_warding", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 173940,
toggle = "defensives",
handler = function ()
applyBuff( "stoneskin", 8 )
end,
} )
all:RegisterAura( "stoneskin", {
id = 313060,
duration = 16,
max_stack = 1,
} )
all:RegisterAbility( "writhing_segment_of_drestagath", {
cast = 0,
cooldown = 80,
gcd = "off",
item = 173946,
toggle = "cooldowns",
} )
all:RegisterAbility( "lingering_psychic_shell", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 174277,
toggle = "defensives",
handler = function ()
applyBuff( "" )
end,
} )
all:RegisterAura( "psychic_shell", {
id = 314585,
duration = 8,
max_stack = 1
} )
-- Azshara's EP
all:RegisterAbility( "orgozoas_paralytic_barb", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 168899,
toggle = "defensives",
handler = function ()
applyBuff( "paralytic_spines" )
end,
} )
all:RegisterAura( "paralytic_spines", {
id = 303350,
duration = 15,
max_stack = 1
} )
all:RegisterAbility( "azsharas_font_of_power", {
cast = 4,
channeled = true,
cooldown = 120,
gcd = "spell",
item = 169314,
toggle = "cooldowns",
start = function ()
applyBuff( "latent_arcana_channel" )
end,
breakchannel = function ()
removeBuff( "latent_arcana_channel" )
applyBuff( "latent_arcana" )
end,
finish = function ()
removeBuff( "latent_arcana_channel" )
applyBuff( "latent_arcana" )
end,
copy = { "latent_arcana" }
} )
all:RegisterAuras( {
latent_arcana = {
id = 296962,
duration = 30,
max_stack = 5
},
latent_arcana_channel = {
id = 296971,
duration = 4,
max_stack = 1
}
} )
all:RegisterAbility( "shiver_venom_relic", {
cast = 0,
cooldown = 60,
gcd = "spell",
item = 168905,
toggle = "cooldowns",
usable = function ()
if debuff.shiver_venom.stack < 5 then return false, "shiver_venom is not at max stacks" end
return true
end,
aura = "shiver_venom",
cycle = "shiver_venom",
handler = function()
removeDebuff( "target", "shiver_venom" )
end,
} )
all:RegisterAura( "shiver_venom", {
id = 301624,
duration = 20,
max_stack = 5
} )
do
local coralGUID, coralApplied, coralStacks = "none", 0, 0
-- Ashvane's Razor Coral, 169311
all:RegisterAbility( "ashvanes_razor_coral", {
cast = 0,
cooldown = 20,
gcd = "off",
item = 169311,
toggle = "cooldowns",
usable = function ()
if active_dot.razor_coral > 0 and target.unit ~= coralGUID then
return false, "current target does not have razor_coral applied"
end
return true
end,
handler = function ()
if active_dot.razor_coral > 0 then
removeDebuff( "target", "razor_coral" )
active_dot.razor_coral = 0
applyBuff( "razor_coral_crit" )
setCooldown( "ashvanes_razor_coral", 20 )
else
applyDebuff( "target", "razor_coral" )
end
end
} )
local f = CreateFrame("Frame")
f:RegisterEvent( "COMBAT_LOG_EVENT_UNFILTERED" )
f:RegisterEvent( "PLAYER_REGEN_ENABLED" )
f:SetScript("OnEvent", function( event )
if not state.equipped.ashvanes_razor_coral then return end
if event == "COMBAT_LOG_EVENT_UNFILTERED" then
local _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName = CombatLogGetCurrentEventInfo()
if sourceGUID == state.GUID and ( subtype == "SPELL_AURA_APPLIED" or subtype == "SPELL_AURA_REFRESH" or subtype == "SPELL_AURA_APPLIED_DOSE" ) then
if spellID == 303568 and destGUID then
coralGUID = destGUID
coralApplied = GetTime()
coralStacks = ( subtype == "SPELL_AURA_APPLIED_DOSE" ) and ( coralStacks + 1 ) or 1
elseif spellID == 303570 then
-- Coral was removed.
coralGUID = "none"
coralApplied = 0
coralStacks = 0
end
end
else
coralGUID = "none"
coralApplied = 0
coralStacks = 0
end
end )
Hekili:ProfileFrame( "RazorCoralFrame", f )
all:RegisterStateExpr( "coral_time_to_30", function()
if coralGUID == 0 then return 3600 end
return Hekili:GetTimeToPctByGUID( coralGUID, 30 ) - ( offset + delay )
end )
all:RegisterAuras( {
razor_coral = {
id = 303568,
duration = 120,
max_stack = 100, -- ???
copy = "razor_coral_debuff",
generate = function( t, auraType )
local name, icon, count, debuffType, duration, expirationTime, caster, stealable, nameplateShowPersonal, spellID, canApplyAura, isBossDebuff, nameplateShowAll, timeMod, value1, value2, value3 = FindUnitDebuffByID( "target", 303568, "PLAYER" )
if name then
-- It's on our actual target, trust it.
t.name = name
t.count = count > 0 and count or 1
t.expires = expirationTime
t.applied = expirationTime - duration
t.caster = "player"
coralGUID = state.target.unit
coralApplied = expirationTime - duration
coralStacks = count > 0 and count or 1
return
elseif coralGUID ~= "none" then
t.name = class.auras.razor_coral.name
t.count = coralStacks > 0 and coralStacks or 1
t.applied = coralApplied > 0 and coralApplied or state.query_time
t.expires = coralApplied > 0 and ( coralApplied + 120 ) or ( state.query_time + Hekili:GetDeathClockByGUID( coralGUID ) )
t.caster = "player"
return
end
t.name = class.auras.razor_coral.name
t.count = 0
t.applied = 0
t.expires = 0
t.caster = "nobody"
end,
},
razor_coral_crit = {
id = 303570,
duration = 20,
max_stack = 1,
}
} )
end
-- Dribbling Inkpod
all:RegisterAura( "conductive_ink", {
id = 302565,
duration = 60,
max_stack = 999, -- ???
copy = "conductive_ink_debuff"
} )
-- Edicts of the Faithless, 169315
-- Vision of Demise, 169307
all:RegisterAbility( "vision_of_demise", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 169307,
toggle = "cooldowns",
handler = function ()
applyBuff( "vision_of_demise" )
end
} )
all:RegisterAura( "vision_of_demise", {
id = 303431,
duration = 10,
max_stack = 1
} )
-- Aquipotent Nautilus, 169305
all:RegisterAbility( "aquipotent_nautilus", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 169305,
toggle = "cooldowns",
handler = function ()
applyDebuff( "target", "surging_flood" )
end
} )
all:RegisterAura( "surging_flood", {
id = 302580,
duration = 4,
max_stack = 1
} )
-- Chain of Suffering, 169308
all:RegisterAbility( "chain_of_suffering", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 169308,
toggle = "defensives",
handler = function ()
applyBuff( "chain_of_suffering" )
end,
} )
all:RegisterAura( "chain_of_suffering", {
id = 297036,
duration = 25,
max_stack = 1
} )
-- Mechagon
do
all:RegisterGear( "pocketsized_computation_device", 167555 )
all:RegisterGear( "cyclotronic_blast", 167672 )
all:RegisterGear( "harmonic_dematerializer", 167677 )
all:RegisterAura( "cyclotronic_blast", {
id = 293491,
duration = function () return 2.5 * haste end,
max_stack = 1
} )
--[[ all:RegisterAbility( "pocketsized_computation_device", {
-- key = "pocketsized_computation_device",
cast = 0,
cooldown = 120,
gcd = "spell",
-- item = 167555,
texture = 2115322,
bind = { "cyclotronic_blast", "harmonic_dematerializer", "inactive_red_punchcard" },
startsCombat = true,
unlisted = true,
usable = function() return false, "no supported red punchcard installed" end,
copy = "inactive_red_punchcard"
} ) ]]
all:RegisterAbility( "cyclotronic_blast", {
id = 293491,
known = function () return equipped.cyclotronic_blast end,
cast = function () return 1.5 * haste end,
channeled = function () return cooldown.cyclotronic_blast.remains > 0 end,
cooldown = function () return equipped.cyclotronic_blast and 120 or 0 end,
gcd = "spell",
item = 167672,
itemCd = 167555,
itemKey = "cyclotronic_blast",
texture = 2115322,
bind = { "pocketsized_computation_device", "inactive_red_punchcard", "harmonic_dematerializer" },
startsCombat = true,
toggle = "cooldowns",
usable = function ()
return equipped.cyclotronic_blast, "punchcard not equipped"
end,
handler = function()
setCooldown( "global_cooldown", 2.5 * haste )
applyBuff( "casting", 2.5 * haste )
end,
copy = "pocketsized_computation_device"
} )
all:RegisterAura( "harmonic_dematerializer", {
id = 293512,
duration = 300,
max_stack = 99
} )
all:RegisterAbility( "harmonic_dematerializer", {
id = 293512,
known = function () return equipped.harmonic_dematerializer end,
cast = 0,
cooldown = 15,
gcd = "spell",
item = 167677,
itemCd = 167555,
itemKey = "harmonic_dematerializer",
texture = 2115322,
bind = { "pocketsized_computation_device", "cyclotronic_blast", "inactive_red_punchcard" },
startsCombat = true,
usable = function ()
return equipped.harmonic_dematerializer, "punchcard not equipped"
end,
handler = function ()
addStack( "harmonic_dematerializer", nil, 1 )
end
} )
-- Hyperthread Wristwraps
all:RegisterAbility( "hyperthread_wristwraps", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 168989,
handler = function ()
-- Gain 5 seconds of CD for the last 3 spells.
for i = 1, 3 do
local ability = prev[i].spell
if ability and ability ~= "no_action" then
gainChargeTime( ability, 5 )
end
end
end,
copy = "hyperthread_wristwraps_300142"
} )
all:RegisterAbility( "neural_synapse_enhancer", {
cast = 0,
cooldown = 45,
gcd = "off",
item = 168973,
handler = function ()
applyBuff( "enhance_synapses" )
end,
copy = "enhance_synapses_300612"
} )
all:RegisterAura( "enhance_synapses", {
id = 300612,
duration = 15,
max_stack = 1
} )
end
-- Shockbiter's Fang
all:RegisterAbility( "shockbiters_fang", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 169318,
toggle = "cooldowns",
handler = function () applyBuff( "shockbitten" ) end
} )
all:RegisterAura( "shockbitten", {
id = 303953,
duration = 12,
max_stack = 1
} )
all:RegisterAbility( "living_oil_canister", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 158216,
})
-- Remote Guidance Device, 169769
all:RegisterAbility( "remote_guidance_device", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 169769,
toggle = "cooldowns",
} )
-- Modular Platinum Plating, 168965
all:RegisterAbility( "modular_platinum_plating", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 168965,
toggle = "defensives",
handler = function ()
applyBuff( "platinum_plating", nil, 4 )
end
} )
all:RegisterAura( "platinum_plating", {
id = 299869,
duration = 30,
max_stack = 4
} )
-- Crucible
all:RegisterAbility( "pillar_of_the_drowned_cabal", {
cast = 0,
cooldown = 30,
gcd = "spell", -- ???
item = 167863,
toggle = "defensives", -- ???
handler = function () applyBuff( "mariners_ward" ) end
} )
all:RegisterAura( "mariners_ward", {
id = 295411,
duration = 90,
max_stack = 1,
} )
-- Abyssal Speaker's Guantlets (PROC)
all:RegisterAura( "ephemeral_vigor", {
id = 295431,
duration = 60,
max_stack = 1
} )
-- Fathom Dredgers (PROC)
all:RegisterAura( "dredged_vitality", {
id = 295134,
duration = 8,
max_stack = 1
} )
-- Gloves of the Undying Pact
all:RegisterAbility( "gloves_of_the_undying_pact", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 167219,
toggle = "defensives", -- ???
handler = function() applyBuff( "undying_pact" ) end
} )
all:RegisterAura( "undying_pact", {
id = 295193,
duration = 6,
max_stack = 1
} )
-- Insurgent's Scouring Chain (PROC)
all:RegisterAura( "scouring_wake", {
id = 295141,
duration = 20,
max_stack = 1
} )
-- Mindthief's Eldritch Clasp (PROC)
all:RegisterAura( "phantom_pain", {
id = 295527,
duration = 180,
max_stack = 1,
} )
-- Leggings of the Aberrant Tidesage
-- HoT spell ID not found.
-- Zaxasj's Deepstriders (EFFECT)
all:RegisterAura( "deepstrider", {
id = 295167,
duration = 3600,
max_stack = 1
} )
-- Trident of Deep Ocean
-- Custody of the Deep (shield proc)
all:RegisterAura( "custody_of_the_deep_shield", {
id = 292675,
duration = 40,
max_stack = 1
} )
-- Custody of the Deep (mainstat proc)
all:RegisterAura( "custody_of_the_deep_buff", {
id = 292653,
duration = 60,
max_stack = 3
} )
-- Malformed Herald's Legwraps
all:RegisterAbility( "malformed_heralds_legwraps", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 167835,
toggle = "cooldowns",
usable = function () return buff.movement.down end,
handler = function () applyBuff( "void_embrace" ) end,
} )
all:RegisterAura( "void_embrace", {
id = 295174,
duration = 12,
max_stack = 1,
} )
-- Idol of Indiscriminate Consumption
all:RegisterAbility( "idol_of_indiscriminate_consumption", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 167868,
toggle = "cooldowns",
handler = function() gain( 2.5 * 7000 * active_enemies, "health" ) end,
} )
-- Lurker's Insidious Gift
all:RegisterAbility( "lurkers_insidious_gift", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 167866,
toggle = "cooldowns",
handler = function ()
applyBuff( "insidious_gift" )
applyDebuff( "suffering" )
end
} )
all:RegisterAura( "insidious_gift", {
id = 295408,
duration = 30,
max_stack = 1
} )
all:RegisterAura( "suffering", {
id = 295413,
duration = 30,
max_stack = 30,
meta = {
stack = function ()
return buff.insidious_gift.up and floor( 30 - buff.insidious_gift.remains ) or 0
end
}
} )
-- Void Stone
all:RegisterAbility( "void_stone", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 167865,
toggle = "defensives",
handler = function ()
applyBuff( "umbral_shell" )
end,
} )
all:RegisterAura( "umbral_shell", {
id = 295271,
duration = 12,
max_stack = 1
} )
-- ON USE
-- Kezan Stamped Bijou
all:RegisterAbility( "kezan_stamped_bijou", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 165662,
toggle = "cooldowns",
handler = function () applyBuff( "kajamite_surge" ) end
} )
all:RegisterAura( "kajamite_surge", {
id = 285475,
duration = 12,
max_stack = 1,
} )
-- Sea Giant's Tidestone
all:RegisterAbility( "sea_giants_tidestone", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 165664,
toggle = "cooldowns",
handler = function () applyBuff( "ferocity_of_the_skrog" ) end
} )
all:RegisterAura( "ferocity_of_the_skrog", {
id = 285482,
duration = 12,
max_stack = 1
} )
-- Ritual Feather
all:RegisterAbility( "ritual_feather_of_unng_ak", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 165665,
toggle = "cooldowns",
handler = function () applyBuff( "might_of_the_blackpaw" ) end
} )
all:RegisterAura( "might_of_the_blackpaw", {
id = 285489,
duration = 16,
max_stack = 1
} )
-- Battle of Dazar'alor
all:RegisterAbility( "invocation_of_yulon", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 165568,
toggle = "cooldowns",
} )
all:RegisterAbility( "ward_of_envelopment", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 165569,
toggle = "defensives",
handler = function() applyBuff( "enveloping_protection" ) end
} )
all:RegisterAura( "enveloping_protection", {
id = 287568,
duration = 10,
max_stack = 1
} )
-- Everchill Anchor debuff.
all:RegisterAura( "everchill", {
id = 289525,
duration = 12,
max_stack = 10
} )
-- Incandescent Sliver
all:RegisterAura( "incandescent_luster", {
id = 289523,
duration = 20,
max_stack = 10
} )
all:RegisterAura( "incandescent_mastery", {
id = 289524,
duration = 20,
max_stack = 1
} )
all:RegisterAbility( "variable_intensity_gigavolt_oscillating_reactor", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 165572,
toggle = "cooldowns",
buff = "vigor_engaged",
usable = function ()
if buff.vigor_engaged.stack < 6 then return false, "has fewer than 6 stacks" end
return true
end,
handler = function() applyBuff( "oscillating_overload" ) end
} )
all:RegisterAura( "vigor_engaged", {
id = 287916,
duration = 3600,
max_stack = 6
-- May need to emulate the stacking portion.
} )
all:RegisterAura( "vigor_cooldown", {
id = 287967,
duration = 6,
max_stack = 1
} )
all:RegisterAura( "oscillating_overload", {
id = 287917,
duration = 6,
max_stack = 1
} )
-- Diamond-Laced Refracting Prism
all:RegisterAura( "diamond_barrier", {
id = 288034,
duration = 10,
max_stack = 1
} )
all:RegisterAbility( "grongs_primal_rage", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 165574,
toggle = "cooldowns",
handler = function()
applyBuff( "primal_rage" )
setCooldown( "global_cooldown", 4 )
end
} )
all:RegisterAura( "primal_rage", {
id = 288267,
duration = 4,
max_stack = 1
} )
all:RegisterAbility( "tidestorm_codex", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 165576,
toggle = "cooldowns",
} )
-- Bwonsamdi's Bargain
all:RegisterAura( "bwonsamdis_due", {
id = 288193,
duration = 300,
max_stack = 1
} )
all:RegisterAura( "bwonsamdis_bargain_fulfilled", {
id = 288194,
duration = 360,
max_stack = 1
} )
all:RegisterAbility( "mirror_of_entwined_fate", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 165578,
toggle = "defensives",
handler = function() applyDebuff( "player", "mirror_of_entwined_fate" ) end
} )
all:RegisterAura( "mirror_of_entwined_fate", {
id = 287999,
duration = 30,
max_stack = 1
} )
-- Kimbul's Razor Claw
all:RegisterAura( "kimbuls_razor_claw", {
id = 288330,
duration = 6,
tick_time = 2,
max_stack = 1
} )
all:RegisterAbility( "ramping_amplitude_gigavolt_engine", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 165580,
toggle = "cooldowns",
handler = function() applyBuff( "r_a_g_e" ) end
} )
all:RegisterAura( "rage", {
id = 288156,
duration = 18,
max_stack = 15,
copy = "r_a_g_e"
} )
-- Crest of Pa'ku
all:RegisterAura( "gift_of_wind", {
id = 288304,
duration = 15,
max_stack = 1
} )
all:RegisterAbility( "endless_tincture_of_fractional_power", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 152636,
toggle = "cooldowns",
handler = function ()
-- I don't know the auras it applies...
end
} )
all:RegisterAbility( "mercys_psalter", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 155564,
toggle = "cooldowns",
handler = function ()
applyBuff( "potency" )
end,
} )
all:RegisterAura( "potency", {
id = 268523,
duration = 15,
max_stack = 1,
} )
all:RegisterAbility( "clockwork_resharpener", {
cast = 0,
cooldown = 60, -- no CD reported in-game yet.
gcd = "off",
item = 161375,
toggle = "cooldowns",
handler = function ()
applyBuff( "resharpened" )
end,
} )
all:RegisterAura( "resharpened", {
id = 278376,
duration = 14,
max_stack = 7,
meta = {
-- Stacks every 2 seconds until expiration; should generalize this kind of thing...
stacks = function ( aura )
if aura.up then return 1 + floor( ( query_time - aura.applied ) / 2 ) end
return 0
end
}
} )
all:RegisterAbility( "azurethos_singed_plumage", {
cast = 0,
cooldown = 88,
gcd = "off",
item = 161377,
toggle = "cooldowns",
handler = function ()
applyBuff( "ruffling_tempest" )
end,
} )
all:RegisterAura( "ruffling_tempest", {
id = 278383,
duration = 15,
max_stack = 1,
-- Actually decrements but doesn't appear to use stacks to implement itself.
} )
all:RegisterAbility( "galecallers_beak", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 161379,
toggle = "cooldowns",
handler = function ()
applyBuff( "gale_call" )
end,
} )
all:RegisterAura( "gale_call", {
id = 278385,
duration = 15,
max_stack = 1,
} )
all:RegisterAbility( "sublimating_iceshard", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 161382,
toggle = "cooldowns",
handler = function ()
applyBuff( "sublimating_power" )
end,
} )
all:RegisterAura( "sublimating_power", {
id = 278869,
duration = 14,
max_stack = 1,
-- Decrements after 6 sec but doesn't appear to use stacks to convey this...
} )
all:RegisterAbility( "tzanes_barkspines", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 161411,
toggle = "cooldowns",
handler = function ()
applyBuff( "barkspines" )
end,
} )
all:RegisterAura( "barkspines", {
id = 278227,
duration = 10,
max_stack = 1,
} )
--[[ Redundant Ancient Knot of Wisdom???
all:RegisterAbility( "sandscoured_idol", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 161417,
toggle = "cooldowns",
handler = function ()
applyBuff( "secrets_of_the_sands" )
end,
} )
all:RegisterAura( "secrets_of_the_sands", {
id = 278267,
duration = 20,
max_stack = 1,
} ) ]]
all:RegisterAbility( "deployable_vibro_enhancer", {
cast = 0,
cooldown = 105,
gcd = "off",
item = 161418,
toggle = "cooldowns",
handler = function ()
applyBuff( "vibro_enhanced" )
end,
} )
all:RegisterAura( "vibro_enhanced", {
id = 278260,
duration = 12,
max_stack = 4,
meta = {
-- Stacks every 2 seconds until expiration; should generalize this kind of thing...
stacks = function ( aura )
if aura.up then return 1 + floor( ( query_time - aura.applied ) / 3 ) end
return 0
end
}
} )
all:RegisterAbility( "dooms_wake", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 161462,
toggle = "cooldowns",
handler = function ()
applyBuff( "dooms_wake" )
end,
} )
all:RegisterAura( "dooms_wake", {
id = 278317,
duration = 16,
max_stack = 1
} )
all:RegisterAbility( "dooms_fury", {
cast = 0,
cooldown = 105,
gcd = "off",
item = 161463,
toggle = "cooldowns",
handler = function ()
applyBuff( "bristling_fury" )
end,
} )
all:RegisterAura( "bristling_fury", {
id = 278364,
duration = 18,
max_stack = 1,
} )
all:RegisterAbility( "lions_guile", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 161473,
toggle = "cooldowns",
handler = function ()
applyBuff( "lions_guile" )
end,
} )
all:RegisterAura( "lions_guile", {
id = 278806,
duration = 16,
max_stack = 10,
meta = {
stack = function( t ) return t.down and 0 or min( 6, 1 + ( ( query_time - t.app ) / 2 ) ) end,
}
} )
all:RegisterAbility( "lions_strength", {
cast = 0,
cooldown = 105,
gcd = "off",
item = 161474,
toggle = "cooldowns",
handler = function ()
applyBuff( "lions_strength" )
end,
} )
all:RegisterAura( "lions_strength", {
id = 278819,
duration = 18,
max_stack = 1,
} )
all:RegisterAbility( "mr_munchykins", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 155567,
toggle = "cooldowns",
handler = function ()
applyBuff( "tea_time" )
end,
} )
all:RegisterAura( "tea_time", {
id = 268504,
duration = 15,
max_stack = 1,
} )
all:RegisterAbility( "bygone_bee_almanac", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 163936,
toggle = "cooldowns",
handler = function ()
applyBuff( "process_improvement" )
end,
} )
all:RegisterAura( "process_improvement", {
id = 281543,
duration = 12,
max_stack = 1,
} ) -- extends on spending resources, could hook here...
all:RegisterAbility( "mydas_talisman", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 158319,
toggle = "cooldowns",
handler = function ()
applyBuff( "touch_of_gold" )
end,
} )
all:RegisterAura( "touch_of_gold", {
id = 265954,
duration = 20,
max_stack = 1,
} )
all:RegisterAbility( "merekthas_fang", {
cast = 3,
channeled = true,
cooldown = 120,
gcd = "off",
item = 158367,
toggle = "cooldowns",
-- not sure if this debuffs during the channel...
} )
all:RegisterAbility( "razdunks_big_red_button", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 159611,
toggle = "cooldowns",
velocity = 10,
} )
all:RegisterAbility( "galecallers_boon", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 159614,
toggle = "cooldowns",
usable = function () return buff.movement.down end,
handler = function ()
applyBuff( "galecallers_boon" )
end,
} )
all:RegisterAura( "galecallers_boon", {
id = 268311,
duration = 10,
max_stack = 1,
meta = {
remains = function( t ) return max( 0, action.galecallers_boon.lastCast + 10 - query_time ) end
}
} )
all:RegisterAbility( "ignition_mages_fuse", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 159615,
toggle = "cooldowns",
handler = function ()
applyBuff( "ignition_mages_fuse" )
end,
} )
all:RegisterAura( "ignition_mages_fuse", {
id = 271115,
duration = 20,
max_stack = 1,
} )
all:RegisterAbility( "lustrous_golden_plumage", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 159617,
toggle = "cooldowns",
handler = function ()
applyBuff( "golden_luster" )
end,
} )
all:RegisterAura( "golden_luster", {
id = 271107,
duration = 20,
max_stack = 1,
} )
all:RegisterAbility( "mchimbas_ritual_bandages", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 159618,
toggle = "defensives",
handler = function ()
applyBuff( "ritual_wraps" )
end,
} )
all:RegisterAura( "ritual_wraps", {
id = 265946,
duration = 6,
max_stack = 1,
} )
all:RegisterAbility( "rotcrusted_voodoo_doll", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 159624,
toggle = "cooldowns",
handler = function ()
applyDebuff( "target", "rotcrusted_voodoo_doll" )
end,
} )
all:RegisterAura( "rotcrusted_voodoo_doll", {
id = 271465,
duration = 6,
max_stack = 1,
} )
all:RegisterAbility( "vial_of_animated_blood", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 159625,
toggle = "cooldowns",
handler = function ()
applyBuff( "blood_of_my_enemies" )
end,
} )
all:RegisterAura( "blood_of_my_enemies", {
id = 268836,
duration = 18,
max_stack = 1,
} )
all:RegisterAbility( "jes_howler", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 159627,
toggle = "cooldowns",
handler = function ()
applyBuff( "motivating_howl" )
end,
} )
all:RegisterAura( "motivating_howl", {
id = 266047,
duration = 12,
max_stack = 1,
} )
all:RegisterAbility( "balefire_branch", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 159630,
toggle = "cooldowns",
handler = function ()
applyBuff( "kindled_soul" )
end,
} )
all:RegisterAura( "kindled_soul", {
id = 268998,
duration = 20,
max_stack = 1,
} )
all:RegisterAbility( "sanguinating_totem", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 160753,
toggle = "defensives",
} )
all:RegisterAbility( "fetish_of_the_tormented_mind", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 160833,
toggle = "defensives",
handler = function ()
applyDebuff( "target", "doubting_mind" )
end,
} )
all:RegisterAura( "doubting_mind", {
id = 273559,
duration = 5,
max_stack = 1
} )
all:RegisterAbility( "whirlwings_plumage", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 158215,
toggle = "cooldowns",
handler = function ()
applyBuff( "gryphons_pride" )
end,
} )
all:RegisterAura( "gryphons_pride", {
id = 268550,
duration = 20,
max_stack = 1,
} )
-- PvP Trinkets
-- Medallions
do
local pvp_medallions = {
{ "dread_aspirants_medallion", 162897 },
{ "dread_gladiators_medallion", 161674 },
{ "sinister_aspirants_medallion", 165220 },
{ "sinister_gladiators_medallion", 165055 },
{ "notorious_aspirants_medallion", 167525 },
{ "notorious_gladiators_medallion", 167377 },
{ "old_corrupted_gladiators_medallion", 172666 },
{ "corrupted_aspirants_medallion", 184058 },
{ "corrupted_gladiators_medallion", 184055 },
{ "sinful_aspirants_medallion", 184052 },
{ "sinful_gladiators_medallion", 181333 },
{ "unchained_aspirants_medallion", 185309 },
{ "unchained_gladiators_medallion", 185304 },
}
local pvp_medallions_copy = {}
for _, v in ipairs( pvp_medallions ) do
insert( pvp_medallions_copy, v[1] )
all:RegisterGear( v[1], v[2] )
all:RegisterGear( "gladiators_medallion", v[2] )
end
all:RegisterAbility( "gladiators_medallion", {
cast = 0,
cooldown = 120,
gcd = "off",
item = function ()
local m
for _, medallion in ipairs( pvp_medallions ) do
m = medallion[ 2 ]
if equipped[ m ] then return m end
end
return m
end,
items = { 162897, 161674, 165220, 165055, 167525, 167525, 167377, 172666, 184058, 184055, 184052, 181333, 185309, 185304 },
toggle = "defensives",
usable = function () return debuff.loss_of_control.up, "requires loss of control effect" end,
handler = function ()
applyBuff( "gladiators_medallion" )
end,
copy = pvp_medallions_copy
} )
all:RegisterAura( "gladiators_medallion", {
id = 277179,
duration = 20,
max_stack = 1
} )
end
-- Badges
do
local pvp_badges = {
{ "dread_aspirants_badge", 162966 },
{ "dread_gladiators_badge", 161902 },
{ "sinister_aspirants_badge", 165223 },
{ "sinister_gladiators_badge", 165058 },
{ "notorious_aspirants_badge", 167528 },
{ "notorious_gladiators_badge", 167380 },
{ "corrupted_aspirants_badge", 172849 },
{ "corrupted_gladiators_badge", 172669 },
{ "sinful_aspirants_badge_of_ferocity", 175884 },
{ "sinful_gladiators_badge_of_ferocity", 175921 },
{ "unchained_aspirants_badge_of_ferocity", 185161 },
{ "unchained_gladiators_badge_of_ferocity", 185197 },
}
local pvp_badges_copy = {}
for _, v in ipairs( pvp_badges ) do
insert( pvp_badges_copy, v[1] )
all:RegisterGear( v[1], v[2] )
all:RegisterGear( "gladiators_badge", v[2] )
end
all:RegisterAbility( "gladiators_badge", {
cast = 0,
cooldown = 120,
gcd = "off",
item = function ()
local b
for _, badge in ipairs( pvp_badges ) do
b = badge[ 2 ]
if equipped[ b ] then return b end
end
return b
end,
items = { 162966, 161902, 165223, 165058, 167528, 167528, 167380, 172849, 172669, 175884, 175921, 185161, 185197 },
toggle = "cooldowns",
handler = function ()
applyBuff( "gladiators_badge" )
end,
copy = pvp_badges_copy
} )
all:RegisterAura( "gladiators_badge", {
id = 277185,
duration = 15,
max_stack = 1
} )
end
-- Insignias -- N/A, not on-use.
all:RegisterAura( "gladiators_insignia", {
id = 277181,
duration = 20,
max_stack = 1,
copy = 345230
} )
-- Safeguard (equipped, not on-use)
all:RegisterAura( "gladiators_safeguard", {
id = 286342,
duration = 10,
max_stack = 1
} )
-- Emblems
do
local pvp_emblems = {
dread_combatants_emblem = 161812,
dread_aspirants_emblem = 162898,
dread_gladiators_emblem = 161675,
sinister_aspirants_emblem = 165221,
sinister_gladiators_emblem = 165056,
notorious_gladiators_emblem = 167378,
notorious_aspirants_emblem = 167526,
corrupted_gladiators_emblem = 172667,
corrupted_aspirants_emblem = 172847,
sinful_aspirants_emblem = 178334,
sinful_gladiators_emblem = 178447,
unchained_aspirants_emblem = 185242,
unchained_gladiators_emblem = 185282,
}
local pvp_emblems_copy = {}
for k, v in pairs( pvp_emblems ) do
insert( pvp_emblems_copy, k )
all:RegisterGear( k, v )
all:RegisterGear( "gladiators_emblem", v )
end
all:RegisterAbility( "gladiators_emblem", {
cast = 0,
cooldown = 90,
gcd = "off",
item = function ()
local e
for _, emblem in pairs( pvp_emblems ) do
e = emblem
if equipped[ e ] then return e end
end
return e
end,
items = { 161812, 162898, 161675, 165221, 165056, 167378, 167526, 172667, 172847, 178334, 178447, 185242, 185282 },
toggle = "cooldowns",
handler = function ()
applyBuff( "gladiators_emblem" )
end,
copy = pvp_emblems_copy
} )
all:RegisterAura( "gladiators_emblem", {
id = 277187,
duration = 15,
max_stack = 1,
} )
end
-- 8.3 Corrupted On-Use
-- DNI, because potentially you have no enemies w/ Corruption w/in range.
--[[
all:RegisterAbility( "corrupted_gladiators_breach", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 174276,
toggle = "defensives",
handler = function ()
applyBuff( "void_jaunt" )
-- +Debuff?
end,
auras = {
void_jaunt = {
id = 314517,
duration = 6,
max_stack = 1,
}
}
} )
]]
all:RegisterAbility( "corrupted_gladiators_spite", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 174472,
toggle = "cooldowns",
handler = function ()
applyDebuff( "target", "gladiators_spite" )
applyDebuff( "target", "lingering_spite" )
end,
auras = {
gladiators_spite = {
id = 315391,
duration = 15,
max_stack = 1,
},
lingering_spite = {
id = 320297,
duration = 3600,
max_stack = 1,
}
}
} )
all:RegisterAbility( "corrupted_gladiators_maledict", {
cast = 0,
cooldown = 120,
gcd = "off", -- ???
item = 172672,
toggle = "cooldowns",
handler = function ()
applyDebuff( "target", "gladiators_maledict" )
end,
auras = {
gladiators_maledict = {
id = 305252,
duration = 6,
max_stack = 1
}
}
} )
--[[ WiP: Timewarped Trinkets
do
local timewarped_trinkets = {
{ "runed_fungalcap", 127184, "shell_of_deterrence", 31771, 20, 1 },
{ "icon_of_the_silver_crescent", 129850, "blessing_of_the_silver_crescent", 194645, 20, 1 },
{ "essence_of_the_martyr", 129851, "essence_of_the_martyr", 194637, 20, 1 },
{ "gnomeregan_autoblocker_601", 129849, "gnome_ingenuity", 194543, 40, 1 },
{ "emblem_of_fury", 129937, "lust_for_battle_str", 194638, 20, 1 },
{ "bloodlust_brooch", 129848, "lust_for_battle_agi", 194632, 20, 1 },
{}
}
{ "vial_of_the_sunwell", 133462, "vessel_of_the_naaru", 45059, 3600, 1 }, -- vessel_of_the_naaru on-use 45064, 120 sec CD.
end ]]
-- Galewind Chimes
all:RegisterAura( "galewind_chimes", {
id = 268518,
duration = 8,
max_stack = 1,
} )
-- Gilded Loa Figurine
all:RegisterAura( "will_of_the_loa", {
id = 273974,
duration = 10,
max_stack = 1,
} )
-- Emblem of Zandalar
all:RegisterAura( "speed_of_the_spirits", {
id = 273992,
duration = 8,
max_stack = 1,
} )
-- Dinobone Charm
all:RegisterAura( "primal_instinct", {
id = 273988,
duration = 7,
max_stack = 1
} )
all:RegisterAbility( "pearl_divers_compass", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 158162,
toggle = "cooldowns",
handler = function ()
applyBuff( "true_north" )
end,
} )
all:RegisterAura( "true_north", {
id = 273935,
duration = 12,
max_stack = 1,
} )
all:RegisterAbility( "first_mates_spyglass", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 158163,
toggle = "cooldowns",
handler = function ()
applyBuff( "spyglass_sight" )
end,
} )
all:RegisterAura( "spyglass_sight", {
id = 273955,
duration = 15,
max_stack = 1
} )
all:RegisterAbility( "plunderbeards_flask", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 158164,
toggle = "cooldowns",
handler = function ()
applyBuff( "bolstered_spirits" )
end,
} )
all:RegisterAura( "bolstered_spirits", {
id = 273942,
duration = 10,
max_stack = 10,
} )
all:RegisterAbility( "living_oil_cannister", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 158216,
toggle = "cooldowns",
} )
all:RegisterAura( "sound_barrier", {
id = 268531,
duration = 8,
max_stack = 1,
} )
all:RegisterAbility( "vial_of_storms", {
cast = 0,
cooldown = 90,
gcd = "off",
item = 158224,
toggle = "cooldowns",
} )
all:RegisterAura( "sirens_melody", {
id = 268512,
duration = 6,
max_stack = 1,
} )
all:RegisterAura( "tick", {
id = 274430,
duration = 6,
max_stack = 1,
} )
all:RegisterAura( "tock", {
id = 274431,
duration = 6,
max_stack = 1,
} )
all:RegisterAura( "soulguard", {
id = 274459,
duration = 12,
max_stack = 1,
} )
all:RegisterAbility( "berserkers_juju", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 161117,
toggle = "cooldowns",
handler = function ()
applyBuff( "berserkers_frenzy" )
end,
} )
all:RegisterAura( "berserkers_frenzy", {
id = 274472,
duration = 10,
max_stack = 1,
} )
all:RegisterGear( "ancient_knot_of_wisdom", 161417, 166793 )
all:RegisterAbility( "ancient_knot_of_wisdom", {
cast = 0,
cooldown = 60,
gcd = "off",
item = function ()
if equipped[161417] then return 161417 end
return 166793
end,
items = { 167417, 166793 },
toggle = "cooldowns",
handler = function ()
applyBuff( "wisdom_of_the_forest_lord" )
end,
} )
all:RegisterAura( "wisdom_of_the_forest_lord", {
id = 278267,
duration = 20,
max_stack = 5
} )
all:RegisterAbility( "knot_of_ancient_fury", {
cast = 0,
cooldown = 60,
gcd = "off",
item = 166795,
toggle = "cooldowns",
handler = function ()
applyBuff( "fury_of_the_forest_lord" )
end,
} )
all:RegisterAura( "fury_of_the_forest_lord", {
id = 278231,
duration = 12,
max_stack = 1
} )
-- BREWFEST
all:RegisterAbility( "brawlers_statue", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 117357,
toggle = "defensives",
handler = function ()
applyBuff( "drunken_evasiveness" )
end
} )
all:RegisterAura( "drunken_evasiveness", {
id = 127967,
duration = 20,
max_stack = 1
} )
-- Various Timewalking Trinkets
all:RegisterAbility( "wrathstone", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 45263,
toggle = "cooldowns",
handler = function ()
applyBuff( "wrathstone" )
end,
auras = {
wrathstone = {
id = 64800,
duration = 20,
max_stack = 1
}
}
} )
all:RegisterAbility( "skardyns_grace", {
cast = 0,
cooldown = 120,
gcd = "off",
item = 133282,
toggle = "cooldowns",
handler = function ()
applyBuff( "speed_of_thought" )
end,
auras = {
speed_of_thought = {
id = 92099,
duration = 35,
max_stack = 1
}
}
} )
-- HALLOW'S END
all:RegisterAbility( "the_horsemans_sinister_slicer", {
cast = 0,
cooldown = 600,
gcd = "off",
item = 117356,
toggle = "cooldowns",
} )
-- LEGION LEGENDARIES
all:RegisterGear( 'rethus_incessant_courage', 146667 )
all:RegisterAura( 'rethus_incessant_courage', { id = 241330 } )
all:RegisterGear( 'vigilance_perch', 146668 )
all:RegisterAura( 'vigilance_perch', { id = 241332, duration = 60, max_stack = 5 } )
all:RegisterGear( 'the_sentinels_eternal_refuge', 146669 )
all:RegisterAura( 'the_sentinels_eternal_refuge', { id = 241331, duration = 60, max_stack = 5 } )
all:RegisterGear( 'prydaz_xavarics_magnum_opus', 132444 )
all:RegisterAura( 'xavarics_magnum_opus', { id = 207428, duration = 30 } )
all:RegisterAbility( "draught_of_souls", {
cast = 0,
cooldown = 80,
gcd = 'off',
item = 140808,
toggle = 'cooldowns',
handler = function ()
applyBuff( "fel_crazed_rage", 3 )
setCooldown( "global_cooldown", 3 )
end,
} )
all:RegisterAura( "fel_crazed_rage", {
id = 225141,
duration = 3,
})
all:RegisterAbility( "faulty_countermeasure", {
cast = 0,
cooldown = 120,
gcd = 'off',
item = 137539,
toggle = 'cooldowns',
handler = function ()
applyBuff( "sheathed_in_frost" )
end
} )
all:RegisterAura( "sheathed_in_frost", {
id = 214962,
duration = 30
} )
all:RegisterAbility( "feloiled_infernal_machine", {
cast = 0,
cooldown = 80,
gcd = 'off',
item = 144482,
toggle = 'cooldowns',
handler = function ()
applyBuff( "grease_the_gears" )
end,
} )
all:RegisterAura( "grease_the_gears", {
id = 238534,
duration = 20
} )
all:RegisterAbility( "ring_of_collapsing_futures", {
item = 142173,
spend = 0,
cast = 0,
cooldown = 15,
gcd = 'off',
readyTime = function () return debuff.temptation.remains end,
handler = function ()
applyDebuff( "player", "temptation", 30, debuff.temptation.stack + 1 )
end
} )
all:RegisterAura( "temptation", {
id = 234143,
duration = 30,
max_stack = 20
} )
all:RegisterAbility( "forgefiends_fabricator", {
item = 151963,
spend = 0,
cast = 0,
cooldown = 30,
gcd = 'off',
} )
all:RegisterAbility( "horn_of_valor", {
item = 133642,
spend = 0,
cast = 0,
cooldown = 120,
gcd = 'off',
toggle = 'cooldowns',
handler = function () applyBuff( "valarjars_path" ) end
} )
all:RegisterAura( "valarjars_path", {
id = 215956,
duration = 30
} )
all:RegisterAbility( "kiljaedens_burning_wish", {
item = 144259,
cast = 0,
cooldown = 75,
gcd = 'off',
texture = 1357805,
toggle = 'cooldowns',
} )
all:RegisterAbility( "might_of_krosus", {
item = 140799,
spend = 0,
cast = 0,
cooldown = 30,
gcd = 'off',
handler = function () if active_enemies > 3 then setCooldown( "might_of_krosus", 15 ) end end
} )
all:RegisterAbility( "ring_of_collapsing_futures", {
item = 142173,
spend = 0,
cast = 0,
cooldown = 15,
gcd = 'off',
readyTime = function () return debuff.temptation.remains end,
handler = function () applyDebuff( "player", "temptation", 30, debuff.temptation.stack + 1 ) end
} )
all:RegisterAura( 'temptation', {
id = 234143,
duration = 30,
max_stack = 20
} )
all:RegisterAbility( "specter_of_betrayal", {
item = 151190,
spend = 0,
cast = 0,
cooldown = 45,
gcd = 'off',
} )
all:RegisterAbility( "tiny_oozeling_in_a_jar", {
item = 137439,
spend = 0,
cast = 0,
cooldown = 20,
gcd = "off",
usable = function () return buff.congealing_goo.stack == 6 end,
handler = function () removeBuff( "congealing_goo" ) end
} )
all:RegisterAura( "congealing_goo", {
id = 215126,
duration = 60,
max_stack = 6
} )
all:RegisterAbility( "umbral_moonglaives", {
item = 147012,
spend = 0,
cast = 0,
cooldown = 90,
gcd = 'off',
toggle = 'cooldowns',
} )
all:RegisterAbility( "unbridled_fury", {
item = 139327,
spend = 0,
cast = 0,
cooldown = 120,
gcd = 'off',
toggle = 'cooldowns',
handler = function () applyBuff( "wild_gods_fury" ) end
} )
all:RegisterAura( "wild_gods_fury", {
id = 221695,
duration = 30
} )
all:RegisterAbility( "vial_of_ceaseless_toxins", {
item = 147011,
spend = 0,
cast = 0,
cooldown = 60,
gcd = 'off',
toggle = 'cooldowns',
handler = function () applyDebuff( "target", "ceaseless_toxin", 20 ) end
} )
all:RegisterAura( "ceaseless_toxin", {
id = 242497,
duration = 20
} )
all:RegisterAbility( "tome_of_unraveling_sanity", {
item = 147019,
spend = 0,
cast = 0,
cooldown = 60,
gcd = "off",
toggle = "cooldowns",
handler = function () applyDebuff( "target", "insidious_corruption", 12 ) end
} )
all:RegisterAura( "insidious_corruption", {
id = 243941,
duration = 12
} )
all:RegisterAura( "extracted_sanity", {
id = 243942,
duration = 24
} )
all:RegisterGear( 'aggramars_stride', 132443 )
all:RegisterAura( 'aggramars_stride', {
id = 207438,
duration = 3600
} )
all:RegisterGear( 'sephuzs_secret', 132452 )
all:RegisterAura( 'sephuzs_secret', {
id = 208051,
duration = 10
} )
all:RegisterAbility( "buff_sephuzs_secret", {
name = "Sephuz's Secret (ICD)",
cast = 0,
cooldown = 30,
gcd = "off",
unlisted = true,
usable = function () return false end,
} )
all:RegisterGear( 'archimondes_hatred_reborn', 144249 )
all:RegisterAura( 'archimondes_hatred_reborn', {
id = 235169,
duration = 10,
max_stack = 1
} )
all:RegisterGear( 'amanthuls_vision', 154172 )
all:RegisterAura( 'glimpse_of_enlightenment', {
id = 256818,
duration = 12
} )
all:RegisterAura( 'amanthuls_grandeur', {
id = 256832,
duration = 15
} )
all:RegisterGear( 'insignia_of_the_grand_army', 152626 )
all:RegisterGear( 'eonars_compassion', 154172 )
all:RegisterAura( 'mark_of_eonar', {
id = 256824,
duration = 12
} )
all:RegisterAura( 'eonars_verdant_embrace', {
id = function ()
if class.file == "SHAMAN" then return 257475 end
if class.file == "DRUID" then return 257470 end
if class.file == "MONK" then return 257471 end
if class.file == "PALADIN" then return 257472 end
if class.file == "PRIEST" then
if spec.discipline then return 257473 end
if spec.holy then return 257474 end
end
return 257475
end,
duration = 20,
copy = { 257470, 257471, 257472, 257473, 257474, 257475 }
} )
all:RegisterAura( 'verdant_embrace', {
id = 257444,
duration = 30
} )
all:RegisterGear( 'aggramars_conviction', 154173 )
all:RegisterAura( 'celestial_bulwark', {
id = 256816,
duration = 14
} )
all:RegisterAura( 'aggramars_fortitude', {
id = 256831,
duration = 15
} )
all:RegisterGear( 'golganneths_vitality', 154174 )
all:RegisterAura( 'golganneths_thunderous_wrath', {
id = 256833,
duration = 15
} )
all:RegisterGear( 'khazgoroths_courage', 154176 )
all:RegisterAura( 'worldforgers_flame', {
id = 256826,
duration = 12
} )
all:RegisterAura( 'khazgoroths_shaping', {
id = 256835,
duration = 15
} )
all:RegisterGear( 'norgannons_prowess', 154177 )
all:RegisterAura( 'rush_of_knowledge', {
id = 256828,
duration = 12
} )
all:RegisterAura( 'norgannons_command', {
id = 256836,
duration = 15,
max_stack = 6
} )
ns.addToggle = function( name, default, optionName, optionDesc )
table.insert( class.toggles, {
name = name,
state = default,
option = optionName,
oDesc = optionDesc
} )
if Hekili.DB.profile[ 'Toggle State: ' .. name ] == nil then
Hekili.DB.profile[ 'Toggle State: ' .. name ] = default
end
end
ns.addSetting = function( name, default, options )
table.insert( class.settings, {
name = name,
state = default,
option = options
} )
if Hekili.DB.profile[ 'Class Option: ' .. name ] == nil then
Hekili.DB.profile[ 'Class Option: ' ..name ] = default
end
end
ns.addWhitespace = function( name, size )
table.insert( class.settings, {
name = name,
option = {
name = " ",
type = "description",
desc = " ",
width = size
}
} )
end
ns.addHook = function( hook, func )
class.hooks[ hook ] = func
end
do
local inProgress = {}
ns.callHook = function( hook, ... )
if class.hooks[ hook ] and not inProgress[ hook ] then
local a1, a2, a3, a4, a5
inProgress[ hook ] = true
for _, hook in ipairs( class.hooks[ hook ] ) do
a1, a2, a3, a4, a5 = hook ( ... )
end
inProgress[ hook ] = nil
if a1 ~= nil then
return a1, a2, a3, a4, a5
else
return ...
end
end
return ...
end
end
ns.registerCustomVariable = function( var, default )
state[ var ] = default
end
ns.setClass = function( name )
-- deprecated.
--class.file = name
end
function ns.setRange( value )
class.range = value
end
local function storeAbilityElements( key, values )
local ability = class.abilities[ key ]
if not ability then
ns.Error( "storeAbilityElements( " .. key .. " ) - no such ability in abilities table." )
return
end
for k, v in pairs( values ) do
ability.elem[ k ] = type( v ) == 'function' and setfenv( v, state ) or v
end
end
ns.storeAbilityElements = storeAbilityElements
local function modifyElement( t, k, elem, value )
local entry = class[ t ][ k ]
if not entry then
ns.Error( "modifyElement() - no such key '" .. k .. "' in '" .. t .. "' table." )
return
end
if type( value ) == 'function' then
entry.mods[ elem ] = setfenv( value, Hekili.State )
else
entry.elem[ elem ] = value
end
end
ns.modifyElement = modifyElement
local function setUsableItemCooldown( cd )
state.setCooldown( "usable_items", cd or 10 )
end
-- For Trinket Settings.
class.itemSettings = {}
local function addItemSettings( key, itemID, options )
options = options or {}
--[[ options.icon = {
type = "description",
name = function () return select( 2, GetItemInfo( itemID ) ) or format( "[%d]", itemID ) end,
order = 1,
image = function ()
local tex = select( 10, GetItemInfo( itemID ) )
if tex then
return tex, 50, 50
end
return nil
end,
imageCoords = { 0.1, 0.9, 0.1, 0.9 },
width = "full",
fontSize = "large"
} ]]
options.disabled = {
type = "toggle",
name = function () return format( "Disable %s via |cff00ccff[Use Items]|r", select( 2, GetItemInfo( itemID ) ) or ( "[" .. itemID .. "]" ) ) end,
desc = function( info )
local output = "If disabled, the addon will not recommend this item via the |cff00ccff[Use Items]|r action. " ..
"You can still manually include the item in your action lists with your own tailored criteria."
return output
end,
order = 25,
width = "full"
}
options.minimum = {
type = "range",
name = "Minimum Targets",
desc = "The addon will only recommend this trinket (via |cff00ccff[Use Items]|r) when there are at least this many targets available to hit.",
order = 26,
width = "full",
min = 1,
max = 10,
step = 1
}
options.maximum = {
type = "range",
name = "Maximum Targets",
desc = "The addon will only recommend this trinket (via |cff00ccff[Use Items]|r) when there are no more than this many targets detected.\n\n" ..
"This setting is ignored if set to 0.",
order = 27,
width = "full",
min = 0,
max = 10,
step = 1
}
class.itemSettings[ itemID ] = {
key = key,
name = function () return select( 2, GetItemInfo( itemID ) ) or ( "[" .. itemID .. "]" ) end,
item = itemID,
options = options,
}
end
--[[ local function addUsableItem( key, id )
class.items = class.items or {}
class.items[ key ] = id
addGearSet( key, id )
addItemSettings( key, id )
end
ns.addUsableItem = addUsableItem ]]
function Hekili:GetAbilityInfo( index )
local ability = class.abilities[ index ]
if not ability then return end
-- Decide if more details are needed later.
return ability.id, ability.name, ability.key, ability.item
end
class.interrupts = {}
local function addPet( key, permanent )
state.pet[ key ] = rawget( state.pet, key ) or {}
state.pet[ key ].name = key
state.pet[ key ].expires = 0
ns.commitKey( key )
end
ns.addPet = addPet
local function addStance( key, spellID )
class.stances[ key ] = spellID
ns.commitKey( key )
end
ns.addStance = addStance
local function setRole( key )
for k,v in pairs( state.role ) do
state.role[ k ] = nil
end
state.role[ key ] = true
end
ns.setRole = setRole
function Hekili:GetActiveSpecOption( opt )
if not self.currentSpecOpts then return end
return self.currentSpecOpts[ opt ]
end
function Hekili:GetActivePack()
return self:GetActiveSpecOption( "package" )
end
local optionsInitialized = false
function Hekili:SpecializationChanged()
local currentSpec = GetSpecialization()
local currentID = GetSpecializationInfo( currentSpec )
if currentID == nil then
C_Timer.After( 0.5, function () Hekili:SpecializationChanged() end )
return
end
for k, _ in pairs( state.spec ) do
state.spec[ k ] = nil
end
for key in pairs( GetResourceInfo() ) do
state[ key ] = nil
class[ key ] = nil
end
class.primaryResource = nil
wipe( state.buff )
wipe( state.debuff )
wipe( class.auras )
wipe( class.abilities )
wipe( class.talents )
wipe( class.pvptalents )
wipe( class.powers )
wipe( class.gear )
wipe( class.packs )
wipe( class.resources )
wipe( class.resourceAuras )
wipe( class.pets )
class.potion = nil
local specs = { 0 }
for i = 1, 4 do
local id, name, _, _, role = GetSpecializationInfo( i )
if not id then break end
if i == currentSpec then
table.insert( specs, 1, id )
state.spec.id = id
state.spec.name = name
state.spec.key = getSpecializationKey( id )
for k in pairs( state.role ) do
state.role[ k ] = false
end
if role == "DAMAGER" then
state.role.attack = true
elseif role == "TANK" then
state.role.tank = true
else
state.role.healer = true
end
state.spec[ state.spec.key ] = true
else
table.insert( specs, id )
end
end
for key in pairs( GetResourceInfo() ) do
state[ key ] = nil
class[ key ] = nil
end
if rawget( state, "rune" ) then state.rune = nil; class.rune = nil; end
for k in pairs( class.resourceAuras ) do
class.resourceAuras[ k ] = nil
end
class.primaryResource = nil
for k in pairs( class.stateTables ) do
rawset( state, k, nil )
class.stateTables[ k ] = nil
end
for k in pairs( class.stateFuncs ) do
rawset( state, k, nil )
class.stateFuncs[ k ] = nil
end
for k in pairs( class.stateExprs ) do
class.stateExprs[ k ] = nil
end
for i, specID in ipairs( specs ) do
local spec = class.specs[ specID ]
if spec then
if specID == currentID then
self.currentSpec = spec
self.currentSpecOpts = self.DB.profile.specs[ specID ]
state.settings.spec = self.DB.profile.specs[ specID ]
state.spec.canCastWhileCasting = spec.canCastWhileCasting
state.spec.castableWhileCasting = spec.castableWhileCasting
for res, model in pairs( spec.resources ) do
class.resources[ res ] = model
state[ res ] = model.state
end
if rawget( state, "runes" ) then state.rune = state.runes end
for k,v in pairs( spec.resourceAuras ) do
class.resourceAuras[ k ] = v
end
class.primaryResource = spec.primaryResource
for talent, id in pairs( spec.talents ) do
class.talents[ talent ] = id
end
for talent, id in pairs( spec.pvptalents ) do
class.pvptalents[ talent ] = id
end
class.hooks = spec.hooks or {}
--[[ for name, func in pairs( spec.hooks ) do
class.hooks[ name ] = func
end ]]
class.variables = spec.variables
class.potionList.default = "|cFFFFD100Default|r"
end
if self.currentSpecOpts and self.currentSpecOpts.potion then
class.potion = self.currentSpecOpts.potion
end
if not class.potion and spec.potion then
class.potion = spec.potion
end
for res, model in pairs( spec.resources ) do
if not class.resources[ res ] then
class.resources[ res ] = model
state[ res ] = model.state
end
end
if rawget( state, "runes" ) then state.rune = state.runes end
for k, v in pairs( spec.auras ) do
if not class.auras[ k ] then class.auras[ k ] = v end
end
for k, v in pairs( spec.powers ) do
if not class.powers[ k ] then class.powers[ k ] = v end
end
for k, v in pairs( spec.abilities ) do
if not class.abilities[ k ] then class.abilities[ k ] = v end
end
for k, v in pairs( spec.gear ) do
if not class.gear[ k ] then class.gear[ k ] = v end
end
for k, v in pairs( spec.pets ) do
if not class.pets[ k ] then class.pets[ k ] = v end
end
for k, v in pairs( spec.totems ) do
if not class.totems[ k ] then class.totems[ k ] = v end
end
for k, v in pairs( spec.potions ) do
if not class.potions[ k ] then
class.potions[ k ] = v
end
if class.potion == k and class.auras[ k ] then class.auras.potion = class.auras[ k ] end
end
for k, v in pairs( spec.packs ) do
if not class.packs[ k ] then class.packs[ k ] = v end
end
for name, func in pairs( spec.stateExprs ) do
if not class.stateExprs[ name ] then
if rawget( state, name ) then state[ name ] = nil end
class.stateExprs[ name ] = func
end
end
for name, func in pairs( spec.stateFuncs ) do
if not class.stateFuncs[ name ] then
if rawget( state, name ) then
Hekili:Error( "Cannot RegisterStateFunc for an existing expression ( " .. spec.name .. " - " .. name .. " )." )
else
class.stateFuncs[ name ] = func
rawset( state, name, func )
-- Hekili:Error( "Not real error, registered " .. name .. " for " .. spec.name .. " (RSF)." )
end
end
end
for name, t in pairs( spec.stateTables ) do
if not class.stateTables[ name ] then
if rawget( state, name ) then
Hekili:Error( "Cannot RegisterStateTable for an existing expression ( " .. spec.name .. " - " .. name .. " )." )
else
class.stateTables[ name ] = t
rawset( state, name, t )
-- Hekili:Error( "Not real error, registered " .. name .. " for " .. spec.name .. " (RST)." )
end
end
end
local s = Hekili.DB.profile.specs[ spec.id ]
for k, v in pairs( spec.options ) do
if s[ k ] == nil then s[ k ] = v end
end
for k, v in pairs( spec.settings ) do
if s.settings[ v.name ] == nil then s.settings[ v.name ] = v.default end
end
end
end
for k in pairs( class.abilityList ) do
local ability = class.abilities[ k ]
if ability and ability.id > 0 then
if not ability.texture or not ability.name then
local name, _, tex = GetSpellInfo( ability.id )
if name and tex then
ability.name = ability.name or name
class.abilityList[ k ] = "|T" .. tex .. ":0|t " .. ability.name
end
else
class.abilityList[ k ] = "|T" .. ability.texture .. ":0|t " .. ability.name
end
end
end
state.GUID = UnitGUID( 'player' )
state.player.unit = UnitGUID( 'player' )
ns.callHook( 'specializationChanged' )
ns.updateTalents()
-- ns.updateGear()
state.swings.mh_speed, state.swings.oh_speed = UnitAttackSpeed( "player" )
self:UpdateDisplayVisibility()
if not optionsInitialized then
Hekili:EmbedAbilityOptions()
Hekili:EmbedSpecOptions()
optionsInitialized = true
end
if not self:ScriptsLoaded() then self:LoadScripts() end
Hekili:UpdateDamageDetectionForCLEU()
end
function Hekili:GetSpec()
return state.spec.id and class.specs[ state.spec.id ]
end
ns.specializationChanged = function()
Hekili:SpecializationChanged()
end
RegisterEvent( "PLAYER_ENTERING_WORLD", function( event )
local currentSpec = GetSpecialization()
local currentID = GetSpecializationInfo( currentSpec )
if currentID ~= state.spec.id then
Hekili:SpecializationChanged()
end
end )
function Hekili:IsValidSpec()
return state.spec.id and class.specs[ state.spec.id ] ~= nil
end
class.trinkets = {
[0] = { -- for when nothing is equipped.
},
}
setmetatable( class.trinkets, {
__index = function( t, k )
return t[0]
end
} )
-- LibItemBuffs is out of date.
-- Initialize trinket stuff.
do
local LIB = LibStub( "LibItemBuffs-1.0", true )
if LIB then
for k, v in pairs( class.trinkets ) do
local item = k
local buffs = LIB:GetItemBuffs( k )
if type( buffs ) == 'table' then
for i, buff in ipairs( buffs ) do
buff = GetSpellInfo( buff )
if buff then
all:RegisterAura( ns.formatKey( buff ), {
id = i,
stat = v.stat,
duration = v.duration
} )
class.trinkets[ k ].buff = ns.formatKey( buff )
end
end
elseif type( buffs ) == 'number' then
local buff = GetSpellInfo( buffs )
if buff then
all:RegisterAura( ns.formatKey( buff ), {
id = buff,
stat = v.stat,
duration = v.duration
} )
class.trinkets[ k ].buff = ns.formatKey( buff )
end
end
end
end
end