WoWInterface

WoWInterface (http://www.wowinterface.com/forums/index.php)
-   oUF (Otravi Unit Frames) (http://www.wowinterface.com/forums/forumdisplay.php?f=87)
-   -   Combo Points (and related class powers) (http://www.wowinterface.com/forums/showthread.php?t=44209)

Senit24 09-07-12 10:39 PM

Combo Points (and related class powers)
 
For days, I've been working on creating class class power (specifically combo points) bars. I'm working off some code from another layout. I've tried modifying it numerous ways, but I just can't get any result. I'm not getting any errors, it's just displaying nothing. Can anyone help me find a good sample, or solution to my problem?

Current code: --The function lib.genCPoints being called by my TargetStyle function, obviously.
Code:

do
        ComboDisplay = function(self, event, unit)
                if(unit == 'pet') then return end
               
                local cpoints = self.CPoints
                local cp
                if (UnitHasVehicleUI("player") or UnitHasVehicleUI("vehicle")) then
                        cp = GetComboPoints('vehicle', 'target')
                else
                        cp = GetComboPoints('player', 'target')
                end

                for i=1, MAX_COMBO_POINTS do
                        if(i <= cp) then
                                cpoints[i]:SetAlpha(1)
                        else
                                cpoints[i]:SetAlpha(0.15)
                        end
                end
               
                if cpoints[1]:GetAlpha() == 1 then
                        for i=1, MAX_COMBO_POINTS do
                                cpoints[i]:Show()
                        end
                       
                else
                        for i=1, MAX_COMBO_POINTS do
                                cpoints[i]:Hide()
                        end
                       
                end
        end
end

lib.genCPoints = function(self)
        local bars = CreateFrame("Frame", nil, self)
        bars:SetPoint("BOTTOMLEFT", oUF_Player, "TOPLEFT", 0, 7)
        bars:SetWidth(210)
        bars:SetHeight(2)
        bars:SetBackdrop(backdrop)
        bars:SetBackdropBorderColor(0,0,0,0)
        bars:SetBackdropColor(0,0,0,0)
               
        for i = 1, 5 do               
       
                bars[i] = CreateFrame("StatusBar", self:GetName().."_Combo"..i, bars)
                bars[i]:SetHeight(20)                                       
                bars[i]:SetStatusBarTexture(config.statusbar_texture)
                bars[i]:GetStatusBarTexture():SetHorizTile(false)
                                                       
                if i == 1 then
                        bars[i]:SetPoint("LEFT", bars)
                else
                        bars[i]:SetPoint("LEFT", bars[i-1], "RIGHT", 1, 0)
                end
                bars[i]:SetAlpha(1)
                bars[i]:SetWidth((210 - 4)/5)
        end
               
        bars[1]:SetStatusBarColor(0.69, 0.31, 0.31)               
        bars[2]:SetStatusBarColor(0.69, 0.31, 0.31)
        bars[3]:SetStatusBarColor(0.65, 0.63, 0.35)
        bars[4]:SetStatusBarColor(0.65, 0.63, 0.35)
        bars[5]:SetStatusBarColor(0.33, 0.59, 0.33)
               
        self.CPoints = bars
        self.CPoints.Override = ComboDisplay
               
        bars.FrameBackdrop = CreateFrame("Frame", nil, bars[1])
        bars:SetBackdrop(backdrop)
        bars.FrameBackdrop:SetBackdropBorderColor(0,0,0,1)
        bars.FrameBackdrop:SetPoint("TOPLEFT", bars, "TOPLEFT", -1, 1)
        bars.FrameBackdrop:SetPoint("BOTTOMRIGHT", bars, "BOTTOMRIGHT", 1, -1)
        bars.FrameBackdrop:SetFrameLevel(bars:GetFrameLevel() - 1)
end


Phanx 09-08-12 02:17 AM

Erm, I have no idea why you're defining that ComboDisplay function and using it as an element Override, when it's functionally identical to oUF's standard combo point update function, but contains a lot of unnecessary redundancy. You set the alpha to 15% and then hide the frame, instead of just hiding it, for example. Try getting rid of the Override and see if it works then.

I also don't understand what you're trying to do with the bars.FrameBackdrop section at the end of the block you posted. It's just an extra frame, attached to the bars frame, with no visible anything, since you call SetBackdrop on bars instead of bars.FrameBackdrop, and anyway you're setting the same backdrop that you already set on bars, so even if you did set it on the bars.FrameBackdrop frame, you'd only see 1 pixel of it around the edges since the frames are stacked on top of each other. I'd suggest just getting rid of the whole thing. If you want a 1px border on the bars frame, just change its backdrop to include a 1px border, eg:

Lua Code:
  1. local backdrop = {
  2.     bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = true, tileSize = 8,
  3.     edgeFIle = "Interface\\BUTTONS\\WHITE8X8", edgeSize = 1,
  4.     insets = { left = 1, right = 1, top = 1, bottom = 1 },
  5. }

Finally, your genCPoints function parents bars to self, but anchors it to oUF_Player. If multiple frames call genCpoints, you'll end up with multiple objects piled on top of each other. I'd also suggest combo points be attached to the target frame, rather than the player frame. Not only does that give you more room on the player frame for class powers, but combo points also logically belong on the target, at least for druids, who can have different numbers of combo points on different targets at the same time.

Try this:
Lua Code:
  1. lib.genCPoints = function(self)
  2.     local bars = CreateFrame("Frame", nil, self)
  3.     bars:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 7)
  4.         -- ^^^ Attach to self, and then just call this function from the
  5.         --     frame you actually want it attached to, probably target.
  6.     bars:SetWidth(210)
  7.     bars:SetHeight(2)
  8.     bars:SetBackdrop(backdrop)
  9.     bars:SetBackdropBorderColor(0,0,0,0)
  10.     bars:SetBackdropColor(0,0,0,0)
  11.  
  12.     for i = 1, 5 do
  13.         bars[i] = CreateFrame("StatusBar", nil, bars)
  14.             -- ^^^ No reason to give this a global name.
  15.         bars[i]:SetWidth(41.2) -- (210 - 4) / 5
  16.             -- ^^^ No need to do the math on the fly since it isn't dynamic.
  17.         bars[i]:SetHeight(20)
  18.         bars[i]:SetStatusBarTexture(config.statusbar_texture)
  19.         bars[i]:GetStatusBarTexture():SetHorizTile(false)
  20.         if i == 1 then
  21.             bars[i]:SetPoint("LEFT", bars)
  22.         else
  23.             bars[i]:SetPoint("LEFT", bars[i-1], "RIGHT", 1, 0)
  24.         end
  25.     end
  26.  
  27.     bars[1]:SetStatusBarColor(0.69, 0.31, 0.31)
  28.     bars[2]:SetStatusBarColor(0.69, 0.31, 0.31)
  29.     bars[3]:SetStatusBarColor(0.65, 0.63, 0.35)
  30.     bars[4]:SetStatusBarColor(0.65, 0.63, 0.35)
  31.     bars[5]:SetStatusBarColor(0.33, 0.59, 0.33)
  32.  
  33.     self.CPoints = bars
  34. end

Senit24 09-08-12 10:03 AM

It works great! The original was a rough copy of "oUF_Qulight", hence the redundancy and misfit calls and functions.

As always, thank you Phanx, for you are the reason my UI works. I'm sure you'll be all over the credits :)

Senit24 09-09-12 01:34 PM

After hours of coding, I am more confused than I was to begin with. (Trying to create Warlock Power Bars).
What I wrote for soul shards seems to work:
Lua Code:
  1. UpdateShards = function(self, event, unit, powerType)
  2.     if(self.unit ~= unit or (powerType and powerType ~= 'SOUL_SHARDS')) and (GetSpecialization() ~= SPEC_WARLOCK_AFFLICTION) then return end
  3.         local maxshards = 3
  4.             for i = 1, GetNumGlyphSockets() do
  5.             local glyphID = select(4, GetGlyphSocketInfo(i))
  6.                 if glyphID == 63302 then maxshards = 4 end 
  7.        
  8.             local num = UnitPower(unit, SPELL_POWER_SOUL_SHARDS)
  9.             for i = 1, maxshards do
  10.                 if(i <= num) then
  11.                     self.SoulShards[i]:SetAlpha(1)
  12.                 else
  13.                     self.SoulShards[i]:SetAlpha(0)
  14.                 end    
  15.             end
  16.     end
  17. end

I tried doing the same thing for burning embers, but with no success. Does this function only work because self.SoulShards is predefined in oUF elements? Does this mean I need to write a new element for Embers/Fury/ShadowOrbs/Monks etc?

Phanx 09-09-12 09:45 PM

You must be working with an old version of oUF... get the current one from Haste's GitHub repo:
https://github.com/haste/oUF

There aren't separate elements for Soul Shards, Holy Power, etc. anymore. Instead, all of the class powers that are displayed like combo points are combined into the ClassIcons element. It covers Harmony Orbs (chi), Holy Power, Shadow Orbs, and Soul Shards. If you look at the top of the classicons.lua element file, you'll see an example. You shouldn't need to change much; mainly changing the name of the element from SoulShards to ClassIcons, getting rid of your separate HolyPower element if you have one, and if your layout uses custom textures, add a class check when you're setting up the ClassIcons element to set the appropriate textures.

Here's the ClassIcons example from the oUF/elements/classicons.lua file:
Code:

  local ClassIcons = {}
  for index = 1, 5 do
      local Icon = self:CreateTexture(nil, 'BACKGROUND')
 
      -- Position and size.
      Icon:SetSize(16, 16)
      Icon:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * Icon:GetWidth(), 0)
 
      ClassIcons[index] = Icon
  end
 
  -- Register with oUF
  self.ClassIcons = ClassIcons

