1. Hello, I wanted to first say that I am really enjoying your book and it has helped me greatly in learning to modify some addons, as well as starting to try to build my own. I am considering buying your 2nd edition book, though since I just bought the 1st edition maybe 4 months ago, I am not sure if it would really be worth it yet. Is the 1st edition really outdated enough for it to warrant me upgrading to the 2nd edition at this point in my addon learning?

    Now, on to the real issue. I am trying to modify Healium to add in Mana bars. I have been successful (I believe) in adding the XML portion, but I am having issues with the LUA part of it. It looks like the addon was built very similar to your Group Templates frames and so I was hoping you could help with what I need to add, and where. I have read through Ch 27 a few times but just not getting what I need to do. This is the XML code I added. The first statusbar was what the author had already, I added the second one for mana.

     <StatusBar name="$parent_HealthBar" parentKey="HealthBar" minValue="0" maxValue="100" defaultValue="100" frameStrata="LOW">
                    <Size x="116" y="23"/>
                    <Anchors>
                        <Anchor point="TOPLEFT">
                            <Offset>
                                <AbsDimension x="2" y="-2"/>
                            </Offset>
                        </Anchor>
                    </Anchors>              
                    <BarTexture file="Interface\Addons\SharedMedia\statusbar\smooth.tga" />
                    <BarColor r="1.0" g="1.0" b="1.0"/>
                    <Scripts >
                        <OnLoad function="Healium_StatusBar_OnLoad" />
                    </Scripts>
                </StatusBar>
                <StatusBar name="$parent_ManaBar" parentKey="ManaBar" minValue="0" maxValue="100" defaultValue="100" frameStrata="LOW">
                    <Size x="116" y="12"/>
                    <Anchors>
                        <Anchor point="TOPLEFT">
                            <Offset>
                                <AbsDimension x="2" y="-25"/>
                            </Offset>
                        </Anchor>
                    </Anchors>              
                    <BarTexture file="Interface\Addons\SharedMedia\statusbar\smooth.tga" />
                    <BarColor r="1.0" g="1.0" b="1.0"/>
                    <Scripts >
                        <OnLoad function="Healium_StatusBar_OnLoad" />
                    </Scripts>
                </StatusBar>
    

    This is the relevant LUA code (I think).

     function HealiumUnitFrames_Button_OnShow(self)
        local unit = self:GetAttribute("unit")
        if unit then
            self.TargetUnit = unit 
    
            for i=1, Healium_MaxButtons, 1 do       
                local button = self.buttons[i]
                if not button then break end
    
                -- update cooldowns
                local id = Healium_ButtonIDs[i]
    
                if id then 
                    local start, duration, enable = GetSpellCooldown(Healium_ButtonIDs[i], BOOKTYPE_SPELL)
                    CooldownFrame_SetTimer(button.cooldown, start, duration, enable)            
                end
            end
    
    
            local name = UnitName(unit)
    
            if name then 
                self.name:SetText(strupper(name))
            else 
                self.name:SetText("")
            end
    
            if not Healium_Units[unit] then
                Healium_Units[unit] = { }
            end
    
            table.insert(Healium_Units[unit], self)
    
            for i =1, MaxBuffs, 1 do
                self.buffs[i].unit = unit
            end
    
            Healium_UpdateUnitHealth(unit, self)
            Healium_UpdateBuffs(unit, self)
        end
     end    
    

    Any help will be greatly appreciated! Thank you in advance.

  2. See, without having more context, it makes it incredibly difficult for me to just tell you what to add. If you have a specific question about something you'd like to accomplish than I can try to work that out with you.

    Please let me know.

  3. I actually decided to just start over and build the mod from the ground up with your Chapter 27 lesson. I have looked it over a few times and just don't see where I messed up though. I did decide to purchase the new edition of the book anyways, since our son wants to learn too, so I will give him my old version. So I have it on order from Amazon atm. Currently the bars will show up in game, but they will not be movable, they stay white, and I get an error. I cant post the error currently as servers are down, but I believe it was about the value being nil for OnLoad.

     <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/ ..\FrameXML\UI.xsd">
    
     <!-- Main Frame Template -->
         <Button name="BasicUnitFrames_ButtonTemplate" virtual="true">
            <Size x="120" y="45"/>
            <Layers>
                <Layer level="ARTWORK">
                    <FontString name="$parent_Name" setAllPoints="true" text="Unknown Entity" inherits="GameFontHighlight"/>
                </Layer>    
            </Layers>
            <Frames>
                <StatusBar name="$parent_HealthBar" minValue="0" maxValue="100" defaultValue="100" setAllPoints="true">
                    <BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
                    <BarColor r="1.0" g="1.0" b="1.0"/>
                    <Scripts>
                        <OnLoad>
                            self:SetFrameLevel(self:GetFrameLevel() - 1)
                        </OnLoad>
                    </Scripts>
                </StatusBar>            
            </Frames>
            <Scripts>
                <OnLoad>
                    BasicUnitFrames_Button_OnLoad(self)
                </OnLoad>
                <OnShow>
                    BasicUnitFrames_Button_OnShow(self)
                </OnShow>
                <OnEvent>
                    BasicUnitFrames_Button_OnEvent(self, event, ...)
                </OnEvent>
                <OnDragStart>
                    BasicUnitFrames_Button_OnDragStart(self, button)
                </OnDragStart>
                <OnDragStop>
                    BasicUnitFrames_Button_OnDragStop(self, button)
                </OnDragStop>
                <OnHide>
                    BasicUnitFrames_Button_OnHide(self, button)
                </OnHide>
            </Scripts>
        </Button>
     <!-- Main Header Template -->  
        <Frame name="BasicUnitFrames_Header" parent="UIParent" inherits="SecureGroupHeaderTemplate" movable="true" hidden="false">
            <Anchors>
                <Anchor point="CENTER"/>            
            </Anchors>
        <Attributes>
            <Attribute name="showParty" type="boolean" value="true"/>
            <Attribute name="showRaid" type="boolean" value="true"/>
            <Attribute name="showPlayer" type="boolean" value="true"/>
            <Attribute name="showSolo" type="boolean" value="true"/>
            <Attribute name="maxColumns" type="number" value="8"/>
            <Attribute name="unitsPerColumn" type="number" value="5"/>
            <Attribute name="columnAnchorPoint" type="string" value="LEFT"/>
            <Attribute name="point" type="string" value="TOP"/>
            <Attribute name="template" type="string" value="BasicUnitFrames_ButtonTemplate"/>
            <Attribute name="templateType" type="string" value="Button"/>
        </Attributes>
        </Frame>
     </UI>
    
    
    
     function BasicUnitFrames_Button_OnLoad(self)
         self:RegisterForDrag("LeftButton")
        self:RegisterForEvent("UNIT_HEALTH")
        self:RegisterForEvent("UNIT_MAXHEALTH")
        self.healthbar = getglobal(self:GetName().."_HealthBar")
        self.name = getglobal(self:GetName().."_Name")
     end
    
     function BasicUnitFrames_Button_OnShow(self)
         local unit = self:GetAttribute("unit")
        if unit then
            self.name:SetText(UnitName(unit))
            local class = select(2, UnitClass(unit)) or "WARRIOR"
            local color = RAID_CLASS_COLORS[class]
            self.healthbar:SetStatusBarColor(color.r, color.g, color.b)
        end
     end
    
     function BasicUnitFrames_Button_OnEvent(self, event, ...)
         local unit = ...
        if self:GetAttribute("unit") == unit then
            if event == "UNIT_MAXHEALTH" then
                self.healthbar:SetMinMaxValues(0, UnitHealthMax(unit))
                self.healthbar:SetValue(UnitHealth(unit))
            elseif event == "UNIT_HEALTH" then
                self.healthbar:SetValue(UnitHealth(unit))
            end
        end
     end
    
     function BasicUnitFrames_Button_OnDragStart(self, button)
         BasicUnitFrames_Header:StartMoving()
        BasicUnitFrames_Header.isMoving = true
     end
    
     function BasicUnitFrames_Button_OnDragStop(self, button)
         if BasicUnitFrames_Header.isMoving then
            BasicUnitFrames_Header:StopMovingOrSizing()
        end
     end
    

    I am wondering if I just missed a small mistake or maybe the code rules have changed since book launched and I need to update some code to 3.3 standards. I will try to post error once I can log on.

     Message: [string "BasicUnitFrames_HeaderUnitButton1:OnLoad"]:1: attempt to call global 'BasicUnitFrames_Button_OnLoad' (a nil value)
     Time: 03/30/10 11:25:09
     Count: 1
     Stack: [string "*:OnLoad"]:1: in function <[string "*:OnLoad"]:1>
     [C]: in function `CreateFrame'
     Interface\FrameXML\SecureTemplates.lua:774: in function <Interface\FrameXML\SecureTemplates.lua:729>
     Interface\FrameXML\SecureTemplates.lua:1024: in function <Interface\FrameXML\SecureTemplates.lua:905>
    
     Locals: self = BasicUnitFrames_HeaderUnitButton1 {
      0 = <userdata>
     }
     (*temporary) = nil
     (*temporary) = BasicUnitFrames_HeaderUnitButton1 {
      0 = <userdata>
     }
     (*temporary) = "attempt to call global 'BasicUnitFrames_Button_OnLoad' (a nil value)"
    
  4. What's loading the first, the XML or the Lua? I think the Lua script will need to be loaded first due to some changes in the way script handlers are created. Let me know.

  5. I assume you are asking which is first in the TOC? I had it set to XML first. When I swapped it to LUA first I got 13 errors. The first of which was:

     **Message: Interface\AddOns\BasicUnitFrames\BasicUnitFrames.lua:4: attempt to call method 'RegisterForEvent' (a nil value)
     Time: 03/30/10 12:41:47
     Count: 1
     Stack: Interface\AddOns\BasicUnitFrames\BasicUnitFrames.lua:4: in function `BasicUnitFrames_Button_OnLoad'
     [string "*:OnLoad"]:1: in function <[string "*:OnLoad"]:1>
     [C]: in function `CreateFrame'
     Interface\FrameXML\SecureTemplates.lua:774: in function <Interface\FrameXML\SecureTemplates.lua:729>
     Interface\FrameXML\SecureTemplates.lua:1024: in function <Interface\FrameXML\SecureTemplates.lua:905>
    
     Locals: self = BasicUnitFrames_HeaderUnitButton1 {
      0 = <userdata>
     }
     (*temporary) = nil
     (*temporary) = BasicUnitFrames_HeaderUnitButton1 {
      0 = <userdata>
     }
     (*temporary) = "UNIT_HEALTH"
     (*temporary) = "attempt to call method 'RegisterForEvent' (a nil value)"
     **
    

    And here is TOC just in case:

     ## Interface: 30300
     ## Title: BasicUnitFrames
     ## Notes: Unitframe replacement mod that is inspired from ProfitUI Reborn from EQ2.
    
     BasicUnitFrames.lua
     BasicUnitFrames.xml
    
  6. There is no RegisterForEvent method. It should be RegisterEvent.

  7. Woot! Something so minor.... I looked over that code for hours and just never saw the problem. Thank you for your help! Now on to adding mana bars and other goodies!

  8. Another issue I have run into... I wanna split the Button in half basically, top half being Healhbar and bottom being mana. I assumed what I would do is change the setAllPoints to an actual anchor snippet and then add in the same basic values for manabars, like such:

     <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/ ..\FrameXML\UI.xsd">
    
     <!-- Main Frame Template -->
         <Button name="BasicUnitFrames_ButtonTemplate" virtual="true">
            <Size x="120" y="30"/>
            <Layers>
                <Layer level="ARTWORK">
                    <FontString name="$parent_Name" setAllPoints="true" text="Unknown Entity" inherits="GameFontHighlight"/>
                </Layer>    
            </Layers>
            <Frames>
                <StatusBar name="$parent_HealthBar" minValue="0" maxValue="100" defaultValue="100" parent="UIParent">
                    <Size x="120" y="20"/>
                    <Anchors>
                        <Anchor point="TOPLEFT" relativeTo="BasicUnitFrames_Header"/>
                    </Anchors>
                    <BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
                    <BarColor r="1.0" g="1.0" b="1.0"/>
                    <Scripts>
                        <OnLoad>
                            self:SetFrameLevel(self:GetFrameLevel() - 1)
                        </OnLoad>
                    </Scripts>
                </StatusBar>
                <StatusBar name="$parent_ManaBar" minValue="0" maxValue="100" defaultValue="100" parent="UIParent">
                    <Size x="120" y="10"/>
                    <Anchors>
                        <Anchor point="BOTTOMLEFT" relativeTo="BasicUnitFrames_Header"/>
                    </Anchors>
                    <BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
                    <BarColor r="1.0" g="1.0" b="1.0"/>
                    <Scripts>
                        <OnLoad>
                            self:SetFrameLevel(self:GetFrameLevel() - 1)
                        </OnLoad>
                    </Scripts>
                </StatusBar>    
            </Frames>
            <Scripts>
                <OnLoad>
                    BasicUnitFrames_Button_OnLoad(self)
                </OnLoad>
                <OnShow>
                    BasicUnitFrames_Button_OnShow(self)
                </OnShow>
                <OnEvent>
                    BasicUnitFrames_Button_OnEvent(self, event, ...)
                </OnEvent>
                <OnDragStart>
                    BasicUnitFrames_Button_OnDragStart(self, button)
                </OnDragStart>
                <OnDragStop>
                    BasicUnitFrames_Button_OnDragStop(self, button)
                </OnDragStop>
            </Scripts>
        </Button>
     <!-- Main Header Template -->  
        <Frame name="BasicUnitFrames_Header" parent="UIParent" inherits="SecureGroupHeaderTemplate" movable="true" hidden="false">
            <Anchors>
                <Anchor point="CENTER"/>            
            </Anchors>
        <Attributes>
            <Attribute name="showParty" type="boolean" value="true"/>
            <Attribute name="showRaid" type="boolean" value="true"/>
            <Attribute name="showPlayer" type="boolean" value="true"/>
            <Attribute name="showSolo" type="boolean" value="true"/>
            <Attribute name="maxColumns" type="number" value="8"/>
            <Attribute name="unitsPerColumn" type="number" value="5"/>
            <Attribute name="columnAnchorPoint" type="string" value="LEFT"/>
            <Attribute name="point" type="string" value="TOP"/>
            <Attribute name="template" type="string" value="BasicUnitFrames_ButtonTemplate"/>
            <Attribute name="templateType" type="string" value="Button"/>
        </Attributes>
        </Frame>
     </UI>
    

    When I do this though, it seems to just delete the Statusbars. I used DevTools and dont even see the statusbars anywhere. All I see are the player names and the following frames:

    UIParent, BasicUnitFramesHeader, BasicUnitFramesHeaderButton1

    I had relativeTo wrong, now the bars show, but no longer work and aren't colorcoded. So still working on it.

  9. I finally got the 2nd edition yesterday and it's a very nice book. I have started doing the Unti frames from Chapter 27 and all is working well so far but the power bar is just showing as black.

    I just am not seeing what I did wrong in the code so far. Thanks in advance for anyone that can help.

    LUA:

     function PuirWow_UnitFrames_InitialConfig(frame)
        -- Nudge the status bar frame levels down
        frame.unit.healthBar:SetFrameLevel(frame.unit:GetFrameLevel())
        frame.unit.powerBar:SetFrameLevel(frame.unit:GetFrameLevel())
        frame.unit:RegisterForDrag("LeftButton")
    
        frame:RegisterEvent("UNIT_HEALTH")
        frame:RegisterEvent("UNIT_MAXHEALTH")
        frame:RegisterEvent("PLAYER_ENTERING_WORLD")
        frame:RegisterEvent("UNIT_DISPLAYPOWER")
        frame:RegisterEvent("UNIT_NAME_UPDATE")
     end
    
     function PuirWow_UnitFrames_Frame_OnShow(button)
        local unit = button:GetAttribute("unit")
    
        if unit then
            local guid = UnitGUID(unit)
            if guid ~= button.guid then
                PuirWow_UnitFrames_ResetUnitButton(button.unit, unit)
                button.guid = guid
            end
        end
     end
    
     function PuirWow_UnitFrames_ResetUnitButton(button, unit)
        PuirWow_UnitFrames_ResetHealthBar(button, unit)
        PuirWow_UnitFrames_ResetPowerBar(button, unit)
        PuirWow_UnitFrames_ResetName(button, unit)
     end
    
     function PuirWow_UnitFrames_ResetName(button, unit)
        local name = UnitName(unit) or UNKNOWN
        button.name:SetText(name)
     end
    
     function PuirWow_UnitFrames_ResetHealthBar(button, unit)
        local class = select(2, UnitClass(unit)) or "WARRIOR"
        local classColor = RAID_CLASS_COLORS[class]
    
        button.healthBar:SetStatusBarColor(classColor.r, classColor.g, classColor.b)
        button.healthBar:SetMinMaxValues(0, UnitHealthMax(unit))
        button.healthBar:SetValue(UnitHealth(unit))
     end
    
     function PuirWow_UnitFrames_Button_OnDragStart(self, button)
        PuirWow_UnitFrames_Header:StartMoving()
        PuirWow_UnitFrames_Header.isMoving = true
     end
    
     function PuirWow_UnitFrames_Button_OnDragStop(self, button)
        if PuirWow_UnitFrames_Header.isMoving then
            PuirWow_UnitFrames_Header:StopMovingOrSizing()
        end
     end
    
     function PuirWow_UnitFrames_Frame_OnEvent(self, event, arg1, ...)
        local unit = self:GetAttribute("unit")
        if not unit then
            return
        end
    
        -- Handle any events that don't accept a unit argument
        if event == "PLAYER_ENTERING_WORLD" then
            PuirWow_UnitFrames_ResetUnitButton(self.unit, unit)
        elseif arg1 and UnitIsUnit(unit, arg1) then
            local powerType, powerToken = UnitPowerType(unit)
            if event =="UNIT_MAXHEALTH" then
                self.unit.healthBar:SetMinMaxValues(0, UnitHealthMax(unit))
                self.unit.healthBar:SetValue(UnitHealth(unit))
            elseif event =="UNIT_HEALTH" then
                self.unit.healthBar:SetValue(UnitHealth(unit))
            elseif event == "UNIT_DISPLAYPOWER" then
                PuirWow_UnitFrames_ResetPowerBar(self.unit, unit)
            elseif event == "UNIT_" .. powerToken then
                self.unit.powerBar:SetValue(UnitPower(unit))
            elseif event == "UNIT_MAX" .. powerToken then
                self.unit.powerBar:SetMinMaxValues(0, UnitPowerMax(unit))
                self.unit.powerBar:SetValue(UnitPower(unit))
            elseif event == "UNIT_NAME_UPDATE" then
                PuirWow_UnitFrames_ResetName(self.unit, unit)
            end     
        end
     end
    
     local function unregisterManyEvents(frame, ...)
        for i=1, select("#", ...) do
            local event = select(i, ...)
            frame:UnregisterEvent(event)
        end
     end
    
     function PuirWow_UnitFrames_ResetPowerBar(button, unit)
        local powerType, powerToken = UnitPowerType(unit)
        local powerColor = PowerBarColor[powerToken]
        local alive = not UnitIsDeadOrGhost(unit)
    
        local parent = button:GetParent()
        unregisterManyEvents(parent, "UNIT_MANA", "UNIT_RAGE", "UNIT_FOCUS", "UNIT_ENERGY", "UNIT_RUNIC_POWER")
        unregisterManyEvents(parent, "UNIT_MAXMANA", "UNIT_MAXRAGE", "UNIT_MAXFOCUS", "UNIT_MAXENERGY", "UNIT_MAXRUNIC_POWER")
    
        parent:RegisterEvent("UNIT_" .. powerToken)
        parent:RegisterEvent("UNIT_MAX" .. powerToken)
    
        button.powerBar:SetStatusBarColor(powerColor.r, powerColor.g, powerColor.b)
        button.powerBar:SetMinMaxValues(0, UnitPowerMax(unit))
        button.powerBar:SetValue(UnitPower(unit))
     end
    
     PuirWow_UnitFrames_Header.initialConfigFunction = PuirWow_UnitFrames_InitialConfig
     PuirWow_UnitFrames_Header:Show()
    

    The XML:

     <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/
        ..\FrameXML\UI.xsd">
    
        <Frame name="PuirWow_UnitFrames_UnitTemplate" virtual="true">
            <Size x="120" y="35"/>
            <Layers>
                <Layer level="BACKGROUND">
                    <Texture setAllPoints="true">
                        <Color r="0.0" g="0.0" b="0.0"/>
                    </Texture>
                </Layer>
            </Layers>
            <Frames>
                <Button name="$parent_Unit" parentKey="unit" inherits="SecureUnitButtonTemplate">
                    <Size x="118" y="33"/>
                    <Anchors>
                        <Anchor point="TOPLEFT">
                            <Offset x="1" y="1"/>
                        </Anchor>
                    </Anchors>
                    <Layers>
                        <Layer level="OVERLAY">
                            <FontString name="$parent_Name" parentKey="name" inherits="GameFontHighlight" setAllPoints="true"/>
                        </Layer>
                    </Layers>
                    <Frames>
                        <StatusBar name="$parent_HealthBar" parentKey="healthBar">
                            <Size x="118" y="25"/>
                            <Anchors>
                                <Anchor point="TOPLEFT"/>                           
                            </Anchors>
                            <BarTexture file="Interface\Buttons\UI-Listbox-Highlight2"/>
                            <BarColor r="1.0" g="1.0" b="1.0"/>
                        </StatusBar>
                        <StatusBar name="$parent_PowerBar" parentKey="powerBar">
                            <Size x="118" y="9"/>
                            <Anchors>
                                <Anchor point="TOPLEFT" relativeTo="$parent_HealthBar" relativePoint="BOTTOMLEFT">
                                    <Offset x="0" y="-1"/>
                                </Anchor>
                            </Anchors>
                            <BarTexture file="Interface\TargetingFrame-BarFill"/>
                            <BarColor r="1.0" g="1.0" b="1.0"/>
                        </StatusBar>
                    </Frames>
                    <Scripts>
                        <OnDragStart function="PuirWow_UnitFrames_Button_OnDragStart"/>
                        <OnDragStop function="PuirWow_UnitFrames_Button_OnDragStop"/>
                        <OnHide function="PuirWow_UnitFrames_Button_OnDragStop"/>
                    </Scripts>
                    <Attributes>
                    <Attribute name="useparent-unit" type="boolean" value="true"/>
                    <Attribute name="*type1" type="string" value="target"/>
                </Attributes>
                </Button>
            </Frames>
            <Scripts>
                <OnShow function="PuirWow_UnitFrames_Frame_OnShow"/>
                <OnEvent function="PuirWow_UnitFrames_Frame_OnEvent"/>
            </Scripts>
        </Frame>
    
        <!-- Header Template -->
    
        <Frame name="PuirWow_UnitFrames_Header" parent="UIParent" inherits="SecureGroupHeaderTemplate" movable="true">
            <Anchors>
                <Anchor point="CENTER"/>
            </Anchors>
            <Attributes>
                <Attribute name="showParty" type="boolean" value="true"/>
                <Attribute name="showRaid" type="boolean" value="true"/>
                <Attribute name="showPlayer" type="boolean" value="true"/>
                <Attribute name="showSolo" type="boolean" value="true"/>
                <Attribute name="maxColumns" type="number" value="8"/>
                <Attribute name="unitPerColumn" type="number" value="5"/>
                <Attribute name="columnAnchorPoint" type="string" value="TOP"/>
                <Attribute name="point" type="string" value="LEFT"/>
                <Attribute name="template" type="string" value="PuirWow_UnitFrames_UnitTemplate"/>
                <Attribute name="templateType" type="string" value="Frame"/>
                <Attribute name="xOffset" type="number" value="-1"/>
                <Attribute name="yOffset" type="number" value="1"/>
            </Attributes>
        </Frame>
     </Ui>
    
  10. NM, I found my problem. I didn't type out the power bar XML code poperly for the BarTexture file