Message
|
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.
Documentation
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.
addxml.lua
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
Example:
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.
alphanum.lua
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.
Example:
require "alphanum"
t={
"z18.doc","z19.doc","z2.doc","z16.doc","z17.doc",
"z1.doc","z101.doc","z102.doc","z11.doc","z12.doc",
"z13.doc","z14.doc","z15.doc","z20.doc","z3.doc",
"z4.doc","z5.doc","z6.doc","z10.doc","z100.doc",
"z7.doc","z8.doc","z9.doc", "Z9A.doc",
}
table.sort(t, alphanum (t))
for i=1, #t do
print(t[i])
end
check.lua
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:
http://www.gammon.com.au/scripts/doc.php?general=errors
Note that this function is built into MUSHclient from version 4.28 onwards, so you don't need to "require" it.
Example:
require "check"
check (SetVariable ("abc", "def")) --> works ok
check (SetVariable ("abc-", "def")) --> Error: The name of this object is invalid
commas.lua
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
Example:
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:
http://www.gammon.com.au/forum/?id=9906
copytable.lua
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.
Example:
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
declare.lua
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
Example:
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.
getlines.lua
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
Example:
require "getlines"
s = [[
every good
boy
deserves
fruit]]
for line in getlines (s) do
print (line) --> print each line
end -- for loop
getstyle.lua
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
Example:
require "getstyle"
function my_trigger (name, line, wildcards, styles)
-- find location of word
col = string.find (line, "bleeding")
if not col then
return
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".
getworld.lua
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.
Example:
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.
Example:
function mytrigger (name, line, wildcards, styles)
require "getworld"
send_to_world ("SMAUG chats", styles)
end -- function
movewindow.lua
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)
Example:
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,
windowinfo.window_left,
windowinfo.window_top,
WINDOW_WIDTH,
WINDOW_HEIGHT,
windowinfo.window_mode,
windowinfo.window_flags,
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
pairsbykeys.lua
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
Example:
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".
serialize.lua
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".
Example:
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):
"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
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.
strict.lua
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
Example:
require "strict"
a = 20 --> declare "a" by assigning to it
print (a) --> prints 20
print (b) --> Error: variable 'b' is not declared
tabbed_window.lua
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
Example:
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)
tprint.lua
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
Example:
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:
"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
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).
var.lua
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:
Example:
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"
wait.lua
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).
Example:
require "wait"
wait.make (function () --- coroutine below here
repeat
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 | Top |
|