Plugin to show an experience bar

Posted by Nick Gammon on Sat 07 Feb 2009 08:17 PM — 37 posts, 171,447 views.

Australia Forum Administrator #0
Modern graphical MMORPGs tend to show an "experience bar" near the bottom of the screen, to show visually how close you are to levelling. The plugin below does the same thing for a text MUD (see screenshot in next message).

For the plugin to work it needs to know how much XP you have, and how much to level, in order to work out how far through the level you are.

In the case of Smaug, you need to change your default prompt and fight prompt, as per "help prompt". I made mine the same as the default, plus the experience, like this:


prompt &w<&Y%hhp &C%mm &G%vmv &C%x/&c%X&Cxp&w> 
fprompt &w<&Y%hhp &C%mm &G%vmv &C%x/&c%X&Cxp&w> 


(Note: trailing space after the prompt, as in the trigger)

This makes my prompt look like this:


<28hp 100m 102mv 2875/6325xp> 


The stuff like &w, &C etc. is just colour-coding the prompt.

Below is the plugin.

Save between the lines as Experience_Bar.xml and use File menu -> Plugins to load that file as a plugin.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE muclient>

<!-- Plugin "Health_Bar" generated by Plugin Wizard -->

<muclient>
<plugin
   name="Experience_Bar"
   author="Nick Gammon"
   id="7e2bf8628a8f51bf2115d2f0"
   language="Lua"
   purpose="Shows XP to level"
   date_written="2009-02-08"
   requires="4.35"
   version="1.1"
   >
<description trim="y">
<![CDATA[
Install this plugin to show an how close you are to levelling.
]]>
</description>

</plugin>

<!--  Triggers  -->

<triggers>
  <trigger
   enabled="y"
   match="&lt;*hp *m *mv */*xp&gt; "
   script="do_prompt"
   sequence="100"
  >
  </trigger>
</triggers>


<!--  Script  -->


<script>
<![CDATA[

win = GetPluginID ()  -- get a unique name

-- configuration

GAUGE_HEIGHT = 11
NUMBER_OF_TICKS = 20

BACKGROUND_COLOUR = ColourNameToRGB "gray"
BOX_COLOUR = ColourNameToRGB "dodgerblue"

-- draw the bar here, on getting the prompt, or window resize
function draw_bar ()

  -- check numbers for validity
  if not current_xp or  
     not max_xp or
     current_xp < 0 or
     max_xp <= 0 then
     return
  end -- if

  -- cannot have more than max xp
  if current_xp > max_xp then
     current_xp = max_xp
  end -- if
  
 -- width is window width minus 2
 local gauge_width = GetInfo (281) - 2
 
 -- make room for the bar
 local bottom_margin = GetInfo (275)
 
 -- adjust text rectangle, keeping existing settings where possible
 if bottom_margin == 0 or 
    (bottom_margin < 0 and math.abs (bottom_margin) < (GAUGE_HEIGHT + 2)) then
   TextRectangle(GetInfo (272), GetInfo (273),   -- left, top
                  GetInfo (274), -- right
                  - (GAUGE_HEIGHT + 2),  -- bottom (gauge height plus 2 more)
                  GetInfo (276), GetInfo (282) or 0, GetInfo (277),  --  BorderOffset, BorderColour, BorderWidth
                  GetInfo (278), GetInfo (279)) -- OutsideFillColour, OutsideFillStyle
 end -- if
  
 -- make the miniwindow
 WindowCreate (win, 
             0, 0,   -- left, top (auto-positions)
             gauge_width,     -- width
             GAUGE_HEIGHT,  -- height
             10,       -- auto-position: bottom left
             0,  -- flags
             BACKGROUND_COLOUR) 
  
  WindowRectOp (win, 2, 0, 0, 0, 0, BACKGROUND_COLOUR)  -- fill entire box
 
  -- how far through the level we are 
  local done = current_xp / max_xp
  local bar_width = gauge_width * done
 
  -- box size must be > 0 or WindowGradient fills the whole thing 
  if math.floor (bar_width) > 0 then
    
    -- top half
    WindowGradient (win, 0, 0, 
                    bar_width, GAUGE_HEIGHT / 2, 
                    0x000000,  -- black
                    BOX_COLOUR, 
                    2)   -- vertical gradient
    
    -- bottom half
    WindowGradient (win, 0, GAUGE_HEIGHT / 2, 
                    bar_width, 0, 
                    BOX_COLOUR,
                    0x000000,  -- black
                    2)   -- vertical gradient

  end -- any experience to speak of
  
  -- show ticks
  local ticks_at = gauge_width / NUMBER_OF_TICKS
  
  -- ticks
  for i = 1, NUMBER_OF_TICKS do
    WindowLine (win, i * ticks_at, 0, i * ticks_at, GAUGE_HEIGHT, ColourNameToRGB ("silver"), 0, 1)
  end -- for

  -- draw a box around it
  check (WindowRectOp (win, 1, 0, 0, 0, 0, ColourNameToRGB ("lightgrey")))  -- frame entire box
    
  -- ensure window visible
  WindowShow (win, true)
  
end -- draw_bar

function do_prompt (name, line, wildcards, styles)
 
  -- CHANGE HERE if your prompt is different (eg. different wildcard numbers)
  -- (string.gsub removes commas from the experience figures, if necessary)

  current_xp = tonumber ((string.gsub (wildcards [4], ",", "")))
  max_xp = tonumber ((string.gsub (wildcards [5], ",", ""))) + (current_xp or 0)
  
  draw_bar ()
  
end -- do_prompt

function OnPluginWorldOutputResized ()
  draw_bar ()
end -- function
 
-- hide window on removal
function OnPluginClose ()
  WindowShow (win,  false)  -- hide it
end -- OnPluginClose

-- hide window on disable
function OnPluginDisable ()
  WindowShow (win,  false)  -- hide it
end -- OnPluginDisable


]]>
</script>

