brittyazel / EnhancedRaidFrames

World of Warcraft addon to enhance the built-in raid frames with Grid like functionality!
https://www.curseforge.com/wow/addons/enhanced-raid-frame-indicators
MIT License
14 stars 8 forks source link

Add "dispel" for debuffs that player can dispel #119

Closed mbattersby closed 10 months ago

mbattersby commented 10 months ago

This lets you use the word "dispel" as an aura name to display auras you can dispel.

Edit: retail only, UnitAura() doesn't return isRaid you'd have to do a separate call with 'HARMFUL RAID'.

brittyazel commented 10 months ago

Interesting. Since one of your conditionals is the "isRaid" will that not limit this to only raid situations? Or does "isRaid" work differently than I understand? The documentation on how "isRaid" works is very sparse, so if you can explain what's going on I'd be very interested. Likewise, in Classic we won't have access to this piece of information since "isRaid" is not one of the return parameters of the UnitAura() function as we're using it. We'd have to change our filters or add a "RAID" filter when calling UnitAura.

mbattersby commented 10 months ago

No it's not just raid situations, it's anywhere. As far as I can tell it has nothing to do with actual "raid" instances or groups. You can see some (wiki) documentation here:

https://warcraft.wiki.gg/wiki/API_UnitAura

"RAID" | Buffs the player can apply and debuffs the player can dispell

and obviously the isRaid field matches the RAID filter: https://warcraft.wiki.gg/wiki/UNIT_AURA

You can see Blizzard's use of this to match dispellable debuffs: https://github.com/Gethe/wow-ui-source/blob/9f404c4219578f2d70a1adb1197a6579f42cbbfe/Interface/FrameXML/AuraUtil.lua#L154

    elseif aura.isHarmful and aura.isRaid then
        if displayOnlyDispellableDebuffs and not ignoreDebuffs and not aura.isBossAura and AuraUtil.ShouldDisplayDebuff(aura.sourceUnit, aura.spellId) and not AuraUtil.IsPriorityDebuff(aura.spellId) then
            aura.debuffType = AuraUtil.UnitFrameDebuffType.NonBossRaidDebuff;
            return AuraUtil.AuraUpdateChangedType.Debuff;
        elseif not ignoreDispelDebuffs and AuraUtil.DispellableDebuffTypes[aura.dispelName] ~= nil then
            aura.debuffType = aura.isBossAura and AuraUtil.UnitFrameDebuffType.BossDebuff or AuraUtil.UnitFrameDebuffType.NonBossRaidDebuff;
            return AuraUtil.AuraUpdateChangedType.Dispel;
        end

You are right that classic_era with its poor API would require a separate loop to call UnitAura with 'HARMFUL RAID' and match.

mbattersby commented 10 months ago

I think something like this (untested, I don't play classic) would emulate it. I can't think of any better way to do it.

Edit: updated diff sorry.

diff --git a/Modules/AuraListeners.lua b/Modules/AuraListeners.lua
index 47e1737..c82331d 100644
--- a/Modules/AuraListeners.lua
+++ b/Modules/AuraListeners.lua
@@ -224,6 +224,25 @@ function EnhancedRaidFrames:UpdateUnitAuras_Classic(unit, parentFrame)
        -- Create or clear out the tables for the unit
        parentFrame.ERF_unitAuras = {}

+       -- Emulate isRaid field from retail. This looks inefficient but the number of auras that match
+       -- 'HARMFUL RAID' is very small (in nearly all cases 0 or 1). Matching by spellId doesn't guarantee
+       -- that we matched the exact aura, but the expectation is that if a spellId is dispellable on
+       -- this unit then all copies of it will be.
+       local raidAuras = {}
+       do
+               local shouldStop = false
+               local auraIndex = 1
+               repeat
+                       local spellId = select(10, UnitAura(unit, 'HARMFUL RAID', auraIndex))
+                       if spellId then
+                               raidAuras[spellId] = true
+                       else
+                               shouldStop = true
+                       end
+                       auraIndex = auraIndex + 1
+               until (shouldStop)
+       end
+
        -- Iterate through all buffs and debuffs on the unit
        for _, filter in pairs({ "HELPFUL", "HARMFUL" }) do
                -- Counter to keep track of our aura index
@@ -253,6 +272,9 @@ function EnhancedRaidFrames:UpdateUnitAuras_Classic(unit, parentFrame)
                                        auraData.isHarmful = true
                                end

+                               -- Set isRaid flag to match the C_UnitAuras API syntax as well
+                               auraData.isRaid = raidAuras[auraData.spellId]
+
                                -- Add our auraIndex into the table
                                auraData.auraIndex = auraIndex
brittyazel commented 10 months ago

I think I implemented a version that will work for Classic, but it's also entirely untested as I also don't play Classic... Mind giving commit 5a92613f465e7f9cd1633e0bd88337d363077e0e a look over?

mbattersby commented 10 months ago

I don't play Classic either, but reading through it it looks ok to me.

You get two copies of the aura in ERF_unitAuras if the auraStrings contains both dispel and the name/id/dispel type, but it seems like that won''t cause any issue. Without a unique ID I don't think there's any way around it anyway.

brittyazel commented 10 months ago

Exactly, you'll have two copies. If a person puts Dispel earlier than curse/poison/etc in their list, it should prioritize the Dispel conditional over the others. The tooltip code worried me though, as I had to create tooltip filters for both israid and not israid harmful filters, and the indexes are unique to each filter.

I guess we'll find out if people report issues lol.