Lua/Basics

From SRB2 Wiki
< Lua
Jump to: navigation, search
ToDoIcon.png To do
Make this page primarily about Lua syntax, if possible

Operations and symbols

Red text is used to denote operations that have been added to SRB2's syntax; ergo, are not a part of vanilla Lua implementations.

Arithmetic
Operation Symbol(s)
Addition +
Subtraction -
Multiplication *
Division /
Modulo
(Remainder)
%
Exponentiation
(To the power of)
^
Bitwise
Operation Symbol(s)
AND &
OR |
XOR ^^
NOT ~
!
Left Shift <<
Right Shift >>
Comparison
Operation Symbol(s)
Equals check ==
Not Equals ~=
!=
Less Than <
Greater Than >
Less Than/Equals <=
Greater Than/Equals >=
Strings
Operation Symbol(s)
String formatting (short) "string"
'string'
String formatting (long) [[string]]
[=[string]=]
[==[string]==]
etc
Concatenation (separated) "string1"..variable.."string2"
"string1"+variable+"string2"
Concatenation (within strings) "string1 \$variable\ string2"
Misc.
Operation Symbol(s)
Assignment =
"Len"
(Length)
#
End of line
(optional)
;
"Dots"
(Variable list of arguments)
...

Comments

Comment type Syntax
Short comment
(affects only the rest of the line)
-- comment
// comment
Long comment
(affects all of the space between the two ends)
--[[ comment ]]
/* comment */

Escape sequences (\)

The \ (backslash) character followed by one of certain other characters creates an escape sequence. Escape sequences are typically used within strings, where it is normally impossible to use the characters themselves directly in a Lua script.

Escape sequence Use
\a Bell (has no effect in SRB2)
\b Backspace (has no effect in SRB2)
\f Form feed (has no effect in SRB2)
\n New line
\r Carriage return
\t Horizontal tab
\v Vertical tab (has no effect in SRB2)
\\ Backslash
\' Apostrophe/Single quote
\" Quotation marks/Double quote
Character input
\<number> ASCII input (decimal)
\x<hex> ASCII input (hexadecimal) (should have either 2 or 4 digits after)
\u<hex> UTF-8-encoded Unicode input (should have either 4 or 6 digits after)

If a number up to 3 digits long is placed after the \ character, Lua interprets this as an escape sequence encoded in ASCII – for example, \97 or \097 will result in the 'a' character. This can be used for obfuscation, as the game will interpret the code as whatever character is mapped to it.

Alternatively, the escape sequences \x and \u can be used to place characters hexadecimally, as raw hex literals or UTF-8-encoded Unicode respectively.

Types of variables

