Lua Basics
Lua is a dynamically-typed language which is interpreted by the game when executed. It's beyond the scope of this documentation to provide a thorough lua tutorial, but there will be plenty of exaxmples. Here are a few key things to keep in mind:
Comments
You can add comments to your code in order to make the intent clearer to future readers. Please do this! You may know what the complex code in your prog does today, but when another builder has to update it 4 years from now, what do you want them know?
Comments begin with a --
and can be on their own line or after some code on the same line.
-- This is a comment on its own line. local testVar = 5 -- This is an inline comment.
Declaring Local Variables
In any program, you can define new variables. You should generally only do this inside functions registered via triggers, and always set them as a local variable to avoid unintentional conflicts with other code.
self:onSpeech("test", function(self) -- Correct. The first time you set testVar, it should have -- "local" in front. local testVar = 5 -- Incorrect. badVar hasn't been set inside this scope, so the -- program will create a "global" variable which may mess with -- any other function using a variable with the same name. badVar = 5 -- This is fine, since testVar was already declared earlier in -- the same function. This just changes it to a different value. testVar = 6 end)
If/Else Checks
Here are some examples of how to do if/else checks.
Operators
For numbers:
if someNumber == 1 -- Equals 1 if someNumber ~= 1 -- Not equals 1 if someNumber > 1 -- Greater than 1 if someNumber >= 1 -- Greater than or equal 1 if someNumber < 1 -- Less than 1 if someNumber <= 1 -- Less than or equal 1
For strings:
if someString == "Test" -- Is Test (case sensitive) if someString ~= "Test" -- Is not Test if someString -- Is not nil/empty if someString:find("Test") -- String contains Test
Else / Else If
if testVar == 1 then -- Do something elseif testVar == 2 then -- Do something else -- Do something end
Note that you always need a then
after any condition. else
does not need a then
. The last block in the if/else chain must always be ended with an end
.
Check for nil (empty) variables
local testShip = Ship.getFromName("Testing") -- Check to see if testShip is nil rather than a real ship. -- "Nil" is Lua-speak for empty/missing. It's important to check -- for because calling functions on a nil variable will error. if testShip then -- Do something because it's a real ship else -- Do something if it's not found end
You can also use if <variable> then ...
on numbers or string variables. Numbers set to 0 and strings which are empty will all act like a nil variable.
Not / Not Equals
To reverse the meaning of an if check, put not
before it:
if not testShip then -- Do something if testShip is nil end
To see if something is not equal to something else, use ~=
:
if testShip:getName() ~= "Testing" then -- Do something if testShip's name is not "Testing" end
And / Or
if testShip and testShip:getName() == "Testing" then -- Do something if the ship is non-empty and its name is "Testing" end
Normally, calling testShip:getName()
would fail if testShip was nil because you can't call functions on a nil variable. However, checking for it to be non-nil first protects us from that. It won't even bother checking the ship's name if the first condition ends up being false because the ship is nil.
if testShip:getName() == "Testing" or testShip:getName() == "Other" then -- Do something end
Calling functions
There are two main types of functions: Those which you can call globally, and those which you can call from a variable.
Invoking an object is an example of a global function. These usually look like TypeName.functionName(args)
- note the period.
If, instead, you already have an object variable and you want to get its name, you could call myObject:getName()
. Note the colon. Calling a function on a variable always goes like <var name>:<function>
. myObject.getName()
, with a period instead, would complain that there is no such function.
To see what functions are available on a given variable, go to the relevant module on the sidebar.
Constructing Strings
You can construct strings using other variables by using ..
to concatenate them (join them together). For example:
local firstName = "Han" local lastName = "Solo" -- This will result in "Hello, Han Solo" local greeting = "Hello, "..firstName.." "..lastName
The variables don't all have to be strings. You can put numbers in the string in the same way.
If you want to put a double quote in a string, you'll need to escape it using \. For example:
local greeting = "Hello, \"Han Solo\""
Code Blocks (Scopes)
Like most programming languages, Lua is constructed of blocks of code. All the code inside a function is a block. You can nest other blocks inside that, like if/else statements. You must indicate when each block is done, usually with end
.
Each block is considered a "scope" for variables. If you declare a variable inside a block, it can be used or updated inside that block or any block inside it.
self:onSpeech("test", function(self, ch, fullText) -- Available anywhere after this line in the function local mainVar = 5 if fullText:find("red") then local redVar = 6 -- Here, we could use either mainVar or redVar. end -- We could not use redVar here, since its block has ended end)
Indentation
For readability, it's also best to indent all of the code inside a block so it's clear when it begins and ends.
Consider this example:
self:onSpeech("test", function(self, ch, fullText) if ch:getName() == "Tester" then if ch:getTopLevel() > 50 then ch:echoAt("You said test and you're high-level!") else ch:echoAt("You should get to level 50 first.") end else ch:echoAt("Who are you?") end end)
There's a function with a couple levels of if/else blocks inside, but at a glance it's difficult to see how the program flows. Now, with indentation:
self:onSpeech("test", function(self, ch, fullText) if ch:getName() == "Tester" then if ch:getTopLevel() > 50 then ch:echoAt("You said test and you're high-level!") else ch:echoAt("You should get to level 50 first.") end else ch:echoAt("Who are you?") end end)
Now it's much easier to see what happens if their name is "Tester" and what happens otherwise.
When editing your code, be sure to indent with spaces, since the mud won't recognize tabs. Preferably, use two spaces instead of four, since the game's limited line lengths put space at a premium. These are preferences you can set in any code editor.
To save space, you can also write simple blocks on one line, but you still need to note the end of it.
-- This would exit a function early (return) if the if not ch then return end
Loops
You can run a block a number of times by using a for
loop. When running it a number of times, it's common to use i
as the variable indicating which iteration you're on.
-- This loop will run 10 times and print a message each time for i = 1, 10 do LOTJ.log("In iteration "..i) end
Sometimes you have a list of things you want to loop over rather than a fixed number. For example, you might want to loop over every ship in a starsystem. In that case, the syntax looks like this:
local system = <some starsystem> for ship in system:ships() do -- "ship" is now a local variable which you can use in this block LOTJ.log("Ship in system is"..ship:getName()) end