You don't need to worry about defining your own Update function for the element; oUF takes care of everything. It does support PreUpdate, PostUpdate, and Override methods though, if you want to change how the element updates. I'd recommend using PostUpdate, and changing only the things you want to change, instead of definining an Override and having to do all the work yourself.

The other warlock powers -- Burning Embers and Demonic Fury -- are not yet supported by oUF itself, but Haste is working on a ClassBars element that will cover those plus all other class powers that have fill values or durations. If you want to support them in the meantime, you'll have to either write your own element, or use Tukz' oUF Warlock Spec Bars plugin. If you're writing your own, feel free to look at the WarlockPower.lua file in oUF Phanx for an example.

Senit24 09-10-12 05:32 PM

Yep. Mine was outdated; I'll get the new one. Great info as always!

p.s. I'm very close to finished with my oUF Layout. I'll be sure to post the finished product, then I can start contributing to the other lua newbs!

Edit: Dun broke the entire addon... where to start...

Edit 2: Seems like everything's working except "oUF.TagEvents", know what's up with that?

Seems like the change from
Code:

oUF.Tags = tags
oUF.TagEvents = tagEvents
oUF.UnitlessTagEvents = unitlessEvents

to
Code:

oUF.Tags = {
        Methods = tags,
        Events = tagEvents,
        SharedEvents = unitlessEvents,

}

