Introduction

Welcome to Mudlet, a modern MUD client for GNU/Linux, Windows and Mac OSX that offers all the tools to get the most out of your gaming experience.

Throughout this document, we hope to familiarize you with the basic aspects of Mudlet, from the interface to its very powerful and feature-rich scripting backend. The main focus in the development of Mudlet has been efficiency and performance, but we also try to make it as easily accessible as possible. However, keep in mind that this is a complex piece of software with a large set of tools that does require some deeper understanding of the underlying principles. To use Mudlet in any meaningful way, you should take a closer look at the technical section in this manual.

If you are not familiar with modern MUD clients in general, you should also take a look at the general introduction to MUD clients section at the beginning of this manual. You are welcome to ask questions on the forum of our website. If you find a bug, please let us know.

Note
Everything is centered around the central Lua scripting unit. Everything shares the same variables & functions, and everything is accessible from anywhere.

Quick Start

To connect to the MUD of your choice, click on Connect. !

  • Create a new profile by clicking on Add New Profile.

  • Specify the host and the port of the MUD (This information is usually found on the MUD’s homepage).

  • Now just click Connect to play!

1. General Introduction to Modern MUD Clients

1.1 Mudlet’s automation features

Mudlet offers a vast array of standard features to automate or otherwise improve your gaming experience. These include, but are not limited to:

  • Aliases – user-defined text input, which is converted into a different, usually longer input before being sent to the MUD, e.g. ggget gold from ground;put gold in 2.bag.

  • Keybindings – also known as hotkeys, allow executing certain user-defined commands by simultaneously pressing a specific combination of keys, e.g. CTRL+Hsend say Hello Miyuki! to the MUD or plays La Marseillaise

  • Triggers – execute user-defined commands upon receiving specific out from the MUD, e.g. MUD sends You see Elyssa standing here. → send poke Elyssa to the MUD.

  • Timers – delay the execution of a command or execute it after a specified period of time, e.g. throw gauntlet to Eric-wait 3 seconds-exclaim Let us end this here!

  • Variables – allow the user to store text or numbers for easier use inside scripts.

  • Events – allow the user to make triggers for specific events, like when Mudlet has connected to the MUD, or even user-defined events to use in complex system making.

Scripting allows the user to create automation utilities (triggers, aliases) with the Lua scripting language. The possibilities of what can be achieved by using this technique are, practically speaking, endless - ranging from teaching the client how to heal your character in combat for you to creating a fully automated robot (known as `bot`s) that will completely take control of your character (especially useful for completing repetitive, rudimentary tasks).

1.2 Automation and MUD rules

Effectively speaking, it is possible to create an AI (Artificial Intelligence) that does everything you can do in a MUD. Additionally, the program will be able outperform you in almost every routine operation. The difficulty of creating such a program depends on the task it has to perform-- gathering loot being very easy, walking through a dungeon and leveling you character being moderately easy, and socially interacting with other real people being outrageously difficult (see A.L.I.C.E.). At the end of the day, you’re teaching your client to process information and act the way you consider best-suited. Because scripting is so powerful, it can give you a competitive advantage that some people consider unfair or even cheating. At the moment of this writing (2 November 2008), this sort of automation can be best observed in commercial, massively-multiplayer online role-playing games (MMORPG), known as gold-farming or power-leveling. The basic idea is to create a system that will raise your character to the maximum level and gather in-game currency in the process, both of which can be effectively exchanged for real-world currency. The spread of the above aspects can have much more far-reaching consequences than just being unfair, such as inflation, loss of balance in terms of game-mechanics, or ultimately, a complete crash of in-game economy. For more information, see the paper "Simple Economics of Real-Money Trading in Online Games" by Jun-Sok Huhh of the Seoul National University. For these, and various other, reasons, the administrators and owners of the corresponding virtual worlds can forbid the usage of automation tools. A failure to comply can result in suspension or deletion of the user’s character or account, which can result in future denial of service. By including scripting support in Mudlet, we effectively give you the ability to create and utilize AI tool-kits, however, we do not endorse or promote the usage of these systems if it’s prohibited by your MUD. Keep in mind that by cheating, you can lessen the quality of gameplay for your fellow players and for yourself.

1.3 Basic scripting

The following part of the guide is written for new beginners in scripting. If you’re coming over from zMud or cMud, you may move on to section two.

1.4 Variables - basics

Variables are containers for data. In Lua, they can store numbers or words. You can use variables to store important information, like how much gold you have, or have them remember things for you.

The syntax for making a variable remember a number is the following:

variable = number

Or to make it remember some text:

variable = "my text"

For example, we’ll set the myhealth variable to number 1345, and the myname variable to Bob:

myhealth = 1345
myname = "Bob"

You can also do basic maths easily, for example:

a = 2 + 2 --sets variable a to the value of 4
b = a - 1 --sets variable b to the value of 3

To concatenate strings together, you can use the .. expression:

first_name = "Joe"
last_name = "Plumber"
full_name = firstname .. " " .. last_name --sets the full_name variable to "Joe Plumber", with a space in between.

1.5 How to send text to the mud

To send a command to the MUD, you can use the send() function. Data inside the quotes is sent to the MUD.

For example, the following code sends the command to eat bread:

send("eat bread")

If you’d like to include variables in the send command, you need to prefix and suffix them with two dots outside the quotes, like this:

send("My name is " .. full_name .. ". What's yours?")

1.6 How to echo text to yourself

To echo (show text to yourself), you can use the echo() or the insertText() function. For example, the following code will display Time to eat dinner! on your screen:

echo("Time to eat dinner")

If you’d like to include variables in your echo, you embed the value of your variable to the text:

my_gold = 5
echo("I have " .. my_gold .. " pieces of gold!")

1.7 Aliases

Aliases are the most basic way of automating the gameplay; you can use aliases to shorten the amount of typing you do. For example:

Example - Brew’o'Matic 6000

You’re walking around the epic dungeon of the Unholy Firedragon of Westersand, gathering roots in order to brew a potion and thus restore the growth of hair on Farmer Benedict’s bald head. Once you see a root, you need to:

open the bag of tools
get the sickle of damnation from the bag of tools
cut the root of hair-growth
clean the sickle of damnation of deadly root acid
put the sickle of damnation in the bag of tools
close the bag of tools
open the magical bag of storing
take the root
put the root into the magical bag of storing
close the magical of storing

and once you’re done, do the exact same thing nine more times… trice a day.

Alternatively, you just create an alias that would do this all with a single command - for example, quest.

1.8 Making a simple alias

To get started, click on the Aliases button in Mudlet and then on the Add button. This will make a blank alias for you, which we’ll now fill in.

The Alias name field is optional. It’s mainly used for the alias listing that you see on the left as an easy way to distinguish all of the aliases. Name our alias test for now. The Pattern field is where you put your regex pattern to describe what command you will type in the command line to cause your new alias to spring into action. Let’s say, we want our new alias to send the command "say hello" whenever we type "sh". The regex pattern would be "^sh$". Then we put "say hello" into the substitution field. After you have saved and activated your new alias "test", whenever you type "sh", Mudlet will not send "sh", but "say hello" instead. We call this substitution process alias expansion.

Mudlet uses Perl regular expression aliases. Regexes are a special way of matching patterns of words. For beginners, it is enough to think of them as a general way to specify the words themselves and their placement within the line. For basic alias, it is enough to know that the symbol ^ represents the beginning of the line and the symbol $ represents the end of the line. If you want to make an alias "tw" that sends the command "take weapon", you don’t have to worry about placement or pattern-matching in general. All you need to do is place "tw" in the field called "Regex" and type "take weapon" in the field called "substitution". Then you need to save the new alias by clicking on the "Save" icon in the top middle. The symbol for unsaved items disappears and makes way for a little blue checkbox. If this box is checked, the alias is active. If the blue box is empty, the alias is deactivated and will not work unless you press the "activate" toggle padlock icon. Now you are ready to go. Type "tw" in the command line and press the enter key. Mudlet will send "take weapon" to the MUD. An alias is basically a feature to save you a bit of typing - much like buttons, which will be described in detail in section two of the manual. To learn more about more complex aliases, have a look at section 2 of the manual.

1.9 Simple Triggers

Triggers are an automation feature offered in all MUD clients. They help you respond quicker to a particular situation and generally make things more convenient for you. They will enable you to do less manual work because triggers will do the hard work for you! This helps you concentrate more on the important aspects of the game and lessen stress. The way a trigger works is simple: You define the text that you want to trigger an action. This is called the trigger pattern. When the trigger "sees" this text in the MUD output, it’ll run the commands you’ve told it to. Example: Whenever you see a bunny, you want to attack it. You type "bunny" in the data field titled "add to list" and then either press the enter key or click on the little + icon next to the input line to add this word to the list of texts the trigger fires on. Now you type "kill bunny" in the field called "send plain text". Then click on the save icon to save and activate the trigger (= blue checkbox icon in front of the trigger name in the trigger tree on the right side is checked). When the trigger is active, each time the word "bunny" appears in the MUD output, your trigger will issue the command "kill bunny" automatically—as long as it is active. When you want to stop hunting bunnies, you can simply select the bunny trigger and then click on the padlock icon to deactivate it. The trigger will not fire until you re-enable it again via the padlock icon. If you lock a group of triggers or an entire trigger branch, all triggers in this branch will be locked until you remove the lock again. The locking starts from the root of the tree down to the end. As soon as a lock is met, the trigger engine will skip the locked branch. Locking and unlocking branches is one of the most common actions you have to take care of when playing. You turn on your defensive triggers when engaging into a battle and you turn them off afterwards, or you turn on your harvesting triggers only when you are going to harvest, and so on.

Tip
Beginners should use Mudlet’s automated highlight triggers to highlight the text that has been triggered on (i.e. an enabled trigger) to get the hang of the different trigger and pattern types. Click on the "highlight trigger" option and pick a foreground and a background color that you like to highlight your trigger. When the trigger matches, it automatically highlights its pattern. This is the most-used form of triggers in mudding as it is a quick way of highlighting words that are important to you at the moment. You don’t have to know anything about scripting, regular expressions, etc., to use highlight triggers. Just type in the word you would like to be highlighted, select appropriate colors, save the new trigger, and activate it.
1.10 Matching one unknown

You can also set up a trigger to gather the scimitars, gold or whatever else the skeletons could carry around with them. Since we do not know what the loot is, we will need to set up a trigger to match the line and take whatever was dropped. Examples:

The skeleton drops ring.
The skeleton drops gold.
The skeleton drops scimitar.

The skeleton drops_ is the generic segment of the line and the loot itself varies. Thus, we need to tell the client to take_ whatever the skeleton dropped. We do this by setting up a so-called regular expression:

Perl Style Regular Expression: The skeleton drops (.*)\.
Script: send("take " .. matches[2])

The expression (.*) matches any characters that the client receives between The skeleton drops_ (NB: notice the blank at the end) and the full stop. matches[2] simply transfers the first matched text fitting the search criteria into the output (matches[1] contains the entire matched text, matches[2] contains the first capture group. More on this in section two of the manual).

1.11 Matching multiple unknowns

Now, let’s try making a trigger that would gather the loot from anybody:

Perl Style Regular Expression: (.*) drops (.*).
Script:
send("take " .. matches[3])

In this case, whenever somebody or something drops something else or someone else, the client will pick it up. Note that we used matches[3] instead of matches[2] this time, in order to pick up the second match. If we used matches[2], we’d end up picking up the skeleton’s corpse.

1.12 Matching known variants

If you’re playing a MUD in English, you’ll notice that these triggers probably won’t work due to English syntax. Compare:

The skeleton drops apple.
The skeleton drops an apple.

Chances are that you’ll see the latter a little more often. If we used our old RegEx, the output would look something like this:

INPUT: The skeleton drops an apple.
OUTPUT: take an apple

Most MUDs can’t handle articles, such as (i.e. a, an, the) or quantifiers (e.g. five, some, each), in user input. To match this line, we could either create multiple triggers that match every possible article or a regular expression to filter out these words:

Perl Style Regular Expression: (.*) drops (a|an|the|some|a couple of|a few|) (.*).
Script:
send("take " .. matches[4])

Once again, note that we’re using the third match (matches[4]) this time. NOTE: Certain other languages, with a syntax different than that of English, might require a somewhat different approach. If you’re stuck, and your MUD administrators don’t prohibit the use of triggers, try asking on the corresponding world’s forums.

For more information, see the chapter on regular expressions.

1.13 explain basic regex characters (^, $, (\w+), (\d+) and .*) and how to use them properly.

Retrieving wildcards from triggers

Wildcards from triggers are stored in the matches[] table. The first wildcard goes into matches[1], second into matches[2], and so on, for however many wildcards you have in your trigger.

For example, you’d like to say out loud how much gold you picked up from a slain monster. The message that you get when you pick up the gold is the following:

You pick up 16 gold.

A trigger that matches this pattern could be the following:

Perl Style Regular Expression: You pick up (\d+) gold

And in your code, the variables matches[2] will contain the amount of gold you picked up (in this case, 16). So now to say out loud how much gold you looted, you can do the following:

Script: echo("I got " .. matches[2] .. " gold!")
More advanced example

Here’s an example by Heiko, which makes you talk like Yoda:

Perl Style Regular Expression: ^say (\w+) *(\w*) .*?(.*)
Script:  send( "say "..matches[4].." "..matches[2].." "..matches[3] )

What it does is save the first word, the second word and then the rest of the text into wildcards. It then says rest of the text first, then the first word and then the second word.

1.14 How to highlight words

To highlight something in the MUD output, make a trigger and use the "highlight trigger" option to highlight the matched trigger pattern.

Optionally, you can also make use of the bg() and fg() functions in scripting to highlight.

1.15 Keybindings

Keybindings, or hotkeys, are in many respects very similar to aliases, however, instead of typing in what you want to be done, you simply hit a key (or combination of keys) and let the Mudlet do the work.

HOTKEY: F1
command on button down: sip earl gray

HOTKEY: F2
command on button down: sip ceylon mint

Now you just have to listen, or rather read, carefully and hit either F1 or F2 to claim that prize.

Another practical use for keybindings would be creating a so-called "targeting system", which is especially useful for grinding down armies of pumpkin-men in MUDs without auto-attack. See the Variables chapter for further details.

1.16 Timers

Timers, as the name suggests, can be used to execute a specific command at a certain time, after a certain time or once every so often.

Main Manual

Multi Session Gaming

Mudlet lets you play several simultaneous MUD sessions. However, currently we have the restriction that you cannot use the same profile twice. Consequently, if you want to play three characters on the same MUD at the same time, you need to make 3 profiles with 3 different names e.g. ernie@avalon.de, bert@avalon.de etc.

Split Screen

Mudlet has a split screen. If you scroll up in the MUD text screen (or any other mini console window), the screen will split in two parts. The lower part will follow the MUD output while the upper part will stay focused on your scrolling. This way you can read easier through old passages without missing what is going on at the moment.

Split screen can be activated via the scroll bar, page up / page down keys or the mouse wheel. Scrolling back to the end will close the split screen automatically. A click on the middle mouse button will close the split screen immediately as well as pressing control+return on the keyboard. The size of the 2 parts of the split screen can be modified by dragging the separator bar in the middle with the mouse. Split screen usage is necessary when selecting text in order to copy it to trigger editor e.g. when making triggers. If you don’t use split screen when selecting text, new arriving text will upset your selection.

Command Line Auto-Completion, Tab-Completion and Command History

Mudlets command line is especially designed for MUD and MUSH playing. It aims at reducing the amount of typing by using autocompletion and tab completion schemes that are optimized for typical MUD playing situations. The command line offers tab completion (TAB key with or without shift) and autocompletion (cursor up and cursor down keys).

  1. Tab completion searches the last 100 lines in the MUD output buffer for words matching the word that you are currently typing. This is useful if you have to type complicated long names. You only have to type the first letters and then press the tab key until the proposal is what you want.

  2. Autocompletion tries to match your current typing with your command history. Example: If you typed the same command a while ago, you only have to start typing the first couple of letters and then press the cursor up key until the proposal matches the command that you want to use.

  3. Command History: If you haven’t started to type anything yet, you can browse through your command history with the cursor up and cursor down keys. However, if you have started typing pressing cursor up will result in a shot at autocompletion.

  4. ESC:To get out of autocompletion you can press the ESC key any time. After pressing ESC the entire text gets selected and you can overwrite it or get back into command history mode.

Logging Output to text or HTML Log Files

Press on the little button with the blue folder with the green arrow icon on the lower right side of the command line to turn on plain text logging. Click again to stop logging. This will inform you about the file name and path of the log file. If you want to log in color you can chose to log to files in html format, but note that due to the nature of HTML, these log files tend to get very large quickly.

Log files can be found at the mudlet home directory in your profile directory. To get the path to your mudlet home directory you can run a script like this one:

echo( getMudletHomeDir() .. "\n" )

Log files are stored in "<mudletHomeDir>/logs". Each profile has its own <mudletHomeDir> path. Log files have a similar naming convention to the autosaved profiles: date#time.txt or date#time.html

Exporting and Importing Profiles or Packages

Mudlet supports XML packages that can be imported and exported while playing. You can find a package section on the forum at http://mudlet.sourceforge.net where you can download demo packages or ready made packages for your MUD or upload your own packages to share your work with other players. A package can contain anything ranging from a single trigger to hundreds of button groups, trigger groups aliases - in other words, entire "systems".

Importing Packages

To import a package, open the script editor and click the import icon, select your xml package file and import it. Package files might be compressed to save space. If the file is compressed, you’ll need to uncompress it before importing it. The imported package will be stored permanently in your profile when you safe the profile. If you don’t like the imported package, delete its components manually or simply don’t save the profile. Then the new content will be lost on restart. Good packages will be organized in such a way that they will be easy to update or remove.

Packages are nothing else, but profiles - or parts of profiles that can be exchanged, imported and exported between your own profiles and between different players. From a technical perspective a package and a profile xml file are the same thing.