</muclient>



If you have a different prompt, or find your experience out in a different way, you would need to change the trigger.

The main work is done in draw_bar, based on two global variables current_xp and max_xp. If you need to establish your experience differently, just make sure your trigger, or triggers, set those two variables.

There is also a plugin callback OnPluginWorldOutputResized which redraws the bar if the world window is resized.

The plugin uses TextRectangle to make the output window slightly smaller at the bottom edge, this is to fit in the experience bar.

You can play with the gauge_height variable to make the bar shorter or taller. An odd number would be better to make the bar look more even, as it is drawn with a gradient from top to the middle, then middle to the bottom. A value of 7 looks more discrete, or you could make it larger than 11.

There is also a configurable number of "tick marks" you can show. The default is 20, which means each "bubble" of experience would represent 5% of the way to the next level. If they are too close together (or too far apart) just change the variable NUMBER_OF_TICKS).

[EDIT] Amended on 5th March 2009 to allow for commas in the experience wildcards.
Amended on Wed 04 Mar 2009 07:03 PM by Nick Gammon
Australia Forum Administrator #1

Example of it in operation:

Australia #2
I practically hopped up and down when I came across this plugin :P What a great idea!

I've got it to match on my prompts, the thing is that at 4000/4000 TNL it only takes up 50% of it's bar, and at 2000/4000 TNL it takes up one quarter etc.

I tried doing it exactly like it is in the original plugin too, changing my prompt and all. Still does the same thing!

Is there anything I can do to fix that? Or is that how it's supposed to be? It just seems that it should take up the whole bar then tick down from there...

My prompt -
|100%| |100%| |100%| Tnl[3092/4000] [0] [] Q[0] [The Grand City of Aylor]