would indicate that I need to change "oUF.Tags" to "Methods" and "oUF.TagEvents" to "Events", is there more to it than that?

Edit 3: Nevermind, figured it out! oUF.Tags.Methods and oUF.Tags.Events. Hope this helps anyone else reading!

Senit24 09-12-12 09:03 PM

Okay -- I finally had a chance to look this over and this was my result for holy power (not working):
lua Code:
  1. lib.genHoly = function(self)
  2.     if select(2, UnitClass("player")) ~= "PALADIN" then return end
  3.     local ClassIcons = {}
  4.     for i = 1, 3 do
  5.         local Icon = CreateFrame("StatusBar", nil, ClassIcons)
  6.         Icon:SetSize(20, 20)
  7.         Icon:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 7)
  8.         Icon:SetStatusBarTexture(config.statusbar_texture)
  9.         Icon:GetStatusBarTexture():SetHorizTile(false)
  10.         Icon:SetBackdrop(backdrop)
  11.         Icon:SetBackdropColor(0,0,0,1)
  12.         if i == 1 then
  13.             ClassIcons[i]:SetPoint("LEFT", ClassIcons)
  14.         else
  15.             ClassIcons[i]:SetPoint("LEFT", ClassIcons[i-1], "RIGHT", 10, 0)
  16.         end
  17.         ClassIcons[i] = Icon
  18.     end
  19.      
  20.     ClassIcons[1]:SetStatusBarColor(0.69, 0.31, 0.31)
  21.     ClassIcons[2]:SetStatusBarColor(0.69, 0.31, 0.31)
  22.     ClassIcons[3]:SetStatusBarColor(0.65, 0.63, 0.35)
  23.  
  24.    self.ClassIcons = ClassIcons
  25. end

