Developer Stuff - Hekili/hekili GitHub Wiki

Projects / TODO List

Table of Contents

Table of contents generated with markdown-toc

Track refreshable status of debuffs in real-time across all enemies

Has a lot of potential, needs work.

Targets.lua

ns.refreshableAuraCount = function(auraName)
    local startTime = debugprofilestop()  -- Start timing

    local aura = class.auras[auraName]
    if not aura then 
        return 0 
    end

    local auraID = aura.id
    -- Handle dynamic duration (if duration is a function, evaluate it)
    local duration = type(aura.duration) == "function" and aura.duration() or aura.duration or 30
    local refreshThreshold = 0.3 * duration  -- Calculate threshold as 30% of the duration
    local refreshableCount = 0

    -- Iterate over each nameplate unit (up to 40)
    for i = 1, 40 do
        local unit = "nameplate" .. i
        if not UnitExists(unit) then break end -- Stop if no more nameplates are present

        local auraFound = false

        -- Check each debuff slot on the unit to find the specific aura
        for j = 1, 40 do
            local auraData = C_UnitAuras.GetAuraDataBySlot(unit, j)
            
            if auraData and auraData.spellId == auraID then
                auraFound = true
                local currentTime = GetTime()
                local expirationTime = auraData.expirationTime or 0
                local remainingTime = expirationTime - currentTime

                if remainingTime <= refreshThreshold then
                    refreshableCount = refreshableCount + 1
                end
                break
            end
        end

        if not auraFound then
            -- If the aura is not found on the unit, consider it refreshable.
            refreshableCount = refreshableCount + 1
        end
    end

    -- Calculate elapsed time and add it to the profiling data
    local timeSpent = debugprofilestop() - startTime
    Hekili:AddProfileData("Refreshable", timeSpent)

    return refreshableCount
end

SpecFile.lua

-- Count of refreshable Garrotes
spec:RegisterStateExpr( "refreshable_garrotes", function ()
    return ns.refreshableAuraCount("garrote")
end )

-- Count of refreshable Ruptures
spec:RegisterStateExpr( "refreshable_ruptures", function ()
    return ns.refreshableAuraCount("rupture")
end )

Priority View that shows all abilities/items that are actually used in that priority.

  • related: A way to display/print all referenceable auras for the spec/class within the GUI, sort of a tinkerer's corner

Persistent List Insertions

List Insertions for adding pre-precombat, pre-default, fallthrough recommendations that persist when priorities update (with better name than "list insertions").

Ability Modifiers

toggle

  • this entry is controlled by the specified toggle

display

  • this entry will only display in the specified display

strict

Allow this to be scripted/logical; this would allow us to short-circuit if a required part of the if= will fail (i.e., if=talent.doodoo.enabled&buff.poopoo.down -> strict=talent.doodoo.enabled,if=buff.poopoo.down image if condition in box is false, skip the whole list, there's no point. Otherwise, allow checking based on existing code structure. box would correlate to strict=talent.cold_heart.enabled in simc APL sense.

Yeah, more or less; right now there's no strict option in the UI but it's currently configured to parse as 1/0 true/false and doesn't get evaluated dynamically (I think).

Ability Handlers

Similarly, I've been thinking about rebuilding all handlers and ability/aura functions on talent changes and other critical updates, and building constructors instead of writing functions. I just don't know if it's worth the squeeze.

Something like:

handler = function()
    if talent.alpha.enabled then applyBuff( "alpha" ) end
    if talent.beta.enabled then applyBuff( "beta" ) end
end,

vs

handler = function()
    local func = ""
    if talent.alpha.enabled then func = func .. [[applyBuff( "alpha" )\n]] end
    if talent.beta.enabled then func = func .. [[applyBuff( "beta" )\n]] end
    if func ~= "" then return Hekili:LoadString( func ) end
end,

Could also put the conditional items in a table and iterate over each

builders = {
    handler = {
        { talent.alpha.enabled, [[applyBuff( "alpha" )]] },
        { talent.beta.enabled , [[applyBuff( "beta"  )]] }
    }
},

handler = function()
    if spec.abilities.this_ability.builders and spec.abilities.this_ability.builders.handler then
        local func

        for i, line in ipairs( spec.abilities.this_ability.builders.handler ) do
            if line[1] then func = strformat( "%s\n%s", ( func or "" ), line[2] ) end
        end

        if len( func ) > 0 then return Hekili:LoadString( func ) end
    end
end,

Basically, removing tons of non time-sensitive conditionals across the board.

Caching is probably a better solution, though.

In-game spell names

Instead of needing to pause the addon, add in an option to either show a simple spellname (or blizz tooltip) on mouseover, or a weakaura-like name display.

Global item / trinket toggle

pls

Sandbox encounter timer system

Allow users to input their own timers for an NPC / encounter ID and have this timer be able to trigger things like the cooldown toggle. There would be 0 support for pre-determined or suggested timers as that is dangerous territory.

Make Fire mage great again (projectiles)

More Weakaura hooks

In-game tutorial/walkthrough via dialogue boxes

More target count options

  • Such as a "max" number of targets, or a N-target display

Macro'd cooldowns

More visual indicators

More snapshot output

Flags

  • Hero Tree Selection
  • combat status / timer

Per-Recommendation

  • When an ability is chosen, list some of the effects that will happen via handler Example for Beast Mastery Cobra Shot
        handler = function ()

            if talent.dire_summons.enabled then reduceCooldown( "howl_of_the_pack_leader", 1 ) end

            if talent.serpentine_rhythm.enabled then
                if buff.serpentine_rhythm.stacks == 3 then
                    removeBuff( "serpentine_rhythm" )
                    applyBuff( "serpentine_blessing" )
                else addStack( "serpentine_rhythm" )
                end
            end

            if talent.barbed_scales.enabled then
                gainChargeTime( "barbed_shot", 2 )
            end

            if talent.killer_cobra.enabled and buff.bestial_wrath.up then setCooldown( "kill_command", 0 ) end

            -- Legacy / PvP Stuff
            if debuff.concussive_shot.up then debuff.concussive_shot.expires = debuff.concussive_shot.expires + 3 end
            if set_bonus.tier30_4pc > 0 then reduceCooldown( "bestial_wrath", 1 ) end
        end,
    },

The snapshot output may say something like

Cobra shot was chosen
    Handler Analysis
            if talent.dire_summons.enabled[true] then reduceCooldown( "howl_of_the_pack_leader", 1 ) end
            if talent.serpentine_rhythm.enabled[false] then
                if buff.serpentine_rhythm.stacks == 3 then
                    removeBuff( "serpentine_rhythm" )
                    applyBuff( "serpentine_blessing" )
                else addStack( "serpentine_rhythm" )
                end
            end
            if talent.barbed_scales.enabled[true] then
                gainChargeTime( "barbed_shot", 2 )
            end
            if talent.killer_cobra.enabled and buff.bestial_wrath.up[false] then setCooldown( "kill_command", 0 ) end
    Effects applied by this action
            reduceCooldown( "howl_of_the_pack_leader", 1 )
            gainChargeTime( "barbed_shot", 2 )

Auto-Removal of useless variables

Example: Unholy DK

actions+=/mind_freeze
## actions+=/variable,name=st_planning,op=set,value=active_enemies=1
## actions+=/variable,name=adds_remain,op=set,value=active_enemies>1

Replace st_planning with active_enemies=1 Replace adds_remain with active_enemies>1

Currently this is done manually, and occasionally gets overwritten. Make specific cases in the SIMC importer function to translate them inside the addon?

⚠️ **GitHub.com Fallback** ⚠️