Thread Tools Display Modes
04-05-12, 09:08 AM   #1
wiMp
A Deviate Faerie Dragon
Join Date: Mar 2008
Posts: 10
Help with creating basic debuff frames.

Hey,

I've just started off with my first little script for WoW. Which I basically want to show debuffs on the default enemy arena frames.

I came up with the following code:
Lua Code:
  1. function ArenaEnemyDebuffUpdate()
  2.     for i=1,10 do local name,_,icon,_,debuffType,duration,timeLeft=UnitDebuff("target",i);
  3.     if name then
  4.         local f = CreateFrame("Button","ArenaEnemyFrameDebuff"..i,UIParent)
  5.         f:SetWidth(22)
  6.         f:SetHeight(22)
  7.         local t = f:CreateTexture(nil,"BACKGROUND")
  8.         t:SetTexture(icon)
  9.         t:SetAllPoints(f)
  10.         f.texture = t
  11.         f:SetPoint("BOTTOM","PlayerFrame",22*(i-1),0)
  12.     end
  13.     end
  14. end
  15.  
  16.  
  17. local g = CreateFrame("Frame")
  18. g:RegisterEvent("UNIT_AURA")
  19. g:SetScript("OnEvent",function(self,event,a1)
  20.         if arg1 == target then
  21.             ArenaEnemyDebuffUpdate()
  22.         end
  23. end)

This is currently set to work for the target, as I use this for testing purposes mostly.

However the error I've run into is; the frames don't hide when the debuff runs off.

Hopefully it's an easy fix and I haven't started off going into the wrong direction.

Please keep in mind that I'm very new at this, and it's probably pretty poorly written, so any advice is welcome!

Thanks
  Reply With Quote
04-05-12, 05:45 PM   #2
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Your main problem is that every time any buffs or debuffs update on the target, your code is creating 1-10 new frames. You need to create those frames ONCE, outside of your event handler, and then update them when auras change.

Other problems include the fact that while you are showing/configuring buttons when the debuff exists, you aren't hiding buttons when the debuff doesn't exist.

Consistent line-breaking and indentation will also make your code more readable, as will omitting the use of semicolons, which are (almost always) useless in Lua.

Lua Code:
  1. -- Create a table to hold all the debuff icons, so you do not have to
  2. -- waste CPU cycles on slow global lookups and string concatenations
  3. -- later.
  4. local debuffIcons = {}
  5.  
  6. -- Create all the icons ahead of time.
  7. for i = 1, 10 do
  8.     local f = CreateFrame("Button", "ArenaEnemyFrameDebuff"..i, UIParent)
  9.     f:SetPoint("BOTTOM", "PlayerFrame", 22 * (i - 1), 0)
  10.     f:SetWidth(22)
  11.     f:SetHeight(22)
  12.     f:Hide() -- Hide the button for now.
  13.  
  14.     local t = f:CreateTexture(nil, "BACKGROUND")
  15.     t:SetAllPoints(true)
  16.     f.texture = t
  17.  
  18.     -- Put the icon into the table.
  19.     debuffIcons[i] = f
  20. end
  21.  
  22. local eventFrame = CreateFrame("Frame")
  23. eventFrame:RegisterEvent("UNIT_AURA")
  24. eventFrame:SetScript("OnEvent", function(self, event, unit)
  25.     if unit ~= "target" then
  26.         -- Wrong unit. Quit.
  27.         return
  28.     end
  29.  
  30.     for i = 1, 10 do
  31.         -- Figure out which button to use for this slot.
  32.         local button = debuffIcons[i]
  33.         -- Get information about the debuff in this slot, if any.
  34.         local name, _, icon, _, debuffType, duration, timeLeft = UnitDebuff("target", i)
  35.         if name then
  36.             -- There's a debuff in this slot.
  37.             -- Set the correct texture, and show the button.
  38.             button.texture:SetTexture(icon)
  39.             button:Show()
  40.         else
  41.             -- There's no debuff in this slot.
  42.             -- Clear the texture, and hide the button.
  43.             button.texture:SetTexture("")
  44.             button:Hide()
  45.         end
  46.     end
  47. end)
  Reply With Quote