Exporting Packages

Exporting items or groups is also easy. Select your item or a group containing many items or subgroups and then click on the "Export" button. You’ll be prompted for a file name and that’s it. Package file names should end with ".xml" to make import easier for users on all platforms. You can send your cool trigger, buttons, timers etc. to your friends or use them in another profile of yours. Exporting your good stuff is strongly recommended as it makes MUDding more enjoyable for everybody. Share your knowledge and help others! Mudlet stores your saved profiles as XML files in your home directory under "<mudletHomeDir>/current". To get <mudletHomeDir> run a script like this:

echo( getMudletHomeDir() .. "\n" )

To export your entire profile e. g. to make a backup on a flash drive, use the "save profile as" button. You can export packages of a trigger branch, alias branch, function key, scripts etc. by clicking on a folder in the tree of the particular item in question and then click on the export icon. You’ll be asked to give a filename for your package. You can export arbitrarily complex structures by moving them into a folder that e.g. is named after the package you’d like to make.

Sharing your System with others - Making complex Packages

If you have written a nice set of triggers, buttons, scripts etc. or maybe even a fully fledged "system" of some sort and you want to share it with others, you can make a nice packages that other people can import with a single mouse click. The recommended procedure to make a large package that contains groups of all sorts of items e.g. trigger groups, individual triggers, scripts, buttons, aliases etc., is to export the entire profile with "save profile as". Then create a new empty profile e.g. with your package name. Don’t give a server or port name in the connection dialog and "connect". Mudlet will load the new empty profile although you are offline. Open the script editor and import your previously exported profile and then delete all items that are not part of the package that you are making. Finally, make a folder (group) that is named after your package name and version number e.g. "Johnny’s curing system 12-3-2009" and move all respective items into this folder and repeat the same procedure for all triggers/aliases/scripts etc.. This will make it much easier for other people to import your package and stay updated if you release a newer version. Then save your profile and use the "save profile as" button to create your package.

Using Variables in Mudlet

One of the major design goals in Mudlet was to integrate scripts and variables into triggers/aliases/buttons etc. as seamlessly as possible. The usage of variables in Mudlet is distinctly different from the other major clients, as native Lua scripting has been integrated into Mudlet from the ground up. As scripts are so closely intertwined with the core of Mudlet, variables do not need any special treatment as in other clients i.e. there is no need for code such as:

totalKills = getVariable("killedMonsters") + getVariable("killedVillains")
echo( "kills=" .. totalKills )

In Mudlet, the above code translates into:

totalKills = killedMonsters + killedVillains
echo( "kills=" .. totalKills )

If you define a variable in any given script in Mudlet, be it a trigger, a button, an alias key, an event handler, a free function, etc. It can be used from within any context without any special getVariable() type of function or any special variable symbols, such as @myVar etc.. In Mudlet all variables are native Lua variables. Each session (= profile/connection tab) runs in its own dedicated Lua interpreter. Consequently, all scripts of a profile are compiled into the same Lua interpreter and thus their code runs in the same variable space. All scripts from another simultaneously opened profile will not interfere because each profile uses its own Lua interpreter.

Note
Everything (alises, triggers, scripts, buttons, keybindings) shares the same variables & functions.

To give you an example: Let’s make a little trigger that counts how many monsters you have killed. Each time you have made a new kill, the trigger matches on the kill message and runs a little script that increases the amount of kills by one each time the trigger fires - in other words, each time you kill a monster and the kill message is sent from the MUD. For the kill counter we declare a variable and call it myKills. This variable is going to hold the number of kills we’ve made so far. The script will look like this:

myKills = myKills + 1

Then we add a little alias, a button or a keybindings that executes another little script that prints your current kill statistics on the screen. The attached script would look like this:

echo( "I have killed " .. myKills .. " monsters today." )

Let’s get back to our example. The trigger script expects myKills to be a number so you have to initialze the variable myKills to 0 before running the script for the first time. The best place to initialize variables is in script script outside of a function definition as this code is executed when the session is loaded or if you compile the script again after you have edited it. To do this click on the "Scripts" icon and select the standard script "My Global Variable Definitions". If you are using an older version of Mudlet or a profile that doesn’t have this script item, simply click on the "Add" icon and make your own script. You can call it whatever you want to. Add following code to initialize your new variable myKills to a number and set its value to 0:

myKills = 0

Whenever you edit this script, it will be recompiled and the code will be run as it is not part of a function definition. This is the major difference between trigger-scripts, alias-scripts etc. and script-scripts. Script-scripts can contain an unlimited amount of function definitions and also free code i. e. code outside of a function definition - code that is not enclosed by function xyz() …. end. On saving the script the script gets compiled and the free code is run instantly. All other item scripts, i. e. trigger-scripts etc., secretly define a function name for the script and thus the script is not free code, but function code. When a trigger fires Mudlet calls this invisible function name to run the script e.g. trigger738(), button82(), alias8(). This means that if you define variables inside a trigger script the variable will not be defined before the trigger runs for the first time. However, if you define this variable as free code in a script-script the definition becomes available immediately on script save. Now, whenever you add new variables to your variable definition script, the script gets run and your old variables will be reinitialized and reset to 0. This will be no big problem in most cases as you won’t work on your systems while really playing in most cases. To solve this problem you have two options:

First option: Add a script group (a folder) and add a new script item for each variable you define. This way, editing a variable definition will only reset the edited variable and none of the others that are defined in different scripts. This has the added advantage that you have a nice graphical overview of your defined variables.

Note
Organize your variables

Second option (more advanced): Change the variable initialization to only initialize the variable if it hasn’t been initialized before, thus keeping the values of previously defined variables. This would look like this:

if myKills == nil then    -- this code initializes the variable myKills to the number 0 if it hasn't been initialed before
    myKills = 0
end

In Lua all undefined variables are initialized to the value nil. The value nil is not the same thing as the number 0 or the empty string "". What it means is that a variable that has the value nil has not been declared yet and does not exist. If a variable does not exist, it cannot be used as its value is undefined at this point. Consequently, increasing the value of nil by one is impossible as the variable doesn’t exist yet and will lead to a Lua error. The above script simply checks if the variable myKills has been defined yet and if it hasn’t, it will declare the variable and set its value to 0. === Lists Having variables that hold a single value is the most important usage of variables, but very often you’ll like to define variables that hold a list of values e. g. a list of your enemies, a list the items you are currently carrying etc.. To define a variable to be a list you need to declare it to be a Lua table. Let’s declare the variable myEnemies as a list containing the names of your enemies:

myEnemies = {}

You can now add new enemies to this list by calling the Lua function table.insert( listName, item ) e.g.

table.insert( myEnemies, "Tom" )
table.insert( myEnemies, "Jim" )

To print the contents of your enemy list on the screen you can run this script

display( myEnemies )

Now let’s make a little alias that adds a new name to your enemy list when you type "add enemy " followed by the name of the enemy e. g. "add enemy Peter" Open the alias editor by clicking on the alias icon. Click on the "Add" icon to add a new alias. Choose any name you like for your alias e.g. "add new enemy" and then define following pattern for the alias: ^add enemy (.*) Then add this little script in the script editor below:

table.insert( myEnemies, matches[2] )
echo( "Added a new enemy:" .. matches[2] .. "\n" )

Save the alias and try. Alias are explained in detail below. Another way to declare a list is to define its values directly.

myEnemies = { "Peter", "Jim", "Carl", "John" }

To remove an item from the list you can use the function listRemove( listName, item ). === Saving Variable Values to Disc Having statistics scripts that last as long as the session lasts is a nice thing, but it makes more sense to write the variables to disc and reload them when you play the next time. To do this you have to save your variables. Mudlet has 2 ways to implement variable persistence. First, you can tell Mudlet to save all of your variables on exit automatically and ask Mudlet to automatically restore them when the session gets reloaded the next time you play on this profile. Second, you can take care of saving your variables yourself and reloading them yourself. This gives you more control and will be the preferred solution in bigger systems.

Saving variables

You might notice that Mudlet doesn’t save your variables between profiles restarts. The reasons for this are technical, but all it means is that you have flexibility in how to deal with them. There are several ways, so the most common and easiest ones will be explained here.

Saving via explicit assignments in scripts

The title sounds a bit complicated, but that’s pretty much what you do. Go to Scripts, click Add Item, and create your variables like so:

myname = "Bob"
mypack = "pack1234"
rapierID = 67687

Now, since scripts are compiled & run when the profile is started, these variables will be created and assigned to those values. This was simple to do, but it has one problem - if you want to change the value of the variables to be saved, you have to edit the script by hand each time; and if you change the value of variables while playing via scripting, the new values won’t be recorded.

Saving via table.save & table.load

Next, enter a more proper solution. This’ll actually save the variables to a file and load them from it - so if you change the variable values, the current ones will be saved, and will be loaded next time properly. This method works with a table containing your variables though, not individual variables themselves - see Lua tables tutorial on how to create and use those.

table.save(where to save, what table to save) takes the location of a file to save variables to, and a table containing your variables to save. Location can be anywhere on your computer, but a good default place is your profile folder, whose location can be obtained with getMudletHomeDir().

mychar = {
  name = "Bob",
  age = 26,
  sex = "male"
}

table.save(getMudletHomeDir() .. "mychar", mychar)
echo(string.format("Variables saved in: '%s'", getMudletHomeDir() .. "mychar")) -- demonstrational echo to show where the file went

table.load(where to load from, what table to use) is similar - it takes the location of the file to load, and a table name to use for the loaded variables.

echo("My name is: ".. tostring(mychar.name))
table.load(getMudletHomeDir() .. "mychar", mychar)
display(mychar)
echo("My name is: ".. tostring(mychar.name))

Now that you have a way to save and load your tables, you can create triggers to load and save your variables at appropriate times, and you’ll be set.

Input Triggers - Mudlets Alias Engine

Important
QUICKSTART: Here is a video tutorial on how to do basic aliases in Mudlet: http://blip.tv/file/2288749

Alias are triggers that operate on user input. Mudlet uses hierarchically ordered powerful Perl regex expression alias. We have explicitly chosen not to offer multi condition alias, alias chains or the same trigger types the trigger engine offers because this would be way over the top and is simply not needed for alias expansion - although it should be noted that the processes are closely related, except that aliases, i.e. input triggers, operate on a different data stream, namely the user input stream, whereas triggers operate on the MUD output data stream. The only real difference between output triggers and input triggers is that input triggers can change the input stream they work on, whereas output triggers cannot change the stream itself - output triggers can change what is printed on the screen as a result of the stream, but they cannot change the stream itself. This is a fundamental difference and a deeper understanding is key to getting to grips with Mudlets alias engine. When you enter a command on the keyboard and press enter or return, the text that you have typed in the command line will be forwarded to the alias unit, i. e. the input trigger unit, in form of the Lua variable command. This variable will be matched against all active alias in the hierarchy unless access to an alias branch is locked by the user or by a script. If an input trigger matches, it will intercept the user command and the original command will be ignored. Upon a match the clear text command is being send as a command to the MUD in replacement of the original command, if a clear text command has been specified by the user and the attached alias script is being executed. However, the initial command that the user has typed in the command line will not be sent unless you do this as part of your script. Consequently, if you want your input trigger to send a command to the MUD, you’ll either have to specify a clear text command for simple cases or send commands via the attached alias script e.g. send("kill monster"). You may argue that you feel that it is unnecessary work to be forced to send a command replacement yourself, but this very fact makes our alias system way more powerful because it gives you complete control about what is happening. Why is this so? The initial user command is being held in the Lua variable command. When this value changes within the alias unit processing chain, the initial user input that the input triggers work on can be rewritten and changed in the process. Consequently, you can substitute the user input step by step - or alias by alias - without that anything happens as far as sending commands is being concerned unless you explicitly decide to do so.

Note
.

The example in the diagram above shows 2 matching aliases, but only one of them sends commands to the MUD - and only if the player is healthy enough to attack the opponent. The other alias that matched the user input (enemy) choses a fitting opponent and sets the variable enemy accordingly, otherwise it issues a warning that attacking one of the available enemies would be too dangerous.

For an input trigger to match the command text the same rules as explained above in the trigger section apply. However, to simplify matters there is only one alias type. As alias are not performance critical we could reduce the amount of trigger types to just Perl regex as this type can do it all and performance is no issue with alias as the amount of data is much less. Even if you type like a madman you’ll never get close to sending the same amount of text to the MUD than the amount of text the MUD sends back to you.

What does it mean that a regex is true or "matched"? A trigger or an alias fires - or executes its commands/script - when the text matches the pattern of the trigger or alias. In most cases this means that the text contains the trigger/alias pattern. If the regex pattern is reen then a text "The green house" will match because "reen" is contained in the text. More complex regex patterns can also hold information on where in the text a certain pattern must occur in order to match. ^tj only matches when the letters "tj" occur at the beginning of the text. Consequently, a text like "go tj" would not match. Regex patterns can also capture data like numbers, sequences of letters, words etc. at certain positions in the text. This is very useful for MUD related scripting and this is why it is explained below.

Let’s get back to alias. We start with a simple example.

We want Mudlet to send "put weapon in bag" whenever we type "pwb". Consequently, the pattern is pwb and as the task is so simple it’s enough to enter "put weapon in bag" in the send field. Then we click on save to save the changes and activate the alias by clicking on the padlock icon. Then we leave the trigger editor and test our new alias. After typing "pwb" and pressing return Mudlet will send the command "put weapon in bag" to the MUD.

Let’s move on to a more complicated example that is needed very often.

We want our script to automatically put the weapon in the correct bag as we have many bags and many weapons. The pattern stays the same. ^pwb The ^ at the beginning of the line means that the command starts with pwd and no other letter in front of this. If we define our pattern more clearly, the pattern will match less often. Without the ^ the alias will match and the alias script will always be run whenever there is the sequence of letters "pwd" in your commands. This may not always be what you want. This is why it’s usually a good idea to make the pattern definition as exact as needed by being less general. The more general the pattern, the more often it will match.

