Thread Tools Display Modes
01-10-08, 11:00 AM   #1
dudgeon
A Defias Bandit
Join Date: Oct 2007
Posts: 3
I need help making simple energy display

I have not idea what I am doing. I want to make a simple energy display on my screen so I don't have to keep looking at the text on my unit frame. I have tried for a while to get something working but I really have no clue what I am doing and have just been trying to reverse engineer several other addons. I actually am really struggling to understand lua. My only coding knowledge is XHTML :\

Here is what I've got that doesn't work. I am sure I am way off base with it but I will post it just to show what I am thinking.

Code:
local class = select(2, UnitClass("player"))
if class == "ROGUE" or class == "DRUID" then
    class = nil
else
    DisableAddOn("Energetic")
    return
end

function Energetic_OnUpdate(player)
local frame = CreateFrame("Frame", "EnergeticFrame", UIParent);
frame:SetScript("OnEvent", Energetic_OnUpdate);
frame:RegisterEvent("UNIT_ENERGY");
frame:RegisterEvent("UNIT_MAXMANA");

frame:SetFrameStrata("BACKGROUND")
frame:SetWidth(30)
frame:SetHeight(30)
frame:Show()
frame:SetParent(UIParent)
frame:SetPoint("CENTER", UIParent, "CENTER", 0, -120)

local text = frame:CreateFontString(nil,"OVERLAY")
text:SetPoint("CENTER", display, "CENTER")
local font = "Fonts\\FRIZQT__.TTF"
text:SetFont(font, 15)
text:SetTextColor(1, .8, 0, .8)
text:SetText(UnitMana("player"))
end
So if anyone feels like helping me along in my first journey into making an addon I would really appreciate it. Or if anyone has any suggestions on where to start to learn how toto write an addon I am all ears. Thanks in advance.

- Dudgeon
  Reply With Quote
01-10-08, 11:24 AM   #2
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Moved to Developer section of the forums. There is some good info here as well - take a look at this sticky in the Tutoriails and Other Helpful Info forum as well: http://www.wowinterface.com/forums/showthread.php?t=107