I feel like it's still over complicated, but I'm not sure where to put the frame options in the example given. I must be functionally retarded. How do!?

Phanx 09-12-12 10:29 PM

I'm not sure what "frame options" you mean, but there are a couple issues with your code.

For one, oUF expects 5 objects, not 3, so you should be getting errors from that. Paladins start out with a max of 3 holy power, but gain an additional 2 (for a total of 5) from the Boundless Conviction passive ability at level 85. oUF will automatically hide the ones that aren't currently in use.

Also, oUF will try to call :SetVertexColor on your objects; since StatusBar objects don't have this method, this should trigger another error unless you remap it to SetStatusBarColor (if you want oUF to color your objects) or a dummy function (if you don't).

Make sure you have BugSack or Swatter or something running when you're working on addons; it will make your life a lot easier.

Try this. It will make sure the last holy power is always the one with the different color, and stop oUF from setting its own holy power color.

Code:

local noop = function() return end

local HolyPostUpdate = function(icons, cur, max, changed)
        for i = 1, 5 do
                if i == max then
                        ClassIcons[i]:SetStatusBarColor(0.65, 0.63, 0.35)
                else
                        ClassIcons[i]:SetStatusBarColor(0.69, 0.31, 0.31)
                end
        end
end


lib.genHoly = function(self)
        if select(2, UnitClass("player")) ~= "PALADIN" then return end
        local ClassIcons = {}
        for i = 1, 5 do
                local Icon = CreateFrame("StatusBar", nil, ClassIcons)
                Icon:SetSize(20, 20)
                Icon:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 7)
                Icon:SetStatusBarTexture(config.statusbar_texture)
                Icon:GetStatusBarTexture():SetHorizTile(false)
                Icon:SetBackdrop(backdrop)
                Icon:SetBackdropColor(0,0,0,1)
                -- Map the method oUF tries to call to one that actually exists:
                Icon.SetVertexColor = noop
                if i == 1 then
                        ClassIcons[i]:SetPoint("LEFT", ClassIcons)
                else
                        ClassIcons[i]:SetPoint("LEFT", ClassIcons[i-1], "RIGHT", 10, 0)
                end
                ClassIcons[i] = Icon
        end
        ClassIcons.PostUpdate = HolyPostUpdate
        self.ClassIcons = ClassIcons
end

If you want to let oUF color the bars, change:

Code:

Icon.SetVertexColor = noop
to:

Code:

Icon.SetVertexColor = Icon.SetStatusBarColor
... and feel free to delete the noop function definition.

Senit24 09-13-12 11:38 PM

So I got BugSack, which is fairly more informative than the regular lua error reports. Anyway, I seem to have a circle of errors with this function:

Code:

