• Dear Guest,

    You're browsing our forum as a Guest meaning you can only see a portion of the forum in read-only mode.
    To view all forum nodes and be able to create threads/posts please register or log-in with your existing account.

    TwinStar team

[Programming] Getting the amount of Buffs and its content

Geigerkind

Authorized
Joined
Aug 9, 2014
Location
Germany
Hey,
I currently try to get the amount of the players buffs but for some reason it always returns 0 although I have 2 buffs on me.

Code:
function VCB_getNumBuffs()
    local i = 1;
    while true do
        local name, rank, icon, charges, timemax, timeleft = UnitBuff("player", i);
        if not icon then break end
        i = i + 1;
    end
    return i - 1;
end

I think I'm doing something terribly wrong^^
 
Code:
function VCB_getNumBuffs()
    local i = 1;
    while true do
        local [COLOR=#ff8c00][B]texture, stacks[/B][/COLOR] = UnitBuff("player", i);
        if not texture then break end
        i = i + 1;
    end
    return i - 1;
end
Welcome to vanilla, where everything is different and _G doesn't exists.
 
To get _G you must first call
Code:
_G = getfenv()
.

As moh highlited in his post, UnitBuff in vanilla returns only 2 values. In your code you are trying to get 3rd value that is always nil (false).

Code:
function GetNumBuffs()
local a=0; while UnitBuff("player", a+1) do a=a+1 end
return a;
end
 
Thanks for the advice!
It's working properly now.
Now I wanted to implement an interface with XML. I tried to initialize the lua script via the onLoad tag in XML. Nevertheless, I think the lua doesnt get fired when I load the interface.

VCB.toc
Code:
#
## Interface: 10900
## Title: VCB
## SavedVariables: VCB_save
## OptionalDeps:
## Dependencies: 

VCB.xml

VCB.xml
Code:
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
C:\Projects\WoW\Bin\Interface\FrameXML\UI.xsd">

    <Script file="VCB.lua"/>
    <Frame name="VCB" parent="UIParent" hidden="false">
        <Scripts>
            <OnLoad>
                VCB_OnLoad();
            </OnLoad>
        </Scripts>
    </Frame>
    <Frame name="VCB_Container" parent="UIParent" hidden="false" movable="true">
        <Size>
            <AbsDimension x="116" y="26"/>
        </Size>
        <Anchors>
            <Anchor point="CENTER">
                <Offset>
                    <AbsDimension x="0" y="80"/>
                </Offset>
            </Anchor>
        </Anchors>
        <Layers>
            <Layer level="BACKGROUND">
                <Texture>
                    <Size>
                        <AbsDimension x="107" y="13"/>
                    </Size>
                    <Anchors>
                        <Anchor point="TOP">
                            <Offset>
                                <AbsDimension x="0" y="-2"/>
                            </Offset>
                        </Anchor>
                    </Anchors>
                    <Color r="0" g="0" b="0" a="0.5"/>
                </Texture>        
            </Layer>
        </Layers>
    </Frame>
</UI>

Does anyone know a solution for that?
 
First of all, creating a frame in xml just to execute lua code is memory expensive. For example, you have a lua file with following code:

Code:
function VCB_OnLoad()
 print("test");
end

all you can do now is to add this line at the end of your lua file:
Code:
VCB_OnLoad()

or if you just want to use function once on load, it does not need to be function. Simple

Code:
print("test");

is better option.
 
Thanks for the advice!
It's working properly now.
Now I wanted to implement an interface with XML. I tried to initialize the lua script via the onLoad tag in XML. Nevertheless, I think the lua doesnt get fired when I load the interface.

VCB.toc
Code:
#
## Interface: 10900
## Title: VCB
## SavedVariables: VCB_save
## OptionalDeps:
## Dependencies: 

VCB.xml

VCB.xml
Code:
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
C:\Projects\WoW\Bin\Interface\FrameXML\UI.xsd">

    <Script file="VCB.lua"/>
    <Frame name="VCB" parent="UIParent" hidden="false">
        <Scripts>
            <OnLoad>
                VCB_OnLoad();
            </OnLoad>
        </Scripts>
    </Frame>
    <Frame name="VCB_Container" parent="UIParent" hidden="false" movable="true">
        <Size>
            <AbsDimension x="116" y="26"/>
        </Size>
        <Anchors>
            <Anchor point="CENTER">
                <Offset>
                    <AbsDimension x="0" y="80"/>
                </Offset>
            </Anchor>
        </Anchors>
        <Layers>
            <Layer level="BACKGROUND">
                <Texture>
                    <Size>
                        <AbsDimension x="107" y="13"/>
                    </Size>
                    <Anchors>
                        <Anchor point="TOP">
                            <Offset>
                                <AbsDimension x="0" y="-2"/>
                            </Offset>
                        </Anchor>
                    </Anchors>
                    <Color r="0" g="0" b="0" a="0.5"/>
                </Texture>        
            </Layer>
        </Layers>
    </Frame>
</UI>

Does anyone know a solution for that?

If you want to output a message "MyAddonThatMakesCoffe v1.0 loaded" to the chat frame it's often needed (I had so much issues with that, sometimes I still do lol) to register and use game events, for start you'll need event named ADDON_LOADED and when checking it you'll need to make sure that the first argument passed to your function arg1 = MyAddonThatMakesCoffe is called at that moment.

Example:
VBC.xml
Code:
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
C:\Projects\WoW\Bin\Interface\FrameXML\UI.xsd">

    <Script file="VCB.lua"/>
    <Frame name="VCB" parent="UIParent" hidden="false">
        <Scripts>
            <OnLoad>
                VCB_OnLoad();
            </OnLoad>
            [B][COLOR="#FFA500"]<OnEvent>
                VCB_OnEvent(event, arg1);
            </OnEvent>[/COLOR][/B]
        </Scripts>
    </Frame>
    <Frame name="VCB_Container" parent="UIParent" hidden="false" movable="true">
        <Size>
            <AbsDimension x="116" y="26"/>
        </Size>
        <Anchors>
            <Anchor point="CENTER">
                <Offset>
                    <AbsDimension x="0" y="80"/>
                </Offset>
            </Anchor>
        </Anchors>
        <Layers>
            <Layer level="BACKGROUND">
                <Texture>
                    <Size>
                        <AbsDimension x="107" y="13"/>
                    </Size>
                    <Anchors>
                        <Anchor point="TOP">
                            <Offset>
                                <AbsDimension x="0" y="-2"/>
                            </Offset>
                        </Anchor>
                    </Anchors>
                    <Color r="0" g="0" b="0" a="0.5"/>
                </Texture>        
            </Layer>
        </Layers>
    </Frame>
</UI>

VCB.lua
Code:
-- some code stripped down  --

local function VCB_OnLoad()
	-- some code --
	this:RegisterEvent("ADDON_LOADED");
	-- some code --
end

local function VCB_OnEvent(event, arg1)
	if ( event == "ADDON_LOADED" and arg1 == "VCB" ) then
		DEFAULT_CHAT_FRAME:AddMessage("VCB loaded!");
	end
end

-- some code stripped down  --

Depending on your goal, the Flynn's suggestion might or might not be better advice.
 
I will fill the frame of course^^ It's not finished yet.
But thanks for the advice moh and Flynn, you really helped me a lot. Finally I can finish this addon!
 
Personally, I have steered away from using XML if not absolutely necessary. All arguments are global at all times anyway. So you can, for example, do very simple event routing:

Code:
QuestieTracker = CreateFrame("Frame", "QuestieTracker", UIParent, "ActionButtonTemplate")


function QuestieTracker:OnEvent() -- functions created in "object:method"-style have an implicit first parameter of "this", which points to object || in 1.12 parsing arguments as ... doesn't work
	QuestieTracker[event](QuestieTracker, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) -- route event parameters to Questie:event methods
end

This way, by registering an event to QuestieTracker, it automatically gets routed to the correct function and you can name arguments more conveniently.

Code:
QuestieTracker:SetScript("OnEvent", QuestieTracker.OnEvent)
QuestieTracker:RegisterEvent("PLAYER_LOGIN")
QuestieTracker:RegisterEvent("ADDON_LOADED")

QuestieTracker:ADDON_LOADED(addonName)
   DEFAULT_CHAT_FRAME:AddMessage(addonName)
end
 
Personally, I have steered away from using XML if not absolutely necessary. All arguments are global at all times anyway.

Me too. It is always better to have frames created dynamically (programatically).
-No "onload" events that call external lua code when the frame is created. You just write the code after the CreateFrame calls.
-No mixed codes. No needs to learn xml, everything can be done using lua.
-Editing existing frames cannot be done in xml.
-It is clearer. No wall of text. And you can dynamically create a lot of frames at once.
-You can set easily available global variable to set some value of frame that is created somewhere in the middle of the file.
 
Code:
UnitBuffInfo = function(unit,index) 
 if UnitBuff(unit, index) then
    GameTooltip:SetOwner(UIParent, "ANCHOR_NONE");
    GameTooltip:SetUnitBuff(unit, index);
    local name = GameTooltipTextLeft1:GetText();
    local desc = GameTooltipTextLeft2:GetText();
    GameTooltip:Hide();
    return name, desc;
 end
 return nil;
end
 
Last edited:
Hey,
another question: is there an event that is fired when a Weapon enchantment is applied/removed/updated ?

And how can I make a frame clickable? I tried HookScript but this function does not seem to be implemented in 1.12.
 
Last edited:
frame:EnableMouse(true);

Also if you want to hook a function in Vanilla, you just overwrite it

Code:
local _functionName = originalFunction;

function originalFunction(arg1, arg2, arg3, arg4)
-- do code here
   _functionName(arg1, arg2, arg3, arg4)
-- do code here
end
 
I guess you'll have to find the function that adds buffs to "BuffFrame" and hook it. Or use the player castbar, since with the exception of shaman enchants, they're all casts (poison, stones, etc).

And/or look how XPerl handles it in TBC.
 
I ran into another problems with GameTooltips:

I have a Button-Frame that changes its parent dynamicly. This Button is created once with this OnEnter script:
Code:
button:SetScript("OnEnter", function()
                GameTooltip:SetOwner(button, "ANCHOR_BOTTOMLEFT")
                if VCB_BF:IsButton(button) then
                    GameTooltip:SetPlayerBuff(GetPlayerBuff(button:GetID()-1, "HELPFUL"))
                else
                    GameTooltip:SetPlayerBuff(GetPlayerBuff(button:GetID()-1, "HARMFUL"))
                end
                GameTooltip:Show()
                if button:GetParent() == fb then VCB_BF:BuffFrame_Show() end
            end)

The problem is: The tooltip is not shown but the event is fired. If you add an Messageoutput and ask him to output the parent etc. it gives the correct values. If you fill the tooltip manually and try to make it visible it does not show up, so it is not about the content of the tooltip. Still I am very confused. The Tooltip does seem to work as long as I don't change the parent manually and keep it with its original parent. But why does it not work if I change the parent? Did I forget something? I don't know. Hope for some suggestions to solve the problem!

Edit: If I check if it is owned, it returns false. So I wonder why.
 
Last edited:
Don't question what the default UI does. You can add/remove lines from GameToolTip, but as a general rule of thumb, you should not touch that frame. Create your own tooltip frame and play with that.
 
Not really smart, performance wise to create a new Tooltip frame. Why shouldnt the UI one be recycled. Thats what it is supposed to. Can you link me the source code of the GameTooltip, so maybe I can figure out what causes this problem
 
That's why I said don't question what the default UI does. A lot of Lua code is hardcoded into the client and not accessible. Then a lot of UI code that you can find in the MPQ interacts with that hardcoded Lua part. Take the UnitBuff and UnitDebuff functions for example, they're interacted with by ALL parts of the client but not actually anywhere to be found, because they offer a direct interface from Lua to the client's C/C++ functions.

You can hook those functions and change what they return. In fact, you can even hook something like Cooldown_SetTimer, which is what OmniCC does.
Some parts of the client expect the tooltip to be in a very specific format, changing that will break it, will break everything in fact. Creating ONE more tooltip, anchored to the default tooltip perhaps, that you can then reuse, is really not expensive at all. The client could easily it if you constantly redrew frames from scratch instead of reusing them, especially on current machines. All this interface code is not even close to heavy. The only way we managed to make the client lag with Questie was by basically iterating over a table with 30,000 entries several times each second.

And if you're worried about memory, you can always force a GC.
 
IF the 'button' in your code is a local variable, you need to have a global name or global reference (pointer) to the frame and then call SetOwner method with it.

GameTooltip:SetOwner(button, "ANCHOR_BOTTOMLEFT")
 
Using a global variable has done the trick, but nevertheless the tooltip is not shown :/

Have you encountered a similiar problem?
 
Last edited:
I am not sure now whether the method IsButton even exists. Can you remove the 'If' condition and test whether or not the addon works with only the first line? -> GameTooltip:SetPlayerBuff(GetPlayerBuff(button:GetID()-1, "HELFUL"))
 
IsButton is a selfmade method to check if it is a Debuff or a Buff button. Even if I add GameTooltip:AddLine("Test"), nothing appears.
 
I don't know what might be wrong as I can't see rest of your code but what I know using colons in function names often lead to confusion. GameTooltip's true owner could be hidden or non existant at time you call its show method. You can try to replace 'button' with 'this' to see if it helps.

Code:
button:SetScript("OnEnter", function()
                GameTooltip:SetOwner(this, "ANCHOR_BOTTOMLEFT")
                if VCB_BF:IsButton(this) then
                    GameTooltip:SetPlayerBuff(GetPlayerBuff(this:GetID()-1, "HELPFUL"))
                else
                    GameTooltip:SetPlayerBuff(GetPlayerBuff(this:GetID()-1, "HARMFUL"))
                end
                GameTooltip:Show()
                if this:GetParent() == fb then VCB_BF:BuffFrame_Show() end
            end)
 
That the owner is hidden before or after could be a think, I will check it. This does work with the debuff buttons and the buff buttons that were not put into a frame before -> Whoms parent was not changed

Edit: This is the log:
uXM34Wp.png


Edit: Replacing button with this, does work in the way if I check if it is owned after the code is executed it is true.

Code:
button:SetScript("OnEnter", function()
                if VCB_BF:IsButton(button) then
                    GameTooltip:SetOwner(this, "ANCHOR_BOTTOMLEFT")
                    GameTooltip:AddLine("Test")
                    --GameTooltip:SetPlayerBuff(GetPlayerBuff(button:GetID()-1, "HELPFUL"))
                else
                    GameTooltip:SetOwner(getglobal("DeVCBButton"..button:GetID()), "ANCHOR_BOTTOMLEFT")
                    GameTooltip:SetPlayerBuff(GetPlayerBuff(button:GetID()-1, "HARMFUL"))
                end
                if GameTooltip:IsOwned(this) then
                    DEFAULT_CHAT_FRAME:AddMessage("Tooltip shown!")
                end
                GameTooltip:Show()
                if button:GetParent() == fb then VCB_BF:BuffFrame_Show() end
            end)

Edit 3: Found the issue!
The problem was indeed that the parents were shown/hidden. When the parent is hidden every child is hidden as well. When it is shown the childs are not shown (by function) but are visible. Therefore the GameTooltip couldnt be applied because it thought the owner was not visible
 
Last edited:
Top Bottom