Thread Tools Display Modes
07-18-23, 09:23 PM   #1
Tair
A Deviate Faerie Dragon
Join Date: Aug 2020
Posts: 10
[Classic] Toggled spells: stance bar, action bars, and :SetTexture

Hi everyone.

I enjoy writing small addons that are by no means practical but address personal visual gripes and help me learn a bit about the addon API in the process.

In this instance, I dislike how toggled spells (Devotion Aura, druid forms, hunter Aspects, shadow form) have their icons all change to the same icon whenever they are active, which seems to be: Interface\Icons\Spell_Nature_WispSplode

My goal is to prevent the icon from changing and simply desaturate it. I think the ideal approach would be to intercept the function that changes these icons to begin with, but looking through the default interface code, I haven't determined if that's possible.

In lieu of that, I've temporarily narrowed my scope to the stance bar and have come up with a method that fires on UNIT_SPELLCAST_SUCCEEDED to desaturate the icon, but I haven't successfully reverted the actual icon texture.

Code:
for i = 1, 10 do
        local btn = _G["StanceButton" .. i]
        if not btn then return end
        local icon, isActive, isCastable, spellID = GetShapeshiftFormInfo(btn:GetID())
        local iconTexture = _G[btn:GetName() .. "Icon"] -- the button's icon
        local texture = GetSpellTexture(spellID) -- the texture ID/path
        if isActive then
            iconTexture:SetTexture(texture) -- doesn't change the texture; is this because by the time this code runs, the icon has already changed?
            iconTexture:SetDesaturated(true) -- works 
            iconTexture:Show() -- force the icon to update?
        else
            iconTexture:SetDesaturated(false) -- works 
            iconTexture:SetTexture(texture)
        end
    end



In terms of the default interface code for the stance bar, I believe the icon switching might be occurring in the function StanceBarMixin:UpdateState():

Code:
if ( isActive ) then
	self.lastSelected = button:GetID();
	button:SetChecked(true); -- it's most likely this that is changing the icon
else
	button:SetChecked(false);
end

However, based on the searching I've done through the code so far, SetChecked() seems to be a fairly common function and thus far I haven't found any specific code that where this function is switching the icon.

I am by no means an experienced addon developer, so I would be grateful for any perspectives here. Is this even feasible?
Attached Thumbnails
Click image for larger version

Name:	desaturate.gif
Views:	101
Size:	635.4 KB
ID:	9830  
  Reply With Quote
07-19-23, 01:14 AM   #2
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,358
I would look at <button>:SetHighlightTexture(id or path) and / or <button>::SetPushedTexture(id or path)
  Reply With Quote
07-19-23, 03:48 AM   #3
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,304
The "checked" texture is the yellow/white border around the icon when the ability is active. The pushed and highlight textures are similar border styles and not the actual icon either.

Hooking directly into the function that sets the icons worked for me.
Lua Code:
  1. hooksecurefunc("StanceBar_UpdateState",function()
  2.     for i=1,math.min(NUM_STANCE_SLOTS,GetNumShapeshiftForms()) do
  3.         local _,active,_,spellid=GetShapeshiftFormInfo(i);
  4.         local icon=StanceBarFrame.StanceButtons[i].icon;
  5.         icon:SetTexture(GetSpellTexture(spellid));
  6.         icon:SetDesaturated(active);
  7.     end
  8. end);

The actionbars on the other hand don't have a clear way to identify if a toggled ability is active. You could compare the action texture with the spell texture and see if they differ, but this causes some false positives for auto-attack type abilities that show the equipped weapon's icon instead of their internal spell texture.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 07-19-23 at 04:11 AM.
  Reply With Quote
07-19-23, 10:51 AM   #4
Tair
A Deviate Faerie Dragon
Join Date: Aug 2020
Posts: 10
Thank you both for the replies!

Originally Posted by SDPhantom View Post
Hooking directly into the function that sets the icons worked for me.
This does indeed work. And more importantly, the code you provided made me confident that I was looking through incorrect code last night. I exported the interface code on my computer this morning and was able to find the function you referenced as well as similar one for the action bars. Thank you for steering me in the right direction.

Code:
hooksecurefunc("ActionButton_UpdateState",function(button)
    local spellType, spellId, subType = GetActionInfo(button.action);
    if spellType ~= "spell" then return end; -- only check spells for now
    -- local aura = GetPlayerAuraBySpellID(spellId) -- not available in classic?
    local spellName = GetSpellInfo(spellId);
    -- assume that a player aura w/ no duration and name equal to the spell's name is a toggle...
    local auraName, buff, count, buffType, duration, expirationTime, isMine, isStealable, _, auraId = AuraUtil.FindAuraByName(spellName, "player");
    if auraName == spellName and duration == 0 then
        print('Matching aura found: ' .. auraName); -- works
        print('Spell icon texture: ' .. GetSpellTexture(spellId)); -- debug; returns the correct icon
        print('Aura icon texture: ' .. GetSpellTexture(auraId)); -- debug; returns the correct icon
        button.icon:SetTexture(GetSpellTexture(spellId)); -- does not change the icon
        button.icon:SetDesaturated(true) -- works;
    end;
end);
The only issue with this is that the icon texture doesn't update. Which made me wonder if the icon switching is being handled by a different function that's maybe running after my code?

Edit 1: The default code is calling GetActionTexture() instead of GetSpellTexture(). GetActionTexture returns the wisp icon.

Solved it, sort of. I needed to hook ActionButton_Update, as opposed to ActionButton_UpdateState. The mostly-working code for the action bars is:

Code:
hooksecurefunc("ActionButton_Update",function(self)
    local action = self.action;
    local icon = self.icon;
    local type, id = GetActionInfo(action);
    -- only check spells for now
    if type ~= "spell" then return end;
    local spellName = GetSpellInfo(id);
    -- assume player aura w/ no duration and name equal to spell name is a toggle
    local auraName, buff, count, buffType, duration, expirationTime, isMine, isStealable, _, auraId = AuraUtil.FindAuraByName(spellName, "player");
    if auraName == spellName and duration == 0 then
        icon:SetTexture(GetSpellTexture(id));
        icon:SetDesaturated(true);
    end;
end);
The only outstanding issue I've found so far is that the icon will eventually revert to the wisp icon.

After some further testing, it seems as though both ActionButton_Update and ActionButton_OnEvent need to be hooked in order to cover all of the apparent cases where the default code is changing the icon.

Last edited by Tair : 07-19-23 at 12:51 PM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » [Classic] Toggled spells: stance bar, action bars, and :SetTexture

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off