lib.genHoly = function(self)
        if select(2, UnitClass("player")) ~= "PALADIN" then return end
        local ClassIcons = {}
        for i = 1, 5 do
                local Icon = CreateFrame("StatusBar", nil, ClassIcons)
                Icon:SetSize(20, 20)
                Icon:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 7)
                Icon:SetStatusBarTexture(config.statusbar_texture)
                Icon:GetStatusBarTexture():SetHorizTile(false)
                Icon:SetBackdrop(backdrop)
                Icon:SetBackdropColor(0,0,0,1)
                -- Map the method oUF tries to call to one that actually exists:
                Icon.SetVertexColor = noop
                if i == 1 then
                      ClassIcons[i]:SetPoint("LEFT", ClassIcons)
                else
                      ClassIcons[i]:SetPoint("LEFT", ClassIcons[i-1], "RIGHT", 10, 0)
                end
                ClassIcons[i] = Icon
        end
        ClassIcons.PostUpdate = HolyPostUpdate
        self.ClassIcons = ClassIcons
end

The CreateFrame is telling me it "can't find "this" in parent object", but when I try to change it then it breaks the last two highlighted lines.

haste 09-14-12 02:12 AM

Quote:

Originally Posted by Senit24 (Post 263956)
So I got BugSack, which is fairly more informative than the regular lua error reports.

The default error handler is superb now. I though BugSack only provided coloring and logging these days.

Quote:

Originally Posted by Senit24 (Post 263956)
The CreateFrame is telling me it "can't find "this" in parent object", but when I try to change it then it breaks the last two highlighted lines.

You're anchoring your frame to a table, that won't work. You either need to anchor it to the frame or calculate out the position like the example does.

Phanx 09-14-12 06:40 AM

Quote:

Originally Posted by haste (Post 263963)
The default error handler is superb now. I though BugSack only provided coloring and logging these days.

The default error handler does not showing errors that occur during the initial loading process. Since 90% of the errors I've ever seen while developing addons occur during loading, that makes it superbly worthless. :p

haste 09-14-12 08:23 AM

Odd, I've always had that problem with custom error handlers :P.

Talyrius 09-14-12 10:46 AM

BugSack is able to capture loading errors, because it uses a separate module (!BugGrabber) that is loaded ahead of other addons (! precedes A-Z).

Rainrider 09-15-12 04:57 AM

Addons are not always loaded alphabetically as far as I know. I depends on the operating system and on what dependencies the individual .toc files contain. WoW just loads addons starting with ! prior to others.

Phanx 09-15-12 06:30 AM

Addons are loaded alphabetically on NTFS filesystems, which, as the filesystem used by Windows, covers the vast majority of users.

I don't know what the Mac filesystem does, or Linux filesystems...

Rainrider 09-15-12 09:40 PM

World of Warcraft Programming (Second Edition), p. 141, 6a:

Quote:

If the addon is dependent on any other addons and they are not currently loaded, load them first in an order that is dependent on the operating system (some are alphabetic, others are by date created).
P.S: Would this mean we can't catch load errors form !BlizzBugsSuck because !BugGrabber is loaded later? :)

Senit24 09-15-12 09:45 PM

Okay... let me be more precise.
I'm getting the error, "CreateFrame: Couldn't find "this" in parent object" on this line.
However, if I change it, I get the error, "attempt to index field "?" (a nil value)" here.
Code:

lib.genHoly = function(self)
        if select(2, UnitClass("player")) ~= "PALADIN" then return end
        local ClassIcons = {}
        for i = 1, 5 do
                local Icon = CreateFrame("StatusBar", nil, ClassIcons)
                Icon:SetSize(20, 20)
                Icon:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 7)
                Icon:SetStatusBarTexture(config.statusbar_texture)
                Icon:GetStatusBarTexture():SetHorizTile(false)
                Icon:SetBackdrop(backdrop)
                Icon:SetBackdropColor(0,0,0,1)
                -- Map the method oUF tries to call to one that actually exists:
                Icon.SetVertexColor = noop
                if i == 1 then
                        ClassIcons[i]:SetPoint("LEFT", ClassIcons)
                else
                        ClassIcons[i]:SetPoint("LEFT", ClassIcons[i-1], "RIGHT", 10, 0)
                end
                ClassIcons[i] = Icon
        end
        ClassIcons.PostUpdate = HolyPostUpdate
        self.ClassIcons = ClassIcons
end