What I have in the match part -
* Tnl[*/*] *

I've got the wildcard matching on the 2nd & 3rd asterisks for current/max exp.
Australia Forum Administrator #3
Quote:

the thing is that at 4000/4000 TNL it only takes up 50% of it's bar


It depends what the figures mean. In Smaug, that means you have 4000 xp, and you have 4000 to go. Thus it is 8000 to level and you are halfway through, thus it correctly shows you as 50%.

I originally had the line:


 max_xp = tonumber (wildcards [5])  + (current_xp or 0)


as:


 max_xp = tonumber (wildcards [5])  


As I thought that it meant 4000 out of 4000. You might change it to that, if that is what the prompt means for you.


Amended on Sun 08 Feb 2009 08:48 AM by Nick Gammon
Australia #4
Ah right! I removed the '+ (current_xp or 0)' and it works perfectly now.

Thank you very much!
#5
Would anyone care to see if this can be modified for Aardwolf? Here's my prompt:

<5257/5257hp 4816/4932m 3813/3813mv $29828 -2468al [2624tnl] 0tnq>

One possible quirk, is that i don't know of a way to display my total experience required for my current level. There's no 'token' available to represent that in prompt configuration - that i can find at least. I've heard that Aardwolf stores that info, and lots more, in client-accessible variables. I know nothing else concerning that though, sorry...

If it would just be much simpler to use a trigger and modify the current plugin, then i have a suggestion. How about an alias to manually set the max_xp variable? I'd just need to know how to implement that change near the bottom of the plugin, where it says:

-- CHANGE HERE if your prompt is different (eg. different wildcard numbers)
current_xp = tonumber (wildcards [4])
max_xp = tonumber (wildcards [5]) + (current_xp or 0)

Right?

This stuff is starting to make sense, but it's coming along slowly. Thanks for any insight.
Australia Forum Administrator #6
See this:

http://www.gammon.com.au/forum/bbshowpost.php?id=8776

That is how you get the experience to next level.

Assuming you have that plugin installed (which actually finds the experience and other stuff from the {stats} prompt), I had an earlier version designed for Aardwolf:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE muclient>

<!-- Plugin "Health_Bar" generated by Plugin Wizard -->

<muclient>
<plugin
   name="Aardwolf_Exp_Bar"
   author="Nick Gammon"
   id="5a686c03d20d8f6c3ef501f4"
   language="Lua"
   purpose="Shows Aardwolf XP to level"
   date_written="2008-08-04"
   requires="4.35"
   version="1.0"
   save_state="y"
   >
<description trim="y">
<![CDATA[
Install this plugin to show how close you are to levelling.
]]>
</description>

</plugin>

<!--  Script  -->


<script>
<![CDATA[

gauge_height = 5
gauge_width = 600
max_xp = 1000

background_colour = 0x808080
box_colour = ColourNameToRGB "magenta"

require "checkplugin"


function draw_bar ()

 
               
  check (WindowRectOp (win, 2, 0, 0, 0, 0, background_colour))  -- fill entire box
  
  local done = (max_xp - stats.to_level) / max_xp
 
  check (WindowRectOp (win, 2, 0, 0, gauge_width * done, 0, box_colour)) 

  local ticks_at = gauge_width / 20
  
  -- ticks
  for i = 1, 20 do
    WindowLine (win, i * ticks_at, 0, i * ticks_at, 0, ColourNameToRGB ("silver"), 0, 1)
  end -- for
  
  WindowShow (win, true)
  
end -- draw_bar

function OnPluginBroadcast (msg, id, name, text)
  if msg == 1 and id == "8a710e0783b431c06d61a54c" then
  
   -- get all variables
   stats = GetPluginVariableList("8a710e0783b431c06d61a54c")
   draw_bar ()
   
  end -- stats changed
end

function OnPluginInstall ()
  
  win = GetPluginID ()
 
  if GetVariable ("enabled") == "false" then
    ColourNote ("yellow", "", "Warning: Plugin " .. GetPluginName ().. " is currently disabled.")
    check (EnablePlugin(GetPluginID (), false))
    return
  end -- they didn't enable us last time
  
  OnPluginEnable ()  -- do initialization stuff
  
end -- OnPluginInstall

function OnPluginEnable ()
  checkplugin ("8a710e0783b431c06d61a54c", "Stats_Detector.xml")
  
  WindowCreate (win, 
               0, 0,   -- left, top (auto-positions)
               gauge_width,     -- width
               gauge_height,  -- height
               10,       -- auto-position: bottom left
               0,  -- flags
               background_colour) 
               
end -- OnPluginEnable

function OnPluginDisable ()
  WindowShow (win, false)
end -- OnPluginDisable

function OnPluginSaveState ()
  SetVariable ("enabled", tostring (GetPluginInfo (GetPluginID (), 17)))
end -- OnPluginSaveState


]]>
</script>

</muclient>



The bar isn't as pretty, though. A bit of copying and pasting and you might have the best of both worlds.
Amended on Wed 25 Feb 2009 12:55 AM by Nick Gammon
#7
As soon as i click 'open', while installing the plugin, a window tries to pop up, then i crash to desktop.

Should i mention i'm using Ubuntu/Wine? Latest Aardwolf edition MUSHclient, dowloaded here.

I didn't modify the Aardwolf version of the exp bar plugin that you posted in any way.
Australia Forum Administrator #8
Open up the Wine configuration, and set the operating system emulation to Windows 98, then try again.
#9
Hello again!

Well, the Win98 fix for wine worked great.

When i logged in just now, i got:

Run-time error
Plugin: Aardwolf_Exp_Bar (called from world: Aardwolf)
Function/Sub: OnPluginBroadcast called by Plugin Aardwolf_Exp_Bar
Reason: Executing plugin Aardwolf_Exp_Bar sub OnPluginBroadcast
[string "Plugin"]:15: attempt to call global 'WindowRectOp' (a nil value)
stack traceback:
[string "Plugin"]:15: in function 'draw_bar'
[string "Plugin"]:37: in function <[string "Plugin"]:32>
Error context in script:
11 : function draw_bar ()
12 :
13 :
14 :
15*: check (WindowRectOp (win, 2, 0, 0, 0, 0, background_colour)) -- fill entire box
16 :
17 : local done = (max_xp - stats.to_level) / max_xp
18 :
19 : check (WindowRectOp (win, 2, 0, 0, gauge_width * done, 0, box_colour))

this sorta looks like the part where you said i could do some copy/pasting.
Australia Forum Administrator #10
What version of MUSHclient are you using?
#11
I re-read my post and i hope i didn't sound sarcastic about the win98 thing 'working great'. What i meant was, i no longer crash to desktop when loading a plugin. It had something to do with the error window popping up....

Now for the part that will make you pull your hair out...

I thought i was being really smart when i changed 'requires="4.35"' to 4.33, to make that error go away.

I would love to upgrade, but i don't see a newer version of the aardclient version. Is there one available?
#12
You can just download the latest mushclient from this website and install it. It will install over the aard client and you will have the aardclient with mush 4.4.

Bast
#13
Do you play aard and have you tried that? It seems to me that it would wipe out all my custom aard plugins and such.
#14
Yes, I play aard, and I have most of the standard aard plugins. Installing a new mushclient doesn't touch the worlds/plugin/Aardwolf directory or the worlds/Aardwolf directory, so your aard plugins don't change.

Bast
#15
Alrighty, it works now with the upgrade. I apologize for all the hassle. Now to pretty up the bar some :)

Thanks for both of your time.
USA #16
Trying to put this on a slightly different prompt. I changed the trigger to this:
  <trigger
   enabled="y"
   name="XPprompt"
   match="\&lt;Health:[([\d,]+)\/([\d,]+)] (Jakai|Chi):[([\d,]+)\/([\d,]+)] Stamina:[([\d,]+)\/([\d,]+)]\&gt; [\d,]+\/[\d,]+xp(.*?)$"
   script="do_prompt"
   regexp="y"
   sequence="100"
  >


Which matches the prompt correctly.

Then I am using wildcards[8] and wildcards[9], but it appears they are both nil values for some reason. wildcards[7] is the last Stamina num, so 8 and 9 should be the XP. Not sure why it's nil.
Australia Forum Administrator #17

\<Health:\[([\d,]+)\/([\d,]+)\] (Jakai|Chi):\[([\d,]+)\/([\d,]+)\] Stamina:\[([\d,]+)\/([\d,]+)\]\> [\d,]+\/[\d,]+xp(.*?)$
              1          2           3           4         5                    6         7                           8


I only count 8 wildcards, including the rest of the line, see above. Did you forget the brackets?
#18
I can't get the bar to appear, is there some tab I should have open or anything?
Australia Forum Administrator #19
The bar appears when the trigger matches the prompt line. If it doesn't appear, it hasn't matched.

As I indicated on the first page of this thread, you need to change your prompt in Smaug to show experience. If you haven't done that, try that. Otherwise if it is a different MUD, please show what a prompt line looks like, and what you have changed the trigger to, if anything.
#20
I did everthing you said in your post nick and it's still not poping up.

here's the prompt lines.

<1,099/1,099 hp 585,302/585,302 m 100/100 mv>
Amended on Tue 03 Mar 2009 08:17 PM by Trayn318
USA #21
Turn on Game->Trace and see if the trigger is being matched.
Australia Forum Administrator #22
The original plugin matched this prompt:


<28hp 100m 102mv 2875/6325xp> 


(The numbers may differ).

Yours doesn't look anything like that. For one thing, you aren't showing experience at all.

How can it draw an experience bar, if the prompt doesn't have xp figures in it?
Amended on Tue 03 Mar 2009 08:30 PM by Nick Gammon
#23
ok here's what it says now and it still now working.

<1,099hp 585,302m 100mv 3,986,839,823,207/3,986,839,823,207xp>

and i got this error

[string "Plugin"]:97: attempt to perform arithmetic on a nil value
stack traceback:
[string "Plugin"]:97: in function <[string "Plugin"]:93>
Amended on Wed 04 Mar 2009 02:06 AM by Trayn318
Australia Forum Administrator #24
It hasn't alllowed for commas in the numbers. Inside the plugin, change lines 135 and 136 from:


  current_xp = tonumber (wildcards [4])
  max_xp = tonumber (wildcards [5]) + current_xp


to:


  current_xp = tonumber ((string.gsub (wildcards [4], ",", "")))
  max_xp = tonumber ((string.gsub (wildcards [5], ",", ""))) + current_xp


Make sure you reinstall the plugin afterwards (hit the Reinstall button).

That worked for me on your prompt. However I note that both numbers in your example are the same (3,986,839,823,207). As currently written that displays a half-way through experience bar, as it thinks you have 3,986,839,823,207 xp to go.

It seems a bit strange that you are exactly half-way through the level (or completely through, if it is xp/total xp). You may need to remove the "+ current_xp" from the second line. Are you sure you are displaying current xp / maximum xp? Otherwise the bar will always be either half-full or completely full.
Amended on Wed 04 Mar 2009 04:46 AM by Nick Gammon
#25
still won't work. I'm just about to just give up on this and mushclient.
Australia Forum Administrator #26
You got the trigger to match before, because it caused an error message on the commas. In what way does it "still won't work"?

Do you still get the error message? Or does it simply not display the experience bar? You have to give a bit more information than "it doesn't work" if you want any help.

If you get an error message please post it.

If you are still getting the error message make sure you changed the two lines I said, and reinstalled the plugin. If you didn't reinstall the plugin it is still using the old code.

Most MUDs are different in the way they display prompt lines. You can't expect the plugin to just display information it doesn't actually have, or in a format it doesn't understand.
Amended on Thu 05 Mar 2009 12:09 AM by Nick Gammon
#27
Is there anyway to do this plugin for CircleMUD? im new to all of this and i was just wondering how i would do it.
USA #28
Read the first post.
Quote:
If you have a different prompt, or find your experience out in a different way, you would need to change the trigger.
#29
Ok, the MUD I play on runs off of a 5000 xp per level system where it's ALWAYS 5000 xp to level and the script runs off of the assumption that your prompt will output the xp you need to get in order to level when you type %X into the prompt. In the MUD I'm using, %x gives your current xp and %X gives 5000-current xp. How could I change the xp bar so that it's full at 5000, not at %X?
Australia Forum Administrator #30
So %X is xp_to_level?

And if you were at level 2, and levelled at 10000 XP, and had 9000 XP, then it would show:


9000/1000


Because you have 1000 to go?

It seems to me then that max_xp = 5000, because we are always trying to get to 5000. And current_xp is 5000 minus the wildcard (eg. 5000 - 1000 = 4000). Thus we now get:

4000/5000



function do_prompt (name, line, wildcards, styles)

  current_xp = 5000 - tonumber ((string.gsub (wildcards [5], ",", "")))
  max_xp = 5000
  
  draw_bar ()
  
end -- do_prompt


If that doesn't work throw in a print statement or two to see what the figures are.
#31
Ok, I believe that would work but your Health Bar plugin and this plugin do not have the same default prompt. How could I change the prompt for the XP plugin to be "<%h/%H hp %m/%M m %v/%V mv %x/%X xp>" ?
#32
okay so here goes :P
if it is a number that goes downward. such as on my prompt, it was 5678 tnl and i killed something and it goes down. Can I set up the reverse? where its full and as the number gets smaller so does the bar?
Australia Forum Administrator #33
Well we still need to know the maximum right? Because it has to be 5678 out of <something>. Once you know that it is easy.

Let's say the maximum is 10000. If you have 5678 to next level, then you have done 4322. So normally I would supply 4322 (that is, the maximum minus the current), and 10000, so the bar shows you as 43.22 percent done.

But you could just not subtract, so it would show 5678/10000 and then get lower and lower.
#34
theres no way to convert it to a % as the number gets lower, the bar gets higher? We don't have the max exp shown on our MUD it only shows how much you have to go till the next lvl :(
#35
I really appreciate your help Nick. Its like getting help from a MUD celebrity lol. The creator of Mushclient :P
#36
Im trying to configure this addon for 3kingdoms.

I do not have xp on the bar it comes from typing XP and then I get this:

You have 14,725,973 total xp.
You need 49,027 experience to achieve your next level.
You have 1,975,973 to spend.

XP Gain for the last 30 minutes: 61,605
At this rate you will level in 23 minutes

I seem to be having tons of issues in regards to adapting plugins to this MUD.

I even tried adapting the autohealer and failed.