Back to our task: The pattern is ^pwb. Let’s assume that we have defined 2 variables in some other script. The variable "weapon" is the weapon we use and the variable "bag" is the name of the bag. NOTE: In Mudlet global variables can be accessed anywhere from within Mudlet scripts - no matter if they have been defined in a trigger script, in an alias script or in a key or button script. As soon as it’s been defined it somewhere it is usable. To make sure that a variable is local only, i. e. cannot be referenced from other scripts, you have to use the keyword local in front of your variable definition. Back to our alias: Pattern is:[,#b0e0e6]^pwb Script is:

send( "put " .. weapon .. " in " .. bag )

Depending on the values of our variables Weapon and bag the command "pwd" will be substituted with an appropriate command. To set your weapon and bag variables we use 2 more aliases: Alias to set the weapon: uw (\w)+ Script:

weapon = matches[2];
send( "wield " .. weapon )

To set our bag variable: Pattern:[,#b0e0e6]^set bag (.*)

bag = matches[2]

Now let’s go back to our initial problem. We want an alias to put our current weapon into our current bag. But what happens if we are in the middle of a fight and absolutely need to sip a healing potions because we are close to death and cannot take the risk that the bag may be too full to take the weapon? We want to upgrade out little alias to take into account that the bag may be full and chose an empty bag instead. To do this we set up a trigger that detects messages that indicate that the attempt to put the weapon in the bag failed. In this trigger we execute this little bag-is-full-detection-trigger Trigger Pattern: (type substring) "Your bag is full." script:

bagIsFull = true;

This detection trigger will set the variable bagIsFull to true as soon as it sees the message "Your bag is full.". Then you know that you have to use your spare bag to take the weapon.

Now we have the tools to write an improved version of our little alias script:

if bagIsFull then
    send( "put " .. weapon .. " in " .. spareBag )
else
    send( "put " .. weapon .. " in " .. bag )
end

The next example is one of the most common aliases a tell alias: Pattern:[,#b0e0e6]^tj (.*) Script:

send( "tell Jane " .. matches[2]

Sadly, Jane is your fiancée and the one thing she is a vegetarian and absolutely hates all words that relate to meat. Luckily, you know enough about aliases by now to make her believe that you’d never ever even think about meat. So you head to your global function script (any script item will do as long as you define your variables outside of your function definitions. See the scripts chapter below for more information. In your script "my global functions" you add a Lua table containing a list of all of all words that a vegetarian might hate. For example:

happyJaneTable = { "meat", "burger", "steak", "hamburger", "chickenburger" }

Now you can upgrade your tell-jane script to automatically search our tell for all words that Jane might not like. In case such a word is found we substitute the entire tell with "How is the weather?".

for key, value in ipairs( happyJaneTable ) do     -- looking at each element of the list
    badWord = happyJaneTable[key]                 -- check out the Lua table chapter below for more info
    begin, end = string.find( command, badWord )  -- begin holds the start position of the word, end* the end-position
    if begin ~= nil then                          -- we have found a bad word
        send( "tell Jane How is the weather?" )
        return
    end
end

Mudlets Trigger Engine

Unlike alias that define patterns that match on user input, triggers define patterns that match on MUD output. In other words, triggers react to text that has been sent by the MUD, whereas alias react to user commands that have been typed into the command line.

Simple Trigger Matching

Note
.script editor screenshot
Important
QUICKSTART: Here is a simple video tutorial on how to make basic triggers in Mudlet: http://blip.tv/file/2288760

To begin with, click on the "Add" button to create a new trigger. Then put the text pattern that you’d like to trigger on into the trigger conditions table on the right side of the screen above the script editor. Afterwards, chose the correct pattern type of your trigger pattern in the drop down list on the right side of the trigger pattern i.e. in the second column of the trigger pattern table. If you define multiple patterns in the same trigger, your trigger will run whenever any one of these patterns matches unless you chose the AND-trigger option, in which case the trigger will only fire if all patterns match within a specified amount of lines from the MUD. For more advanced information on AND and OR trigger see the corresponding AND/OR trigger section below. The next step is to define what should happen when the trigger matches. Usually, this will be done by a Lua script in the Lua editor below the table with the pattern list. In the beginning, you can simply chose the "highlight trigger" option to make your trigger highlight the text that it has triggered on or send a clear text command to the MUD whenever the trigger fires until you have learned enough Lua to more meaningful scripts. Clear text command can be defined in the "send plain text" input box next to the trigger name above the pattern table. Finally, you need to save the new trigger and then activate it with the padlock icon button. By default, new triggers are deactivated and thus will do nothing unless you explicitly activate them. Activated triggers show a green tick in the little blue box on the left side of the trigger name in the trigger tree on the left side of the script editor dialog. There is three ways to save your changes. 1. click on the save icon 2. adding a new trigger 3. clicking on another trigger item. Triggers that have not been saved yet cannot be activated. If you see a bug icon instead of an activation box, there is some error that prevents to activate your trigger. Check the error message above the pattern table.

Simple Highlighter Triggers

Tip
Beginners should use Mudlets automated highlight triggers in the beginning to get the hang of the different trigger and pattern types quicker. Click on the "highlight trigger" option and pick a foreground and a background color. When the trigger matches it automatically highlights its pattern. This is the most used form of triggers in mudding as it is a quick way of highlighting words that are important to you at the moment. This helps you spot things at a single glance instead of reading the entire text. You don’t have to know anything about scripting, regular expressions etc. to use highlight triggers. Just type in the word you like to be highlighted, select appropriate colors, save the new trigger and activate it.

More advanced users will often want to do custom highlighting from within scripts. This is how it works: If you want to highlight the word "pond" in the above example you have to add the following little Lua script to the script editor on the lower right side of the Script Editor window:

selectString( "pond", 1 )
fg( "red " )
bg( "blue" )
resetFormat()

"AND" and "OR" Condition Triggers

AND -Triggers execute their respective command or script only if all conditions in their respective conditions expression list are fulfilled. OR-Triggers execute when any one of their conditions is true. To make OR-Triggers you simply have to add a few conditions to the conditions list e.g. in our example: "pond", "frog", "Plop". The trigger will now also execute on lines like this: "A frog is green" or "You hear a loud Plop!" However, it will not execute on "With a loud plop the frog dived into the water." because "plop" in the line is in lower case letters and your condition specified a "P" in upper case. The simplest form of AND-Triggers in Mudlet are Trigger Chains or Filter Chains, whatever you’d like to call it.

Trigger Chains & Filter Chains

"Chains" and "filters" are different trigger group entities in Mudlet and serve completely different ends.

Chains

A chain is defined in Mudlet by making a trigger group and adding a trigger pattern to the group. A group without a pattern is a simple trigger group that serves no other purposes than adding structure to your trigger system in order to organize your triggers better. Such a normal trigger group will always grant access to its children unless it has been explicitly disabled (= all access to itself or any of its children is locked) either manually or by a script.

A trigger group with a defined trigger pattern, however, will behave like a normal trigger and match if the pattern matches. Such a trigger group is called "chain head". A chain head will only grant access to its children if the trigger pattern has matched and the chain has been enabled. Thus, chains can be looked at as a mechanism to automatically enable and disable triggers or groups of triggers when a certain condition has been met i. e. the trigger pattern of the chain head has been matched. (However, technically this is not correct as disabled child triggers will not be invoked if the chain head matches. In other words, in chains you can still enabled/disabled elements. The idea of a chain can better be described by necessary and sufficient condition - both of which need to be met before a child trigger is being run.)

Adding child triggers to this group will add elements to the trigger chain. These chain elements will only be activated if the chain head has matched before and thus opened the trigger chain. The chain stays open until the "keep chain open for x lines" value has been reached. The default is 0 which means that the chain only stays open for the current line. When access to the chain has been granted all child triggers will be tested against the content of the current line.. Consequently, trigger chains are a means to automatically enable/disable trigger groups without the hassle of enabling and disabling trigger groups manually. This has 2 important advantages: Chains are faster than conventional solutions and chains reduce the complexity of your scripts and greatly reduce the usual system bugs that inevitably go along with enable/disable trigger xy function calls as it’s very difficult and error prone to enable and disable your triggers correctly in large complex trigger systems. This is one of the most powerful features in Mudlet and should be used whenever possible.

Filters

You can turn a trigger chain head into a filter by checking the "filter" option. This changes the content of what is forwarded as trigger text to the children triggers in the chain. Chains forward the content of the current line as trigger text whereas filters forward the matched pattern instead of the current line. In other words, the text of the current line is filtered according to the pattern of the filter. For example: You want to know the exits in the current room. The simplest solution is a simple filter on "You see exits to: (.*)" Then you simply add triggers to the filter chain such as "north", "south", "west", "east" etc. The direction triggers will only be called if the filter head has matched.

Imagine the following scenario: You want to collect some berries. You know that the room contains some berries if the room description contains the words "You are inside a forrest." You make a new substring trigger for this line, but instead of choosing a regular trigger, you chose to add a new trigger group. Now you add "You are inside a forest" to the expression list of the trigger group. When adding conditions to a trigger group, the trigger group turns from an organizational unit into a filter unit. From now on this folder is a filter and will only let data pass through that matches it’s condition. In our case this is exactly what we want, because we don’t want to collect all sorts of berries, but we only want 2 particular kinds, namely, strawberries and blackberries, and we know that these berries can only be trusted if they are picked inside a forest as other areas may contain contaminated berries. Now you add two regular triggers to our berry-in-the-forrest filter - one containing the condition: "strawberries" and the other one "blackberries". Then we add the commands to pick the particular kind of berry to both triggers (send field). Now what happens is that as soon as a room description reads "You are inside a forrest." the filter will let the line containing the room description pass through to our two berry triggers and they will issue commands to pick berries, if there are such berries. However, in any other situation the words "strawberries" and "blackberries" will NOT trigger a pick - only in the above scenario when the filter parent’s condition is met. This is a very nice way to solve complicated problems with a few easy filter chains. This example is trivial, but using filter chains will rapidly show you how formerly complicated things that could only be solved with very complicated regular expressions can be solved easily now with a couple of filter chains. It should be noted that filter chains only work on single lines. This means that if the filter chain head "You are inside a forrest" is in a different line than the other child chain element triggers (stawberr- and black berry triggers) the triggers will not fire as the line that is being let through the filter does not contain the words strawberries or blackberries. Most MUDs, however, offer a feature that lets your client do the word wrapping. This is a very powerful tool for scripting and should be enabled by you in your MUD as then the entire room description or the entire tell will be sent out to Mudlet in one line and Mudlet will do the word wrapping for you. Now you can use filter chains much more effectively as the line content comprises many lines. Triggering will become much easier. Ask your MUD operators how to enable this feature. Most big MUDs can do this these days. Let’s look at a practical example for a trigger chain:

Multi-Line Triggers and Multi-Condition Triggers

Multi Condition Triggers are the most advanced feature of Mudlets trigger engine. Like trigger chains or filter chains they are a form of AND-Triggers. All conditions in the list must have matched within the specified margin of lines (delta), in order to trigger the script. Normal triggers fire and run the script as soon as one of the conditions in the regex list is met i.e. if one of the regex/string matches match - or the Lua function condition returns true, the trigger script is run. In multiline triggers, however, each single regex/string/Lua function condition in the list has to have matched within the specified margin of lines at least once to trigger the script. The sequence of the conditions is binding. This means that if the 10th regex on the regex list would be matched on the eleventh line after the match of the first line happened, the trigger will NOT run unless the margin of lines is set to 11. If condition #3 is true but currently #2 is waiting to be true, condition #3 is ignored and must be true again after condition #2 has been true. Conditions can also be Lua Functions or plain Lua code that returns a boolean truth value. You can mix all types of conditions to build complex multi-condition triggers that only fire if all conditions are met. This is a very powerful feature as it reduces the amount of scripting to a minimum or even takes away with the need to script formerly complex processes completely. Multicondition triggers are multi-line triggers, i. e. the conditions can all be met in a single line or many lines after the first condition has been fulfilled. This effectively reduces the amount of complexity as you have all the important conditions placed into a single trigger and all the tedious bookkeeping, variable and condition state accounting is being done by Mudlets trigger engine. The result of this is that the amount of manual condition checking via many different trigger scripts and legions of if condition1 == true then check condition2 can be forgotten about. All you have to do is to define the conditions and the final action that is taken if the trigger fires.

Note
This diagram shows what steps are involved in the process of problem solving with Mudlets trigger engine. The main question is: How do we arrive at a solution to our problem, and how can we simplify the problem as much as possible?

Example: Let’s go back to our pond & frog example. We have explained the difference between AND-triggers and OR-triggers. If you have a room description consisting of 3 lines:

1. You see a pond
2. You see a frog.
3. The frog sits on a stone.

Every single one of these 3 lines will be fed into the trigger engine one after another. If we define an OR-trigger with a condition list consisting of 3 condition patterns:

condition #1 pattern = pond condition #2 pattern = frog condition #3 pattern = stone

Whether or not a condition is found to be true also depends on another property, namely the type of the condition. The condition type can be among others:

  1. substring matching → the condition is true if the condition pattern is a substring of the output line from the MUD. In other words: If the pattern "pond" is contained in any line of output, the condition is true.

  2. begin of line matching → the condition is only true if the condition pattern can be found at the beginning of a line from the MUD.

  3. Perl regular expression → the condition is true if the Perl regex pattern is matched. You’ll find more information on Perl regex below.

  4. Lua code that returns a truth value e.g. a call to a function check() that return either true or false depending on the condition

In our example we chose condition type "substring" for all three conditions. Consequently, the trigger will fire the command or script 3 times i. e. the trigger will do on each line it is matched against because in every line at least one condition evaluates to true because the pattern is a substring of the line.

in line #1 we get: pond = true.
in line #2 we get frog = true and
in line #3 two conditions are true i.e. frog=true and stone = true

Because an OR-trigger fires on the first condition that is true and ignores the rest the trigger will only execute 3 times on these 3 lines although 4 conditions are true.

CAUTION: The multi line condition switch must be turned off to get an OR-trigger! If the multi-line condition switch is turned on the trigger becomes and AND trigger which means that the trigger only fires if all conditions are true and fulfilled in the correct sequence. With OR-triggers the sequence is irrelevant.

To complicate matters, however, you don’t want your trigger to fire 3 commands, because you want to use this room description as a whole to fire your trigger e. g. this pond is the only kind of ponds in the entire world that doesn’t have poisoned water. So you want to make sure that you only drink water from a pond of this kind and from no other pond. Your solution is to use Multi Condition Triggers (MCT). If you check the MCT checkbox this trigger will fire only once from now on - and only if all conditions are met i e. when you can guarantee that you only drink water from a good pond because your drinking trigger is matching on the entire room description despite that this room description my be spread over a number of lines. (NOTE: If you have word wrap turned off in your MUD chances are that the entire room description will be contained in a single line, but we are trying to keep the examples as easy as possible.)

Sadly, there are many unfriendly people in this world and somebody goes around and poisons your good ponds. Consequently, you would want to examine the frog and find out if it is poisoned before drinking water from the pond. This is difficult because the villain is a mean magician who used illusion spells to make everything look like the good pond. To solve the problem you can now resort to Lua function conditions in the trigger condition list that perform certain check ups to put the current room description into a wider context e. g. check if you have been here before etc. This adds yet another level of complexity to your problem but this is a very powerful means to use the full potential of Mudlets MCTs.

You can combine all forms of conditions with trigger chains, filters and Lua functions. Mudlet gives you relatively easy to use tools that require no programming background. However, these tools can evolve into complex powerful problem solving mechanisms if they are combined with each other thus enabling non-programmer users to solve problems that would need a profound programming background in other MUD clients. However, unlocking the full potential of Mudlet requires you do learn some Lua basics. In this manual we’ll try to be as easy on you as we can in this respect, but it’s highly recommended that you dig deeper into Lua after a while. It’s one of the easiest fully fledged scripting languages available, easy to learn and the fastest of them all, and this is why it has been chosen by us. You don’t need to become a programmer to be able to use Mudlet effectively. All you have to know is how to work with variables and how to do if conditions and maybe a few loops. But knowing more won’t harm you and it will make your systems more effective.

Lua Code Conditions & Variable Triggers - Expression Triggers

In a Lua Code/Function Condition (LFC) you can run Lua code inside the trigger engine directly. The easiest example would be a simple variable trigger: Add a new trigger and chose pattern type Lua Function Condition. Then define this pattern: if health ⇐ 100 then escape() end Another formulation of the same would be: checkHealth() For the last formulation to work you have defined a Lua function checkHealth(). Open the script editor, add a new script "health care" and add this code to the new script-script.

function checkHealth()
    if health <= 100 then
        echo( "WARNING: Low health! I have to run away!\n" )
        startEscape()
        return true
    else
        return false
    end
end

Lua function conditions effectively means that you run the Lua code they represent on every single line that is received from the MUD, unless the LFCs are part of a multi-condition trigger, in which case the LFCs would only be run when they would be the current test-condition of their respective trigger state. LFCs are implemented in such a way that the trigger engine only calls the compiled byte code, but running as few scripts as possible is always the best idea. LFCs are nice and handy, and for most people the performance aspect will not be relevant at all.

Scripting: Generating Triggers - Special Trigger Types for Scripting Needs

Temporary Triggers (scripting only)

Temporary triggers are lightweight triggers that are tailored for typical scripting needs. These are only available via Lua scripting. They are not stored in profiles, but stay in memory as long as the program runs or until they are deleted (killTimer()). There are several forms of temp-triggers that address different scripting needs. Check the Lua API table for reference.

Line Triggers (scripting only)

Line triggers trigger on a specified line in the future - or a sequence of lines - irrespective of the content of the line. This type of trigger can be very handy in scripting if you know what is coming e.g. you want to parse a table from the MUD, maps etc.

Enabling and Disabling Triggers in Scripts

enableTrigger() disableTrigger()

Testing your triggers

Externally

RegexPal - a good website for testing your triggers against a set of text. [kiki-re - stand-alone program which will also tell you which matches are translated to what wildcard number.

The Timer Engine

Mudlet supports 4 different sort of timers:

  1. Regular GUI Timers that fire repeatedly in a certain interval specified by the user.

  2. Offset Timers are child timers of a parent timer and fire a single shot after a specified timeout after their parent fired its respective timeout. This interval is an offset to the interval of its parent timer. Example: parent timer fires every 30 seconds and by doing so kicks off 3 offset timers with an offset of 5 seconds each. Consequently, the 3 children fire 5 seconds after each time the parent timer fired. Offset timers differ visually from regular timers and are represented with a + icon for offset. Offset timers can be turned on and off by the user just like any other timer.

  3. Temporary Timers are very useful, and are the most common type of timer used for scripting purposes. They behave like regular timers, but they are one shot only timers.

The most common usage of temporary timers is the function tempTimer(). It lets you specify a timeout after which a script is being run e.g.

tempTimer( 0.3, [[send("kill rat")]] )

This will issue the command "kill rat" after 0.3 seconds. Other clients call this kind of function wait() or doAfter() etc. It is one of the most used functions in MUD scripting. tempTimer() is a single shot timer. It will only fire once and is then marked for deletion. TempTriggers(), by contrast, live through the entire session and are never deleted unless you explicitly delete them or disable them.

Another often used function in the context of timers is enableTimer( timerName ), or disableTimer( timerName ). Those are the counterparts of enableTrigger( triggerName ) and disableTrigger( triggerName ), enableKey( keyName ) etc..

NOTE: Temporary timers cannot be accessed from the GUI and are not saved in profiles.

To be continued ….

Buttons and Custom User Toolbars

Note
.

Scripting with Mudlet

Lua tables can basically be considered multidimensional arrays and dictionaries at the same time. If we have the table matches, matches[1] is the first element, matches[n] the n-th element.

a = "Tom"
matches[1] = "Betty"
b = matches[1]
c = a .. b and e will equal "TomBetty"

To output a table you can use a convenience function display( name ). This function is defined in LuaGlobal.lua and can be found in your home directory under ./mudlet (note the leading dot ) Profiles and mudlet_documentation.html are stored in this directory as well.

Lua interface functions to Mudlet - or how do I access triggers, timers etc. from Lua scripts

How to get data from regex capture groups? Regular expression capture groups (e.g. "(\d+)" ) are passed on to Lua scripts as a Lua table matches. To make use of this information inside Lua scripts, you need to specify the number of the capture group within the regex.

Example: You have (\d+) weapons and they are (?:(\b\w+\W+)+)

This regex contains 3 capture groups, but only the 2 green colored ones contain data as the red capture group is a non-capturing group. Consequently, your Lua script gets passed only 2 instead of 3 capture groups and matches[3] is undefined.

In your Lua script you may write following program in order to print the number and status of your weapons on the screen:

number_of_weapons = matches[1]
status_of_weapons = matches[2]
notice = number_of_weapons .. status_of_weapons
echo( notice )
send( "put weapons in backpack" )

-- the following 2 lines color the first capture
-- group red and the second group blue
-- see below for details

selectCaptureGroup( 1 )
setFgColor( 255,0,0 )

selectCaptureGroup( 2 )
setFgColor( 0,0,255 )

The best way is to use selectCaptureGroup( number ) to select the proper capture group and then perform your actions on it e.g. replace(), highlight etc. Note: Both selectCaptureGroup() and matches[n] start with group 1.

How to select all occurrences of "Tom" and highlight them?

You add a function like this to a script containing you main function definitions. Note that script items differ from all other "scripts" in triggers, timers, actions etc. because they require you to put your code in proper functions that can be called by your other trigger-scripts, timer-scripts etc. via normal function calls. Trigger-scripts, timer-scripts etc. cannot contain any function definitions because they are automatically generated functions themselves because this makes usage a lot easier.

To come back to our question how to select all occurrences of "Tom" and highlight them:

function setBgColorAll( word, r, g, b )
    i = 0
    word_count = 1
    while i > -1 do
        i = selectString(word, word_count)
        if i == -1 then
             return
        end
        word_count = word_count +1
        setBgColor( r, g, b )
    end
end

Then you simply define a substring matching trigger on the word "Tom" and in the trigger script you call above function:

setBgColorAll("Tom", 255,50,50)

Sending commands to the MUD or printing information messages on the screen

To print information messages on the session screen you can use the echo( message ) function, or insertText( text). Currently, it only takes one string as argument.

To send a command to the MUD, you can use the send( command ) function. Note: everything you send via send() will be processed by the alias processing unit. In Alias scripts the command that is being sent to the MUD is contained in the variable command that you can change in the context of Alias scripts. Alias take regular expressions, as well. As a result, you can use following regex and script to talk like Yoda: Perl regex:

say (\w+).*(\w*).*(.*)

script:

send( "say " .. matches[3] .." " .. matches[1] .." ".. matches[2] )

Note: The variable "command" contains what was entered in the command line or issued via the expandAlias( ) function. If you use expandAlias( command ) inside an alias script the command would be doubled. You have to use send( ) inside an alias script to prevent recursion. This will send the data directly and bypass the alias expansion.

Changing text from the MUD or reformatting text (highlight, make bold etc.)

When sending commands to the MUD - from now on referred to as output stream - alias scripts find the command that was issued by the user stored in the variable "command".

By manipulating the value, the command can easily be changed before it is being sent to the MUD.

However, things get much more complicated with the data received from the MUD – from now on referred to as input stream. Before triggers can be run on the MUD data, Mudlet has to strip all format codes from the text and store it in data structures associated with the text. Consequently, the text that is being passed on to the trigger processing unit is a small subset of the data received from the MUD. If you want to edit, replace, delete or reformat text from within your trigger scripts you have to keep this in mind if you don’t want to lose all text format information such as colors etc.

As the text is linked with data structures containing the format of the text, the cursor position inside the line is important if data is being changed. You select a word or a sequence of characters from the line and then issue commands to do actions on the selected data.

Replacing the word "Tom" with "Betty" in the line: Jim, Tom and Lucy are learning a new spell. This could be done with following script:

selectString("Tom",1)
replace("Betty")

Things get more complicated if there are two or more occurrences of "Tom" in the line e.g. Jim and Tom like magic. Jim, Tom and Lucy are learning a new spell.

The above example code would select the first occurrence of "Tom" in this line and ignore the second. If you want to work on the the second occurrence of "Tom" you have to specify the occurrence number in the call to select().

selectString( "Tom", 2 )
replace( "Betty" )

This code would change the second "Tom" and leave the first "Tom" alone. The function call

replaceAll("Tom", "Betty" )

will replace all occurrences of "Tom" with "Betty". replaceAll() is a convenience function defined in LuaGlobal.lua.

Colorization example: You want to change to color of the words "ugly monster" to red on a white background.

You add a new trigger and define the regex: ugly monster In the script you write:

selectString("ugly monster", 1 )
setFgColor(255,0,0)
setBgColor(255,255,255)
resetFormat()

Another means to select text is to select a range of characters by specifying cursor positions. If we have following line: Jim and Tom like magic. Jim, Tom and Lucy are learning a new spell.

selectSection( 28, 3 )

This example would select the second Tom. The first argument to selectSection is the cursor position within the line and the second argument is the length of the selection.

selectCaptureGroup( number )

Deleting Text - Gagging

This function selects the captureGroup number if you use Perl regular expressions containing capture groups. The first capture group starts with index 1.

deleteLine()

This function deletes the current line - or any line where the cursor is currently placed. You can use repeated calls to this function to effectively erase the entire text buffer. If you want to delete or gag certain words only, you can select the text that you want to delete and then replace it with an empty string e.g:

If you get this line form the MUD: "Mary and Tom walk to the diner."

selectString( "Tom", 1 )
replace( "" )

Then the output will be changed to: "Mary and walk to the diner."

Cursor Movement and Cursor Placement

moveCursor( windowName, x, y ) This will move the user cursor of window windowName to the absolute (x/y) coordinates in the text.

moveCursor( "main", 20, 3950 ) will move the cursor on the 20th character from the left on line number 3950. To determine the current cursor position you can use getLineNumber() and getColumnNumber() as well as getLastLineNumber() to get the number of the last line in the text buffer. moveCursorEnd("main") will move the cursor of the main display to end of the buffer. This is always a new line of size 1 containing the character \n.

number_of_last_line_in_text = getLineCount()

returns the number of the last line of the text in the console buffer. This number will change as soon as a new \n is printed either by the user or

when a new line arrives from the MUD. All lines from the MUD are terminated with \n which is called line feed or the new line character. This control character ends the current line and move the cursor to the beginning of the next line, thus creating a new, empty line below the line that contains the \n.

line_number_of_the_current_cursor_position = getLineNumber()

column_number_of_the_current_cursor_position = getColumnNumber()

luaTable_containing_textlines = getLines( absolute_line_number_from, absolute_line_number_to )

this will return a Lua table containing all lines between the absolute positions from and to. NOTE: This function uses absolute line numbers, not relative ones like in moveCursor(). This little demo script shows you how to use cursor functions:

moveCursor() return true or false depending on whether the move was possible.

User defined dockable windows

You may want to use dock windows to display information you gathered in your scripts, or you may want to use them as chat windows etc. Adding a user defined window:

openUserWindow( string window_name )

echoUserWindow( string window_name, string text )

setWindowSize( int x, int y )

clearWindow( string window_name )

Dynamic Timers

tempTimer( double timeout, string lua code_to_execute, string/float/int timer_name ) disableTimer( name ) enableTimer( name )

Dynamic Triggers

triggerID = tempTrigger( regex, code ) creates a fast substring matching trigger triggerID = tempRegexTrigger( regex, code ) creates a regular expression matching trigger

Event system

Events in Mudlet allow a paradigm of system-building that is easy to maintain (because if you’d like to restructure something, you’d have to do less work), enables interoperability (making a collection of scripts that work with each other is easier) and enables an event-based way of programming.

The essentials of it are as such: you use Scripts to define which events should a function to listen to, and when the event is raised, the said function(s) will be called. Events can also function parameters with them, which’ll be passed onto the receiving functions.

Registering an event handler

Registering an event handler means that you’ll be telling Mudlet what function should it call for you when an event is raised, so it’s a two step process - you need to tell it both what function you’d like to be called, and on what event should it be called.

To tell it what function should be called, create a new script, and give the script the name of the function you’d like to be called. This is the only time where an items name matters in Mudlet. You can define the function right inside the script as well, if you’d like.

Next, we tell it what event or events should this function be called on - you can add multiple ones. To do that, enter the events name in the Add User Defined Event Handler: field, press enter, and it’ll go into the list - and that is all.

Note
Mudlet also uses the event system for the ATCP and GMCP events.

Raising an event

To raise an event, you’d use the raiseEvent function:

raiseEvent(name, [arguments...])

It takes an event name as the first argument, and then any amount of arguments after it which will be passed onto the receiving functions.

Note
Mini-tutorial
As an example, our prompt trigger could raise an onPrompt event if you want to attach 2 functions to it. In your prompt trigger, all you’d need to do is raiseEvent("onPrompt"). Now we go about creating functions that attach to the event - lets say the first one is check_health_stuff() and the other is check_salve_stuff(). We would like these to be executed when the event is raised. So create a script and give it a name of check_health_stuff. In the Add user defined event handler, type onPrompt, and press enter to add it to the list. In the script box, create: function check_health_stuff()blah blah end. When the onPrompt event comes along, that script catches it, and does check_health_stuff() for you.

Mudlet-raised events

Mudlet itself also creates events for your scripts to hook on. The following events are generated currently:

sysWindowResizeEvent

Raised when the main window is resized, with the new height and width coordinates passed to the event. A common usecase for this event is to move/resize your UI elements according to the new dimensions.

Example

This sample code will echo whenever a resize happened with the new dimensions:

function resizeEvent( event, x, y )
        echo("RESIZE EVENT: event="..event.." x="..x.." y="..y.."\n")
end

sysWindowMousePressEvent

Raised when a mouse button is pressed down anywhere on the main window (note that a click is composed of a mouse press and mouse release). The button number and the x,y coordinates of the click are reported.

Example
function onClickHandler( event, button, x, y )
        echo("CLICK event:"..event.." button="..button.." x="..x.." y="..y.."\n")
end

sysWindowMouseReleaseEvent

Raised when a mouse button is released after being pressed down anywhere on the main window (note that a click is composed of a mouse press and mouse release). See sysWindowMousePressEvent for example use.

sysLoadEvent

Raised when Mudlet is loading the profile. Note that when it does so, it also compiles and runs all scripts - which could be a good idea to initialize everything at, but beware - scripts are also run when saved. Hence, hooking only on the sysLoadEvent would prevent multiple re-loads as you’re editing the script.

sysExitEvent

Raised when Mudlet is shutting down the profile - a good event to hook onto for saving all of your data.

sysDownloadDone

Raised when Mudlet is finished downloading a file successfully - the location of the downloaded file is passed as a second argument. For a practical example, see the downloadFile() function.

sysDownloadError

Raised when downloading a file failed - the second argument contains the error message. Does not specify which file download has failed yet, however.

ATCP events

Mudlets ATCP implementation generates events for each message that comes, allowing you to trigger on them easily. Since ATCP messages vary in name, event names will vary as well. See the atcp section on how to use them.

Handling Tables in Lua

Nick Gammon has written a very nice overview on how to deal with Lua tables. You can find it here: http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=6036.

How to use multilinematches[n][m]

(The following example can be tested on the MUD batmud.bat.org)

In the case of a multiline trigger with these 2 Perl regex as conditions:

^You have (\w+) (\w+) (\w+) (\w+)
^You are (\w+).*(\w+).*

The command "score" generates the following output on batMUD:

You have an almost non-existent ability for avoiding hits.
You are irreproachably kind.
You have not completed any quests.
You are refreshed, hungry, very young and brave.
Conquer leads the human race.
Hp:295/295 Sp:132/132 Ep:182/181 Exp:269 >

If you add this script to the trigger:

showMultimatches()

The script, i.e. the call to the function showMultimatches() generates this output:

 -------------------------------------------------------
 The table multimatches[n][m] contains:
 -------------------------------------------------------
 regex 1 captured: (multimatches[1][1-n])
           key=1 value=You have not completed any quests
           key=2 value=not
           key=3 value=completed
           key=4 value=any
           key=5 value=quests
 regex 2 captured: (multimatches[2][1-n])
           key=1 value=You are refreshed, hungry, very young and brave
           key=2 value=refreshed
           key=3 value=young
           key=4 value=and
           key=5 value=brave
 -------------------------------------------------------

The function showMultimatches() prints out the content of the table multimatches[n][m]. You can now see what the table multimatches[][] contains in this case. The first trigger condition (=regex 1) got as the first full match "You have not completed any quests". This is stored in multimatches[1][1] as the value of key=1 in the sub-table matches[1] which, in turn, is the value of key=1 of the table multimatches[n][m].

The structure of the table multimatches:

multimatches {
                1 = {
                       matches[1] of regex 1
                       matches[2] of regex 1
                       matches[3] of regex 1
                              ...
                       matches[n] of regex 1 },
                2 = {
                       matches[1] of regex 2
                       matches[2] of regex 2
                             ...
                       matches[n] of regex 2 },
                 ...         ...
                n = {
                       matches[1] of regex n
                       matches[2] of regex n
                             ...
                       matches[n] of regex n }
}

The sub-table matches[n] is the same table matches[n] you get when you have a standard non-multiline trigger. The value of the first key, i. e. matches[1], holds the first complete match of the regex. Subsequent keys hold the respective capture groups. For example: Let regex = "You have (\d+) gold and (\d+) silver" and the text from the MUD = "You have 5 gold and 7 silver coins in your bag." Then matches[1] contains "You have 5 gold and 7 silver", matches[2] = "5" and matches[3] = "7". In your script you could do:

myGold = myGold + tonumber( matches[2] )
mySilver = mySilver + tonumber( matches[3] )

However, if you’d like to use this script in the context of a multiline trigger, matches[] would not be defined as there are more than one regex. You need to use multimatches[n][m] in multiline triggers. Above script would look like this if above regex would be the first regex in the multiline trigger:

myGold = myGold + tonumber( multimatches[1][2] )
mySilver = mySilver + tonumber( multimatches[1][3] )

What makes multiline triggers really shine is the ability to react to MUD output that is spread over multiple lines and only fire the action (=run the script) if all conditions have been fulfilled in the specified amount of lines.

Scripting howtos

How to highlight my current target?

You can put the following script into your targetting alias:

if id then killTrigger(id) end
id = tempTrigger(target, [[selectString("]] .. target .. [[", 1) fg("gold") resetFormat()]])

Where target is your target variable. Note that you have to use the full name, capitalized. If you’d like the script to auto-capitalize for you, you can use this version*:

target = target:title()
if id then killTrigger(id) end
id = tempTrigger(target, [[selectString("]] .. target .. [[", 1) fg("gold") resetFormat()]])

^*requires Mudlet 1.1.0

ATCP

Since version 1.0.6, Mudlet includes support for ATCP. This is primarily available on IRE-based MUDs, but Mudlets impelementation is generic enough such that any it should work on others.

The latest ATCP data is stored in the atcp table. Whenever new data arrives, the previous is overwritten. An event is also raised for each ATCP message that arrives. To find out the available messages available in the atcp table and the event names, you can use display(atcp).

Note that while the typical message comes in the format of Module.Submodule, ie Char.Vitals or Room.Exits, in Mudlet the dot is removed - so it becomes CharVitals and RoomExits. Here’s an example:

room_number = tonumber(atcp.RoomNum)
echo(room_number)

Triggering on ATCP events

If you’d like to trigger on ATCP messages, then you need to create scripts to attach handlers to the ATCP messages. The ATCP handler names follow the same format as the atcp table - RoomNum, RoomExits, CharVitals and so on.

While the concept of handlers for events is to be explained elsewhere in the manual, the quick rundown is this - place the event name you’d like your script to listen to into the Add User Defined Event Handler: field and press the + button to register it. Next, because scripts in Mudlet can have multiple functions, you need to tell Mudlet which function should it call for you when your handler receives a message. You do that by setting the Script name: to the function name in the script you’d like to be called.

For example, if you’d like to listen to the RoomExits event and have it call the process_exits() function - register RoomExits as the event handler, make the script name be process_exits, and use this in the script:

function process_exits(event, args)
    echo("Called event: " .. event .. "\nWith args: " .. args)
end

Feel free to experiment with this to achieve the desired results. A ATCP demo package is also available on the forums for using event handlers and parsing its messages into Lua datastructures.

Aardwolf’s 102 subchannel

Similar to ATCP, Aardwolf includes a hidden channel of information that you can access in Mudlet since 1.1.1. Mudlet deals with it in the same way as with ATCP, so for full usage instructions see the ATCP section. All data is stored in the channel102 table, such you can do

display(channel102)

To see all the latest information that has been received. The event to create handlers on is titled channel102Message, and you can use the sendTelnetChannel102(msg) function to send text via the 102 channel back to Aardwolf.

db: Mudlet DB Frontend

The DB package is meant to provide easier access to a database, so you don’t have to know SQL or use the luasql module to set and get at your data. However, it does require that the luasql module be compiled and included in Mudlet to function - and this all is available since Mudlet 1.0.6.

Creating a Database

Before you can store anything in a database, you need to create one. You may have as many independent databases as you wish, with each having as many unique tables-- what we will call sheets in this package, so as to avoid confusion with Lua tables - think spreadsheets.

To create a database, you use the db:create() function, passing it the name of your database and a Lua table containing its schema configuration. A schema is a mold for your database - it defines what goes where. Using the spreadsheet example, ths would mean that you’d define what goes into each column. A simple example:

        db:create("people", {friends={"name", "city", "notes"}, enemies={"name", "city", "notes"}})

This will create a database which contains two sheets: one named friends, the other named enemies. Each has three columns, name, city and notes-- and the datatype of each are strings, though the types are very flexible and can be changed basically whenever you would like. It’ll be stored in a file named Database_people.db in your Mudlet config directory on the hard drive should you want to share it.

It’s okay to run this function repeatedly, or to place it at the top-level of a script so that it gets run each time the script is saved: the DB package will not wipe out or clear the existing data in this case. More importantly, this allows you to add columns to an existing sheet. If you change that line to:

        db:create("people", {friends={"name", "city", "notes"}, enemies={"name", "city", "notes", "enemied"}})

It will notice that there is a new column on enemies, and add it to the existing sheet-- though the value will end up as nil for any rows which are already present. Similarly, you can add whole new sheets this way. It is not presently possible to -remove- columns or sheets without deleting the database and starting over.

A note on column or field names: you may not create a field which begins with an underscore. This is strictly reserved to the db package for special use.

Adding Data

To add data to your database, you must first obtain a reference (variable) for it. You do that with the db:get_database function, such as:

        local mydb = db:get_database("people")

The database object contains certain convenience functions (discussed later, but all are preceded with an underscore), but also a reference to every sheet that currently exists within the database. You then use the db:add() function to add data to the specified sheet.

        db:add(mydb.friends, {name="Ixokai", city="Magnagora"})

If you would like to add multiple rows at once to the same table, you can do that by just passing in multiple tables:

        db:add(mydb.friends,
                {name="Ixokai", city="Magnagora"},
                {name="Vadi", city="New Celest"},
                {name="Heiko", city="Hallifax", notes="The Boss"}
        )

Notice that by default, all columns of every table are considered optional-- if you don’t include it in the add, then it will be set to its default value (which is nil by default)

For those familiar with databases: with the DB package, you don’t have to worry about committing or rolling back any changes, it will commit after each action automatically. If you would like more control then this, see Transactions below.

You also cannot control what is the primary key of any sheets managed with DB, nor do you have to create one. Each row will get a unique integer ID that automatically increments, and this field can be accessed as "_row_id".

Querying

Putting data in isn’t any fun if you can’t get it out. If you want every row from the sheet, you can do:

        db:fetch(mydb.friends)

But rarely is that actually useful; usually you want to get only select data. For example, you only want to get people from the city of Magnagora. To do that you need to specify what criteria the system should use to determine what to return to you. It looks like this:

        db:fetch(mydb.friends, db:eq(mydb.friends.city, "Magnagora"))

So the basic command is - db:fetch(_sheet_, _what to filter by_)

The following filter operations are defined:

        db:eq(field, value[, case_insensitive]) -- Defaults to case insensitive, pass true as the last arg to
                                                        reverse this behavior.
        db:not_eq(field, value[, case_insensitive) -- Not Equal To
        db:lt(field, value) -- Less Than
        db:lte(field, value) -- Less Than or  Equal to.
        db:gt(field, value) -- Greater Than
        db:gte(field, value) -- Greater Than or Equal To
        db:is_nil(field) -- If the column is nil
        db:is_not_nil(field) -- If the column is not nil
        db:like(field, pattern) -- A simple matching pattern. An underscore matches any single character,
                                        and a percent(%) matches zero or more characters. Case insensitive.
        db:not_like(field, pattern) -- As above, except it'll give you everything but what you ask for.
        db:between(field, lower_bound, upper_bound) -- Tests if the field is between the given bounds (numbers only).
        db:not_between(field, lower_bound, upper_bound) -- As above, only... not.
        db:in_(field, table) -- Tests if the field is in the values of the table. NOTE the trailing underscore!
        db:not_in(field, table) -- Tests if the field is NOT in the values of the table *

The db:in_ operator takes a little more explanation. Given a table, it tests if any of the values in the table are in the sheet. For example:

        db:in_(mydb.friends.city, {"Magnagora", "New Celest"})

It tests if city == "Magnagora" OR city == "New Celest", but with a more concise syntax for longer lists of items.

There are also two logical operators:

        db:AND(operation1, ..., operationN)
        db:OR(operation1, operation2)

You may pass multiple operations to db:fetch in a table array, and they will be joined together with an AND by default. For example:

        db:fetch(mydb.friends,
                {db:eq(mydb.friends.city, "Magnagora"), db:like(mydb.friends.name, "X%")}
        )

This will return every record in the sheet which is in the city of Magnagora, and has a name that starts with an X. Again note that in LIKE patterns, a percent is zero or more characters — this is the same effect as "X.*" in pcre patterns. Similarly, an underscore matches any single characters and so is the same as a dot in pcre.

Passing multiple expressions in an array to db:fetch is just a convenience, as its exactly the same as:

        db:fetch(mydb.friends, db:AND(db:eq(mydb.friends.city, "Magnagora"), db:like(mydb.friends.name, "I%")))

The db:OR operation only takes two arguments, and will check to see if either of the two is true. You can nest these logical operators as deeply as you need to.

You can also just pass in a string directly to db:fetch, but you have to be very careful as this will be passed straight to the SQL layer. If you don’t know any SQL then you want to avoid this… for example, in SQL there’s a very big difference between double and single quotes. If you don’t know that, then stick to the db functions. But an example is:

        db:fetch(mydb.friends, "city == 'Magnagora'")

Now, the return value of db:fetch() is always a table array that contains a table dictionary representing the full contents of all matching rows in the sheet. These are standard Lua tables, and you can perform all normal Lua operations on them. For example, to find out how many total items are contained in your results, you can simply do #results. If a request from the friends sheet were to return one row that you stored in the results variable, it would look like this if passed into the display() function:

    table {
        1: table {
            'name': 'Bob',
            'city': 'Magnagora',
            'notes': 'Trademaster of Tailoring'
        }
    }

And if you were to echo(#results), it would show 1.

The order of the returned rows from db:fetch is generally the same as the order in which you entered them into the database, but no actual guarantees are made to this. If you care about the order then you can pass one or two optional parameters after the query to db:fetch() to control this.

The first table array of fields that indicate the column names to sort by; the second is a flag to switch from the default ascending(smallest to largest) sort, to a descending(largest to smallest) sort. For example:

        db:fetch(mydb.friends, db:eq(mydb.friends.city, "Magnagora"), {mydb.friends.city})

This will return all your friends in Magnagora, sorted by their name, from smallest to largest. To reverse this, you would simply do:

        db:fetch(mydb.friends, db:eq(mydb.friends.city, "Magnagora"), {mydb.friends.city}, true)

Including more then one field in the array will indicate that in the case that two rows have the same value, the second field should be used to sort them.

If you would like to return ALL rows from a sheet, but still sort them, you can do that by passing nil into the query portion. For example:

        db:fetch(mydb.friends, nil, {mydb.friends.city, mydb.friends.name})

This will return every friend you have, sorted first by city and then their name.

Indexes and Types

The sheets we’ve defined thus far are very simple, but you can take more control over the process if you need to. For example, you may assign default values and types to columns, and the DB package will attempt to coerce them as appropriate. To do that, you change your db:create() call as:

        db:create("people", {
                friends={"name", "city", "notes"},
                enemies={
                        name="",
                        city="",
                        notes="",
                        enemied="",
                        kills=0
                }
        })

This is almost the same as the original definition, but we’ve defined that our first four fields are strings with a default value of blank, and the new kills field which is an integer that starts off at 0. The only way to set a datatype is to set a default value at this time.

Please note, beneath the DB package is SQLite, and SQLite is very data-type neutral. It doesn’t really care very much if you break those rules and put an integer in a string field or vice-versa, but the DB package will — to a limited degree — attempt to convert as appropriate, especially for the operations that work on numbers.

You may also create both standard and unique indexes. A unique index enforces that a certain criteria can only happen once in the sheet. Now, before you go and make indexes, pause and consider. There is no right or wrong answer when it comes to what to index: it depends on what kind of queries you do regularly. If in doubt, don’t make an index. Indexes will speed up reading data from the sheet, but they will slow down writing data.

To add an index, pass either the _index or _unique keys in the table definition. An example:

        db:create("people", {
                friends={"name", "city", "notes"},
                enemies={
                        name="",
                        city="",
                        notes="",
                        enemied="",
                        kills=0,
                        _index = { "city" },
                        _unique = { "name" }
                }
        })

You can also create compound indexes, which is a very advanced thing to do. One could be: _unique = { {"name", "city"} }

This would produce an effect that there could be only one "Bob" in Magnagora, but he and "Bob" in Celest could coexist happily.

Now, bear in mind: _index = { "name", "city"} creates two indexes in this sheet. One on the city field, one on the name field. But, _index = { {"name", "city"} } creates one index: on the combination of the two. Compound indexes help speed up queries which frequently scan two fields together, but don’t help if you scan one or the other.

The admonition against making indexes willy-nilly holds double for compound indexes: do it only if you really need to!

Uniqueness

As was specified, the _unique key can be used to create a unique index. This will make it so a table can only have one record which fulfills that index. If you use an index such as _unique = { "name" } then names must be unique in the sheet. However, if you use an index such as _unique = { {"name", "city"} } then you will allow more then one person to have the same name — but only one per city.

Now, if you use db:add() to insert a record which would violate the unique constraint, a hard error will be thrown which will stop your script. Sometimes that level of protection is too much, and in that case you can specify how the db layer handles violations.

There are three possible ways in which the layer can handle such violations; the default is to FAIL and error out.

You can also specify that the db layer should IGNORE any commands that would cause the unique constraint to be violated, or the new data should REPLACE the existing row.

For example:

        db:add(mydb.enemies, {name="Bob", city="Sacramento"})
        db:add(mydb.enemies, {name="Bob", city="San Francisco"})

With the name field being declared to be unique, these two commands can’t succeed normally. The first db:add() will create a record with the name of Bob, and the second would cause the uniqueness of the name field to be violated. With the default behavior (FAIL), the second db:add() call will raise an error and halt the script.

If you want the IGNORE behavior, the second command will not cause any errors and it will simply fail silently. Bob’s city will still be Sacramento.

With the REPLACE behavior, the second command will cause its data to completely overwrite and replace the first record. Bob’s city will now be San Francisco.

A word of caution with REPLACE, given:

        db:add(mydb.enemies, {name="Bob", city="Sacramento", notes="This is something."})
        db:add(mydb.enemies, {name="Bob", city="San Francisco"})

With the REPLACE behavior, the second record will overwrite the first-- but the second record does not have the notes field set. So Bob will now not have any notes. It doesn’t -just- replace existing fields with new ones, it replaces the entire record.

To specify which behavior the db layer should use, add a _violations key to the table definition:

        db:create("people", {
                friends={"name", "city", "notes"},
                enemies={
                        name="",
                        city="",
                        notes="",
                        enemied="",
                        kills=0,
                        _index = { "city" },
                        _unique = { "name" },
                        _violations = "IGNORE"
                }
        })

Note that the _violations behavior is sheet-specific.

Timestamps

In addition to strings and floats, the db module also has basic support for timestamps. In the database itself this is recorded as an integer (seconds since 1970) called an epoch, but you can easily convert them to strings for display, or even time tables to use with Lua’s built-in time support.

The most common use for the Timestamp type is where you want the database to automatically record the current time whenever you insert a new row into a sheet. The following example illustrates that:

        local mydb = db:create("combat_log",
           {
              kills = {
                 name = "",
                 area = "",
                 killed = db:Timestamp("CURRENT_TIMESTAMP"),
                 _index = { {"name", "killed"} }
              }
           }
        )


        db:add(mydb.kills, {name="Drow", area="Undervault"})

        results = db:fetch(mydb.kills)
        display(results)

The result of that final display would show you this on a newly created sheet:

        table {
          1: table {
            '_row_id': 1
            'area': 'Undervault'
            'name': 'Drow'
            'killed': table {
              '_timestamp': 1264317670
            }
          }

As you can see from this output, the killed fields contains a timestamp-- and that timestamp is stored as an epoch value. For your convienance, the db.Timestamp type offers three functions to get the value of the timestamp in easy formats. They are as_string, as_number and as_table, and are called on the timestamp value itself.

The as_number function returns the epoch number, and the as_table function returns a time table. The as_string function returns a string representation of the timestamp, with a default format of "%m-%d-%Y %H:%M:%S". You can override this format to anything you would like. Details of what you can do with epoch values, time tables, and what format codes you can use are specified in the Lua manual at: http://www.lua.org/pil/22.1.html for the Lua date/time functions.

A quick example of the usage of these functions is:

        results = db:fetch(mydb.kills)
        for _, row in ipairs(results) do
                echo("You killed " .. row.name .. " at: " .. row.killed:as_string() .."\n")
        end

Deleting

The db:delete function is used to delete rows from the sheet. It takes two arguments, the first being the sheet you are deleting and the second a query string built using the same functions used to build db:fetch() queries.

For example, to delete all your enemies in the city of Magnagora, you would do:

        db:delete(mydb.enemies, db:eq(mydb.enemies.city, "Magnagora"))

Be careful in writing these! You may inadvertantly wipe out huge chunks of your sheets if you don’t have the query parameters set just to what you need them to be. Its advised that you first run a db:fetch() with those parameters to test out the results they return.

As a convienence, you may also pass in a result table that was previously retrieved via db:fetch and it will delete only that record from the table. For example, the following will get all of the enemies in Magnagora, and then delete the first one:

        results = db:fetch(mydb.enemies, db:eq(mydb.enemies.city, "Magnagora"))
        db:delete(mydb.enemies, db:eq(mydb.enemies._row_id, results[1]._row_id))

That is equivelent to:

        db:delete(mydb.enemies, results[1])

You can even pass a number directly to db:delete if you know what _row_id you want to purege.

A final note of caution: if you want to delete all the records in a sheet, you can do so by only passing in the table reference. To try to protect you from doing this inadvertantly, you must also pass true as the query after:

        db:delete(mydb.enemies, true)

Updating

If you make a change to a table that you have received via db:fetch(), you can save those changes back to the database by doing:

        db:update(mydb.enemies, results[1])

A more powerful (and somewhat dangerous, be careful!) function to make changes to the database is db:set, which is capable of making sweeping changes to a column in every row of a sheet. Beware, if you have previously obtained a table from db:fetch, that table will NOT represent this change.

The db:set() function takes two arguments: the field to change, the value to set it to, and the db:fetch() like query to indicate which rows should be affected. If you pass true as the last argument, ALL rows will be changed.

To clear out the notes of all of our friends in Magnagora, we could do:

        db:set(mydb.friends.notes, "", db:eq(mydb.friends.notes, "Magnagora"))

Be careful in writing these!

Transactions

As was specified earlier, by default the db module commits everything immediately whenever you make a change. For power-users, if you would like to control transactions yourself, the following functions are provided on your database instance:

        local mydb = db:get_database("my_database")
        mydb:_begin()
        mydb:_commit()
        mydb:_rollback()
        mydb:_end()

Once you issue a mydb:_begin() command, autocommit mode will be turned off and stay off until you do a mydb:_end(). Thus, if you want to always use transactions explicitly, just put a mydb:_begin() right after your db:create() and that database will always be in manual commit mode.

Viewing and editing the database contents

A good tool to view and edit the database contents in raw form is SQlite Sorcerer (free and available for Linux, Windows, Mac).

Migrating to Mudlet

From Nexus

Trigger patterns

Lets start with triggers. For translating Nexus patterns into Mudlet, use the following table below. Make sure to set the pattern type in Mudlet to be perl regex, because the default substring works differently.

Mudlet Nexus What it does

(\w+)

{w}

Match one or more non-whitespace characters (a 'word')

(\d+)

{d}

Match one or more numeric digits (a number)

([abc])

{[abc]}

Match one or more of either 'a', 'b' or 'c'. (a character class)

([^abc])

{[^abc]}

Match one or more of anything EXCEPT 'a', 'b', or 'c'

(.*)

{*}

Match zero or more characters (anything)

^

{<}

Match the beginning of a line (not the actual newline character)

$

{>}

Match the end of a line (not the actual newline character)

Note
If you just have a pattern with a {<} and {>} and nothing else, copy the pattern over without the {<}{>} and select the exact match pattern type. For example {<}You sit down.{>} in Nexus would become You sit down. in Mudlet with the pattern type of exact match. This is easier to read and matches way faster!

Basic scripting

The Nexus way of doing a function is like this: #function stuff it does. In Mudlet, it’s function(stuff it does). Note that if you’d like to give text to a function, you put it inside double or single quotes.

Nexus
#send hi
#echo Hello to me!
Mudlet
send ("hi")
echo ("Hello to me!")

If you’d like to use a variable inside text, you’d put it outside the quotes and glue it together with two dots.

Nexus
#set number 1234
#echo My number is: $number
#echo the $number is in the middle of my text
Mudlet
number = 1234
echo ("My number is: " .. number)
echo ("the " .. number .. " is in the middle of my text")

wildcards in Mudlet

To use the wildcard variable in Nexus, you’d use $1 for the first match, $2 for the second and so on. In Mudlet, the matches[] table contains the matches - and it starts placing the matches from 2. So the Nexus $1 would be matches[2], $2 would be matches[3].

Nexus:
{w} kicks you.
#set badguy $1
#echo $badguy kicked me!

Mudlet:
(\w+) kicks you\.
badguy = matches[2]
echo(badguy .. " kicked me!")

Another example would be the targetting alias:

Nexus:
alias name: t
alias script: #set target $1

Mudlet:
alias pattern: ^t (.*)$
alias script: target = matches[2]

The reason the first match goes into matches[2] and not matches[1] is because matches[1] contains the part of the line that matched your trigger / alias.

#wait in Mudlet

In Nexus, a #wait will freeze the script while it’s executing - such that commands after it are delayed. In Mudlet, we use tempTimer which that works a bit differently - it doesn’t freeze the script, but instead makes it so commands a tempTimer is asked to do will get done in the future.

So the difference is that a tempTimer doesn’t freeze the commands following it at all, everything gets done at once as usual. Just things a tempTimer was asked to do get done in the future.

Nexus script:
#send hello
#wait 1000
#send hi
#wait 500
#send bye

Mudlet:
send("hello")
tempTimer(1, [[send("hi")]])
tempTimer(1.5, [[send("bye")]])

ifs in Mudlet

Next are the #if statements. Here’s a table comparing the syntaxes of Nexus and Mudlet:

Mudlet Nexus

if <condition> then <text> end

#if <condition> <text>

#if <condition> { <script> }

if <condition> then <script> else <script> end

#if <condition> { <script> } else { <script> }

#if <condition> { <script> } { <script> }

if <condition> then <script> elseif <condition> then <script> end

#if <condition> { <script> } elsif <condition> { <script> }

if <condition> then <script> elseif <condition> then <script> else <script> end

#if <condition> { <script> } elsif <condition> { <script> } else { <script> }

Here is the sample side-by-side comparison of how you’d use it:

Mudlet Nexus
-- If foo is true, echo that fact.
if foo then echo ("Foo is true!") end -- If foo is true, echo that fact.

-- A slight modification of the above that illustrates an 'else' clause.
-- Note that the 'then' is always necessary to avoid confusion.
if foo then echo ("Foo is true!") else echo ("Foo is false!") end

-- Illustration of putting more than one statement in a block (also
-- spans lines here). Note the if doesn't end until the last 'end' is
-- encountered.
-- We also add a \n at the end of multiple echos so each one is on it's own line.
if foo then
   echo ("Foo is true!\n")
   echo ("Isn't it grand?\n")
   echo ("These commands are all on separate lines too!\n")
end

-- This shows how ifs continue (on 'logical' lines) even though the
-- blocks in its constituent clauses may have multiple lines. The
-- following lines are all _one_ single if statement.
if foo > 50 then
   echo ("Foo is big!\nYes it is.")
elseif foo > 10 then
   echo ("Foo is pretty big...\n")
   echo ("I've seen bigger.")
else
   echo ("Foo is actually kind of small.")
end

-- Ifs can be nested too.
if foo then
   if bar then
      echo ("Both foo and bar are true.")
   else
      echo ("Foo's true, but bar isn't.")
   end
end
// If $foo is true, echo that fact.
#if $foo #echo Foo is true!          // If $foo is true, echo that fact.

// A slight modification of the above that illustrates an 'else' clause.
// The second form shows that the word 'else' is actually optional too.
// (The two lines are functionally the same.)
#if $foo { #echo Foo is true! } else { #echo Foo is false! }
#if $foo { #echo Foo is true! } { #echo Foo is false! }

// Illustration of putting more than one statement in a block (also
// spans lines here). Note the if doesn't end until the last '}' is
// encountered.
#if $foo {
   #echo Foo is true!
   #echo Isn't it grand?
   #echo These commands are all on separate lines too!
}

// This shows how ifs continue (on 'logical' lines) even though the
// blocks in its constituent clauses may have multiple lines. The
// following lines are all _one_ single if statement.
#if $foo > 50 {
   #echo Foo is big!
   #echo Yes it is.
} elsif $foo > 10 {
   #echo Foo is pretty big...
   #echo I've seen bigger.
} else {
   #echo Foo is actually kind of small.
}

// Ifs can be nested too.
#if $foo {
   #if $bar {
      #echo Both foo and bar are true.
   } else {
      #echo Foo's true, but bar isn't.
   }
}

Mudlet equivalents of Nexus functions

Now that we got the ifs covered, lets go over the Mudlet equivalents of other Nexus functions. Note that this is a direct Nexus→Mudlet comparison; certain functions in Mudlet have much more capability.

Mudlet Nexus
<variable> = <variablename> <+ - /  *> <number or variable>    
#add <variablename> <expression>
echo "text\n" or echo("text\n")        
#echo <text>
echo "text" or echo("text")            
#echo_ <text>
enableAlias("<group name>"), enableTrigger(), enableKey() or enableTimer() 
#groupon <group name>
disableAlias("<group name>"), disableTrigger(), disableKey() or disableTimer() 
#groupoff <group name>
selectString (line, 1) bg("<color>") resetFormat() 
#highlight <color>
deleteLine()                       
#gag
openUrl("<url>")*                  
#openurl <url>
send("<stuff>")                    
#send <text>
sendAll("hi", "hello", "bye")      
#send_ hi #send_ hello #send bye
<variable name> = "<text value>"   
#set <variable name> <text value>
<variable name> = <expression>     
#set <variable name> = <expression>
<variable name> = nil              
#unset <variable name>
tempTimer(<time in s>, [[<lua code to do once time is up>]])
#wait <milliseconds>

*Planned for Mudlet 1.0.6

How to call aliases in Mudlet

The typical workflow in Nexus is that you’d define the aliases for yourself to use, and also use aliases for system-related things (things like checking if you’d need to eat a herb, etc).

While the first use is good, the second isn’t - because the user can also run this alias at an inopportune time, because if you want to call an alias it has to match all alises again, and so on.

Now, while in Mudlet you can call another alias with the expandAlias() function, this is strongly discouraged. What you do instead if create a function (for example, send() and echo() are functions) that you can then call from your alias or trigger. This has many advantages - it’s faster, you can easily give your function values, and your function can return you values, too.

To make a function, you go to the Scripts section, create a new script, and write in your function:

function <name> ()
    <stuff it does>
end

For example, if we want to make a function that does two things for us at once, we’d do this:

function eat_bloodroot()
    send ("outr bloodroot")
    send ("eat bloodroot")
end

Then just do this in our alias or trigger to outr and eat bloodroot:

eat_bloodroot()

As mentioned, you can also give things to functions - in this case lets expand the function to eat any herb for us we tell it:

function eat (what)
    send ("outr " .. what)
    send ("eat " .. what)
end

[...]
eat ("bloodroot")
eat ("kelp")
eat ("ginseng")

Lastly, functions can also give you data back. One useful example for this is to break down tasks into functions, which will help your code readibility:

function can_i_stand()
    if not paralyzed and not prone and not stunned then
        return true
    else
        return false
end

[...]

if can_i_stand() and have_balance and have_equilibrium then
    send ("stand")
end

Notes to be aware of

To finish off, a couple of points that should be remembered:

  • Mudlet does profile snapshots (nexus archives) automatically - to load a different one, select it from the list when connecting

  • Mudlet can import and export xml

  • Mudlet and Nexus xml formats aren’t compatible

  • Mudlet can do nexus graphics, here is a package for - Achaea

  • Mudlet has a ton more features such are more speed, less bugs, copy from the normal window, replay logging, color html logging, more powerful scripting, and the list goes on.

Lua API

Mudlet defines several global Lua variables that are accessible from anywhere.

Table 1. Built-in Lua Variables
Variable Name Description

command

This variable holds the current user command. This is typically used in alias scripts.

line

This variable holds the content of the current line as being processed by the trigger engine. The engine runs all triggers on each line as it arrives from the MUD.

matches[n]

This Lua table is being used by Mudlet in the context of triggers that use Perl regular expressions. matches[1] holds the entire match, matches[2] holds the first capture group, matches[n] holds the n-th capture group.

If the trigger uses the Perl style /g switch to evaluate all possible matches of the given regex within the current line, matches[n+1] will hold the second entire match, matches[n+2] the first capture group of the second match and matches[n+m] the m-th capture group of the second match.

multimatches[n][m]

This table is being used by Mudlet in the context of multiline triggers that use Perl regular expression. It holds the table matches[n] as described above for each Perl regular expression based condition of the multiline trigger. multimatches[5][4] may hold the 3rd capture group of the 5th regex in the multiline trigger. This way you can examine and process all relevant data within a single script. Have a look at this example.

Alphabetical Function Index

Click on the respective function to get more information:

A

B

C

D

E

F

G

H

I

K

L

M

O

P

R

S

T

W

Most Important Functions

send( command, echo the value = true/false )

This sends "command" directly to the network layer, skipping the alias matching. The optional second argument of type boolean (print) determines if the outgoing command is to be echoed on the screen.

If you want your command to be checked if it’s an alias, use expandAlias() instead. example:

send( "Hello Jane" ) --echos the command on the screen
send( "Hello Jane", true ) --echos the command on the screen
send( "Hello Jane", false ) --does not echo the command on the screen

echo( windowName, text )

This function appends text at the end of the current line. The current cursor position is ignored. Use moveCursor() and insertText() if you want to print at a different cursor position.

If the first argument is omitted the main console is used, otherwise the mini console windowName. === Example 1:

echo( "Hello world\n" ) -- writes "Hello world" to the main screen.
echo( "info", "Hello this is the info window" ) -- writes text to the mini console named "info" if such a window exists

Echos a piece of text as a clickable link.

  • text - text to display in the echo. Same as a normal echo().

  • command - lua code to do when the link is clicked.

  • hint - text for the tooltip to be displayed when the mouse is over the link.

  • boolean - if true, then the link will use the current selection style (colors, underline, etc). If missing or false, it will use the default link style - blue on black underlined text.

Available since 1.1.0-pre1.

Example:

echoLink("hi", [[echo("hey bub!")]], "click me now")

selectString( text, number_of_match ) returns position in line or -1 on error (text not found in line)

Selects a substring from the line where the user cursor is currently positioned. You can move the user cursor with moveCursor(). When a new line arrives from the MUD, the user cursor is positioned at the beginning of the line. However, if one of your trigger scripts moves the cursor around you need to take care of the cursor position yourself and make sure that the cursor is in the correct line if you want to call one of the select functions. To deselect text, see deselect().

Note
To prevent selection of random data use the error return if not found like this: if selectString( "big monster", 1 ) > -1 then setFgColor( 255,0,0) end

decho([name of console, ] text) * name of console - optional name of the console to echo to. Defaults to main. * text - the text that you’d like to echo with embedded color tags. Tags take the RGB values only, see below for an explanation.

How text works

Color changes can be made using the format <FR,FG,FB:BR,BG,BB> where each field is a number from 0 to 255. The background portion can be omitted using <FR,FG,FB> or the foreground portion can be omitted using <:BR,BG,BB>.

deselect()

Clears the current selection in the main window.

deselect(windowname)

Clears the current selection in the given miniConsole.

deleteLine()

deletes the current Line under the user cursor. Note: This is a high speed gagging tool and it is very good at this task. It is meant to be used when the line can be omitted entirely in the output. If you want to replace this line with something else have a look at the replace() functions below. Note that scripts such as: deleteLine(); echo("this line is gone"); will not work because lines that have been gagged with deleteLine() will not be rendered even if there is text in the buffer. → wrapLine() for details on how to force a re-render if this is necessary for some reason. This is not the recommended way of replacing text. → replace() and wrapLine()

disableAlias (name)

Disables/deactivates an alias with the given name. This means that when you type in text that should match it’s pattern, it won’t match and will be sent to the MUD. If several aliases have this name, they’ll all be disabled.

enableTrigger( name )

Enables the Trigger name. → enableTrigger()

disableTrigger( name )

Use trigger name or the id returned by tempTrigger() to identify the timer that you want to disable. → disableTrigger( name )

insertText( text )

inserts text at the current cursor position in the main window; if the cursor has not been explicitly moved this function will always print at the beginning of the line whereas the echo() function will always print at the end of the line

insertText( windowName, text )

inserts text at cursor position in window windowName

Same as echoLink() but inserts the text at the current cursor position, while echoLink inserts at the end of the current line.

Available since 1.1.0-pre1.

insertPopup([window], text, {commands}, {hints}, [bool current or default format])

Same as echoPopup(), but inserts text at the current cursor position.

Available since 1.1.0-pre1.

suffix( text )

Suffixes text at the end of the current line when used in a trigger.

prefix( text )

Prefixes text at the beginning of the current line when used in a trigger.

Example:

-- Prefix the hours, minutes and seconds onto our prompt even though Mudlet has a button for that
prefix(os.date("%H:%M:%S "))

result = string:title(text)

Capitalizes the given text for you.

Examples:

test = "bob"
test = string.title(test)
-- test is now "Bob"

testname = string.title("anna")
-- testname is now Anna

permAlias(name, parent, regex, lua code)

Creates a persistent alias that stays after Mudlet is restarted and shows up in the Script Editor.

  • name is the name you’d like the alias to have.

  • parent is the name of the group, or another alias you want the trigger to go in - however if such a group/alias doesn’t exist, it won’t do anything. Use "" to make it not go into any groups.

  • regex is the pattern that you’d like the alias to use.

  • lua code is the script the alias will do when it matches.

Examples:

-- creates an alias called "new alias" in a group called "my group"
permAlias("new alias", "my group", "^test$", [[echo ("say it works! This alias will show up in the script editor too.")]])
Note

Note that Mudlet by design allows duplicate names - so calling permAlias with the same name will keep creating new aliases. You can check if an alias already exists with the exists() function.

permSubstringTrigger( name, parent, pattern, lua code )

Creates a persistent trigger with a substring pattern that stays after Mudlet is restarted and shows up in the Script Editor.

  • name is the name you’d like the trigger to have.

  • parent is the name of the group, or another trigger you want the trigger to go in - however if such a group/trigger doesn’t exist, it won’t do anything. Use "" to make it not go into any groups.

  • pattern table is a table of patterns that you’d like the trigger to use - it can be one or many.

  • lua code is the script the trigger will do when it matches.

Example:

-- Create a trigger to highlight the word "pixie" for us
permSubstringTrigger("Highlight stuff", "General", {"pixie"},
[[selectString(line, 1) bg("yellow") resetFormat()]])

-- Or another trigger to highlight several different things
permSubstringTrigger("Highlight stuff", "General", {"pixie", "cat", "dog", "rabbit"},
[[selectString(line, 1) fg ("blue") bg("yellow") resetFormat()]])
Note

Note that Mudlet by design allows duplicate names - so calling permSubstringTrigger with the same name will keep creating new triggers. You can check if a trigger already exists with the exists() function.

permRegexTrigger( name, parent, pattern, lua code )

Creates a persistent trigger with a regex pattern that stays after Mudlet is restarted and shows up in the Script Editor.

  • name is the name you’d like the trigger to have.

  • parent is the name of the group, or another trigger you want the trigger to go in - however if such a group/trigger doesn’t exist, it won’t do anything. Use "" to make it not go into any groups.

  • pattern table is a table of patterns that you’d like the trigger to use - it can be one or many.

  • lua code is the script the trigger will do when it matches.

Example:

-- Create a regex trigger that will match on the prompt to record your status
permRegexTrigger("Prompt", "", {"^(\d+)h, (\d+)m"}, [[health = tonumber(matches[2]; mana = tonumber(matches[3])]]
Note

Note that Mudlet by design allows duplicate names - so calling permRegexTrigger with the same name will keep creating new triggers. You can check if a trigger already exists with the exists() function.

permBeginOfLineStringTrigger( name, parent, pattern table, lua code )

Creates a persistent trigger with a begin of line substring pattern that shows up in the Script Editor andstays after Mudlet is restarted.

  • name is the name you’d like the trigger to have.

  • parent is the name of the group, or another trigger you want the trigger to go in - however if such a group/trigger doesn’t exist, it won’t do anything. Use "" to make it not go into any groups.

  • pattern table is a table of patterns that you’d like the trigger to use - it can be one or many.

  • lua code is the script the trigger will do when it matches.

Example:

-- Create a trigger that will match on anything that starts with "You sit" and do "stand".
-- It will not go into any groups, so it'll be on the top.
permBeginOfLineStringTrigger("Stand up", "", {"You sit"}, [[send ("stand")]])

-- Another example - lets put our trigger into a "General" folder and give it several patterns.
permBeginOfLineStringTrigger("Stand up", "General", {"You sit", "You fall", "You are knocked over by"}, [[send ("stand")]])
Note

Note that Mudlet by design allows duplicate names - so calling permBeginOfLineStringTrigger with the same name will keep creating new triggers. You can check if a trigger already exists with the exists() function.

permTimer(name, parent, seconds, lua code)

Creates a persistent timer that stays after Mudlet is restarted and shows up in the Script Editor.

Name is the timer name, parent is the name of the timer group you want the timer to go in. Seconds is a number specifying a delay after which the timer will do the lua code you give it as a string.

Examples:

permTimer("my timer", "first timer group", 4.5, [[send ("my timer that's in my first timer group fired!")]])
Note

Note that Mudlet by design allows duplicate names - so calling permTimer with the same name will keep creating new timers. You can check if a timer already exists with the exists() function.

selectSection( from, length_of_string )

Select text on the line under the current cursor position. Use absolute column number for start of selection and length of selection The function returns true on success and false if the selection is not possible.

selectSection( windowName, from, length )

just like selectSection() but does not operate on the main window, but on window windowName. See selectSection() for a detailed description

selectCaptureGroup( groupNumber ) with first group = 0

Selects the content of the capture group number in your Perl regular expression e.g. "you have (\d+) Euro". If you want to color the amount of money you have green you do: selectCaptureGroup(1); setFgColor(0,255,0)

replace( with )

Replaces the currently selected text with the new text. To select text, use selectString() and similar function.

If you’d like to delete/gag the whole line, use deleteLine().

example:

-- replace word "troll" with "cute trolly"
selectString("troll",1)
replace("cute trolly")

-- lets replace the whole line
selectString(line, 1)
replace("Out with the old, in with the new!")

replace( windowName, with )

Same as above, but replaces text in a window (miniConsole, label).

Example:

replaceAll( what, with )

replaces all occurrences of what in the current line with with → replace()

feedTriggers( text )

This function will have Mudlet parse the given text as if it came from the MUD - one great application is trigger testing. You can use \n to represent a new line - you also want to use it before and after the text you’re testing, like so:

feedTriggers("\nYou sit yourself down.\n")

The function also accept ANSI color codes that are used in MUDs. A sample table can be found here.

Example:

feedTriggers("\nThis is \27[1;32mgreen\27[0;37m, \27[1;31mred\27[0;37m, \27[46mcyan background\27[0;37m," ..
"\27[32;47mwhite background and green foreground\27[0;37m.\n")

fg( color_name )

Sets the current selection foreground color to color_name which is one of the pre defined colors in the table below.

Table 2. Color table (for use in the fg("colorname") and bg("colorname") functions)

snow

ghost_white

white_smoke

gainsboro

floral_white

old_lace

linen

antique_white

papaya_whip

blanched_almond

bisque

peach_puff

navajo_white

moccasin

cornsilk

ivory

lemon_chiffon

seashell

honeydew

mint_cream

azure

alice_blue

lavender

lavender_blush

misty_rose

white

black

dark_slate_gray

dark_slate_grey

dim_gray

dim_grey

slate_gray

slate_grey

light_slate_gray

light_slate_grey

gray

grey

light_grey

light_gray

midnight_blue

navy

navy_blue

cornflower_blue

dark_slate_blue

slate_blue

medium_slate_blue

light_slate_blue

medium_blue

royal_blue

blue

dodger_blue

deep_sky_blue

sky_blue

light_sky_blue

steel_blue

light_steel_blue

light_blue

powder_blue

pale_turquoise

dark_turquoise

medium_turquoise

turquoise

cyan

light_cyan

cadet_blue

medium_aquamarine

aquamarine

dark_green

dark_olive_green

dark_sea_green

sea_green

medium_sea_green

light_sea_green

pale_green

spring_green

lawn_green

green

chartreuse

medium_spring_green

green_yellow

lime_green

yellow_green

forest_green

olive_drab

dark_khaki

khaki

pale_goldenrod

light_goldenrod_yellow

light_yellow

yellow

gold

light_goldenrod

goldenrod

dark_goldenrod

rosy_brown

indian_red

saddle_brown

sienna

peru

burlywood

beige

wheat

sandy_brown

tan

chocolate

firebrick

brown

dark_salmon

salmon

light_salmon

orange

dark_orange

coral

light_coral

tomato

orange_red

red

hot_pink

deep_pink

pink

light_pink

pale_violet_red

maroon

medium_violet_red

violet_red

magenta

violet

plum

orchid

medium_orchid

dark_orchid

blue_violet

purple

medium_purple

thistle

Note that you may use the showColors() function in an alias to display these names with their respective colors in Mudlet.

The colour names are taken from X11’s rgb.txt file, for the curious!

Example:

-- in a trigger, lets color all words on the current line green
selectString(line, 1)
fg("green")
resetFormat()

-- or lets only color Anne's name in tomato color
selectString("Anne", 1)
fg("tomato")
resetFormat()

bg( color_name )

Same as fg(), but changes the background color of the text (ie, highlights).

See also: fg(), setBgColor().

Example:

-- in a trigger, lets highlight all words on the current line red
selectString(line, 1)
fg("red")
resetFormat()

-- or lets only color dogs in blue
selectString("dog", 1)
fg("tomato")
resetFormat()

resetFormat()

Resets the character format to default. This should be used after you have highlightd some text or changed the current foreground or background color, but you don’t want to keep using these colors for further prints. If you set a foreground or background color, the color will be used until you call resetFormat() on all further print commands.

setBgColor( r,g,b )

Sets the current text background color in the main window. Values are RGB: red, green, blue ranging from 0-255 e.g. for red: setFgColor(255,0,0) If you set a foreground or background color, the color will be used until you call resetFormat() on all further print commands.

setBgColor( windowName, r, g, b )

Sets the current text background color in window windowName. If you have selected text prior to this call, the selection will be highlightd otherwise the current text background color will be changed. If you set a foreground or background color, the color will be used until you call resetFormat() on all further print commands.

example 1 highlights the first occurrence of the string "Tom" in the current line with a red background color.

selectString( "Tom", 1 )
setBgColor( 255,0,0 )

example 2 prints "Hello" on red background and "You" on blue.

setBgColor(255,0,0)
echo("Hello")
setBgColor(0,0,255)
echo(" You!")
resetFormat()

setFgColor( r, g, b )

Sets the current text foreground color in the main window. Values are RGB: red, green, blue ranging from 0-255 e.g. for blue: setBgColor(0,0,255)

setFgColor( windowName, r, g, b )

Sets the current text foreground color in window windowName If the windowName parameters omitted, the main screen will be used.

setBold( windowName, bool )

Sets the current text font to bold (true) or non-bold (false) mode. If the windowName parameters omitted, the main screen will be used.

setItalics( windowName, bool )

Sets the current text font to italics/non-italics mode. If the windowName parameters omitted, the main screen will be used.

setUnderline( windowName, bool )

Sets the current text font to underline/non-underline mode. If the windowName parameters omitted, the main screen will be used.

openUserWindow( name )

Opens a user dockable console window for user output e.g. statistics, chat etc. If a window of such a name already exists, nothing happens. You can move these windows, dock them, make them into notebook tabs or float them.

openUrl ( url )

Opens the default OS browser for the given URL.

Examples:

openUrl("http://google.com")
openUrl("www.mudlet.org")

disableTimer( name )

Disables a timer from running it’s script when it fires - so the timer cycles will still be happening, just no action on them. If you’d like to permanently delete it, use killTrigger() instead.

Use timer name or the id returned by tempTimer() to identify the timer that you want to disable.

disableTrigger( name )

Use trigger name or the id returned by tempTrigger() to identify the timer that you want to disable.

disableKey( name )

Uses trigger name as id or the id returned by tempTrigger()

enableAlias(name)

Enables/activates the alias by it’s name. If several aliases have this name, they’ll all be enabled.

enableTimer( name )

enables or activates a timer that was previously disabled. The parameter "name" expects the timer ID that was returned by tempTimer() on creation of the timer or the name of the timer in case of a GUI timer

enableTrigger( name )

enables a Trigger. see enableTimer() for more details.

enableKey( name )

enable key or key group "name" (hot keys or action keys).

expandAlias( command, print=1 )

like send(), but without bypassing alias expansion. This function may lead to infinite recursion if you are not careful. This function can be used to make recursive alias expansion. expandAlias( "Hello Tom" ) echos the command on the screen expandAlias( "Hello Jane" ) sends the command visually unnoticeable by the user send

howmany = exists (name, type)

Tells you how many things of the given type exist. Type can be "alias", "trigger", or "timer".

Example:

echo("I have " .. exists("my trigger", "trigger") .. " triggers called 'my trigger'!")

You can also use this alias to avoid creating duplicate things, for example:

-- this code doesn't check if an alias already exists and will keep creating new aliases
permAlias("Attack", "General", "^aa$", [[send ("kick rat")]])

-- while this code will make sure that such an alias doesn't exist first
-- we do == 0 instead of 'not exists' because 0 is considered true in Lua
if exists("Attack", "alias") == 0 then
    permAlias("Attack", "General", "^aa$", [[send ("kick rat")]])
end

raiseEvent( event_name, arg-1, … arg-n )

Raises the event event_name. The event system will call the main function (the one that is called exactly like the script name) of all such scripts that have registered event handlers. If an event is raised, but no event handler scripts have been registered with the event system, the event is ignored and nothing happens. This is convenient as you can raise events in your triggers, timers, scripts etc. without having to care if the actual event handling has been implemented yet - or more specifically how it is implemented. Your triggers raise an event to tell the system that they have detected a certain condition to be true or that a certain event has happened. How - and if - the system is going to respond to this event is up to the system and your trigger scripts don’t have to care about such details. For small systems it will be more convenient to use regular function calls instead of events, however, the more complicated your system will get, the more important events will become because they help reduce complexity very much.

The corresponding event handlers that listen to the events raised with raiseEvent() need to use the script name as function name and take the correct number of arguments. NOTE: If you raise an event with 5 arguments but your event handlers functions only take 2,10 or 0 arguments, the functions will not be called. For example: raiseEvent("fight") a correct event handler function would be: myScript( event_name ). In this example raiseEvent uses minimal arguments, name the event name. There can only be one event handler function per script, but a script can still handle multiple events as the first argument is always the event name. So you can call your own special handlers for individual events. The reason behind this is that you should rather use many individual scripts instead of one huge script that has all your function code etc. Scripts can be organized very well in trees and thus help reduce complexity on large systems.

tempTimer( seconds, lua code ) returns timer ID, ID is a string and not a number.

Creates a temporary single shot timer and returns the timer ID for subsequent enableTimer(), disableTimer() and killTimer() calls. You can use 2.3 seconds or 0.45 etc. After it has fired, the timer will be deactivated and killed. example:

tempTimer( 0.3, [[send("kill monster")]] )

This script will send the command "kill monster" 0.3 seconds after this function has been called. Note that this function does not wait until 0.3 seconds have been passed, but it will start a timer that will run the Lua script that you have provided as a second argument after 0.3 seconds.

Note
[[ ]] can be used to quote strings in Lua. The difference to the usual `" " quote syntax is that `[[ ]] also accepts the character ". Consequently, you don’t have to escape the " character in the above script. The other advantage is that it can be used as a multiline quote, so your script can span several lines.

Also note that the Lua code that you provide as an argument is compiled from a string value when the timer fires. This means that if you want to pass any parameters by value e.g. you want to make a function call that uses the value of your variable myGold as a parameter you have to do things like this:

tempTimer( 3.8, [[echo("at the time of the tempTimer call I had ]] .. myGold .. [[ gold.")]] )

tempTimer also accepts functions (and thus closures) - which can be an easier way to embed variables and make the code for timers look less messy:

local variable = matches[2]
tempTimer(3, function () send("hello, " .. variable) end)

tempTrigger( string, lua code ) returns trigger ID, ID is a string and not a number.

This function creates a temporary trigger using substring matching. Contrary to tempTimers, tempTriggers lives throughout the entire session until it is explicitly disabled or killed. Disabled tempTimers can be re-enabled with enableTrigger(). This is much faster than killing the trigger and creating a new one. This is the second fastest trigger (with begin of line substring patterns being the fastest) and should be used instead of regex triggers whenever possible.

tempLineTrigger( from, howMany, LuaCode ) returns trigger ID, ID is a string and not a number.

Temporary trigger that will fire on n consecutive lines following the current line. This is useful to parse output that is known to arrive in a certain line margin or to delete unwanted output from the MUD. Example: tempLineTrigger( 1, 3, ) will fire 3 times starting with the line from the MUD. tempLineTrigger( 20, 2, ) will fire 20 lines after the current line and fire twice on 2 consecutive lines. The function returns the ID of the newly created temporary trigger. You can use this ID to enable/disable or kill this trigger later on.

tempRegexTrigger( regex, lua code ) returns trigger ID

temporary trigger using Perl regex pattern matching <<tempTrigger, This function returns the ID of the newly created temporary trigger. ID is a string and not a number. You can use this ID to enable/disable or kill this trigger later on. → tempTrigger()

killAlias (name)

Deletes an alias with the given name. If several aliases have this name, they’ll all be deleted.

killTimer( id ) returns true or false

Deletes a tempTimer. Use the Timer ID returned by tempTimer() as name parameter. ID is a string and not a number. This function returns true on success and false if the timer id doesn’t exist anymore (=timer has already fired) or the timer is not a temp timer. Note that non-temporary timers that you have set up in the GUI cannot be deleted with this function. Use disableTimer() to turn them on or off.

killTrigger( id ) returns true or false

Deletes a tempTrigger according to trigger ID. ID is a string value, not a number.

See also: killTimer()

openUserWindow( name )

Opens a user dockable console window for user output e.g. statistics, chat etc. If a window of such a name already exists, nothing happens. You can move these windows, dock them, make them into notebook tabs or float them. Most often a mini console is more useful than a dockable window → createMiniConsole()

x,y = calcFontSize(font_size)

This returns you the height and the length of letters for the given font size. As the primary intended usage is for calculating the needed dimensions of a miniConsole, it doesn’t accept a font argument - as the miniConsoles currently only work with the default font for the sake of portability.

Examples:

-- Create a miniConsole that is 45 letters in length and 25 letters in height for font size 7
font_size = 7

local x, y = calcFontSize( font_size )
createMiniConsole("map",0,0,0,0)
setMiniConsoleFontSize("map", font_size)
resizeWindow( "map", x*45, y*25 )

clearUserWindow( window_name )

Clears the user window or a mini console with the name given as argument.

copy()

Copies the current selection to the clipboard. This function operates on rich text, i. e. the selected text including all its format codes like colors, fonts etc. in the clipboard until it gets overwritten by another copy operation. example: This script copies the current line on the main screen to a user window (mini console) named chat and gags the output on the main screen.

selectString( line );
copy();
appendBuffer("chat");
replace("This line has been moved to the chat window!")

getLineNumber()

Gets the absolute line number of the current user cursor.

getColumnNumber()

Gets the absolute column number of the current user cursor.

getLineCount()

Gets the absolute amount of lines in the current console buffer

timestamp = getTimestamp( optional console_name, lineNumber )

Returns the timestamp string as it’s seen when you enable the timestamps view (blue i button bottom right).

Example:

Echo the timestamp of the current line in a trigger:

echo(getTimestamp(getLineCount()))

getLines( from_line_number, to_line_number ) returns a Lua table with the content of the lines on a per line basis

Returns a section of the content of the screen text buffer. The form of the return value is: Lua_table[relative_linenumber, content] Absolute line numbers are used.

Example:

— retrieve & echo the last line: echo(getLines(getLineNumber()-1, getLineNumber())[1])

getLineCount() returns number

Returns the number of the last line in the buffer.

moveCursor( windowName, x, y ) returns true or false

Moves the user cursor of the window windowName to the absolute point (x,y). This function returns false if such a move is impossible e.g. the coordinates don’t exist. To determine the correct coordinates use getLineNumber(), getColumnNumber() and getLastLineNumber(). The trigger engine will always place the user cursor at the beginning of the current line before the script is run. If you omit the windowName argument, the main screen will be used.

Example:

-- set up the small system message window in the top right corner

-- determine the size of your screen
WindowWidth=0;
WindowHeight=0;
WindowWidth, WindowHeight = getMainWindowSize();

-- define a mini console named "sys" and set its background color
createMiniConsole("sys",WindowWidth-650,0,650,300)
setBackgroundColor("sys",85,55,0,255);

-- you *must* set the font size, otherwise mini windows will not work properly
setMiniConsoleFontSize("sys", 12);
-- wrap lines in window "sys" at 65 characters per line
setWindowWrap("sys", 60);
-- set default font colors and font style for window "sys"
setTextFormat("sys",0,35,255,50,50,50,0,0,0);
-- clear the window
clearUserWindow("sys")

moveCursorEnd("sys")
setFgColor("sys", 10,10,0)
setBgColor("sys", 0,0,255)
echo("sys", "test1---line1\n<this line is to be deleted>\n<this line is to be deleted also>\n")
echo("sys", "test1---line2\n")
echo("sys", "test1---line3\n")
setTextFormat("sys",158,0,255,255,0,255,0,0,0);
--setFgColor("sys",255,0,0);
echo("sys", "test1---line4\n")
echo("sys", "test1---line5\n")
moveCursor("sys", 1,1)

-- deleting lines 2+3
deleteLine("sys");
deleteLine("sys");

-- inserting a line at pos 5,2
moveCursor("sys", 5,2);
setFgColor("sys", 100,100,0)
setBgColor("sys", 255,100,0)
insertText("sys","############## line inserted at pos 5/2 ##############");

-- inserting a line at pos 0,0
moveCursor("sys", 0,0)
selectCurrentLine("sys");
setFgColor("sys", 255,155,255);
setBold( "sys", true );
setUnderline( "sys", true );
setItalics( "sys", true );
insertText("sys", "------- line inserted at: 0/0 -----\n");

setBold( "sys", true )
setUnderline( "sys", false )
setItalics( "sys", false )
setFgColor("sys", 255,100,0)
setBgColor("sys", 155,155,0)
echo("sys", "*** This is the end. ***\n");

moveCursorEnd( windowName ) returns true or false

Moves the cursor to the end of the buffer. "main" is the name of the main window, otherwise use the name of your user window. → moveCursor()

paste(windowName)

pastes the previously copied text including all format codes like color, font etc. at the current user cursor position. The copy() and paste() functions can be used to copy formated text from the main window to a user window without losing colors e. g. for chat windows, map windows etc.

appendBuffer( name )

Pastes the previously copied rich text (including text formats like color etc.) into user window name.

Example:

selectString( line, 1 )
copy()
appendBuffer( "chat" )

showCaptureGroups()

Lua debug function that highlights in random coolors all capture groups in your trigger regex on the screen. This is very handy if you make complex regex and want to see what really matches in the text. This function is defined in LuaGlobal.lua.

Example:

Make a trigger with the regex (\w+) and call this function in a trigger. All words in the text will be highlighted in random colors.

showColors()

Displays all color names that the bg() and fg() functions know about on the main screen along with their respective colors. Very handy for seeing which name is actually what color.

showMultimatches()

Lua helper function to show you what the table multimatches[n][m] contains. This is very useful when debugging multiline triggers - just doing showMultimatches() in your script will make it give the info.

table.load( file, table )

Restores a Lua table from a data file that has been saved with table.save().

Example:

table.load(getMudletHomeDir().."/mytable.lua", mytable)

table.save( file, table )

Saves the given table into the given file.

Example:

table.save(getMudletHomeDir().."/mytable.lua", mytable)

sendAll( command1, command2, … [,true or false])

Sends a list of commands to the MUD. You can use this to send some things at once instead of having to use multiple send() commands one after another. You can also include false at the end of all arguments not to have the commands echoed back, similarly to send().

Example:

sendAll("stand", "wield shield", "say ha!")

-- instead of:
send ("stand")
send ("wield shield")
send ("say ha!")

-- send all commands quietly
sendAll("stand", "wield shield", "say ha!", false)

See also: send()

sendTelnetChannel102(msg)

Sends a message via the 102 subchannel back to the MUD (that’s used in Aardwolf). The msg is in a two byte format - see help telopts in Aardwolf on how that works.

Example:

-- turn prompt flags on:
sendTelnetChannel102("\52\1")

-- turn prompt flags off:
sendTelnetChannel102("\52\2")

replaceWildcard(which, replacement)

Replaces the given wildcard (as a number) with the given text. Equivalent to doing:

selectString(matches[2], 1)
replace("text")

Example:

replaceWildcard(2, "hello") -- on a perl regex trigger of ^You wave (goodbye)\.$, it will make

resetFormat (window)

Resets the user character format to the default. If you don’t specify a window, it’ll reset the main console - otherwise it’ll reset the specified miniConsole.

Example:

resetFormat() -- resets the format on the main window
resetFormat("chat console") -- resets the format on the specified window

playSoundFile( fileName )

This function plays a sound file. To make sound work on your operating system you may need to install additional packages:

  • Microsoft Windows: The underlying multimedia system is used; only WAVE format sound files are supported. (works out of the box)

  • Linux: The Network Audio System is used if available, otherwise all operations work silently. NAS supports WAVE and AU files.

  • Mac OS X: NSSound is used. All formats that NSSound supports, including QuickTime formats, are supported by Qt for Mac OS X. (should work out of the box)

Examples:

-- play a sound in Windows
playSoundFile([[C:\My folder\boing.wav]])

-- play a sound in Linux
playSoundFile([[/home/myname/Desktop/boingboing.wav]])

cecho (text[, )

  • name of console - optional name of the console to echo to. Defaults to main.

  • text - the text that you’d like to echo with embedded color tags. Tags take the color names only, see below for an explanation.

How text works

Color changes can be made using the format <foreground:background> where each field is one of the colors listed by showColors(). The background portion can be omitted using <foreground> or the foreground portion can be omitted using <:background>.

Examples:

cecho("Hi! This text is <red>red, <blue>blue, <green> and green.")

cecho("<:green>Green background on normal foreground. Here we add an <ivory>ivory foreground.")

cecho("myinfo", "<green>All of this text is green in the myinfo miniconsole.")

createConsole(consoleName, fontSize, charsPerLine, numberOfLines, Xpos, Ypos)

Make a new console window with ease. The default background is black and text color white.

This will create a miniconsole window that has a font size of 8pt, will display 80 characters in width, hold a maximum of 20 lines and be place at 200x400 of your mudlet window. If you wish to change the color you can easily do this when updating your text or manually somewhere, using setFgColor() and setBackgroundColor().

Example:

-- this will create a console with the name of "myConsoleWindow", font size 8, 80 characters per line and default height fr 20 lines at 200x, 400y coordinates.
createConsole("myConsoleWindow", 8, 80, 20, 200, 400)

createBuffer( name )

Creates a named buffer for formatted text, much like a user terminal window, but the buffer cannot be shown on the screen. Intended for temporary buffer work.

appendBuffer( name )

Works like paste(), but pastes at the end of the buffer/window and wraps new text automatically.

See also: paste()

number = getNetworkLatency()

returns the last measured response time between the sent command and the server reply e.g. 0.058 (=58 milliseconds lag) or 0.309 (=309 milliseconds)

number = createStopWatch()

This function creates a stop watch. It is high resolution time measurement tool. Stop watches can be started, stopped, reset and asked how much time has passed since the stop watch has been started. Returns the ID of a high resolution clock with milliseconds to measure time more accurately than what is possible with std. Lua routines → startStopWatch(), stopStopWatch(), resetStopWatch(), getStopWatchTime() example: In a global script you create all stop watches that you need in your system and store the respective stopWatch-IDs in global variables:

fightStopWatch = createStopWatch(); -- you store the watchID in a global variable to access it from anywhere

Then you can start the stop watch in some trigger/alias/script with:

startStopWatch( fightStopWatch );

To stop the watch and measure its time in e.g. a trigger script you can write:

fightTime = stopStopWatch( fightStopWatchID )
echo( "The fight lasted for " .. fightTime .. " seconds." )
resetStopWatch( fightStopWatchID );

You can also measure the elapsed time without having to stop the stop watch with getStopWatchTime()

startStopWatch( watchID )

Starts the stop watch. → createStopWatch()

stopStopWatch( watchID ) returns time as a number

Stops the stop watch and returns the elapsed time in milliseconds in form of 0.001. → createStopWatch()

resetStopWatch( watchID )

This function resets the time to 0:0:0.0, but does not start the stop watch. You can start it with startStopWatch()createStopWatch()

getStopWatchTime( watchID ) returns number

Returns the time (milliseconds based) in form of 0.058 (= clock ran for 58 milliseconds before it was stopped) → createStopWatch()

getTime(returntype, format)

returntype takes a boolean value (in Lua anything but false or nil will translate to true). If true, the function will return a table in the following format:

{ hour = #, min = #, sec = #, msec = # }

If false or nil, it will return the time as a string using a format passed to the second arg or the default of hh:mm:ss.zzz

Format expressions:

h               the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
hh              the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
H               the hour without a leading zero (0 to 23, even with AM/PM display)
HH              the hour with a leading zero (00 to 23, even with AM/PM display)
m               the minute without a leading zero (0 to 59)
mm              the minute with a leading zero (00 to 59)
s               the second without a leading zero (0 to 59)
ss              the second with a leading zero (00 to 59)
z               the milliseconds without leading zeroes (0 to 999)
zzz             the milliseconds with leading zeroes (000 to 999)
AP or A         use AM/PM display. AP will be replaced by either "AM" or "PM".
ap or a         use am/pm display. ap will be replaced by either "am" or "pm".

d               the day as number without a leading zero (1 to 31)
dd              the day as number with a leading zero (01 to 31)
ddd             the abbreviated localized day name (e.g. 'Mon' to 'Sun'). Uses QDate::shortDayName().
dddd            the long localized day name (e.g. 'Monday' to 'Qt::Sunday'). Uses QDate::longDayName().
M               the month as number without a leading zero (1-12)
MM              the month as number with a leading zero (01-12)
MMM             the abbreviated localized month name (e.g. 'Jan' to 'Dec'). Uses QDate::shortMonthName().
MMMM            the long localized month name (e.g. 'January' to 'December'). Uses QDate::longMonthName().
yy              the year as two digit number (00-99)
yyyy            the year as four digit number

All other input characters will be ignored. Any sequence of characters that are enclosed in singlequotes will be treated as text and not be used as an expression. Two consecutive singlequotes ("''") are replaced by a singlequote in the output.

*Available since Mudlet 1.0.6.

appendBuffer( name, text )

append text at the end of temp buffer name (fast function)

setWindowWrap( windowName, wrapAt )

sets at what position in the line the console or miniconsole will start word wrap

createGauge(name, width, height, Xpos, Ypos, gaugeText, color1, color2, color3)

Creates a gauge that you can use to express completion with. For example, you can use this as your healthbar or xpbar.

  • name is the gauge name. Must be unique - so don’t have two or more gauges with the same name.

  • width is the width (left to right dimensions) of the gauge.

  • height is the height (top to bottom dimensions) of the gauge.

  • Xpos is the X (so left to right) coordinate of the top-left corner of the gauge. It starts counting from the top-left corner of Mudlets window. So a coordinate of 5 will place it 5 pixels to the right from the top-left part of Mudlet.

  • Ypox is the Y coordinate of the top-left corner of the gauge, relative to the top-left corner of Mudlet.

  • gaugeText is optional text that you can have on the gauge. If you don’t want to have text, use nil in it’s place.

  • color# are the RGB color values to color the gauge with.

See also: moveGauge(), setGauge(), setGaugeText(). Examples:

createGauge("healthBar", 300, 20, 30, 300, nil, 0, 255, 0)
createGauge("healthBar", 300, 20, 30, 300, nil, "green")
-- This would make a gauge at that's 300px width, 20px in height, located at Xpos and Ypos and is green.
-- The second example is using the same names you'd use for something like fg() or bg().

-- If you wish to have some text on your label, you'll change the nil part and make it look like this:
createGauge("healthBar", 300, 20, 30, 300, "Now with some text", 0, 255, 0)
-- or
createGauge("healthBar", 300, 20, 30, 300, "Now with some text", "green")

createMiniConsole( name, posX, posY, width, height ) returns true or false

opens a console window inside the main window of Mudlet at position posX/posY with size according to width/height (values depend on your own screen resolution usually between 0-1600 for x and 0-1024 for y). This console is the ideal fast colored text display for everything that requires a bit more text e.g. status screens, log windows, chat windows etc.. You can use clearWindow/moveCursor etc. functions for this window for custom printing as well as copy & paste functions for colored text copies from the main window or normal echoUserWindow( name, text) for normal printing.

To set word wrap see setWindowWrap().

To move the main window to make room for miniconsole windows on your screen (if you want to do this as you can also layer mini console and label windows) see setBorderTop(), setBorderColor() To have your screen layout adjusted after the window size of the main screen gets resized see handleWindowResizeEvent()

Example 1:

-- set up the small system message window in the top right corner

-- determine the size of your screen
WindowWidth = 0;
WindowHeight = 0;
WindowWidth, WindowHeight = getMainWindowSize();

createMiniConsole("sys",WindowWidth-650,0,650,300)
setBackgroundColor("sys",85,55,0,255)
setMiniConsoleFontSize("sys", 8)
-- wrap lines in window "sys" at 65 characters per line
setWindowWrap("sys", 40)
-- set default font colors and font style for window "sys"
setTextFormat("sys",0,35,255,50,50,50,0,0,0)

echo("sys","Hello world!")

This script would create a mini text console called "sys" and write with yellow foreground color and blue background color "This is a test".

Example 2:

The next example is more advanced. The user Thylacine has written a tabbed chat widget on the basis of layered mini consoles and on screen buttons (labels). Each tab page holds the output of certain MUD channels e.g. All, Guild, Market, City etc.. You can click on the tab to change the tab page and read what was said in the respective channel. You can get the package here: http://mudlet.sourceforge.net/phpBB3/viewtopic.php?f=6&t=171

Note
.

createLabel( name, posX, posY, width, height, fillBackground) returns true or false

labels are intended for very small variable or prompt displays or images. labels are clickable and if you specify a callback function with setLabelClickCallback( labelName, myLabelOnClickFunction ) your function will get called if the user clicks on the label with the mouse. If fillBackground = 0, the background will be hidden, if fillBackground = 1 the background will be shown i.e. you can see the background color. labels can be transparent. You can place labels anywhere within then main display, also als overlays over the main displays e.g. for on screen buttons, micro display, etc. DON’T use labels for larger text displays because they are a lot slower than the highspeed mini consoles

Labels accept some HTML and CSS code for text formating.

Example 1:

Note
. screenshot example 1

This example creates a transparent overlay message box to show a big warning message "You are under attack!" in the middle of the screen. Because the background color has a transparency level of 150 (0-255, with 0 being completely transparent and 255 non-transparent) the background text can still be read through. The message box will disappear after 2.3 seconds.

local width, height = getMainWindowSize();
createLabel("messageBox",(width/2)-300,(height/2)-100,250,150,1);
resizeWindow("messageBox",500,70);
moveWindow("messageBox", (width/2)-300,(height/2)-100 );
setBackgroundColor("messageBox", 150,100,100,200);
echo("messageBox", [[<p style="font-size:35px"><b><center><font color="red">You are under attack!</font></center></b></p>]] );
showWindow("messageBox");
tempTimer(2.3, [[hideWindow("messageBox")]] ) -- close the warning message box after 2.3 seconds

Example 2:

Note
. screenshot example 2

This example creates a mouse clickable compass (taken from the GUI demo package. You can download this package with the image data etc. → Mudlet forum → packages section http://mudlet.sourceforge.net/phpBB3/viewtopic.php?f=6&t=95

-- define the path to the location of the images
-- this needs to be adapted to your own system e.g. "c:\images\mudimages"
-- on my linux system the folder are in my home directory in the folder gfx
gfx_path = "/home/heiko/gfx";

-- determine the size of your screen
WindowWidth=0;
WindowHeight=0;
WindowWidth, WindowHeight = getMainWindowSize();

-- create clickable compass with clickable images = labels with on click callback functions
createLabel("north",82,WindowHeight-220,50,50,1);
setBackgroundImage("north",gfx_path .. "/n.png" );
setBackgroundColor("north", 0,0,0,0);
setLabelClickCallback("north", "walk_north" )

createLabel("south",82,WindowHeight-80,50,50,1);
setBackgroundImage("south",gfx_path .. "/s.png" );
setBackgroundColor("south", 0,0,0,0);
setLabelClickCallback("south", "walk_south" )

createLabel("west",0,WindowHeight-150,55,55,1);
setBackgroundImage("west",gfx_path .. "/w.png" );
setBackgroundColor("west", 0,0,0,0);
setLabelClickCallback("west", "walk_west" )

createLabel("east",150,WindowHeight-150,50,50,1);
setBackgroundImage("east",gfx_path .. "/e.png" );
setBackgroundColor("east", 0,0,0,0);
setLabelClickCallback("east", "walk_east" )

createLabel("northeast",125,WindowHeight-190,40,40,1);
setBackgroundImage("northeast",gfx_path .. "/ne.png" );
setBackgroundColor("northeast", 0,0,0,0);
setLabelClickCallback("northeast", "walk_northeast" )

createLabel("northwest",30,WindowHeight-190,40,40,1);
setBackgroundImage("northwest",gfx_path .. "/nw.png" );
setBackgroundColor("northwest", 0,0,0,0);
setLabelClickCallback("northwest", "walk_northwest" )

createLabel("southwest",30,WindowHeight-95,40,40,1);
setBackgroundImage("southwest",gfx_path .. "/sw.png" );
setBackgroundColor("southwest", 0,0,0,0);
setLabelClickCallback("southwest", "walk_southwest" )

createLabel("southeast",135,WindowHeight-95,40,40,1);
setBackgroundImage("southeast",gfx_path .. "/se.png" );
setBackgroundColor("southeast", 0,0,0,0);
setLabelClickCallback("southeast", "walk_southeast" )

createLabel("compass",64,WindowHeight-162,75,75,1)
setBackgroundColor("compass",0,0,0,0);
setBackgroundImage("compass",gfx_path .. "/compass.png");
setLabelClickCallback("compass", "callbackTest", 1, "score", 94, 104, 99, "lastParameter" );
--setLabelClickCallback("compass", "callbackTest", 948, "qw", 49, 52 )

function callbackTest( p1, p2, p3, p4, p5, p6  )
        echo("p1="..p1.." p2<"..p2.."> p3<"..p3.."> p4<"..p4..">p5="..p5.." p6<"..p6..">");
        if p1 == 1 then
                send( p2 );
        else
                send( p2 );
        end
end

function walk_north()
        expandAlias("n;map")
        compileRoomDescription()
end

function walk_south()
        expandAlias("s;map")
        compileRoomDescription()
end

function walk_west()
        expandAlias("w;map");
        compileRoomDescription()
end

function walk_east()
        expandAlias("e;map");
        compileRoomDescription()
end

function walk_northeast()
        expandAlias("ne;map");
        compileRoomDescription()
end

function walk_northwest()
        expandAlias("nw;map");
        compileRoomDescription()
end

function walk_southwest()
        expandAlias("sw;map");
        compileRoomDescription()
end

function walk_southeast()
        expandAlias("se;map");
        compileRoomDescription()
end

Example 3 (advanced)

Note
. screenshot example 3

This is yet a more advanced demo of interactive graphical user interface programming in Mudlet on the basis of labels. Eraldo has implemented interactive icon buttons, vertical & horizontal gauges for status reports and on screen mini buttons to show status information of his character in-game that is extracted invisibly by his system and reported to the user via interactive or non-interactive icons or other graphical or textual representations. You can download the full package in the package section of the Mudlet forum at http://mudlet.sourceforge.net/phpBB3/viewtopic.php?f=6&t=865

hideWindow( name )

This function hides a mini console label. To show it again, use showWindow().

showWindow( name )

This function shows a mini console or label. To hide it use hideWindow().

resizeWindow( name, width, height )

Resizes a mini console or label to the new given width and height dimensions (in pixels).

-- resize the "my map" miniConsole to be 250 pixels wide and 600 pixels in height
resizeWindow("my map", 250, 600)

moveWindow( name, x, y )

This function moves window name to the given x/y coordinate. The main screen cannot be moved. Instead you’ll have to set appropriate border values → preferences to move the main screen e.g. to make room for chat or information mini consoles, or other GUI elements. In the future moveWindow() will set the border values automatically if the name parameter is omitted.

moveGauge (gaugeName, newX, newY)

Moves a gauge created with createGauge() to the new x,y coordinates. Remember the coordinates are relative to the top-left corner of the output window.

Example:

moveGauge("healthBar", 1200, 400)
-- This would move the health bar gauge to the location 1200, 400

setMiniConsoleFontSize( name, fontSize )

Sets the font size of the mini console.

setGauge(gaugeName, currentValue, maxValue, gaugeText)

Use this function when you want to change the gauges look according to your values. Typical usage would be in a prompt with your current health or whatever value, and throw in some variables instead of the numbers.

Examples:

setGauge("healthBar", 200, 400)

In that example, we’d change the looks of the gauge named healthBar and make it fill to half of its capacity. The height is always remembered.

If you wish to change the text on your gauge, you’d do the following:

setGauge("healthBar", 200, 400, "some text")

setGaugeText(gaugeName, gaugeText, color1, color2, color3)

Set the color and text on a custom gauge built by createGauge().

Example:

setGaugeText("healthBar", "HP: 100%", 40, 40, 40)
setGaugeText("healthBar", "HP: 100%", "red")

An empty gaugeText will clear the text entirely. Colors are optional and will default to 0,0,0(black) if not passed as args.

setTextFormat( windowName, r1, g1, b1, r2, g2, b2, bold, underline, italics )

sets current text format of window windowName: foreground color(r1,g1,b1), background color(r2,g2,b2), bold(1/0), underline(1/0), italics(1/0) A more convenient way to control the text format in a mini console is to use setFgColor( windowName, r,g,b ), setBold( windowName, true ), setItalics( windowName, true ), setUnderline( windowName, true ) etc.

Example:

createMiniConsole( "con1", 0,0,300,100);
setTextFormat("con1",0,0,255,255,255,0,1,1,1);
echo("con1","This is a test")

This script would create a mini text console and write with yellow foreground color and blue background color "This is a test".

getCurrentLine()

returns the content of the current line under the user cursor in the buffer. The Lua variable line holds the content of getCurrentLine() before any triggers have been run on this line. When triggers change the content of the buffer, the variable line will not be adjusted and thus hold an outdated string. line = getCurrentLine() will update line to the real content of the current buffer. This is important if you want to copy the current line after it has been changed by some triggers. selectString( line,1 ) will return false and won’t select anything because line no longer equals getCurrentLine(). Consequently, selectString( getCurrentLine(), 1 ) is what you need.

selectCurrentLine()

Selects the content of the current line that the cursor at. By default, the cursor is at the start of the current line that the triggers are processing, but you can move it with the moveCursor() function.

See also: moveCursor()

setBackgroundImage( labelName, imageFileName )

loads an image file (png) as a background image for a label. This can be used to display clickable images etc.

setBackgroundColor( window name, red, green, blue, transparency )

Sets rgb color values and the transparency for the given window. Colors are from 0 to 255 (0 being black), and transparency is from - to 255 (0 being completely transparent).

Note that transparency only works on labels, not miniConsoles for efficiency reasons.

setLabelClickCallback( labelName, luaFunctionName, optional any amount of arguments )

specify a Lua function to be called if the us