Once again I am revisiting the idea of having a standalone custom status bar. This subject comes up from time to time, and it always seems a bit problematic to get it working properly.
A while back I did a Visual Basic plugin that showed an external "status bar" window, but that had various problems ...
To compile it you needed Visual Basic, which costs money, and takes time to learn
You need to register the control with the Windows registry, something that didn't always work for me
It used COM objects, which seem to have a habit of popping in and out of memory when you don't want them to
"There must be a better way", I thought.
So this time, I looked at doing it in a way that could be easily reproduced, using free compilers, such as Cygwin. Also, that didn't need to be registered in the Registry.
I toyed with the idea of doing it in Lua, but abandoned that principally because Lua is standard C, not a system for writing Windows GUI programs.
Then I thought of MFC (Microsoft Foundation Class) libraries, but again, you need to own them, and Visual Studio, which isn't a free solution.
Finally I reached for my old copy of "Programming Windows 95" by Charles Petzold, and looked at doing a small Windows program in C "from scratch".
This turned out to be surprisingly easy. Using an example program from Chapter 2, it was possible to do a simple external status bar program (see screen shots below).
The entire source is in a single file of just over 700 lines. The source is available in the download, so you can modify it, or just use the precompiled version if that does the trick for you.
The status bar window is designed to be configurable on-the-fly by MUSHclient (or another program) by sending "commands" to it, as will be discussed shortly. The commands would be to do things like:
Set window title
Set size and position of window on the screen
Define text colour
Define background colour
Define font for drawing text
Define a set of labels for status bars (eg. hp, mana, movement, xp)
Set current values as a percentage (eg. 80,40,70,20)
Set colours for drawing each bar - both "bar" colour and filler colour
Define how big each bar is (width and height) and gaps between linees
Tell the window to quit
In the next post is a screenshot of it in operation.
The trick with any system like this is to get messages to it - tell it to update the bar widths, for example.
I wanted to avoid using COM, which always seems to cause problems, you need to register controls, make sure they exist, worry about what happens if the control window is closed an so on.
Then the idea occurred - use UDP (User Datagram Protocol).
UDP is a "connectionless" protocol for sending packets around the Internet. It is quick because you don't need to establish a connection, however there is a danger that packets may be lost. This is not a big issue with a status bar running on your own PC. Sending a packet from one program to another on the same PC is unlikely to take very long, and is unlikely to get lost. Even if it does, it just means the status bar might be slighly out of date for a moment.
The great thing about UDP is it doesn't matter if the status bar goes away, the packets will simply be discarded. Also you can leave the status bar program running all the time. If MUSHclient sends it information it will update, and if not, no matter.
Indeed you can have a bit of fun, by using a "broadcast address" at the sending end, any PC on the same subnet can receive the same packet. So you could conceivably have multiple PCs all showing the same information.
Getting started
If you download the status bar program above, and run the statusbar.exe file, you will see a window like the one above except without text, and with a white background.
It can be moved and resized in the usual way.
Now even before using MUSHclient we can "talk" to it with any program that sends UDP packets. To help you play with it, I have written a small "UDP send" program. The source and executable (19 Kb) are available from:
This tells it to send packets to localhost (your own PC) at port 4111, which is the default port for statusbar.exe.
Now you can send commands to it, eg.
magic,title,hello there,
All being well, the title on the status bar window should update.
Then you can try changing the background colour:
magic,backcolour,25600
The window background should change to dark green.
What is all this 'magic' stuff?
The intention was to make sure that packets received by the statusbar program were intended for it. Thus, each packet is checked for a "magic string" at the start, which defaults to the word "magic". You can configure that when you execute the statusbar program. For example, if you had multiple worlds each with their own status bar, you could use the world name as the magic string.
A more concrete example of talking to the status bar is this example, which I used to do the screenshot above. It uses the Lua socket library to send UDP packets:
However since not everyone will want to use Lua to talk to status bars, MUSHclient 3.56 now has a UdpSend function added to it. This simply lets you send a single UDP packet to the network.
Here is an example of using the UdpSend function (in Lua again, but it could just as easily be VBscript) to capture an inventory and display it:
function multiline_trigger (name, line, wildcards)
local function udp (msg)
UdpSend ("127.0.0.1", 4111, "m," .. msg)
end
udp ("title,Inventory")
udp ("size,10,10,300,300")
udp ("config,10,5,100,15,80,300,20")
udp ("font,Harem,12")
udp ("textcolour,0")
udp ("backcolour,14804223")
udp ("text,5,5," .. wildcards.inventory)
end -- function
The above example uses a "helper" function to send to the correct address and port, and put the magic word at the start of the line. It illustrates, by the way, the method of declaring "local" functions in Lua, which are functions that are visible only inside another function.
The code above sets the window title and size, sets the font to Harem, defines the text and background colours, and sends the inventory as multi-line text. See below for how it looks:
If you want to add more customisation, then simply update the source for the statusbar window, and then recompile, either using Visual C++ or Cygwin (or your own favourite compiler). To compile under Cygwin:
For example, you might add the ability to play sounds, change the style of the window (maybe make it semi-transparent?), make the labels right-justified, the possibilities are endless.
Nice little program, I'll go test it right now.
By the way, if you need a better(?) UDP program, NetWorkshop on my page (www.poromenos.org) works and it's free.
I wonder how hard it would be to make it show a two dimensional progress dialog, to show you how your health or whatever changes over time... Interesting, I'll have to work on it.
By the way, since MC has a UDP send function, could you add a OnUDPReceived(pckPacket) event? It would be great if we could make MC communicate with other instances/people around the world/whatever. Imagine if you could write a plugin to see your friend's status in realtime in a MC window. This would also allow callbacks, since programs could send a packet with the function name and your plugin would call it. I'm not very big on adding extra non-mud functionality, but since we already have UDP send let's be symmetric and enable receive.
Note to developers about something that has not yet even been created: If you want to communicate through UDP I would suggest you did a GetUniqueID and then sent it to the other side as a handshake, then use it as a prefix for every packet you want to receive. This way you make sure the packet is coming from the original source.
Which also leads me to think, which plugin of which world would receive the packet? They could all get it and then choose if they want it, but I'll leave that up for discussion.
NetWorkshop on my page (www.poromenos.org) works and it's free.
Yes, thanks. Mine is free too. :)
The one I wrote comes with source, it is only 168 lines of code, so if you want to incoporate it into a bigger project, it is simple to see how it is done.
As for the cr/lf appearing as boxes, you can suppress that by using a trailing comma, as the strtok function used in the code just looks for commas as delimiters.
In a plugin (eg. a trigger) you wouldn't have cr/lf anyway.
Don't be so antagonistic :P I didn't say yours wouldn't work, I was just providing an alternative (and plugging my site!).
Quote:
As for the cr/lf appearing as boxes, you can suppress that by using a trailing comma, as the strtok function used in the code just looks for commas as delimiters.
Yes yes, I noticed right after I had written the comment :)
Quote:
See UdpListen.
Niiice, do they all receive every packet coming? Sounds good.
I didn't mean it to sound like that. I thought your comment might imply I was charging for mine. You seem to have some interesting stuff on your site. :)
Er yes, it should receive every packet directed at that port, from the IP address you specify.
Which also leads me to think, which plugin of which world would receive the packet? They could all get it and then choose if they want it, but I'll leave that up for discussion.
I didn't want this idea to go crazy, it remembers which plugin installed the listener, and that one gets it. However you could have multiple plugins that listen on different ports.
Oh, I see. Well, there are 65000 ports, so it'll take a while for someone to bump into two plugins that use the same port. Does it return an error if another application is listening to the port, or does UDP allow that? I'm a bit rusty on it, but that could account for erratic behaviour. The best way is for the plugin writer to prefix each text they send with the plugin's name or another string and discard everything else.
Here is what I have tried. First make a little plugin that displays the incoming packets:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Tuesday, November 30, 2004, 3:15 PM -->
<!-- MuClient version 3.56 -->
<!-- Plugin "udptest" generated by Plugin Wizard -->
<muclient>
<plugin
name="udptest"
author="Nick Gammon"
id="03f4d34b49652923953d9c19"
language="VBscript"
purpose="testing udplisten"
date_written="2004-11-30 15:13:41"
requires="3.56"
version="1.0"
>
</plugin>
<!-- Script -->
<script>
<![CDATA[
sub GotPacket (which)
ColourTell "white", "green", which
end sub
sub OnPluginInstall ()
status = UdpListen ("0.0.0.0", 4222, "GotPacket")
if status <> 0 then
ColourNote "white", "red", _
"UdpListen not installed, error code " & status
else
ColourNote "white", "darkgreen", "UdpListen installed"
end if
end sub
]]>
</script>
</muclient>
Now go to a different PC (or the same PC, or whatever) and pipe a Unix command to your MUSHclient PC...
ls | ./udpsend 10.0.0.3 4222
Then you see the directory listing on your MUSHclient world. Now you can see various possibilities here. You might have something installed on your MUD server box (maybe hosted at a different site) and that could send you a UDP packet if, say, the disk is filling up, or the server has crashed, or whatever.
Tests would seem to indicate that multiple copies of the status bar listening on the same port on a particular PC will not necessarily all get the message. So if you want to have multiple ones (eg. an inventory, and a health bar) choose different ports.
You can specify the port when you run the statusbar program:
StatusBar port ip magic
eg.
StatusBar 4222 0.0.0.0 gandalf
However if you broadcast, the same message can appear on different PCs. For example in my network I have a private IP address range 10.0.0.1 onwards. If I use the udpsend program to send to 10.0.0.255 then all PCs listening on that port get the packet at the same time (roughly).
Also, tests have shown that re-installing the plugin seems to fail every second time. It would appear that re-using the port in quick succession causes an "address in use" message from the Windows sockets. You normally wouldn't do that anyway, once you have the plugin installed it would stay there.
However I amended the plugin code above to show an error message, so you can see if it installed or not.
If you really need to reinstall it, I would suggest using some technique to remove the old listener, wait a second, and then install a new one.
eg.
'
' remove the old one
'
UdpListen ("0.0.0.0", 4222, "")
'
' use a timer here to wait a second
'
' ------ timer delay ------
'
' install the new one
'
UdpListen ("0.0.0.0", 4222, "GotPacket")
Soooo, how do you make the statusbar react to changes in the mud? I don't have a clue about how to make MC send UDP packets. Also, the MUD I play on has this nifty thing for MXP. First it sends this:
The first part looks like it just sets up the bar area, and then the second actually has all the info. So you could do something similar in the window. You'd just need a trigger that gets sent with the MXP info (the tick perhaps?) to set off the update. Does the info get sent before or after the tick?
After a bit of mucking around I got a timer to do it, like Flannel suggested. I did it in Lua, so either switch your scripting to Lua, or make a plugin out of it. If you have trouble doing that let me know and I'll do one.
I decided it was easier to hard-code the names of each bar rather than trying to interpret the STAT and GAUGE MXP elements, which MUSHclient doesn't currently support.
<timers>
<timer enabled="y" second="5" send_to="12"
>
<send>do
t = t or {}
local old_t = {}
-- make copy of current values
for k, v in t do
old_t [k] = t [k]
end
t.mud_hp = GetEntity ("mud_hp")
t.mud_maxhp = GetEntity ("mud_maxhp")
t.mud_sp = GetEntity ("mud_sp")
t.mud_maxsp = GetEntity ("mud_maxsp")
t.mud_ep = GetEntity ("mud_ep")
t.mud_maxep = GetEntity ("mud_maxep")
t.mud_monster_name = GetEntity ("mud_monster_name")
t.mud_monster_health = GetEntity ("mud_monster_health")
t.mud_max_mon_health = GetEntity ("mud_max_mon_health")
-- see if changed
local changed = false
for k, v in t do
if old_t [k] ~= t [k] then
changed = true
end -- if
end
-- exit if nothing changed
if not changed then
return
end -- if
-- function to send UDP packets with magic keyword and port number
local function udp (msg)
UdpSend ("127.0.0.1", 4111, "magic," .. msg)
end -- function udp
-- function to calculate percent, with guard against divide by zero
local function percent (amount, max)
amount = tonumber (amount)
max = tonumber (max)
if not (amount and max) then
return 0
end -- if no values supplied
if max <= 0 then
return 0
end -- if too low
if amount > max then
return 100
end -- if too high
return math.floor (amount / max * 100)
end -- function percent
-- title, colours, bar sizes, labels
udp ("title,Status")
udp ("textcolour,0")
udp ("backcolour,14804223")
udp ("config,10,5,100,15,70,320,20")
udp ("labels,HP,SP,EP,Monster")
-- bar "foreground" colours
udp ("colours," ..
ColourNameToRGB ("darkgreen") .. "," ..
ColourNameToRGB ("darkblue") .. "," ..
ColourNameToRGB ("saddlebrown") .. "," ..
ColourNameToRGB ("dimgray"))
-- bar "background" colours
udp ("fillcolours," ..
ColourNameToRGB ("lightgreen") .. "," ..
ColourNameToRGB ("lightblue") .. "," ..
ColourNameToRGB ("tan") .. "," ..
ColourNameToRGB ("gainsboro"))
-- percentages
udp ("values," ..
percent (t.mud_hp, t.mud_maxhp) .. "," ..
percent (t.mud_sp, t.mud_maxsp) .. "," ..
percent (t.mud_ep, t.mud_maxep) .. "," ..
percent (t.mud_monster_health, t.mud_max_mon_health)
)
-- monster name
udp ("text,5,95," .. t.mud_monster_name)
end -- do</send>
</timer>
</timers>
What this does is, every 5 seconds, check the entity values, and if they have changed, send an update to the status window. You need to download the status bar window as mentioned above and start it up (ie. execute the .exe) manually.
What you should see 5 seconds later is the status bar with the 4 bars drawn, and then as the updates arrive from the MUD the length of the bars will update. You can see the names of the colours for each bar in the timer above, you can customise that to your choice.
Just drag the window around to a convenient location on the screen.
So can you use this to capture channel conversations?
Also, will it scroll if too many lines show up?
Additionally, How would I use it for an external statusbar for my prompt? Considering I know what % life and what not I'm at. I don't need to calculate it out.
Thanks _ALOT_ for the help with the statusbar Nick!
Though I seem to have a rather odd problem now. After an hour or two the statusbars disappear leaving a white window with only the labels left. I downloaded ShellEnhanced to make the Statusbar always on top, other than that I have no clue about what might be messing with it :/
I don't think it is the ShellEnhanced stuff. It happened to me once yesterday, and I just reproduced it.
I don't quite know why, the program itself is so simple it shouldn't go wrong. However I am guessing from what seems to be happening is that sometimes when it tries to draw on its little window it somehow grabs the entire desktop and draws on that, hence the desktop changes colour. Why, I'm not sure. For one thing, Windows should not allow programs to interfere with each others like it seems to be doing.
I'm trying to Google my way to finding an article that explains if there is some sort of exception situation that should be handled differently.
OK, I think I fixed it. Download the new source/executable from the same spot as before.
In case anyone is wondering, the problem seemed to be that it was not freeing resources, and what eventually happened was that Windows ran out of drawing resources, and in my case at least, the desktop went crazy. This is the change (in a few places):
HBRUSH barbrush = CreateSolidBrush (colours [i]);
if (barbrush)
{
FillRect (hdc, &rect, barbrush);
DeleteObject (barbrush);
} // end of having brush
What the original was doing was CreateSolidBrush for each bar drawn, and each background of the bar, plus the background for the whole window, every time the window was redrawn. This meant that it would have used around 9 brushes per redraw (for 4 bars).
The new version frees each resource as it uses it, so it should never use them up.
Rock on Nick, just one more thing.
I didn't really get how to print multiple textlines in the window. I'd like to put some statistics as well as some affecting protections information, wether spells are up or not etc. To make it a bit easier to keep track off :)
OK, it's that last line with "text" in it that is the key. If you change:
-- monster name
--udp ("text,5,95," .. t.mud_monster_name)
... to:
udp ("text,5,95," ..
[[You stand at the entrance to the Darkhaven Academy. A large flight of
stone stairs lead down into the massive subterranean structure, which
has the responsibility of training the young adventurers of the world.
A small cobbled street leads eastward to a shop catering to the needs
of these adventurers. To the north, you see the lengthy Horizon Road.
]])
Then you will see (especially if you resize the window a bit) all that text. The "text" line lets you send multi-line text to appear that the nominated pixel onwards (horizontal 5, vertical 95 in this case).
So, you can append a few things together as required, with \r\n at the end of each line for a line break. The multi-line literal in Lua does that automatically for you.
Well, a Scrolling Text window would basically be what I've been looking for for channel capturing... I know, Notepad works too but I don't like that way.
Basically, with this window it looks like what I'm looking for, if it could just scroll like the output window.
With the status bar window, if you have a comma in your text, then whatever is after the comma will not display (in the "text" section). This is because it uses a comma as a delimiter.
This could be worked around with a few changes, however for now, if your text has commas in it replace them with something else if possible (eg. replace-all comma with semicolon).
ok, I'm having some trouble with this. Iv'e dl'd both the http://www.gammon.com.au/files/utils/udpsend.zip and http://www.gammon.com.au/files/utils/statusbar.zip
, the statusbar coems up fine, but when I use the updsend prog, it just flashes a black screen real fast and that's all. I've unzipped both and tried to alter the IP source in the statusbar by hand but that didn't help. I've redone everything, reinstalled and everything to start over and still have problems. I've been trying to do this in VBscript and used the
function multiline_trigger (name, line, wildcards)
local function udp (msg)
UdpSend ("127.0.0.1", 4111, "m," .. msg)
end
part as a script and loaded it. It just gives me errors though and has no effect on the statusbar, Iv'e also tried setting up and alisa to send this information to script. I'm probally just doing this all wrong, so if anyone can help me through this I'd appreciate it. I'm completly lost now, so if someone can lead me through this....
Also, I've seen Zmud users with buttons and bitmaps used with information sent from variables to set these up. Is this basically the same thing?
Well, you need to send the magic text when sending through UDP. So its m,title,Inventory
or whatever.
What errors?
That UDP program isn't required, its just a standalone UDP thing. MC has UDP capabilities built in.
Yes, that stuff should be sent to script, in either a script file, or from an alias/trigger (this one should be in a trigger, since it uses wildcards in the last line).
Oh, wait. No, in VB you need to ditch most of that stuff, and just use the UDPSend built in to MC:
UDPSend "127.0.0.1", 4111, "m,title,Inventory"
would be your first line, for instance.
If you wanted to make a subroutine (to take care of the IP, port, and magic text) you could do that.
sub udp(sSend)
UDPSend "127.0.0.1", 4111, "m," & sSend
end sub
Put that in your script file, then you can use those lines already (except the inventory one, for that you just substitute the wildcard).
Also, I've seen Zmud users with buttons and bitmaps used with information sent from variables to set these up. Is this basically the same thing?
Yes, basically. I think zMUD has some of that built into the client, but this program illustrates how you can expand MUSHclient to add these sorts of things as stand-alone add-ons.
My original examples were in Lua, that should have been mentioned on the page somewhere. If you are not commited to VBscript you could switch your script language to Lua and then they should work unchanged.
And yes, zMud has this sort of thing. Or at least it started with the capabilities to draw things and such, someone still had to code everything as a plugin. And it's capabilities are more limited than MCs currently (since you can only do what it has functions for, with MC you can do literally anything). There just isn't a plugin/program already built for MC.
Error number: -2146827263
Event: Execution of line 1 column 31
Description: Expected end of statement
Line in error:
UdpSend "0.0.0.1", 4111, "m," .. msg
Called by: Immediate execution
in the source for the status bar I have the IP set as 0.0.0.1
I'm just not getting this for some reason. I've tried other options aswell, taking out parts and adding and using the text found in hte contents file, but nothing changes the statusbar
You need to have the IP be 127.0.0.1, since it references your own computer.
Youre using VBscript, so you have to rewrite a lot of that stuff to VBScript.
And I believe you need to put that subroutine in your main script file. Although I may be mistaken, it might be able to go in an alias. However it would make sense to put it in your main script, so other aliases/triggers can call it as well.
Which part are you asking about? To start up the status bar window your plugin would probably need to do os.execute (in Lua) to start the program running.
yes, i want to auto load state bar window at my plugin. i use os.execute("StatusBar.exe") to do it, and it open a dos window to open state bar window, state bar does not work until i close dos window. i don't know why, and how can i do it automatically.
the second question is path of os.execute use, i have to put the file StatusBar.exe at mc directory, if not do this, status bar window can not open.
thank nick for your answer.
my MUSHclient executable directory is "C:\Program Files\MUSHclient\", so when i use start command, it does not work. and i changed it like
os.execute ("start \"\" \"" .. GetInfo (66) .. "\statusbar.exe\"")
it is OK.
it works well now, thank you!
i have new problem now, when i load status bar window at the function called OnPluginInstall, the MUSHclient lost focus, current window change to status bar window. i want to reactive MUSHclient automatically, how can i do it?
hi nick, i have a new problem now, that is when the MCL file which have load status bar window can not be save.
it always say "access to XXX.MCL was denied".
what is this mean, and how can i solve it?
and more question is, how can i close the status bar window when i close one session of the MUSHclient?
i think to use send a close message to status bar window, and status bar window close itself, but i am not a programmer, and can not modifie the C file of status bar window. can u help me?
If you edit the statusbar.cpp file that came with the download, it explains what each of the commands are, in comments near the top. You want the "quit" command.
I don't know why it won't save, try saving under a different name and then quitting MUSHclient or rebooting the PC.
I'm not sure how the status bar is set up. I've dl'ed the statusbar.zip file and unzipped it. The link to the additional Lua files providing socket support in Nick's original post did not work, so I did a google search and found the latest file here:
http://luaforge.net/frs/?group_id=23&release_id=837
Where do I put the .lua files from luasocket-2.0.2-lua-5.1.2-Win32-vc6.zip? The zip file has subfolders which complicates things. The instructions given by the programmer are here: http://www.tecgraf.puc-rio.br/~diego/professional/luasocket/installation.html
I would greatly appreciate it if someone looked into this for me.
Unzip that into the same directory as MUSHclient.exe (eg. c:\Program Files\MUSHclient if that is where you put it).
Manually start up StatusBar.exe (for now) by double-clicking it, and accepting it as a valid program if your firewall complains that it is trying to access the Internet (that is because it opens a "listening" UDP port).
You should see a blank (white) status bar window.
In MUSHclient's File -> Global Preferences -> Lua, make sure "Allow DLLs to be loaded" is checked (as luasocket is a DLL). Make sure your current world is trusted (in the script on that page), or make the first line:
trust_all_worlds = true
If you had to change it, go to the Game menu -> Reload Script File.
Copy and paste the example from page 1 of this thread, minus the 'dofile "lua.lua"' part, as follows, into an Immediate window (Ctrl+I):
However an important point is that you don't need Luasocket to make it work - that was for the example, and is one way of going about it. In this example (also from page 1):
function multiline_trigger (name, line, wildcards)
local function udp (msg)
UdpSend ("127.0.0.1", 4111, "magic," .. msg)
end
udp ("title,Inventory")
udp ("size,10,10,300,300")
udp ("config,10,5,100,15,80,300,20")
udp ("font,Harem,12")
udp ("textcolour,0")
udp ("backcolour,14804223")
udp ("text,5,5," .. wildcards.inventory)
end -- function
That simply uses UdpSend which is built into MUSHclient. If you do a trigger like that, you can skip all the steps about installing Luasocket, letting MUSHclient read DLLs, and so on.
I got a couple of triggers to work nicely, it was a bit trickier than I thought, as I haven't looked at it for a while, and things have changed a bit.
<triggers>
<trigger
enabled="y"
match="<*/* hp */* m */* mv */* xp>*"
name="status_prompt"
send_to="12"
sequence="100"
>
<send>
-- calculate percentages, put them in a table
status_table = {
%1/%2 * 100, -- hp
%3/%4 * 100, -- mana
%5/%6 * 100, -- movement
%7/%8 * 100, -- xp
}
if not status_window_open then
status_window_open = true
udp = function (msg)
UdpSend ("127.0.0.1", 4111, "magic," .. msg)
end
os.execute ('start "statusbar" "' .. GetInfo (66) .. 'StatusBar.exe"')
-- it might take a second to start up StatusBar.exe, so do this a second later
DoAfterSpecial (1, [[
udp ("title,Status Bar - SMAUG")
udp ("config,10,5,100,15,60,320,20")
udp ("size,10,10,350,140")
udp ("textcolour," .. ColourNameToRGB ("indigo"))
udp ("backcolour," .. ColourNameToRGB ("lightsteelblue"))
udp ("labels,HP,Mana,Move,XP")
udp ("font,Comic Sans MS,10,0,700")
udp ("colours," ..
ColourNameToRGB ("darkgreen") .. "," ..
ColourNameToRGB ("darkblue") .. "," ..
ColourNameToRGB ("saddlebrown") .. "," ..
ColourNameToRGB ("dimgray"))
udp ("fillcolours," ..
ColourNameToRGB ("lightgreen") .. "," ..
ColourNameToRGB ("lightblue") .. "," ..
ColourNameToRGB ("tan") .. "," ..
ColourNameToRGB ("gainsboro"))
udp ("values," .. table.concat (status_table or {}, ","))
ActivateClient () -- get focus back
]], 12)
else
udp ("values," .. table.concat (status_table, ","))
end -- first time
</send>
</trigger>
<trigger
enabled="y"
keep_evaluating="y"
match="Exits: *"
send_to="12"
sequence="100"
>
<send>
if udp then
udp ("text,5,88,%0")
end -- status window available
</send>
</trigger>
</triggers>
To make this work, first I set my SMAUG prompt to show all the stuff it needs:
prompt <%h/%H hp %m/%M m %v/%V mv %x/%X xp>
That is, current and max HP, current and max Mana, current and max movement points, xp and XP to go. This lets me calculate percentages for the status bar.
It was ready to work. What the first trigger does is calculate the percentages, and then the first time around, it uses os.execute to start up the statusbar.exe program. (You need to make the world "trusted" for this to work). It then uses DoAfterSpecial to configure the status window a second later. The reason for this is to give the status bar program time to start.
A nice trick is to make the status bar window auto-position itself adajacent to the world window where it is being used. To do this replace the line above:
udp ("size,10,10,350,140")
... by this:
-- where is the world window?
local mc_location = GetWorldWindowPosition (1, 1)
local width = 350
local height = 140
local t = {
mc_location.left - width - 10,
mc_location.top - 30,
width,
height,
}
udp ("size," .. table.concat (t, ","))
What this does is use GetWorldWindowPosition to find the position of the world window, in global screen co-ordinates. We then subtract the width of the status window (350 in this case) from the left of the MUSHclient window, which puts it exactly to the left of it. I added a "fudge" factor of 10, to allow room for the window edge.
Then it takes the top of the MUSHclient window, and subtracts 30 to allow for the width of the title bar, so both title bars line up.