[Home] [Downloads] [Search] [Help/forum]

Gammon Forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Lua
. . -> [Subject]  Lua modules supplied with MUSHclient
Home  |  Users  |  Search  |  FAQ
Register forum user name
Forgotten password?

Lua modules supplied with MUSHclient

This subject is now closed.     [Refresh] Refresh page

Posted by Nick Gammon   Australia  (21,475 posts)  [Biography] bio   Forum Administrator
Date Sat 19 Apr 2008 02:09 AM (UTC)

Amended on Sat 17 Feb 2018 10:26 PM (UTC) by Nick Gammon

This page can be quickly reached from the link: http://www.gammon.com.au/modules

The directory "lua" which is created as part of a MUSHclient standard installation contains the following Lua "modules":

  • addxml.lua - add triggers, timers, aliases, macros by supplying a table (and convert back to a table)
  • alphanum.lua - sort names into a more "natural" order
  • check.lua - check a world function return code
  • commas.lua - rounding, duration and comma functions
  • copytable.lua - does a deep or shallow copy of a Lua table
  • declare.lua - ensure variables in a function are declared
  • getlines.lua - iterator to convert a block of text into lines
  • getstyle.lua - finds a style run corresponding to a given column
  • getworld.lua - finds another world, and lets you send text to it
  • movewindow.lua - lets you drag miniwindows around
  • pairsbykeys.lua - iterator to traverse a table, sorted by key order
  • serialize.lua - serialize Lua variables into a string
  • strict.lua - enforce use of local variables inside functions
  • tabbed_window.lua - lets you make miniwindows with tabs
  • tprint.lua - table printer
  • var.lua - use MUSHclient variables as if they are Lua variables
  • wait.lua - for pausing scripts until time elapsed, or certain text arrives from the MUD

This thread describes the purpose of each one, and where to find out more about them.

The general way to use any of these modules is to "require" the module, which is the file name above without the ".lua" part, and then go ahead and use the documented functions in the module.

For example:

require "tprint"

tprint (math)  --> lists all the math functions in the output window

It is a feature of the way that "require" works, that you can use it repeatedly with very little overhead. Lua first checks to see if the wanted function has already been loaded, and if so, does not reload it from disk.

Thus you could conceivably do a require "serialize" in every function that needs to use it, rather than fiddling around trying to do it once in a central place, if that makes coding easier.


Each of the modules tries to be self-documenting, so if you open them up in a text editor, there may be further examples and suggestions for using them, in addition to what is written below.


This lets you add triggers, aliases, timers, or macros by specifying each parameter in a Lua table, which is easier in many ways than getting the correct arguments to AddTrigger etc.

You can also use the addxml.save to do the inverse operation - save an existing trigger, alias, timer or macro as a table.

See forum thread: http://www.gammon.com.au/forum/?id=7123

Exposed functions are:

  • addxml.trigger (t) --> add a trigger
  • addxml.alias (t) --> add an alias
  • addxml.timer (t) --> add a timer
  • addxml.macro (t) --> add a macro
  • addxml.save (type, name) --> convert one of the above back into a table


require "addxml"