Also - post all of your code here ( http://wowi.pastey.net/ ) and any errors you are getting.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
01-10-08, 02:35 PM   #3
Shirik
Blasphemer!
Premium Member
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2007
Posts: 818
This is a very bad idea:

frame:SetScript("OnEvent", Energetic_OnUpdate);
There IS an OnUpdate script, and naming your function this will likely confuse people that read your code later. Furthermore, this will never run. Why?

Code:
local frame = CreateFrame("Frame", "EnergeticFrame", UIParent);
frame:SetScript("OnEvent", Energetic_OnUpdate);
frame:RegisterEvent("UNIT_ENERGY");
frame:RegisterEvent("UNIT_MAXMANA");
This is your setup code. It should not be in Energetic_OnUpdate() because Energetic_OnUpdate is called BY that code. If that's the case, then it's never going to run, right? Move these outside of and after that function (at the end of your code).
__________________
たしかにひとつのじだいがおわるのお
ぼくはこのめでみたよ
だけどつぎがじぶんおばんだってことわ
しりたくなかったんだ
It's my turn next.

Shakespeare liked regexes too!
/(bb|[^b]{2})/
  Reply With Quote
01-11-08, 05:21 AM   #4
Teif
A Deviate Faerie Dragon
Join Date: May 2006
Posts: 12
Originally Posted by dudgeon
Code:
 
--[[ (Added comment:) This bit of code redefines the width, height and position 
   of the frame each time it's called. Since the frame can't be moved or resized 
   to begin with, there is no need to do this repositioning every time.
]] 
frame:SetFrameStrata("BACKGROUND")
frame:SetWidth(30)
frame:SetHeight(30)
frame:Show()
frame:SetParent(UIParent)
frame:SetPoint("CENTER", UIParent, "CENTER", 0, -120)

 
--[[ (Added comment:) Here a new FontString is created for each time the method 
   is called. Instead we should setup the FontString once, and then update the value 
   of it when the update method is called.
]] 
local text = frame:CreateFontString(nil,"OVERLAY")
text:SetPoint("CENTER", display, "CENTER")
local font = "Fonts\\FRIZQT__.TTF"
text:SetFont(font, 15)
text:SetTextColor(1, .8, 0, .8)
text:SetText(UnitMana("player"))
Having this bit of code in the update method is a bad idea in my opinion. It will cause the frame to be repositioned every time we update the energy value, which would be a waste of resources and time. Furthermore this code would create a new FontString for every update call, which would be placed on top of the previous one instead of just updating the value of the original FontString.

What I would suggest is to split up the frame creation and the actual code. This makes the code a bit more readable in my opinion, since it's very easy to get an overview of the frame's attributes and which scripts get called when by just looking at the XML, rather than perusing a lua file - this is all based on personal preference however.

As far as documentations and resources go, I tend to use WOW Wiki to get the information i need about XML elements and the WOW API. Other than that there's a pretty good Lua wiki out there with some nice tutorials and general documentation. Other than that it's much the same procedure as you mention, finding inspiration or ideas from other AddOns or browsing the web for tutorials - there's plenty out there of both kinds.

Below is a suggestion of how I would go about creating the energy display.

Energetic.xml
Code:
<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">

   <Script file="Energetic.lua" />
   
   <!-- Here we define the frame for the AddOn. This frame will be receiving the
        events we register for and will contain the FontString that displays the 
        player's current energy level -->
   <Frame name="Energetic" parent="UIParent" hidden="false">
      <Size x="40" y="30" />
      <Anchors>
         <Anchor point="CENTER" relativeTo="$parent" relativePoint="CENTER">
            <Offset x="0" y="-120" />
         </Anchor>
      </Anchors>

      
       <!-- This is where we define the FontString. It should default to the same size as the
            parent frame and be anchored by it's center point to the center point of the 
            parent, so we should be fine without defining that manually. -->
      <Layers>
         <Layer level="ARTWORK">
            <FontString name="$parentText" text="100" inherits="NumberFontNormal" />
         </Layer>
      </Layers>

      
      <!-- Here we define which scripts to run from the Energetic.lua file when the AddOn
           is loaded, or when one of the events we register for is triggered. -->
      <Scripts>
         <OnLoad>
            Energetic_OnLoad(self);
         </OnLoad>
         <OnEvent>
            Energetic_OnEvent(self, event, ...);
         </OnEvent>
      </Scripts>
   </Frame>
</Ui>
We are going to be using some events in the following, so here's a link to the WowWiki page on Unit Events: WowWik: Events/Unit Info

Energetic.lua
Code:

--[[
   While the AddOn is loaded, we register the events we want to trigger the OnEvent 
   method for.
]] 
function Energetic_OnLoad(frame)
   frame:RegisterEvent("UNIT_ENERGY");
   frame:RegisterEvent("UNIT_MAXENERGY");
end


--[[
   Whenever UNIT_ENERGY or UNIT_MAXENERGY is triggered (for the player) the
   FontString should be updated to display the current value.
]]  
function Energetic_OnEvent(frame, event, ...)
   local unit = select(1, ...); -- this will return arg1, which will be the UnitID 
   if (unit == "player") then
      -- Update the FontString with the current Energy value 
      local fs = getglobal("EnergeticText");
      if (fs) then
         fs:SetText(UnitMana("player"));
      end
   end
end
Lastly we need to make sure the scripts and the XML are loaded, when the AddOn is loaded, which is done by including the XML file at the bottom of the TOC. Since the lua file is included through the XML we don't have to list it here.

Energetic.toc
Code:
## Interface: 20300
## Title: Energetic
Energetic.xml
Sorry for the lengthy post there, but hope some of the information in here will be helpful to you.

*EDIT: I'm not at my WOW computer at the time of writing this, so I haven't actually tested the code posted here. Might be some typos and such in there, but the general idea of it should be working ... I hope :P*
  Reply With Quote
01-11-08, 10:46 AM   #5
dudgeon
A Defias Bandit
Join Date: Oct 2007
Posts: 3
Originally Posted by Teif
Sorry for the lengthy post there, but hope some of the information in here will be helpful to you.
No reason to be sorry at all! This is an amazingly generous response. I have absolutely no idea how this stuff works and have been having a really hard time figuring it out by looking at the code of others. This is becoming way more clearer to me now after your commenting and information.

Thank you so much.

I will add your corrections and try and play around with adding a few more features that I was interested in having and post the final product here.

- Dudgeon
  Reply With Quote
01-12-08, 12:44 PM   #6
dudgeon
A Defias Bandit
Join Date: Oct 2007
Posts: 3
Thanks again for the help. If you see anything that can be improved here, I would love to know. Here is my final product:

Code:
local class = select(2, UnitClass("player"))
if class == "ROGUE" or class == "DRUID" then
	class = nil
else
	DisableAddOn("Energetic")
	return
end

function Energetic_OnLoad(frame)
    frame:RegisterEvent("UNIT_ENERGY");
    frame:RegisterEvent("MAX_ENERGY");
end

function Energetic_OnEvent(frame, event, ...)
    local unit = select(1, ...)
    if (unit == "player") then
        local fs = getglobal("EnergeticText")
        if (UnitMana("player") < UnitManaMax("player")) then
            fs:SetText(UnitMana("player"));
        elseif (UnitMana("player") == UnitManaMax("player")) then
            fs:SetText("");
        end
    end
end
I made it so that it will only display when i am below full energy.

- Dudgeon
  Reply With Quote
01-12-08, 02:18 PM   #7
Slakah
A Molten Giant
 
Slakah's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2007
Posts: 863
Originally Posted by dudgeon
Thanks again for the help. If you see anything that can be improved here, I would love to know. Here is my final product:

Code:
local class = select(2, UnitClass("player"))
if class == "ROGUE" or class == "DRUID" then
	class = nil
else
	DisableAddOn("Energetic")
	return
end

function Energetic_OnLoad(frame)
    frame:RegisterEvent("UNIT_ENERGY");
    frame:RegisterEvent("MAX_ENERGY");
end

function Energetic_OnEvent(frame, event, ...)
    local unit = select(1, ...)
    if (unit == "player") then
        local fs = getglobal("EnergeticText")
        if (UnitMana("player") < UnitManaMax("player")) then
            fs:SetText(UnitMana("player"));
        elseif (UnitMana("player") == UnitManaMax("player")) then
            fs:SetText("");
        end
    end
end
I made it so that it will only display when i am below full energy.

- Dudgeon


"MAX_ENERGY" isn't an event according to wowwiki its "UNIT_MAXENERGY" also it doesn't have any arg's so registering the event will do nothing because your comparing "player" with nil.

Why use local fs = getglobal("EnergeticText") when you could use the arg frame from the function.


Code:
 local class = select(2, UnitClass("player"))
if class == "ROGUE" or class == "DRUID" then
        class = nil
        else
	DisableAddOn("Energetic")
	return
end

function Energetic_OnLoad(frame)
    frame:RegisterEvent("UNIT_ENERGY");
end

function Energetic_OnEvent(frame, event, unit)
    if (unit == "player") then
        if (UnitMana("player") < UnitManaMax("player")) then
            frame:SetText(UnitMana("player"));
        elseif (UnitMana("player") == UnitManaMax("player")) then
            frame:SetText("");
        end
    end
end

Should work, be warned I'm not to good at lua myself :P.

Last edited by Slakah : 01-12-08 at 02:21 PM.
  Reply With Quote
01-14-08, 05:43 AM   #8
Teif
A Deviate Faerie Dragon
Join Date: May 2006
Posts: 12
Assuming Dudgeon's XML is similar to the XML I posted in a previous reply, the frame arg will refer to the Frame object itself, and not the FontString, which is why the call to getglobal("EnergeticText") is in the code.

There are of course other and perhaps better ways of getting a handle to the FontString, but I find getglobal() to be easy to remember and use .

Code:
local fs = getglobal("EnergeticText");
if (UnitMana("player") < UnitManaMax("player")) then
   fs:SetText(UnitMana("player"));
elseif (UnitMana("player") == UnitManaMax("player")) then
   fs:SetText("");
end
The current energy/mana/rage level of the player should never exceed the maximum value, so you don't actually have to check for both - if the current level is not less than the maximum, then they must be equal - hence you can spare the second if statement in the above snippet:

Code:
local fs = getglobal("EnergeticText");
--[[
   Storing the result of UnitMana("player") in a local variable saves you from having
   to call the method twice (when checking it against the maximum, and when updating
   the FontString).
]] 
local nrg = UnitMana("player"); 
if (nrg < UnitManaMax("player")) then
   fs:SetText(nrg);
else
   fs:SetText("");
end
Glad to "hear" you were able to get something out of the information I posted!
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » I need help making simple energy display


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