Sorry if I'm asking for too complex of an explanation, but I'm still not getting this. What should I set as the parent frame?

Phanx 09-16-12 12:29 AM

The parent frame must actually be a frame. You are currently passing ClassIcons, which is a table, not a frame. Similarly, you cannot use SetPoint to position things relative to a table, because a table does not have any position or of the other "physical" attributes a frame has.

The easiest solution would be to make ClassIcons a frame, like the combo point holder is:

Code:

local noop = function() return end

lib.genHoly = function(self)
        if select(2, UnitClass("player")) ~= "PALADIN" then return end

        local ClassIcons = CreateFrame("Frame", nil, self)
        ClassIcons:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 7)
        ClassIcons:SetSize(140, 20) -- 5 icons * 20 width + 4 spaces * 10 width

        -- Optional, to match the combo points:
        bars:SetBackdrop(backdrop)
        bars:SetBackdropBorderColor(0,0,0,0)
        bars:SetBackdropColor(0,0,0,0)

        for i = 1, 5 do
                local Icon = CreateFrame("StatusBar", nil, ClassIcons)
                Icon:SetSize(20, 20)

                -- You do not need a SetPoint line here, because you have some
                -- later that just override the one that was here.       

                Icon:SetStatusBarTexture(config.statusbar_texture)
                Icon:GetStatusBarTexture():SetHorizTile(false)

                Icon:SetBackdrop(backdrop)
                Icon:SetBackdropColor(0,0,0,1)

                -- Map the method oUF tries to call to one that actually exists:
                Icon.SetVertexColor = noop

                if i == 1 then
                        Icon:SetPoint("LEFT", ClassIcons)
                else
                        Icon:SetPoint("LEFT", ClassIcons[i-1], "RIGHT", 10, 0)
                end
                ClassIcons[i] = Icon
        end

        ClassIcons.PostUpdate = HolyPostUpdate
        self.ClassIcons = ClassIcons
end


Senit24 09-16-12 11:44 AM

Thanks so much Phanx, it's working again! I made a couple modifications. Also got rid of the post update entirely.
Code:

lib.genHoly = function(self)
        if select(2, UnitClass("player")) ~= "PALADIN" then return end

        local ClassIcons = CreateFrame("Frame", nil, self)
        ClassIcons:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 7)
        ClassIcons:SetSize(140, 20) -- 5 icons * 20 width + 4 spaces * 10 width
       
        for i = 1, 5 do
                local Icon = CreateFrame("StatusBar", nil, ClassIcons)
                Icon:SetSize(20, 20)

                -- You do not need a SetPoint line here, because you have some
                -- later that just override the one that was here.       

                Icon:SetStatusBarTexture(config.statusbar_texture)
                Icon:GetStatusBarTexture():SetHorizTile(false)

                Icon:SetBackdrop(backdrop)
                Icon:SetBackdropColor(0,0,0,1)

                -- Map the method oUF tries to call to one that actually exists:
                Icon.SetVertexColor = noop

                if i == 1 then
                        Icon:SetPoint("LEFT", ClassIcons)
                else
                        Icon:SetPoint("LEFT", ClassIcons[i-1], "RIGHT", 10, 0)
                end
                ClassIcons[i] = Icon
        end

        ClassIcons[1]:SetStatusBarColor(0.69, 0.31, 0.31)
    ClassIcons[2]:SetStatusBarColor(0.69, 0.31, 0.31)
    ClassIcons[3]:SetStatusBarColor(0.65, 0.63, 0.35)
    ClassIcons[4]:SetStatusBarColor(0.69, 0.31, 0.31)
    ClassIcons[5]:SetStatusBarColor(0.65, 0.63, 0.35)
       
        --ClassIcons.PostUpdate = HolyPostUpdate
        self.ClassIcons = ClassIcons
end


dartz 09-16-12 12:28 PM

thank you Phanx, you solved my problem too.


All times are GMT -6. The time now is 08:14 PM.

vBulletin © 2014, Jelsoft Enterprises Ltd
©2012 ZAM Network LLC