addxml.trigger {
  enabled = 'y',
  custom_colour = '17',
  sequence = '100',
  other_text_colour = 'salmon',
  match = '[Public] * says, "*"',
  name = 'mytrigger',

This adds a new trigger with all the appropriate values as specified.


This lets you sort strings with numbers in them into a more "natural" order. For example, normal sorting would put "a100" before "a2". This module provides a comparison routine that "chunks" up strings into batches of letters and numbers, and sorts them individually.

See forum thread: http://www.gammon.com.au/forum/?id=8698

Exposed function is alphanum.


require "alphanum"

"z7.doc","z8.doc","z9.doc", "Z9A.doc",

table.sort(t, alphanum (t))

for i=1, #t do


This implements a simple check function, that checks the return codes from the many MUSHclient script functions that return a "status code". This can be useful for catching errors in things like AddTrigger, which would otherwise silently fail.

See forum thread: http://www.gammon.com.au/scripting - look about halfway down at the posting about "Checking return codes".

Exposed functions are:

  • check (code) --> checks argument is zero, if not raises an error

The error message is the correct message from this page:


Note that this function is built into MUSHclient from version 4.28 onwards, so you don't need to "require" it.


require "check"

check (SetVariable ("abc", "def"))  --> works ok
check (SetVariable ("abc-", "def")) --> Error: The name of this object is invalid


This implements four useful functions:

  • round - to round a floating-point number to the nearest integer
  • convert_time - express an interval of seconds as days/hours/minutes etc.
  • commas - add commas to big numbers
  • scan_dir - directory scanner

See forum thread: http://www.gammon.com.au/forum/?id=7805

If you can't find commas.lua in your distribution, there is a copy of it in that thread.

Exposed functions are:

  • round (x) - rounds the argument to the nearest integer
  • convert_time (secs) - converts a numbers of seconds to the nearest relevant interval (eg. 65 seconds becomes "1 m" whereas 119 seconds becomes "2 m")
  • commas (num) - takes a number and adds commas to it (eg. 123456 becomes "123,456")
  • scan_dir (path, f) - scans disk starting at "path" calling function "f" for each file


require "commas"

print (round (1.5))   --> 2
print (round (-99.8)) --> -100

print (convert_time (70))     --> 1 m
print (convert_time (1000))   --> 17 m
print (convert_time (10000))  --> 3 h
print (convert_time (100000)) --> 1 d

print (commas (123456789)) --> 123,456,789

scan_dir (GetInfo (60),  function (name, stats) print (name, stats.size) end)

More information about the scan_dir function:



Implements a deep or shallow copy of a Lua table.

See forum thread: http://www.gammon.com.au/forum/?id=8042

Normally in Lua if you simply assign a table variable to another variable, you get the original table, not a copy. However by using copytable you actually get a copy of the table.

Exposed functions are:

  • copytable.shallow (t) --> shallow copy of first level values
  • copytable.deep (t) --> copies table, and any nested tables are also copied

For tables which themselves contain nested tables, you may wish to use copytable.deep which effectively "recurses" to make a copy of those tables as well.


t1 = {5, 6, 7}
t2 = t1 
t2 [3] = 8  --> change t2
print (t1 [3])  --> prints 8, not 7
print (t2 [3])  --> prints 8, as expected

However by using copytable, you get a completely new table:

require "copytable"

t1 = {5, 6, 7}
t2 = copytable.shallow (t1)
t2 [3] = 8
print (t1 [3])  --> prints 7
print (t2 [3])  --> prints 8


Forces you to declare variables (by using the "local" keyword), rather than relying upon "on-the-fly" creation of new variables, which Lua normally does.

See forum thread: http://www.gammon.com.au/forum/?id=7327

Exposed functions are:

  • force_declarations () --> after calling this, all variables must be declared


require "declare"

a = 42  --> works OK, we haven't called "force_declarations" yet
force_declarations ()  --> from now on, we have to declare variables
local b = 55  --> works OK, we used "local" to declare the variable "b"
c = 66  --> Error: assign to undeclared variable 'c'

The purpose of this is to catch spelling errors in functions, for example, in the above code, if we really meant to say "b = 66" rather than "c = 66" then the error message would alert us.

Also see "strict.lua" below for doing this a bit differently.


Provides an iterator function to break a string into individual lines.

See forum thread: http://www.gammon.com.au/forum/?id=6544

Exposed functions are:

  • getlines (s) --> iterator to be used in a for loop


require "getlines"
s = [[
every good

for line in getlines (s) do
  print (line)  --> print each line
end -- for loop


Finds a style run corresponding to a given column. This is intended to be used in situation (like triggers) where you have a "style run" table provided by MUSHclient, and want to find the style of a column (eg. column 15).

You might use this to see if a particular word in a particular column is a certain colour (eg. is the word "bleeding" in red?).

See forum thread: http://www.gammon.com.au/forum/?id=7818

Exposed functions are:

  • GetStyle (styles, column) --> get style items for this column


require "getstyle"

function my_trigger (name, line, wildcards, styles)
  -- find location of word
  col = string.find (line, "bleeding")
  if not col then
  end -- word not found

  -- get style at that location
  style = GetStyle (styles, col)

  -- display it
  print ("word is in", RGBColourToName (style.textcolour))
end -- function my_trigger

The above example trigger function uses the style runs table supplied as the fourth argument to a trigger function. It first locates the column in which "bleeding" is, and then finds the style of that column.

It then displays the colour in which the (first letter of) the word "bleeding" is.

Note - capitalization of the function name is "GetStyle", but the module is "getstyle".


Lets you get a reference to another MUSHclient world, loading it from disk if necessary. Also lets you send trigger data from one world to another.

See forum thread: http://www.gammon.com.au/forum/?id=7991&page=3

Exposed functions are:

  • get_a_world (name) --> returns a "world object" for operating on the named world

The world file is opened if not already opened by appending ".mcl" to the name, and looking in the default MUSHclient worlds directory. If the world cannot be opened nil is returned.


require "getworld"

local w = GetWorld ("SMAUG chats")
if w then  -- if found
    w:DeleteOutput ()
end -- if

  • send_to_world (name, styles) --> sends the style runs to the named world

Sends the style runs to the named world. It first calls get_a_world (above) and if successful, sends the style runs to it. This effectively lets you write a trigger that sends the matching line, including all colours, to another world window. For example, to filter chats, who lists, and suchlike.


function mytrigger (name, line, wildcards, styles)
  require "getworld"
  send_to_world ("SMAUG chats", styles)
end -- function


This lets you attach a "drag handler" to a miniwindow, letting you drag the window around on the screen to reposition it.

See forum thread: http://www.gammon.com.au/forum/?id=9594

Exposed functions are:

  • movewindow.install (win, default_position, default_flags, nocheck, friends, preprocess, start_position)


  require "movewindow" 
  windowinfo = movewindow.install (win, miniwin.pos_center_right, 0)  -- default position / flags

The values in "windowinfo" table can now be used to create the miniwindow in the desired position. For example:

  WindowCreate (win, 
                ColourNameToRGB "slategray") 

  • movewindow.add_drag_handler (win, 0, 0, 0, 0, miniwin.cursor_both_arrow)

Installs the drag handler for the miniwindow. Part or all of the window can be designated as the "drag zone". In the above example, the entire window is the drag zone. Typically you would use the title bar (if the window has one) as the drag zone.

  • movewindow.save_state (win)

This is used to save the window position when saving the plugin state (if you do that). For example:

function OnPluginSaveState ()
  -- save window current location for next time  
  movewindow.save_state (win)
end -- function OnPluginSaveState


Provides an iterator function to access a table in alphabetic order, by key.

See forum thread: http://www.gammon.com.au/forum/?id=6036

Exposed functions are:

  • pairsByKeys (t, f) --> iterator to be used in a for loop using optional comparison function f


require "pairsbykeys"

-- This prints the math functions in key order
for k, v in pairsByKeys (math) do
  print (k, v)
end -- for

The iterator function works by making a temporary table into which it copies all the keys, sorts this temporary table, and then returns each one per iteration, in alphabetic order.

You can provide your own comparison function (less-than function) if you want to compare in some other sequence (eg. descending). For example:

require "pairsbykeys"

function gt (a, b)
  return a > b
end -- gt

-- This prints the math functions in descending key order
for k, v in pairsByKeys (math, gt) do
  print (k, v)
end -- for

This example reverses the normal sort sequence, because the supplied function is supposed to compare for "less than" but we compare for "greater than".

Note - capitalization of the function name is "pairsByKeys", but the module is "pairsbykeys".


Converts a table into a string, suitable for storing to disk.

See forum thread: http://www.gammon.com.au/forum/?id=4960

Exposed functions are:

  • serialize.save (name, v, t) --> complex serialization
  • serialize.save_simple (v) --> serialize simple tables

Read the forum thread for full details, but basically if you have a table of iteme (eg. mob names, and how many HP each one has) you can use serialize.save to turn that table into a string. It can then be sequently loaded back as a Lua table by doing a "loadstring".


require "serialize"

mobs = {}  -- create mobs table

mobs.kobold = {
  name = 'killer',
  hp = 22,
  gold = 5,
  location = 'city square',
  treasure = { "sword", "gold", "helmet" } -- sub table

-- and another one ...

mobs.worm = {
  name = 'gordon',
  hp = 4,
  gold = 15,
  location = 'underground',
  treasure = { "food", "knife" },
  attacks = { "bite", "poison" }

s = serialize.save ("mobs")

print (s)

This prints:

mobs = {}
  mobs.kobold = {}
    mobs.kobold.treasure = {}
      mobs.kobold.treasure[1] = "sword"
      mobs.kobold.treasure[2] = "gold"
      mobs.kobold.treasure[3] = "helmet"
    mobs.kobold.name = "killer"
    mobs.kobold.gold = 5
    mobs.kobold.location = "city square"
    mobs.kobold.hp = 22
  mobs.worm = {}
    mobs.worm.attacks = {}
      mobs.worm.attacks[1] = "bite"
      mobs.worm.attacks[2] = "poison"
    mobs.worm.treasure = {}
      mobs.worm.treasure[1] = "food"
      mobs.worm.treasure[2] = "knife"
    mobs.worm.name = "gordon"
    mobs.worm.gold = 15
    mobs.worm.location = "underground"
    mobs.worm.hp = 4

In the above example, we can get our table back like this:

mobs = nil  --> table gone now
assert (loadstring (s)) ()  --> load string "s"
require "tprint"  --> for printing
tprint (mobs) --> table exists, see below

This prints (using tprint described later on):

  "location"="city square"

This shows that we have recreated our mobs table, from the string we got after doing a serialize.

We can also use serialize.save_simple to make a simpler looking table than the one earlier, like this:

s = "mobs = " .. serialize.save_simple (mobs)

print (s)

This prints (for the same mobs table as before) the following:

mobs = {
  kobold = {
    treasure = {
      [1] = "sword",
      [2] = "gold",
      [3] = "helmet",
    name = "killer",
    gold = 5,
    location = "city square",
    hp = 22,
  worm = {
    attacks = {
      [1] = "bite",
      [2] = "poison",
    treasure = {
      [1] = "food",
      [2] = "knife",
    name = "gordon",
    gold = 15,
    location = "underground",
    hp = 4,

Notice how this example looks less "wordy" then doing serialize.save.

I also needed to concatenate "mobs = " to the string returned by serialize.save_simple as this works slightly differently in that it doesn't know the name of the variable, thus I have to supply it.


This function was written by Roberto Ierusalimschy, the developer of Lua. Once you "require" it, it modifies the "global namespace" so that you must declare variables before using them. To "declare" a variable you simply assign to it in global scope. Until you have done that, you are not allowed to read from "undeclared" variables.

See forum thread: http://www.gammon.com.au/forum/?id=7335

If you can't find strict.lua in your distribution, there is a copy of it in that thread.

This works a bit differently from declare.lua described earlier. Here, you simply need to assign something to a variable in global scope (that is, not inside a function) for it to become declared.

Exposed functions are:

  • (none) - you simply "require" it to get the functionality


require "strict"

a = 20  --> declare "a" by assigning to it
print (a)  --> prints 20
print (b)  --> Error: variable 'b' is not declared


This lets you set up a miniwindow with "tabs". That is, you can have selectable panes of information which display depending on which tab you click on.

See forum thread: http://www.gammon.com.au/forum/?id=14161

Exposed functions are:

  • init (context) - initialize the module
  • draw_window (context, which_tab) - draws the window, switching to which_tab
  • hide_window (context) - hides the window
  • save_state (context) - to be called from OnPluginSaveState


require "tabbed_window"

function DrawFoo (win, left, top, right, bottom, context)
  WindowText (win, context.tabfont.id, "This is the foo tab", 
             left + 10, top + 10, 0, 0, ColourNameToRGB "green")
end -- DrawStats

function DrawBar (win, left, top, right, bottom, context)
  WindowText (win, context.tabfont.id, "This is the bar tab", 
              left + 10, top + 10, 0, 0, ColourNameToRGB "darkblue")
end -- DrawEquipment

context = { 

 win = "tabbed_window" .. GetPluginID (),

 tabs = {
      { name = "Foo",       handler = DrawFoo },
      { name = "Bar",       handler = DrawBar },
      } -- end of tabs
    }  -- end of context
tabbed_window.init (context)
tabbed_window.draw_window (context, 1)


Table printer - prints a Lua table recursively - that is, it shows every item in the table, and then recurses to show sub-tables.

See forum thread: http://www.gammon.com.au/forum/?id=4903

Exposed functions are:

  • tprint (t) - print table t


require "tprint"

mobs = {}  -- create mobs table

mobs.kobold = {
  name = 'killer',
  hp = 22,
  gold = 5,
  location = 'city square',
  treasure = { "sword", "gold", "helmet" } -- sub table

-- and another one ...

mobs.worm = {
  name = 'gordon',
  hp = 4,
  gold = 15,
  location = 'underground',
  treasure = { "food", "knife" },
  attacks = { "bite", "poison" }

tprint (mobs)

This prints the mobs table as follows:

  "location"="city square"

Note the way that nested tables are indented. If the key is a string it is quoted, otherwise it is shown not quoted. This helps distinguish a table key 10 (the number) from "10" (the string).


This creates a special table "var" which lets you access MUSHclient variables as if they were inside a Lua table.

See forum thread: http://www.gammon.com.au/forum/?id=4904

Exposed items are:

  • var - variables table


require "var"

var.target = "kobold"   -- set MUSHclient variable 'target' to 'kobold'
print (var.target)      -- print contents of MUSHclient variable 'target'

If the table item does not exist, nil is returned. You can delete an item by assigning nil to it. For example:

print (var.foo)   -- nil (foo does not exist)
var.target = nil  -- delete the variable "target"


Lets you script pauses inside triggers and aliases, where you wait for time to elapse, or some text to arrive from the MUD.

See forum thread: http://www.gammon.com.au/forum/?id=4956 (waiting for time)
and: http://www.gammon.com.au/forum/?id=4957 (waiting for text from the MUD)

Exposed functions are:

  • wait.make (f) - make and calls a function which can pause (a coroutine)

  • line, wildcards, styles = wait.regexp (regexp, timeout) - wait for a trigger with a regular expression

    If no match (ie. a timeout) then the returned values: line, wildcards, styles are all nil.

  • line, wildcards, styles = wait.match (what, timeout) - wait for a trigger with "normal" match text

    If no match (ie. a timeout) then the returned values: line, wildcards, styles are all nil.

  • wait.time (secs) - wait for some time to elapse

(The timeouts are optional and can be omitted).


require "wait"

wait.make (function ()  --- coroutine below here

    Send "cast heal"
    line, wildcards = 
       wait.regexp ("^(You heal .*|You lose your concentration)$", 10)

  until line and string.match (line, "heal")

  -- wait a second for luck
  wait.time (1) 

  Note ("heal done!")

end)  -- end of coroutine

The above example uses make.wait to make an inline (anonymous) function that does the actual waiting. This is needed to create a coroutine which can be paused.

Inside the function we do wait.regexp to wait for certain text to arrive fromt he MUD, with a timeout of 10 seconds. If we successfully heal someone we then use wait.time to wait a further second, and we are done.

If we don't successfully heal, the coroutine loops and casts another "heal".

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (21,475 posts)  [Biography] bio   Forum Administrator
Date Reply #1 on Sat 19 Apr 2008 09:34 PM (UTC)

The modules described above are intended for Lua scripters to use to supplement their own scripts. This differs from Plugins where are self-contained files which can be added to MUSHclient worlds. Plugin authors may well use the above modules to help write a plugin.

If you are not interested in scripting, or do not use Lua, then you should look at the Plugins feature of MUSHclient.

See: http://www.gammon.com.au/plugins/ for a list of available plugins.

Also see: http://www.gammon.com.au/forum/?bbtopic_id=108 - this part of the forum deals with plugins, and has some links to additional plugins not mentioned on the plugins page.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


This subject is now closed.     [Refresh] Refresh page

Go to topic:           Search the forum

[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at FutureQuest]