04-06-12, 08:13 AM   #3
wiMp
A Deviate Faerie Dragon
Join Date: Mar 2008
Posts: 10
Thanks for the help!

I'm off trying to work out how to add cooldown and debuff type borders!
  Reply With Quote
04-10-12, 06:33 AM   #4
wiMp
A Deviate Faerie Dragon
Join Date: Mar 2008
Posts: 10
Hey,

I've added cooldown, count and debufftype borders. The functionality is fine, however I'd still like it if someone could point out any inefficiencies in my code. As I'm mostly doing this for the learning experience.

Here's the code:

Lua Code:
  1. -- Create a table to hold all the debuff icons, so you do not have to
  2. -- waste CPU cycles on slow global lookups and string concatenations
  3. -- later.
  4. local debuffIcons = {}
  5. local debuffBorders = {}
  6. local debuffCount = {}
  7. local debuffCooldown = {}
  8.  
  9. local debuffType, color
  10.  
  11. -- Create all the icons ahead of time.
  12. for i = 1, 10 do
  13.     local f = CreateFrame("Button", "ArenaEnemyFrameDebuff"..i, UIParent)
  14.     local b = CreateFrame("Frame", "ArenaEnemyFrameDebuff"..i.."Border", f)
  15.     local c = f:CreateFontString("ArenaEnemyFrameDebuff"..i.."Count", "OVERLAY", "NumberFontNormalSmall")
  16.     local g = CreateFrame("Cooldown","ArenaEnemyFrameDebuff"..i.."Cooldown",f)
  17.    
  18.     if i == 1 then
  19.         f:SetPoint("BOTTOM", "PlayerFrame", 0, 0)
  20.     else
  21.         f:SetPoint("BOTTOM", "ArenaEnemyFrameDebuff"..i-1, 27, 0)
  22.     end
  23.     f:SetWidth(20)
  24.     f:SetHeight(20)
  25.    
  26.     g:SetAllPoints("ArenaEnemyFrameDebuff"..i)
  27.     g:SetParent(f)
  28.     g:SetReverse(true)
  29.     g:SetDrawEdge(true)
  30.    
  31.     c:SetAllPoints(true)
  32.     c:SetPoint("BOTTOMRIGHT","ArenaEnemyFrameDebuff"..i,18,-10)
  33.     c:SetParent(f)
  34.    
  35.     local t = f:CreateTexture(nil, "ARTWORK")
  36.     t:SetAllPoints(true)
  37.     t:SetTexCoord(.08, .92, .08, .92)
  38.    
  39.     local d = b:CreateTexture(nil, "ARTWORK")
  40.     d:SetAllPoints(true)
  41.     d:SetTexCoord(0.296875,0.5703125,0,0.535625)
  42.    
  43.     b:SetPoint("CENTER","ArenaEnemyFrameDebuff"..i,0,0)
  44.     b:SetHeight(25)
  45.     b:SetWidth(25)
  46.     b:SetParent(f)
  47.    
  48.     f:Hide()
  49.    
  50.     f.cooldown = g
  51.     f.count = c
  52.     f.border = d
  53.     f.texture = t
  54.    
  55.     debuffCooldown[i] = g
  56.     debuffCount[i] = c
  57.     debuffBorders[i] = d
  58.     debuffIcons[i] = f
  59. end
  60.  
  61. local eventFrame = CreateFrame("Frame")
  62. eventFrame:RegisterEvent("UNIT_AURA")
  63. eventFrame:SetScript("OnEvent", function(self, event, unit)
  64.     if unit ~= "target" then
  65.         -- Wrong unit. Quit.
  66.         return
  67.     end
  68.  
  69.     for i = 1, 10 do
  70.         -- Figure out which button to use for this slot.
  71.         local button = debuffIcons[i]
  72.         local border = debuffBorders[i]
  73.         local dbcount = debuffCount[i]
  74.         local cd = debuffCooldown[i]
  75.         -- Get information about the debuff in this slot, if any.
  76.         local name, _, icon, count, debuffType, duration, timeLeft = UnitDebuff("target", i)
  77.         if name then
  78.             if debuffType then
  79.                 color = DebuffTypeColor[debuffType]
  80.             else
  81.                 color = DebuffTypeColor["none"]
  82.             end
  83.             if count > 0 then
  84.                 dbcount:SetText(count)
  85.                 dbcount:Show()
  86.                 dbcount:SetDrawLayer("OVERLAY")
  87.             else
  88.                 dbcount:Hide()
  89.             end
  90.             if duration > 0 then
  91.                 cd:Show()
  92.                 CooldownFrame_SetTimer(cd, timeLeft - duration, duration, 1)
  93.             else
  94.                 cd:Hide()
  95.             end
  96.            
  97.             -- There's a debuff in this slot.
  98.             -- Set the correct texture, and show the button.
  99.             button.texture:SetTexture(icon)
  100.             border:SetTexture("Interface\\Buttons\\UI-Debuff-Overlays")
  101.             button:Show()
  102.             border:SetVertexColor(color.r, color.g, color.b)
  103.         else
  104.             -- There's no debuff in this slot.
  105.             -- Clear the texture, and hide the button.
  106.             cd:Hide()
  107.             dbcount:SetText("")
  108.             button.texture:SetTexture("")
  109.             border:SetTexture("")
  110.  
  111.         end
  112.     end
  113. end)

