Lua
Lua is a scripting language that can be used by SRB2. It allows users to write custom game logic without editing the game's source code, in addition to many of the capabilities SOC also has. For these reasons, Lua scripting is considered a more powerful method of modification available to SRB2 compared to SOC. However, Lua does not supersede SOC completely – there are still a number of aspects of modding that can only be configured through SOC. A file created in the Lua language is commonly called a "Lua script".
SRB2's implementation of Lua is based on a modification of Lua 5.1 called BLUA (which stands for "bastardized Lua"; see below for an overview of the differences). The reference manual for Lua 5.1 can be found here. The name "Lua" itself derives from the Portuguese word for moon (pronounced LOO-ah); it should not be referred to as "L.U.A.", as it is not an acronym.
Script writing
For users new to the Lua language, it is highly recommended to read the Lua Tutorial on the lua-users wiki to learn the basics of Lua.
Changes from standard Lua
SRB2's implementation of Lua is based on BLUA, which has some syntax differences compared to standard Lua, bringing it closer to C. Additionally, some further changes have been made to adapt BLUA for SRB2's purposes. The differences are as follows:
- Whereas standard Lua uses floating-point doubles for all of its math, SRB2's implementation uses signed integers. In situations where real numbers are required, SRB2's Lua uses fixed-point numbers with a base unit of
FRACUNIT
(65536). For example, the number 1.5 is represented byFRACUNIT + FRACUNIT/2
or3*FRACUNIT/2
(98304). Fixed-point math functions such asFixedMul()
andFixedDiv()
are available to assist with math in these situations. - The only standard libraries loaded are the basic library (including the coroutine library), string manipulation, and table manipulation. The other libraries were removed either because they are not useful for SRB2's purposes or because they could be used to write potentially harmful code. Some useful functions from the missing libraries are replaced by SRB2-specific functions.
- All standard bitwise operations are supported. Note that, since Lua uses
^
for powers, bitwise XOR is represented as^^
. - C-style syntax is supported for several operators in addition to standard Lua's syntax, including comments (
//
and/* ... */
) and the "not equals" operator (!=
). - String concatenation can be done with the syntax
"string"+var+"string"
or"string\$var\string"
in addition to standard Lua's"string"..var.."string"
. - The
continue
keyword is supported infor
loops, whereas standard Lua only supportsbreak
andreturn
. Additionally,break N
can be used to break out of N loops at once. - Pseudo-numbers (
$1
,$2
, and so on) can be used in variable assignments to reference the variables being assigned. These represent the values of the referenced variables before the line is executed, sovar, var2 = $2, $1
can be used to swap two values, for instance. - The keywords
do
afterfor
andwhile
, andthen
afterif
have been made optional. - Inline definitions of functions without arguments can be done with the syntax
do ... end
, in addition to standard Lua'sfunction() ... end
. - In strings, ASCII- and Unicode-encoded hexadecimal characters can be supplied with the
\x
and\u
escape sequence, respectively. - The
__usedindex
metatable event, for assigning an index/value to an existing key/variable, has been added.
Syntax
This article gives an overview of the basic language features and syntax of SRB2's Lua implementation. It is not, however, a complete documentation of the Lua language – for this, consult the reference manual for Lua 5.1.
Constants
There are a variety of constants supplied by SRB2 to aid script-writing. The three most commonly used constants are:
FRACUNIT
(65536, or1<<FRACBITS
): The basic unit of measurement in SRB2, for positions, speeds, scales, and other things. Commonly used when conversion to and from a fixed-point representation is desired.TICRATE
(35): The number of tics (game frames) in one second.
Special characters
Certain ASCII characters have special effects for text printed using the functions print
or CONS_Printf
.
Chat text
These characters are reserved for use with player chat messages. They give the text special effects such as playing a sound effect when the text is printed, or changing the text color.
Decimal | Hexadecimal | Usage |
---|---|---|
3 | 0x03
|
Plays a chat beep sound |
4 | 0x04
|
Plays a chat beep sound and colors text yellow |
Text colors
- See also: SOC > Custom colors
These characters change the color of text displayed on the screen. All text following any of these characters will use their respective colors, until a different color is set or the text ends. Use the code for White/Reset to reset the text color back to the default color where appropriate.
Script execution
The most common way to load Lua scripts is to add them to a WAD or PK3 file as a text lump. In PK3 files, lumps in the Lua/
folder are recognized as Lua scripts by SRB2 and are loaded automatically upon loading the PK3 file, in the order that they are found in the file. In WAD files, lumps with the name prefix LUA_
are loaded automatically. Lua scripts that do not meet these requirements are not loaded automatically, and there is no method of loading them after the file containing them has been added. It is important to note that all Lua scripts in a WAD or PK3 file will be loaded before any SOC lumps also within the file, regardless of lump ordering. This means that any changes to the game in the file's SOC lumps will not be recognized in the file's Lua scripts.
Alternatively, Lua scripts can be stored as standalone files with the file ending .lua
. They can be loaded via the Addons menu or by using the console command addfile
.
Global variables
As well as the global variables that come with Lua (e.g.: _G
and _VERSION
), SRB2 allows access to a number of its own pre-defined global variables for use in Lua scripting.
Userdata types
There are many types of userdata that may be encountered in Lua scripts for SRB2. Some of the most commonly used types are mobj_t
, player_t
, mobjinfo_t
and state_t
. The full list of userdata types recognised by SRB2 is given below for reference – note that the type names themselves have no meaning to Lua scripts whatsoever.
General
These userdata types represent components of the game related to Objects or players.
Type name | Accessibility | Allows custom variables | Description |
---|---|---|---|
mobj_t
|
Read + Write | Yes | This userdata type represents an Object.
This is not to be confused with an Object type (e.g., |
player_t
|
Read + Write | Yes | This userdata type represents the properties of a player that are independent of the player Object, which may carry over between maps. This is not to be confused with mobj_t or vice versa.
|
ticcmd_t
|
Read + Write | No | This userdata type represents a player's current button information, i.e., what buttons are being pressed currently. |
skin_t
|
Read-only | No | This userdata type represents the properties of a character skin, which are defined in a character's S_SKIN lump.
|
SOC
These userdata types represent components of the game that can also be modified by SOC.
Type name | Accessibility | Allows custom variables | Description |
---|---|---|---|
mobjinfo_t
|
Read + Write | Yes | This userdata type represents the properties of an Object type. |
state_t
|
Read + Write | No | This userdata type represents the properties of a state. |
sfxinfo_t
|
Read + Write | No | This userdata type represents the properties of a sound. |
hudinfo_t
|
Read + Write | No | This userdata type represents the properties of a HUD item. |
mapheader_t
|
Read-only | SOC-only | This userdata type represents the properties of a level header. |
Map
These userdata types represent components of the the game that are part of a map.
Type name | Accessibility | Allows custom variables | Description |
---|---|---|---|
mapthing_t
|
Read + Write | No | This userdata type represents a Thing. |
sector_t
|
Read + Write | No | This userdata type represents a sector. |
subsector_t
|
Read-only | No | This userdata type represents a subsector. |
line_t
|
Read-only | No | This userdata type represents a linedef. |
side_t
|
Read + Write | No | This userdata type represents a sidedef. |
vertex_t
|
Read-only | No | This userdata type represents a vertex. |
ffloor_t
|
Read + Write | No | This userdata type represents an FOF. |
pslope_t
|
Read + Write | No | This userdata type represents a slope. |
polyobj_t
|
Read + Write | No | This userdata type represents a PolyObject. |
Miscellaneous
These userdata types represent components of the game that do not fit into the above groups.
Type name | Accessibility | Allows custom variables | Description |
---|---|---|---|
camera_t
|
Read-only | No | This userdata type represents a player's camera. |
consvar_t
|
Read-only | No | This userdata type represents a console variable. |
patch_t
|
Read-only | No | This userdata type allows access to the properties of a graphics patch (see the HUD library). |
Functions
There are many functions in SRB2 available for usage by Lua. A few useful functions available include:
print(output, [output2, ...])
: Prints the output specified into the console. Each output string is separated into different lines.P_SpawnMobj(x, y, z, type)
: Spawns an Object at the x, y, and z coordinates specified. Returns the Object spawned.addHook(hook, function, [extra])
: Adds a hook into the game. See below for more information on hooks.
Hooks
Most of a script's interactivity with SRB2 is handled via hooks. At certain pre-determined points in SRB2's source code, the game checks to see if any hooks of a particular type have been added via a loaded Lua script, and if so, executes the Lua code of these hooks. Hooks are added with the addHook()
function, which takes three arguments: a string with the hook's name, a function to be run when the hook is executed (the arguments passed to this function will vary depending on the hook), and a third argument whose purpose depends on the hook (and which is omitted for some hooks). Some of the most-used hooks are:
ThinkFrame
: A function with no arguments (function()
) is executed once every frame while in-game, after all Object thinkers have run.MobjThinker
: A function with up to one argument (function(mobj)
) is executed once per Object every frame while in-game.mobj
is the Object in question, and is of typemobj_t
. An Object type may be passed as the third argument toaddHook()
to limit this hook to Objects of the specified type.LinedefExecute
: A function with up to three arguments (function(line, mobj, sector)
) is executed when called by linedef type 443 (Call Lua Function).line
is the linedef that called the function (of typeline_t
),mobj
is the Object that triggered the linedef executor (of typemobj_t
), andsector
is the triggering sector the Object touched (of typesector_t
), if it exists. As a third argument, a string must be passed toaddHook()
– the same string must be written across the triggering linedef's front upper texture in order to execute the function. This is useful when using Lua scripting in combination with a map, to execute custom code via a map trigger.
Actions
Lua can be used to call or override existing actions, as well as create new actions that can be used in SOC.
Tutorials
These tutorials are designed to demonstrate some of Lua's use cases in SRB2. Each one demonstrates different functionality, so it is recommended to read all of them. These are not designed to be substitutes for learning Lua itself; they assume that you have a basic understanding of how the language works.
To do More tutorials should be written to cover other methods of interaction between the game and Lua scripts. |
Lua | [view] | |
Language features | Syntax • Metatables | |
SRB2 data | Actions • Constants • Functions • Global variables • Hooks • Userdata structures | |
SRB2Kart data | Kart Userdata structures • Kart Functions • Kart Hooks • Kart Global Variables and Constants | |
Tutorials | Freeslots and Object resources • Custom player ability |