Thread Tools Display Modes
12-26-11, 02:14 PM   #1
Jonisaurus
An Aku'mai Servant
 
Jonisaurus's Avatar
Join Date: Aug 2011
Posts: 35
"GetTotemInfo" help

I'm trying to create a function that is triggered by "UNIT_POWER" and checks whether I have a totem active or not.

I'm trying to use the "GetTotemInfo" function for this, but I'm not succeeding.
There are 4 returns for this function
Code:
haveTotem, totemName, startTime, duration = GetTotemInfo(1 through 4)
here is what they do each:
http://www.wowwiki.com/API_GetTotemInfo

Only one argument (integer for each element, 1 through 4).

Now I'm using i as a variable
Code:
for i=1,4 do
for the argument, but that's not the problem.

I need help setting up a functon that checks for each element if there is ONE totem active or not, (NOTE: totemName returns "" instead of "nil" when there is no totem active).

Thank you!
  Reply With Quote
12-26-11, 03:39 PM   #2
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
Code:
local function HasActiveTotem()
  local active = false
  for i = 1, 4 do
    active = active or GetTotemInfo(i)
  end
  return active
end
HasActiveTotem() would return true/false depending if there is minimum one totam active or not.
  Reply With Quote
12-26-11, 06:58 PM   #3
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
You don't even need to store a variable. If you only want to know if any totem is active, you can return out of your function immediately as soon as you find one, without continuing to loop through the rest of the totem slots. You also don't need to explicitly return false, as a nil value is the same.

Code:
local function HasActiveTotem()
     for i = 1, 4 do
          if GetTotemInfo(i) then
               return true
          end
     end
end
  Reply With Quote