Also how would I switch this to working for multiple targets, without repeating the code. I want it to work for arena enemy frames, so would
Lua Code:
  1. for i = 1, MAX_ARENA_ENEMIES do
the way to go? Anything I need to keep in mind while doing this?

Any pointers and help is greatly appreciated, thanks!
  Reply With Quote
04-11-12, 05:50 PM   #5
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
1. You do not need to keep calling x:SetParent(f) when f is already the parent of x because you specified that in the CreateFrame call.

2a. I'd strongly suggest using descriptive variable names, so that when you are looking at this code weeks, months, or even years later you can immediately tell what's what instead of having to puzzle out what a single-letter variable like "g" means.

2b. Similarly, you should keep all of the code related to, for example, the border in the same place instead of putting half of it in one place, and the other half 20 lines later for no apparent reason. It might make sense *now* but will it still make sense 6 months from now? Will it make sense to people trying to help you identify and fix bugs, or add features to your code?

3. I'd recommend against giving every frame, texture, and font string a global name. The only real reasons to give anything a global name are (a) the object is a saved variable, or (b) the object is a top-level addon frame/table and you want it to be accessible to other addons or by in-game /run commands, or (c) you will be using Blizzard templates/functions that are designed to work with Blizzard UI objects with specific global names for their regions and children. Since none of those are the case here, global names aren't needed.