There are various types of variables that are available to Lua, all of which are detailed below (The function type() can be handy for checking the variable type, as it outputs a string displaying the type!):

  • number: self-explanatory, though floats are not available for SRB2's Lua meaning numbers like "1.5" do not work in Lua, only whole-value numbers
  • string: this is just plain text, which can be printed to the console or otherwise; usually written in the format "string", though 'string' and [[string]] are available as alternative string formats. Concatenation is used to link two or more strings or a mix of strings and other variable types together
  • boolean: can be true or false. These are typically used for truth checking such as in if statements (a "nil" value traditionally also acts as "false" in some situations, however SRB2's Lua additionally allows 0 to be used for "false" as well)
  • table: contains a number of values in a single variable, such as in local table = {a,b,c,d,e}
  • nil: not a number, not equal to 0, not ANYTHING whatsoever, just *nil*. When no value is given to a newly created variable, this is typically the default type set (C's NULL is similar in function to this, but in C NULL is only meant for blank pointers)
  • function: functions can also be treated as variables in some situations, in some cases even created (see the Creating functions section). Keep in mind the difference between setting a variable's value to be equivalent to an existing function and setting a variable's value to the result of a function: local func = functionname will make using func be exactly the same as using functionname itself, so func() would be the same as functionname(); local result = functionname() however will only give the result of functionname() after the contents of which have been run
  • userdata: misc. structures from SRB2's source code itself available to be accessed/modified, in general these are similar to tables; see Lua > Userdata types for the full list.

Variable assignment

Creating new "local" variables

These can be in general created in or outside of functions or other blocks for general use within them, as long as they are defined before their actual usage. However, they cannot be used outside of the block(s) they live inside, as they are local to said block, hence the name of the keyword used in the examples below.

To make a "global" variable for the entire script, one could create a local variable right at the top of a Lua script outside of everything else. However, this variable's value may not be kept consistent during netgames (if it is changed at all) without use of the "NetVars" Lua hook (Note: this hook is untested, and may not work properly).

Syntax for usage of creating new variables using "local":

  • With no value set: local name
  • With a value set: local name = value
  • Creating multiple new values: local name1,name2 = value1,value2
    • in this example, name1's value is value1 and name2's is value2.
    • this works for all further numbers of variables being set in the same line, though this will become long quickly.
  • Blank table: local name = {}
  • Table of values: local name = {value1, value2, value3, value4}
    • in this example, name[1] is the same as value1, name[2] is value2, etc. Contrary to C, the first entry number of Lua-created tables is 1 rather than 0.
  • Table of keys with values: local name = {a = value1, b = value2, c = value3, d = value4}
    • in this example, name.a (or name["a"]) is the same as value1, and similar for b, c and d.
  • Blank string: local name = ""
  • String: local name = "text"
  • Userdata pointers: local mymobj = mobj (assuming mobj was already defined beforehand!)
    • in this example mymobj would be exactly the same as mobj, allowing e.g. mymobj.type to work as long as mobj is actually a mobj_t variable.
  • Functions can also be defined this way (see the Creating functions section): local name = function(argument) contents of function end


  • Another trick for variable assignment is to assign either one of two values depending on whether each value checked in order is valid, using the "or" keyword:
local name = true or false
local name = false or true
    • in both examples "true" is picked out of the two possible values; in the first case "true" is not false/nil/0 so it is chosen, and in the second case "false" is obviously false so the second value (which is "true") is picked out of the two.
  • The "not" keyword can invert a boolean type variable:
local name = not true
    • in this example name becomes the inverse of the value "true" (which is false)
local name = not false
    • in this example name becomes the inverse of the value "false" (which is true)
  • The "and" keyword meanwhile works as an inverse of "or"; if the first value checked in order is not false, nil or 0, the second value is chosen, otherwise the first value is chosen:
local name = true and false
local name = false and true
    • in both examples "false" is picked out of the two possible values; in the first case "true" is clearly not false/nil/0 so the second value is chosen (which is "false"), and in the second case "false" is obviously false so is picked out of the two again!

Creating custom variables for existing structs/userdata

mobj.newvar = value

When the above is done, if newvar or the wanted variable name doesn't already exist for the structure, mobj in this example, this will automatically be created and given the new value when run. Otherwise this works the same way as using the "local" keyword.

Be warned though; if these are used in certain ways before they actually exist yet (mainly if newvar happens to be a structure such as mobj_t itself, and e.g newvar.target is used), Lua will print errors in the console and remove the hook the event happened in.

This issue can be prone to happen if a Lua script is loaded mid-level, and e.g custom variables for userdata/structures are initialised in a place that as a result hasn't happened such as "MobjSpawn" hooks for MT_PLAYER or "MapLoad".

Existing userdata types that can be given custom variables:

  • mapheader_t can be supplied custom variables via SOC lumps (such as in the MAINCFG), where custom variable names should be prefixed with LUA. in a map's level header; they should also explicitly be referred to in all-lowercase in Lua scripts to be recognised properly.

Modifying existing variables

  • Syntax:
variable = newvalue
  • Assigning multiple new values to existing variables:
variable1,variable2 = value1, value2
  • Setting a new value by doing an operation on the old value, e.g addition:
variable = variable + value
  • Pseudo-numbers can be used as shortcuts for the values being modified:
variable = $ + value
    • Here "$" is a pseudo-number representing the original value of the variable being modified.
  • This works with multiple-variable assignment also:
variable1, variable2 = $ + value1, $ - value2
    • here "$" represents variable1 in the first case, and then variable2 in the second.
  • "$1", "$2", "$3" and further can be used when it is necessary to refer to specific variable numbers during assignment, most useful for crossing over the variables with each other:
variable1, variable2 = $2, $1
    • Here "$1" reprsents variable1 and "$2" represents variable2; in this instance the two variables' values are effectively swapped over!


  • Just as with creating new variables with "local", the "or", "not" and "and" keywords can be used in assignments involving already existing variables, in the same fashions as shown previously.

Table manipulation

For the examples here table is the name of the example table, with contents {a = value1, b = value2, c = value3, d = value4}

Let's say extra constants are defined in this, such as local VALUEA, VALUEB, VALUEC, VALUED = 1,2,3,4

  • table[i] = value of entry i, e.g table[1] would return value1.
    • table[VALUEA] would in this instance be the same as table[1], which is also value1
    • table["a"] would return the value of "a" as set above, which also is value1.
  • #table = number of entries in table, e.g this will return 4 in this example.
  • #table[i] = entry number of table[i]'s value, e.g table[1] will return 1.
    • the above example would be rather pointless however, this is more useful in cases such as #table[VALUEA] or #table["a"] (both also equal to 1), where the entry number isn't clear from the start.

See also the Table library functions ([[Lua/Functions > Table library|Lua/Functions > Table library]]).

Functions

Creating functions

  • Creating a new "local" function:
local function FunctionName(argument)
 
	//contents of function
 
end
    • Functions can also be created without "local", this allows them to be used outside of the Lua script they were defined in (this works only for creating custom functions beginning with the A_ prefix[confirm? – discuss], allowing them to be used in SOCs as actions):
function GlobalFunctionName(argument)
 
	//contents of function
 
end
  • Creating a new function with multiple arguments:
local function FunctionName(argument1, argument2)
 
 	//contents of function
 
end
  • With no parameters:
local function FunctionName()
 
 	//contents of function
 
end
  • Creating a "prototype" variable to be defined as a function later (for situations involving using a function before actually defining it properly):
local FunctionName
 
 
//[code in-between the two parts]
 
 
function FunctionName(argument1, argument2, [etc])
 
 	//contents of function
 
end
  • Implicitly creating a function, with no arguments. This can freely be made standalone anywhere inside functions or even outside of everything else, so to contain various sections of code if needed.
do
 
	//contents of function
 
end
  • Implicitly creating a function standalone, with arguments (should only be used within a function that requires a function as an argument, e.g addHook or COM_AddCommand)
function(argument1, argument2)
 
	//contents of function'
 
end
  • Functions can also be made as local variables defined using implicitly created functions as above:
local name = do /*contents of function*/ end
    • or
local name = function(argument1, argument2) /*contents of function*/ end
  • Functions can also be tied to tables (including userdata such as mobj_t) in either of two ways:
function myTable.FunctionName(argument1, argument2)
 
	//contents of function
 
end
    • Alternative version:
function myTable:FunctionName(argument1, argument2)
 
	//contents of function
 
end

Note the change from "." to ":" in the syntax, this allows the table itself to be used and modified inside the function, but the name is forced to be "self" whether you like it or not.

Note that any created arguments do not need to have any particular name whatsoever (aside from the one case above), nor do they need to be of any set variable type in most cases. There is exception to functions needed by functions such as addHook and COM_AddCommand as arguments, where the functions requested are to have up to a specific number of arguments which are to be used as certain variable types, but the names are still flexible when defining the functions; it's the ordering and variable types that matter most in this situation.

Functions can also be defined within functions themselves, though this renders them unusable outside of these areas.

Returning

The "return" keyword is very useful in the context of functions; they are frequently needed inside them to end a function before the rest of it can run, AND perhaps even "return" a final value for the function to essentially output for use.

  • return value – the function returns a single value for the function's output. This can be any type of value; a number, string, table/userdata pointers, true/false, or perhaps just nil.
  • return – this is the same as using return nil; the function returns essentially nothing.
  • return value1, value2 – returns multiple values for the functions's two outputs. This can be extended to further numbers of output variables, which can all be assigned to separate variables if needed.

Calling functions

  • Calling a function standalone, usually best for functions that don't return any value at all (or don't return any values you currently need).

FunctionName(argument)

  • Functions that need multiple arguments work exactly the same way:

FunctionName(argument1, argument2, [etc])

  • As do functions that need no arguments whatsoever:

FunctionName()

  • For functions that return an output value of some sort, you can utilise them as such (works with both creating new variables or modifying an existing variable's value):
    • local variable = FunctionName(argument1, argument2, [etc])
    • variable = FunctionName(argument1, argument2, [etc])
  • For functions that return multiple output values:

variable1, variable2 = FunctionName(argument1, argument2, [etc])

    • variable1 will be set to the function's first output value, and variable2 to the second output.
    • if only, say, the first output of the function is needed, the function can be just treated as if it had only a single variable as above.
    • however, if you need the second output and NOT the first output, it is common practise to use "_" as a "dummy" variable (which still has to be created as a typical variable), used as such:
_, variable2 = FunctionName(argument1, argument2, [etc])
    • this trick can be further used to miss out variables rather than the first, such as with a function that returns 3 values but from which you need only the first and third:
variable1, _, variable2 = FunctionName(argument1, argument2, [etc])
  • Functions tied to tables work much the same way as everything above:
    • table.FunctionName(argument1, argument2, [etc])
    • table:FunctionName(argument1, argument2, [etc])
    • variable = table.FunctionName(argument1, argument2, [etc])
    • and so on and so on...

Variable argument count

The ... keyword can be used as an argument definition in functions to retrieve an undetermined number of args after the ones defined explicitly:

local function FunctionName(arg1, arg2, ...)

Inside the function, ... refers to all arguments beyond explicitly-defined arguments in functions. {...} can be used to get these arguments as a table.

Sample function, using print() messages to display the arguments' values in the console:

local function batchecho(player, ...)
	local arg1, arg2, arg3 = ...
	print("arg1 is "+arg1)
	print("arg2 is "+arg2)
	print("arg3 is "+arg3)
	print("Now printing all args...")
	for _,i in ipairs({...}) do
		print(i)
	end
end
 
COM_AddCommand("batchecho", batchecho)

Functions that do this can essentially take any number of arguments beyond the explicitly defined ones as needed, which will all be lumped together into ... when the function itself is run. For instance, in the example above, any number of arguments can be typed after "batchecho" in the console, such as "batchecho 1 2" or "batchecho a b c"

If statements

Often we'll need to check if something is true or not before doing something, so these are important to know about:

  • Single if statement block:
if condition
 
	//contents to run if condition is true
 
end
  • Linked if statement blocks (examples of both "elseif" and "else" usage here):
if condition
 
	//contents to run if condition is true
 
elseif othercondition
 
	//contents to run if othercondition is true
 
else
 
	//contents to run if neither are true
 
end
  • Usage of "and" keyword, for requiring multiple conditions to be true:
if condition1 and condition2
 
	//contents to run if both condition1 AND condition2 are true
 
end
  • Usage of "or" keyword, for requiring one (or both) of two conditions to be true:
if conditiona or conditionb
 
	//contents to run if conditiona OR conditionb are true (can be both)
 
end
  • Usage of "not" keyword, for inverted conditions:
if not condition
 
	//contents to run if condition is NOT true
 
end
  • Examples of mixed usage of "and", "or" and "not" keywords:
if condition1 and not condition2
 
	//contents to run if condition1 is true AND condition2 is NOT true
 
end
if condition1 or not condition2
 
	//contents to run if condition1 is true OR condition2 is NOT true
 
end
if condition1 and (condition2a or condition2b)
 
	//contents to run if condition1 is true AND either of condition2a OR condition2b is true
 
end
if condition1 or (condition2a and condition2b)
 
	//contents to run if condition1 is true OR both condition2a AND condition2b are true
 
end
  • Watch out with these last two, the comments are entirely correct:
if not (condition1 or condition2)
 
	//contents to run if both condition1 AND condition2 are NOT true
	//if either condition1 OR condition2 are true the whole condition would be false
 
end
if not (condition1 and condition2)
 
	//contents to run if either of condition1 OR condition2 are NOT true
	//if both condition1 AND condition2 are true the whole condition would be false 	
 
end

For loops and other iterators

Numeric For loops

  • Simple numeric "for" loop, this runs the content inside a number of times for as long as a newly created variable "i" is between numbers a and b. The value of "i" will start at a and increase by 1 each time until after running the loop for i = b. The loop will then be finished.
for i = a,b
 
	//content to be iterated from all values of i from i = a to i = b
 
end
  • A for loop with a step number "c" specified. This can be used to skip every other number if needed:
for i = a,b,c
 
	//content to be iterated from all values of i from i = a to i = b, adding c to the value of i each time
 
end

Keywords for For loops

  • The keyword "break" can be used to break out of (stop) a loop completely, before it has finished running the code every single time needed:
for i = 0,10
 
	//content to be iterated from all values of i from i = 0 to i = 10
	//...except that the loop finishes at i = 5, as the loop is broken with the code below
 
	if i == 5
		break
	end
end
  • SRB2's Lua supports use of the keyword "continue", which skips the remainder of a loop for one value and starts the next. If the next is out of the range this simply means the loop is done:
for i = 0,10
 
	if i == 5
		continue
	end
 
	//this will print all values 0 to 10 in the console
	//the exception of course is 5, because the loop skips to the next value above before print(i) is reached
 
	print(i)
 
end
  • SRB2's Lua also supports use of "break N", N being the number of loops to break out of:
for i = 0,10
 
	//content to be iterated from all values of i from i = 0 to i = 10
 
	for j = 0,10
 
		//content also to be iterated from all values of j from j = 0 to j = 10, for every value of i
		//however, the code below breaks out of 2 loops, stopping both the j block and the i block at i = 5, j = 5
		//in other words this just stops everything going on here
 
		if i == 5 and j == 5
			break 2
		end
	end
end

while/repeat

  • "while" loops, runs a loop until the starting condition is false:
while condition
 
	//contents of loop
 
end
  • "repeat" loops, runs a loop until the ending condition is true:
repeat
 
	//contents of loop
 
until condition

Non-numeric For loops

The general syntax for generic, non-numeric iterators is this:

for var1,[extravars...] in function, state, start
 
	//contents of loop
 
end
  • var1 and [extravars...] are locally created variables that will be available to use within the loop's contents:
    • var1 is important in that it is used as a "key" within the iterator function (function), starting at the value of start until function no longer returns anything, which will stop the loop from running.
    • [extravars...] here represents the rest of the variables following var1 (i.e. [extravars...] could be var2, var3, var4 ... varN).
Note that "local var1" and so on are not required beforehand, though the variables will cease to exist once the loop has finished unless this is done.
  • start is the starting value of var1 for the iteration.
  • state is an extra value related to the function. Depending on what function does this could be anything; e.g a table containing all the entries to run through, or a limit to the number of times the iterator is run.
  • function is the function to be run, with the state value and the current value of var1 (the "key") as its arguments (i.e function(state, var1) is continuously run for as long as it has a return value). The return values should be the variables (var1 and [extravars...]) for use within the loop's contents.

More commonly a function is used in place of function, state, index, assuming it returns all three. Here is an example with a locally created function called iteratorfunc(a, b), with a function f(s, v), a state value of c and a start value of d:

local function iteratorfunc(a, b)
	local f = function(s, v)
		//function contents
	end
 
	local state = c
	local start = d
 
	return f, state, start
end
for var1 in iteratorfunc(1, 2)
 
	//contents of loop
 
end

Note that iteratorfunc will be run once only , unlike its function return value which will be run for as long as it returns any values at all.

pairs and ipairs

These functions are commonly used for iterating through tables:

for k,v in pairs(myTable)
 
	//contents of loop
 
end
for k,v in ipairs(myTable)
 
	contents of loop
 
end

pairs() and ipairs() largely work in the same way; k is the entry number of an entry in the table (or the "key"), and v is the actual value of that entry in the table. The main difference is that ipairs() loops are for ordered lists, and pairs() loops are for unordered lists. ipairs() loops are run from the first entry (k = 1) onwards until the entry being checked is nil, but pairs() loops will run through all entries in the table whether they are nil or not.

Example uses:

do
	local emlist = {MT_EMERALD1, MT_EMERALD2, MT_EMERALD3, MT_EMERALD4, MT_EMERALD5, MT_EMERALD6, MT_EMERALD7}
 
	for _,i in ipairs(emlist)
		mobjinfo[i].deathsound = sfx_ncitem
	end
end

Here the ipairs() loop above will change the DeathSound of every emerald object type's SOC infotable to the sound of NiGHTS Wing Logos when collected (sfx_ncitem). _ represents the key of each entry here, but it is clear we do not need its value in any case; meanwhile, i for each entry here is an object type number, which is far more useful of course – mobjinfo[i].deathsound will then be mobjinfo[MT_EMERALD1].deathsound, then mobjinfo[MT_EMERALD2].deathsound, mobjinfo[MT_EMERALD3].deathsound, and so on.

do
	local props = {
		spawnstate = S_INVISIBLE,
		flags = MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT
	}
 
	for k,v in pairs(props)
		mobjinfo[MT_RING][k] = v
	end
end

Here the pairs loop above changes specific object type infotable properties of MT_RING so that rings will become invisible and untouchable. The table props is set up so "spawnstate" and "flags" are keys with a value each; k can then act as the name of the property to change each time, and v the new value of the property to change. mobjinfo[MT_RING][k] = v will then be mobjinfo[MT_RING]["spawnstate"] = S_INVISIBLE and mobjinfo[MT_RING]["flags"] = MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT respectively.

Special iterators

SRB2 provides extra iterator functions beyond the base Lua library, specifically designed to run through lists of userdata (most commonly for objects or players). These are generally in the format:

for name in list.iterate
 
	//contents of loop
 
end

list is the list being iterated through (only specific ones can be used, with ".iterate" required to iterate through them), name is the variable name for each of the items in the list to perform the contents of the loop on.

Uniquely for thinkers.iterate, an argument is also provided in the iterator function itself, for determining which thinkers to run through:

  • thinkers.iterate("mobj") will exclusively output only mobj_t userdata, all others are skipped
  • thinkers.iterate("all") will run through all thinkers; however, only mobj_t userdata is of any use as other thinker types will just output "light" userdata which is generally useless for these purposes

Uniquely also for sector_t userdata, sector.ffloors() and sector.thinglist() (for an example sector_t userdata variable "sector") also can be iterated through – sector.ffloors() will iterate though all FOFs (ffloor_t) in the sector, and sector.thinglist() through all Objects (mobj_t) in the sector.

Metatables, metatable events and metamethods

(See this page for a fairly good explanation of what these do)

  • Events = metatable keys
  • Metamethods = values for metatable keys

Syntax for creating metatables:

local metatable = {__event = value}
local metatable = {__event1 = value1, __event2 = value2}

Individual events can be modified afterwards:

metatable.__event = newvalue

...or have their metamethods assigned to other variables when appropriate:

local var = metatable.__event

If the event has a function for a metamethod, the function may be called as such:

metatable.__event(arguments)

setmetatable is used to apply a metatable to a table:

local myTable = {}
local metatable = {__event = value}
 
setmetatable(myTable, metatable)

The metatable can alternatively be applied implicitly:

local myTable = {}
 
setmetatable(myTable, {__event = value})

The metatable can also be applied on the same line the table is created in, as setmetatable then returns the table given (here {} is used as a dummy table):

local myTable = setmetatable({}, {__event = value})

getmetatable can be used to retrieve the metatable for a table or other variable type (if any is set):

local metatable = getmetatable(myTable)

getmetatable can check the metatable of any type of value, rather than just tables, but will return nil if no metatable is set whatever the case.

After retrieving the metatable of the variable this way, modifying the metatable will directly affect the metatable for the variable itself!

Any metatables with the metatable event __metatable set will not be modifiable or retrievable – getmetatable will return the value of __metatable instead of the metatable, while setmetatable will print an error in the console!

List of events

For any examples below, "a" represents the variable the metatable events are applied to. "b" may be a second variable for use in binary operations such as addition or subtraction.

Name Event Type of value Further details
Table indexes
__index Accessing an index/value from a key/variable (a.key or a[key]) any function(a, key)
or table
  • __index is highly useful for allowing a table to fallback on another table if a variable/key doesn't exist in the first, i.e. inheritance. This is used as a backbone for "Object orientated programming" in Lua (see this page for more info).
  • As a reminder, a.key is the same as a["key"]; i.e. key from a.key is a variable of type string in this situation.
  • If a fallback table is used, this table's own keys will be checked – if it doesn't exist there, the table's own __index will be triggered if it has one (this can lead to a long chain of tables falling back on each other).
__newindex Assigning an index/value to a new key/variable
(a[key] = value or a.key = value, old value is nil)
void function(a, key, value)
or table
  • If a fallback table is used, this table's own keys will be checked – if it doesn't exist there, the table's own __newindex can be triggered if it has one; if it does already the table's own __usedindex will be triggered instead if it has one (this can lead to a long chain of tables falling back on each other).
  • The index/value is assigned to a fallback table's keys only if the fallback table has neither __newindex nor usedindex set.
__usedindex Assigning an index/value to an existing key/variable
(a[key] = value or a.key = value, old value is not nil)
void function(a, key, value)
or table
  • This metamethod is unusable for non-tables
  • If a fallback table is used, this table's own keys will be checked – if it doesn't exist there, the table's own __newindex can be triggered if it has one; if it does already the table's own __usedindex will be triggered instead if it has one (this can lead to a long chain of tables falling back on each other).
  • The index/value is assigned to a fallback table's keys only if the fallback table has neither __newindex nor usedindex set.
Arithmetic
__add Addition (a + b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__sub Subtraction (a - b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__mul Multiplication (a * b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__div Division (a / b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__mod Modulus (a % b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__pow Exponentation (a ^ b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__unm Unary negation ( -a ) any function(a)
__len Length ( #a ) any function(a)
Comparison
__eq Equals check (a == b) any function(a, b)
  • Both tables MUST share the same metamethod for __eq for the function to be run.
__lt Less-than (a < b)
or Greater-than (b > a)
any function(a, b)
  • Greater-than operations are done by flipping the order of a and b so it is treated as a Less-than operation.
  • Both tables MUST share the same metamethod for __lt for the function to be run.
  • __lt may also be run for less than operations if a __le metamethod does not exist for both a and b (or they do not share the same __le metamethod).
  • In the above situation, a <= b is checked as b > a, and b >= a as a < b.
__le Less-than-or-equals (a <= b)
or Greater-than-or-equals (b >= a)
any function(a, b)
  • Greater-than-or-equals operations are done by flipping the order of a and b so it is treated as a Less-than-or-equals operation.
  • Both tables MUST share the same metamethod for __le for the function to be run.
Bitwise operations
__and Bitwise AND (a & b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__or Bitwise OR (a | b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__xor Bitwise XOR (a ^^ b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__shl Left shift (a << b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__shr Right shift (a >> b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__not Bitwise NOT ( ~a ) any function(a)
Misc
__concat Concatenation (a..b) any function(a, b)
  • This operation can be done even when the other value doesn't share the same metamethod or doesn't have one.
  • if a doesn't have a metamethod, b's metamethod is used instead.
  • a is always the first argument in the function, and b the second, even if b's metamethod is the one called.
__tostring Conversion to string using tostring string function(a)
  • Lua will pass the table itself to the function set for __tostring, so it can determine the final result (which should be a string).
__strhook Userdata-to-string masquerading function(???) This metamethod is unusable for non-userdata
__call Calling as a function (a([args])) any function(a, [args]) This is used to treat a non-function variable like a function when parenthesis follows it as shown
__gc Garbage collection for userdata function(???) This metamethod is unusable for non-userdata
__mode Weak references handling string Flags for the table are set if certain letters are present in the string:
  • "k" – keys are marked as "weak"
  • "v" – values are marked as "weak"
__metatable Metatable protection any This affects modification/retreval of metatables:
  • getmetatable will return the value set for __metatable instead of the metatable itself.
  • setmetatable will print an error in the console instead of setting a new metatable to the table.

List of existing metatables

Name/type of variable Metamethods set
Userdata
(mobj_t)
  • __index -> mobj.var
  • __newindex -> mobj.var = value
(player_t)
  • __index -> player.var
  • __newindex -> player.var = value
  • __len -> #player
player.powers
(player is player_t)
  • __index -> player.powers[pw_powername]
  • __newindex -> player.powers[pw_powername] = value
  • __len -> #player.powers
(ticcmd_t)
  • __index -> ticcmd.var
  • __newindex -> ticcmd.var = value
(skin_t)
  • __index -> skin.var
  • __newindex -> warning message to state skin_t cannot be modified
  • __len -> #skin
skin.soundsid
(skin is skin_t)
  • __index -> skin.soundsid[SKSNAME]
  • __len -> #skin.soundsid
(mobjinfo_t)
  • __index -> info.var
  • __newindex -> info.var = value
  • __len -> #info
(state_t)
  • __index -> info.var
  • __newindex -> info.var = value
  • __len -> #info
(sfxinfo_t)
  • __index -> info.var
  • __newindex -> info.var = value
  • __len -> #info
(hudinfo_t)
  • __index -> info.var
  • __newindex -> info.var = value
  • __len -> #info
(mapthing_t)
  • __index -> mthing.var
  • __newindex -> mthing.var = value
(sector_t)
  • __index -> sector.var
  • __newindex -> sector.var = value
  • __len -> #sector
sector.lines
(sector is sector_t)
  • __index -> sector.lines[i]
  • __len -> #sector.lines
(subsector_t)
  • __index -> subsector.var
  • __len -> #subsector
(line_t)
  • __index -> line.var
  • __len -> #line
line.sidenum
(line is line_t)
  • __index -> line.sidenum[i]
(side_t)
  • __index -> side.var
  • __newindex -> side.var = value
  • __len -> #side
(vertex_t)
  • __index -> vertex.var
  • __len -> #vertex
(ffloor_t)
  • __index -> ffloor.var
  • __newindex -> ffloor.var = value
(mapheader_t)
  • __index -> mapheader.var
  • __len -> #mapheader
(camera_t)
  • __index -> camera.var
(consvar_t)
  • __index -> consvar.var
(patch_t)
  • __index -> patch.var
  • __newindex -> warning message to state patch_t cannot be modified
(colormap)
  • __index -> warning message to state colormap is not a struct
Tables
mobjinfo
  • __index -> mobjinfo[MT_NAME]
  • __newindex -> mobjinfo[MT_NAME] = { }
  • __len -> #mobjinfo
states
  • __index -> states[S_NAME]
  • __newindex -> states[S_NAME] = { }
  • __len -> #states
S_sfx
or sfxinfo
  • __index -> sfxinfo[sfx_name]
  • __newindex -> sfxinfo[sfx_name] = { }
  • __len -> #sfxinfo
sprnames
  • __index -> sprnames[SPR_NAME] or sprnames["NAME"]
  • __len -> #sprnames
players
  • __index -> players[i]
  • __len -> #players
skins
  • __index -> skins[i] or skins["name"]
  • __len -> #skins
mapthings
  • __index -> mapthings[i]
  • __len -> #mapthings
vertexes
  • __index -> vertexes[i]
  • __len -> #vertexes
lines
  • __index -> lines[i]
  • __len -> #lines
sides
  • __index -> sides[i]
  • __len -> #sides
subsectors
  • __index -> subsectors[i]
  • __len -> #subsectors
sectors
  • __index -> sectors[i]
  • __len -> #sectors
mapheaderinfo
  • __index -> mapheaderinfo[i]
  • __len -> #mapheaderinfo
hudinfo
  • __index -> hudinfo[HUD_NAME]
  • __len -> #hudinfo
Miscellaneous
(string)
  • __add -> Concatenation using "+" ("string1"+variable+"string2")
  • __index -> String library functions, called as stringvar.function([args])
  Lua [view]
General BasicsFunctionsGlobal variablesHooksUserdata structures
Tutorials Freeslots and Object resourcesCustom player ability