Manual:Using Variables in Mudlet

From Mudlet
Jump to navigation Jump to search

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 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." )

Lua variables can be either a string of letters (aka string) or a number, among a few others. They are whatever there were initially created with or what data type they can be converted to.

a = "Jim"
b = "Tom"
c = 350
d = 1

--Then you can write:

e = c + d -- and e will equal 351
e = a .. b -- and e will equal "JimTom" 
e = a .. c -- and e will equal "Jim350"

Note: You can't use a + b to concatenate string values. For this you must use the double-dot: ..

String Interpolation - the f function

However, starting with Mudlet 4.11.0 we have included the f function to perform string interpolation. This is a very fancy way of saying "replacing code in strings with their value". When you run a string through the f function then it replaces anything inside a pair of {} with the value of the variable or outcome of the expression. To expand upon the example above:

a = "Jim"
b = "Tom"
c = 350
d = 1

function simple_addition(a,b)
  return a+b
end

--Then you can write:

e = c + d -- and e will equal 351 (no change here)
e = f"{c + d}" -- end e will equal "351". This is a string, not a number, if you need to do math with e then do it like above.
e = f"{simple_addition(c,d)}" -- same as above, but shows using the function we've defined.
e = f("{a}{b}") -- and e will equal "JimTom" 
e = f"{a}{c}" -- and e will equal "Jim350"

A shrewd observer might notice that I have written the above uses of f without the usual parentheses. In Lua you can omit the () when you are only passing a single string argument to the function. It is usually considered best practice to include the () but in the case of f for interpolation I find it reads a bit better without them. As shown in the example above it works with or without them in place.

For a more 'real world' example and comparison of concatenation, f, and string.format consider the following:

-- For the following, we assume the following variables exist:
-- target which holds the target's name
-- target_health_color which is a cecho color determined elsewhere
-- target_health which is the actual health the target has.

-- this function uses the concatenation operator .. to glue strings together for display
function displayTarget()
  local msg = "\n<green>Target:<r> " .. target .. " <green>Health:<r> " .. target_health_color .. target_health
  cecho(msg)
end

-- this function does the same thing, but uses f
function displayTarget()
  local msg = f"\n<green>Target:<r> {target} <green>Health:<r> {target_health_color}{target_health}"
  cecho(msg)
end

Tables as Lists

There is another form of variables in Lua called tables which can be used for lists, arrays or dictionaries. This is explained later. For an in-depth coverage of variables in Lua take a look at a Lua tutorial e. g. this one on numbers http://Lua-users.org/wiki/NumbersTutorial and this one on strings http://Lua-users.org/wiki/StringsTutorial or this one on Lua tables http://Lua-users.org/wiki/TablesTutorial

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. The following code initializes the variable myKills (to the number 0) but only if it hasn't been initialized before. This would look like this:

if myKills == nil then    
    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.

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 ). For example:

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 "Aliases" icon. Click on the "Add Item" icon to add a new alias. Choose any name you like for your alias (e.g., "Add Enemy Alias"), and then define the following pattern for the alias: ^add enemy (.*). Next, add the following little script in the script input field below your alias:

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

Save the alias by clicking on "Save Item" and try it out by entering into the Mudlet's command input line. Aliases are explained in further detail below.

Another way to declare a list is to define its values directly. For example,

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

To remove an item from the list, you can use the function table.remove( listName, item index ).

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.

Tick the box in the variables view

Head to the variables view in the Mudlet editor and tick the box besides a variable - Mudlet will remember it between restarts now!

Saving variables.png

Saving by coding them in a script

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 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 and name 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"
}

local location = getMudletHomeDir() .. "/mychar.lua"
table.save(location, mychar)
-- sample echo to show where the file went:
echo(f"Variables saved in: '{location}'")

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

mychar = mychar or {}
table.load(getMudletHomeDir() .. "/mychar.lua", mychar)
display(mychar)
echo(f"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.