Lua Code:
  1. -- Create a table to hold all of the units you want to add debuff icons to.
  2. -- To add new units, simply add them to the table; no code modifications are required!
  3. -- The keys in each unit's table define where to place the icons relative to the frame.
  4. local debuffIcons = {
  5.     target = {
  6.         frame = "TargetFrame", pointA = "TOPLEFT", pointB = "BOTTOMLEFT", x = 30, y = 0, spacing = 7,
  7.     }
  8.     arena1 = {
  9.         frame = "ArenaEnemy1Frame", pointA = "TOPLEFT", pointB = "BOTTOMLEFT", x = 30, y = 0, spacing = ,
  10.     },
  11.     arena2 = {
  12.         frame = "ArenaEnemy2Frame", pointA = "TOPLEFT", pointB = "BOTTOMLEFT", x = 30, y = 0, spacing = 7,
  13.     },
  14. }
  15.  
  16. for unit, unitTable in pairs(debuffIcons) do
  17.     local frameName = unitTable.frame
  18.     local frame = _G[frameName]
  19.  
  20.     -- Attach the table to the frame so it's easier to access in-game
  21.     -- if you need to do that, eg. for testing with /run commands.
  22.     frame.debuffIcons = unitTable
  23.  
  24.     for i = 1, 10 do
  25.         local f = CreateFrame("Button", frame, UIParent)
  26.         if i == 1 then
  27.             f:SetPoint(unitTable.pointA, frame, unitTable.pointB unitTable.x, unitTable.y)
  28.         else
  29.             f:SetPoint("LEFT", unitTable[i-1], "RIGHT", unitTable.spacing, 0)
  30.         end
  31.         f:SetWidth(20)
  32.         f:SetHeight(20)
  33.         f:Hide()
  34.  
  35.         local cd = CreateFrame("Cooldown", nil, f)
  36.         cd:SetAllPoints(true)
  37.         cd:SetReverse(true)
  38.         cd:SetDrawEdge(true)
  39.         f.cd = cd
  40.  
  41.         local count = f:CreateFontString(nil, "OVERLAY", "NumberFontNormalSmall")
  42.         count:SetPoint("BOTTOMRIGHT", 18, -10)
  43.         f.count = count
  44.  
  45.         local icon = f:CreateTexture(nil, "ARTWORK")
  46.         icon:SetAllPoints(true)
  47.         icon:SetTexCoord(.08, .92, .08, .92)
  48.         f.icon = icon
  49.  
  50.         local border = f:CreateTexture(nil, "OVERLAY")
  51.         border:SetPoint("CENTER")
  52.         border:SetHeight(25)
  53.         border:SetWidth(25)
  54.         border:SetTexture("Interface\\Buttons\\UI-Debuff-Overlays")
  55.         border:SetTexCoord(0.296875, 0.5703125, 0, 0.535625)
  56.         f.border = border
  57.  
  58.         unitTable[i] = f
  59.     end
  60. end
  61.  
  62. local eventFrame = CreateFrame("Frame")
  63. eventFrame:RegisterEvent("UNIT_AURA")
  64. eventFrame:SetScript("OnEvent", function(self, event, unit)
  65.     if not units[unit] then
  66.         -- We don't care about this unit. Quit.
  67.         return
  68.     end
  69.  
  70.     -- Get the table containing the buttons for this unit.
  71.     local icons = units[unit]
  72.  
  73.     for i = 1, 10 do
  74.         -- Get the button for this slot.
  75.         local button = icons[i]
  76.  
  77.         -- Get information about the debuff in this slot, if any.
  78.         local name, _, icon, count, debuffType, duration, timeLeft = UnitDebuff("target", i)
  79.         if name then
  80.             -- There is a debuff in this slot.
  81.             -- Populate the button accordingly, and show it.
  82.  
  83.             local color = debuffType and DebuffTypeColor[debuffType]
  84.             button.border:SetVertexColor(color.r, color.g, color.b)
  85.  
  86.             if duration > 0 then
  87.                 button.cd:Show()
  88.                 CooldownFrame_SetTimer(button.cd, timeLeft - duration, duration, 1)
  89.             else
  90.                 button.cd:Hide()
  91.             end
  92.  
  93.             if count > 0 then
  94.                 button.count:SetText(count)
  95.                 button.count:Show()
  96.                 button.count:SetDrawLayer("OVERLAY")
  97.             else
  98.                 button.count:Hide()
  99.             end
  100.  
  101.             button.icon:SetTexture(icon)
  102.  
  103.             button:Show()
  104.         else
  105.             -- There is no debuff in this slot.
  106.             -- Clear the button, and hide it.
  107.  
  108.             button.cd:Hide()
  109.             button.count:SetText("")
  110.             button.icon:SetTexture("")
  111.             button:Hide()
  112.         end
  113.     end
  114. end)
  Reply With Quote
04-12-12, 04:23 AM   #6
wiMp
A Deviate Faerie Dragon
Join Date: Mar 2008
Posts: 10
Thanks Phanx!
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Help with creating basic debuff frames.


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