WoW:Identifying buffs using textures: Difference between revisions

From AddOn Studio
Jump to navigation Jump to search
(Typo fixing, typos fixed: occurances → occurrences using AWB)
mNo edit summary
Line 1: Line 1:
In some circumstances, it may be benefecial to use spell textures, rather than names, to identify buff and debuff effects - textures require no additional localization, while buff names will require to be localized for every language your addon should support. This HOWTO describes an easy mechanism to find out if a certain unit is affected by a specific buff or debuff.
In some circumstances, it may be benefecial to use spell textures, rather than names, to identify buff and debuff effects - textures require no additional localization, while buff names will require to be localized for every language your addon should support. This HOWTO describes an easy mechanism to find out if a certain unit is affected by a specific buff or debuff.


==Iterating buff / debuffs==
== Iterating buff / debuffs ==
While we could write separate functions for buffs and debuffs, it's easier to write a single ''iterator'' function and pass the desired spell effect type as an argument - effectively cutting down the amount of code required for the whole routine. We can get the buff's texture from [[API UnitBuff|UnitBuff]] and debuffs from [[API UnitDebuff|UnitDebuff]]:
While we could write separate functions for buffs and debuffs, it's easier to write a single ''iterator'' function and pass the desired spell effect type as an argument - effectively cutting down the amount of code required for the whole routine. We can get the buff's texture from [[API UnitBuff|UnitBuff]] and debuffs from [[API UnitDebuff|UnitDebuff]]:
  name, rank, iconTexture, count, duration, timeLeft =  UnitBuff(unit, buffIndex [, castable]);
  name, rank, iconTexture, count, duration, timeLeft =  UnitBuff(unit, buffIndex [, castable]);
Line 60: Line 60:
==See also==
==See also==
* [[Queriable buff effects|List of buff and debuff textures]]
* [[Queriable buff effects|List of buff and debuff textures]]
[[Category:HOWTOs|Identify Buffs Using Textures]]
[[Category:HOWTOs|Identify Buffs Using Textures]]

Revision as of 02:21, 21 May 2020

In some circumstances, it may be benefecial to use spell textures, rather than names, to identify buff and debuff effects - textures require no additional localization, while buff names will require to be localized for every language your addon should support. This HOWTO describes an easy mechanism to find out if a certain unit is affected by a specific buff or debuff.

Iterating buff / debuffs

While we could write separate functions for buffs and debuffs, it's easier to write a single iterator function and pass the desired spell effect type as an argument - effectively cutting down the amount of code required for the whole routine. We can get the buff's texture from UnitBuff and debuffs from UnitDebuff:

name, rank, iconTexture, count, duration, timeLeft =  UnitBuff(unit, buffIndex [, castable]);
name, rank, texture, count, debuffType, duration, timeLeft  =  UnitDebuff(unitID, debuffIndex [, removable]);

The effect's texture is the third return value of both functions, but UnitDebuff has one more return value - which means that we'll need to store all seven return values in order to return them. Castable and removable arguments allow us to save iterations of the loop if we're only interested in buffs/debuffs the player can cast/remove, so we should allow access to those from the iterator function. For both functions, index starts at 1 and goes up until the function returns nil -- while a while loop is ideal, we can use an infinite loop, and call break; when nil is encountered to save iterator calls. So far, our inner iterator loop would look something like:

qFunc, unit, castable, id, match = UnitBuff, "player", 1, nil, "SomeEffectTexture"; --
while true do
 local name, rank, texture, count, type, duration, timeleft = qFunc(unit, id, castable); -- note UnitDebuff returns; we simply don't care about the names at this point, but we need all seven.
 if not name then
  break; -- There are no more buffs / debuffs, exit infinite loop
 end
 if string.match(texture, match) then
  return name, rank, texture, count, type, duration, timeleft; -- We've found a match
 end
 i = i + 1; -- Go for the next index
end

This would tell return the proper UnitBuff/UnitDebuff returns if the target is affected by a matching buff/debuff, or nil if it's not. Stopping here is good enough; we can, however, make things even better by allowing you to detect multiple textures with the same texture by using another index argument, and then decrementing it on matching effects until we hit zero, returning the found buff entry. Everything combined, the iterator function is:

function iterateQueriableEffect(qFunc, unit, matchTexture, id, castable)
 id = id or 1; -- default value, making id optional;
 while true do
  local name, rank, texture, count, type, duration, timeleft = qFunc(unit, id, castable);
  if not name then
   break;
  end
  if string.match(texture, matchTexture) then
   id = id - 1;
   if id == 0 then
    return name, rank, texture, count, type, duration, timeleft;
   end
  end
 end
end

Using the iterator function to query effects

With the background code written, we can now use it to query actual effects. WoWWiki has a list of buff and debuff textures with associated names; suppose we wanted to know whether the player is buffed with Mark of the Wild: motw is a buff (so we need UnitBuff), player's unitid is "player":

name, rank, texture, count, duration, timeLeft = iterateQueriableEffect(UnitBuff, "player", "Spell_Nature_Regeneration");
if name then
 message("Player is buffed with " .. name .. " (" .. rank .. ")");
else
 message("Player is not buffed with Mark of the Wild.");
end

Or if we wanted to know whether the target is sapped(UnitDebuff, "target"):

name, rank, texture, count, debuffType, duration, timeLeft = iterateQueriableEffect(UnitDebuff, "target", "Ability_Sap");
message(name and "Target is sapped!" or "Target is not sapped"); -- shorthand if syntax -- if name is non-false and non-nil, the first message appears, otherwise, the second.

Other interesting uses

You can find out whether the unit is affected by a debuff you can remove (by using the castable argument, which doubles up as removable for debuffs):

name, rank, texture, count, debuffType, duration, timeLeft = iterateQueriableEffect(UnitDebuff, unit, ".", 1, true); -- "." matches all textures, so we only have to get a return from UnitDebuff(unit, id, true) for this to return something.

You can also use the id argument to find all buffs/debuffs with the same texture on target; for example, "Spell_Fire_FireArmor" is used for almost all fire-shield effects - Fire Ward, greater protection potions, warlock imps' fire thorns spell... suppose you wanted to iterate through them:

local i, out = 1, "";
while true do
 local name, rank = iterateQueriableEffect(UnitBuff, unit, "Spell_Fire_FireArmor", i);
 if not name then break; end
 out = out .. (out == "" and "" or ", ") .. name;
end
message("Following debuffs on unit share Spell_Fire_FireArmor texture: " .. out);

Note that the last example is somewhat inefficient - you would be better off acquiring all the buff names in a single local loop rather than iterating through buffs multiple times to find all occurrences of a certain texture.

See also