Difference between revisions of "Manual:Technical Manual"

From Mudlet
Jump to navigation Jump to search
Line 33: Line 33:
 
{{Manual:Profile and Packages}}
 
{{Manual:Profile and Packages}}
  
=Using Variables in Mudlet=
+
{{Manual: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:
 
<lua>
 
totalKills = getVariable("killedMonsters") + getVariable("killedVillains")
 
echo( "kills=" .. totalKills )
 
</lua>
 
In Mudlet, the above code translates into:
 
<lua>
 
totalKills = killedMonsters + killedVillains
 
echo( "kills=" .. totalKills )
 
</lua>
 
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:
 
<lua>
 
myKills = myKills + 1
 
</lua>
 
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:
 
<lua>
 
echo( "I have killed " .. myKills .. " monsters today." )
 
</lua>
 
 
 
Lua variables can be either a string or a number. They are whatever there were initially initialized with or what data type they can be converted to.
 
<lua>
 
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" note that you cant use a+b to concatenate string values. For this you must use ..
 
e = a .. c and e will equal "Jim350"
 
</lua>
 
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:
 
<lua>
 
myKills = 0
 
</lua>
 
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:
 
<lua>
 
if myKills == nil then    -- this code initializes the variable myKills to the number 0 if it hasn't been initialed before
 
    myKills = 0
 
end
 
</lua>
 
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:
 
<lua>
 
myEnemies = {}
 
</lua>
 
You can now add new enemies to this list by calling the Lua function <code>table.insert( listName, item )</code> e.g.
 
<lua>
 
table.insert( myEnemies, "Tom" )
 
table.insert( myEnemies, "Jim" )
 
</lua>
 
To print the contents of your enemy list on the screen you can run this script
 
<lua>
 
listPrint( myEnemies )
 
</lua>
 
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:
 
<lua>
 
table.insert( myEnemies, matches[2] )
 
echo( "Added a new enemy:" .. matches[2] .. "\n" )
 
</lua>
 
Save the alias and try. Alias are explained in detail below. Another way to declare a list is to define its values directly.
 
<lua>
 
myEnemies = { "Peter", "Jim", "Carl", "John" }
 
</lua>
 
To remove an item from the list you can use the function <code>listRemove( listName, item )</code>.
 
 
 
=== Saving Variable Values to Disc (Stub)===
 
 
 
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.
 
 
 
To be continued …
 
 
 
{{Manual:Aliases}}
 
 
 
{{Manual:Trigger Engine}}
 
 
 
{{Manual:Timer Engine}}
 
[[Category:Mudlet Manual]]
 

Revision as of 23:06, 16 January 2012

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 (command+return for mac). 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).

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.

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.

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.

Escape key - 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: <lua> echo( getMudletHomeDir() .. "\n" ) </lua> 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

Manual:Profile and Packages


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: ..

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

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.

Tables as 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 ). 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.