12-26-11, 09:16 PM   #4
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
It's true, not sure why I wrote what I did... :'(
  Reply With Quote
12-27-11, 04:03 AM   #5
Jonisaurus
An Aku'mai Servant
 
Jonisaurus's Avatar
Join Date: Aug 2011
Posts: 35
I think you guys made a mistake in thinking that "haveTotem" returns anything else than "true", because it doesn't. It in fact tests whether one has the TOTEM REAGENT, so if one is able to cast any totem of that school. It doesn't test for active totems.

I confirmed this ingame using this macro
Code:
/run local haveTotem, name = GetTotemInfo(1) if haveTotem then print("b") end
it always prints "b", regardless of whether I have an active totem or not. It does however not work on my druid.

I think there is no direct way to check for active totems, one has to use
Code:
if name == ""
because "name" returns nothing if there is no active totem.
  Reply With Quote
12-27-11, 05:54 AM   #6
Jonisaurus
An Aku'mai Servant
 
Jonisaurus's Avatar
Join Date: Aug 2011
Posts: 35
Code:
local frame = CreateFrame("frame")
frame:RegisterEvent("PLAYER_REGEN_ENABLED")
frame:RegisterEvent("PLAYER_REGEN_DISABLED")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("UNIT_POWER")

local function HideAndShow(self, event, ...)
	local unitId, resource = ...
	local class, classFileName = UnitClass("player")
	if unitId == "player" and resource == "MANA" and classFileName == "SHAMAN" then
		print("ABC")
		for i = 1, 4 do
			local haveTotem, name = GetTotemInfo(i)
			for o = 1,4 do
				local frame = getglobal("XiTimers_Timer"..o)
				if event == "UNIT_POWER" and name == "" and event == "PLAYER_REGEN_DISABLED" then
					frame:Show()
				else
					frame:Hide()
				end
			end
		end
	end
end

frame:SetScript("OnEvent", HideAndShow)
Okay, this does not work. Can you help me here? Please :P
There is something wrong with that code, and I'm too tired to find the error.
  Reply With Quote
12-27-11, 09:36 AM   #7
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
1. Data that is static/constant does not need to be called each time, i.e. if you know that the player must be a specific class then you don't need to check for it each time inside the routine, instead make it so the routine does not load or run at all if the class is wrong. Unlike when we are checking other targets, the player can only be one class when he logs in.

2. When a frame has several events registered, the function you write runs each time one of the events is received by the game from the server, meaning if you have that code it will run each time you get out of combat, enter combat, power is restored, e.g. This means the "event" will always have one value at a time.

3. It's a good habit to try split up things, like when I know I will run the same code several times I put that code in it's own function and call it when I need it, the idea of CheckTotems below is to run trough the 4 totems, if it's spawned to show the frame, if not then hide it. But since we can only do this outside of combat, at the begining there is the combat check, if the variable inCombat is set then it means we are in combat and we can't work with the frames. NOTE: not all frames are like this, I don't know the addon and such, but if you like try disable the return part so the frames are shown or hidden during combat too, if it works then it's just nicer isn't it?

4. getglobal and _G are the same

5. select will select the n-th value we got 'local class, enClass = UnitClass("player")' if we only want the enClass we can just do 'select(2, UnitClass("player"))' and another way to tackle these is for example "local _, enClass = ..." if you don't bother with the first one but you want the 2nd.

6. When assuming a frame exists like 't = _G["XiTimers_Timer"..i]' it's nice to first check that the object after that actually exists, before trying to run methods like t:Show(), in case it does not exist you will get an error and the addon code will fail, it's nicer for it to not fail like this.

Here is my suggestion, what I think you tried to make:

Code:
if select(2, UnitClass("player")) ~= "SHAMAN" then
  return -- does not load the file because the player is not a Shaman
end

local f = CreateFrame("Frame")

f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:RegisterEvent("PLAYER_REGEN_DISABLED")
f:RegisterEvent("PLAYER_REGEN_ENABLED")
f:RegisterEvent("UNIT_POWER")

local inCombat

local function CheckTotems()
  if inCombat then
    return -- if in combat we cant do anything with these frames
  end
  local t
  for i = 1, 4 do
    t = _G["XiTimers_Timer"..i]
    if t then
      if select(2, GetTotemInfo(i)) ~= "" then
        t:Show()
      else
        t:Hide()
      end
    end
  end
end

local function OnEvent(f, event, unit, power, ...)
  if event == "PLAYER_REGEN_DISABLED" then
    inCombat = 1
  elseif event == "PLAYER_REGEN_ENABLED" then
    inCombat = nil
    CheckTotems()
  elseif event == "PLAYER_ENTERING_WORLD" then
    CheckTotems()
  elseif event == "UNIT_POWER" then
    if unit == "player" and power == "MANA" then
      CheckTotems()
    end
  end
end

f:SetScript("OnEvent" OnEvent)
  Reply With Quote
12-29-11, 09:09 PM   #8
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
That's pretty inefficient, too, with numerous unnecessary extra functions and checks. I also have no idea why you're ignoring all events that occur in combat. I'd say the vast majority of totem drops/deaths/recalls occur in combat. It looks like the OP is trying to write a totem timer, which does not involve any secure frames.

Lua Code:
  1. -- First, check if the player is a shaman.
  2. -- If not, then we don't need to do anything else.
  3. local _, class = UnitClass("player")
  4. if class ~= "SHAMAN" then return end
  5.  
  6. local frame = CreateFrame("Frame")
  7.  
  8. frame:RegisterEvent("PLAYER_ENTERING_WORLD")
  9. -- Unless you actually care whether the player is in combat or not, you
  10. -- do not need to listen for these two events:
  11. frame:RegisterEvent("PLAYER_REGEN_DISABLED")
  12. frame:RegisterEvent("PLAYER_REGEN_ENABLED")
  13. -- Unless you actually care how much mana the player has, you should
  14. -- probably listen for PLAYER_TOTEM_UPDATE instead of UNIT_POWER.
  15. frame:RegisterEvent("UNIT_POWER")
  16.  
  17. frame:SetScript("OnEvent", function(self, event, unit, resource)
  18.     -- Of the events you are watching, only UNIT_POWER passes any
  19.     -- arguments (or fires for units other than the player), so make
  20.     -- sure we're not responding to other units' power update events.
  21.     if event == "UNIT_POWER" and (unit ~= "player" or resource ~= "MANA") then return end
  22.  
  23.     -- Check if the player has ANY totem active.
  24.     local hasTotem
  25.     for i = 1, 4 do
  26.         local _, name = GetTotemInfo(i)
  27.         if name and name:len() > 0 then
  28.             hasTotem = true
  29.             break
  30.         end
  31.     end
  32.  
  33.     -- Do things here depending on whether or not a totem is active.
  34.     if hasTotem then
  35.         self:Show() -- Inside this scope, "self" refers to the frame.
  36.     else
  37.         self:Hide()
  38.     end
  39. end)
  Reply With Quote
12-30-11, 06:50 AM   #9
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
I took a shot, no clue what he was trying to do in the first place... -_-
  Reply With Quote
01-03-12, 02:42 AM   #10
Jonisaurus
An Aku'mai Servant
 
Jonisaurus's Avatar
Join Date: Aug 2011
Posts: 35
Originally Posted by Phanx View Post
That's pretty inefficient, too, with numerous unnecessary extra functions and checks. I also have no idea why you're ignoring all events that occur in combat. I'd say the vast majority of totem drops/deaths/recalls occur in combat. It looks like the OP is trying to write a totem timer, which does not involve any secure frames.

Lua Code:
  1. -- First, check if the player is a shaman.
  2. -- If not, then we don't need to do anything else.
  3. local _, class = UnitClass("player")
  4. if class ~= "SHAMAN" then return end
  5.  
  6. local frame = CreateFrame("Frame")
  7.  
  8. frame:RegisterEvent("PLAYER_ENTERING_WORLD")
  9. -- Unless you actually care whether the player is in combat or not, you
  10. -- do not need to listen for these two events:
  11. frame:RegisterEvent("PLAYER_REGEN_DISABLED")
  12. frame:RegisterEvent("PLAYER_REGEN_ENABLED")
  13. -- Unless you actually care how much mana the player has, you should
  14. -- probably listen for PLAYER_TOTEM_UPDATE instead of UNIT_POWER.
  15. frame:RegisterEvent("UNIT_POWER")
  16.  
  17. frame:SetScript("OnEvent", function(self, event, unit, resource)
  18.     -- Of the events you are watching, only UNIT_POWER passes any
  19.     -- arguments (or fires for units other than the player), so make
  20.     -- sure we're not responding to other units' power update events.
  21.     if event == "UNIT_POWER" and (unit ~= "player" or resource ~= "MANA") then return end
  22.  
  23.     -- Check if the player has ANY totem active.
  24.     local hasTotem
  25.     for i = 1, 4 do
  26.         local _, name = GetTotemInfo(i)
  27.         if name and name:len() > 0 then
  28.             hasTotem = true
  29.             break
  30.         end
  31.     end
  32.  
  33.     -- Do things here depending on whether or not a totem is active.
  34.     if hasTotem then
  35.         self:Show() -- Inside this scope, "self" refers to the frame.
  36.     else
  37.         self:Hide()
  38.     end
  39. end)
Thank you.
Of course I will listen to PLAYER_TOTEM_UPDATE and not to UNIT_POWER, that was just a substitute because I wasn't aware of that event's existence. That would also eliminate the need for querying the power type (and also the unitID?)

I do want to listen to the two "entering combat events".

I'm not at my home WoW installation so I can't work on the addon right now. I will update this post later.
  Reply With Quote
01-03-12, 06:43 AM   #11
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
As the first return of GetTotemInfo is wether a totem exists or not, you don't have to check names.

The cleanest and most efficent way to do this is so:

Lua Code:
  1. if(select(2, UnitClass('player')) ~= 'SHAMAN') then return end
  2.  
  3. local addon = CreateFrame('Frame')
  4. addon:RegisterEvent('PLAYER_REGEN_ENABLED')
  5. addon:RegisterEvent('PLAYER_TOTEM_UPDATE')
  6. addon:SetScript('OnEvent', function(self)
  7.     local hasTotem
  8.  
  9.     for index = 1, 4 do
  10.         if(GetTotemInfo(index)) then
  11.             hasTotem = true
  12.             break
  13.         end
  14.     end
  15.  
  16.     if(hasTotem) then
  17.         self:Show()
  18.     else
  19.         self:Hide()
  20.     end
  21. end)

You can check for each totem if you'd like, through the 1st argument in PLAYER_TOTEM_UPDATE.

I made a simple totem tracking addon for my shaman about a year ago, take a look if you want:
https://github.com/p3lim/Devak/blob/master/Devak.lua
  Reply With Quote
01-03-12, 07:38 AM   #12
Rilgamon
Premium Member
 
Rilgamon's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 822
returns true if you have the totem reagent in your bag ([Earth Totem], [Fire Totem], [Water Totem], [Air Totem]).
The first value is not true if a totem is placed it is only a check if you have the required totem available.
__________________
The cataclysm broke the world ... and the pandas could not fix it!
  Reply With Quote
01-03-12, 08:18 AM   #13
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
Originally Posted by Rilgamon View Post
The first value is not true if a totem is placed it is only a check if you have the required totem available.
http://wowprogramming.com/docs/api/GetTotemInfo
https://github.com/tekkub/wow-ui-sou...mFrame.lua#L53
  Reply With Quote
01-03-12, 09:39 AM   #14
Rilgamon
Premium Member
 
Rilgamon's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 822
This is misleading as mentioned above.
This code will always return true for haveTotem no matter if a totem is active or not
Code:
/run for i=1,4 do print(GetTotemInfo(i)) end
__________________
The cataclysm broke the world ... and the pandas could not fix it!
  Reply With Quote
01-04-12, 07:56 PM   #15
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
After looking at some of my own code, checking the duration also works:

Code:
for slot = 1, 4 do
	local _, name, start, duration, icon = GetTotemInfo(slot)
	if duration > 0 then
		-- This totem is active.
	else
		-- This totem is not active.
	end
end
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » "GetTotemInfo" help

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