Lua in mEldritch

mEldritch embeds lua 5.3 for limited scripting capabilities. You can read the lua manual at https://www.lua.org/manual/5.3/. This file documents the mEldritch specifics.

Lua Blocks

lua blocks are enclosed in curly braces { } and are available in configuration files. They may appear both at the top level (empty context) or within contexts. If a block appears at the global level, any non-local variables or functions defined in that block will be available from lua at the global level. It a block appears within a context, any non-local variables or functions defined in that block will be available from lua in a table that has the same name as the context, and will also be evaluated with this table as their environment.

A block can appear where a name is expected, which is then evaluated within the context it appears in, when it is loaded from a config file, but does not return any values.

A block can also appear where a value is expected (i.e. on the right hand side of an assignment), which is evaluated at load time and, for the purposes of the config file, replaced by it’s return value. In this case, you actually need to return a value from the block.

Configuration values for loadable assets may have a string starting with ‘&’ and followed by lua code instead of a filename. In this case, the lua code is evaluated and expected to return a stream, from which the asset is then read.

Using require()

You can use require() to load custom lua libraries. The standard search path for lua libraries is "/?.lua;/Lua/?.lua", meaning that require("lib") attempts to load lib.lua from the game data directory (where the Mods directory resides, this is the game directory on Windows and Linux and ~/Library/Application Support/Eldritch on Mac), and when that fails, from the Lua directory within the game data directory.

When loading a mod, the path is extended by "/?.lua;/Lua/?.lua". This means that when within a mod, require("lib") will first attempt to load lib.lua from the mod directory. Regardless of where the lua code comes from, the current directory does not change.

When using the mEldritchLua tool, the path is "?.lua;Lua/?.lua;/?.lua;/Lua/?.lua", i.e. the current directory followed by the directory the mEldritchLua interpreter binary is in.

global variables

ARG
contains the commmand line args passed to the script. Only available in mEldritchLua, not in mEldritch. Currently no options (arguments starting with -) are allowed.

variables per context

CONTEXT
the name of the current context, i.e. the context in which the current lua code is loaded.

global functions

log(fmt, ...)
logs a message. Arguments are as for string.format. The output is written to meldritch.log (and, if you have a debug build, also to stdout)
printf(fmt, ...)
basically does print(string.format(fmt, …)). Only available in mEldritchLua, not in mEldritch. Use log() in mEldritch.

Libraries

pkg

This library provides the facility to add and inspect eldritch package files (*.cpk)

ok = pkg.add(pkg)
adds a package file to the load path used by config.load(), texture.load(), room.load() and stream.open(). This is mainly intended for the mEldritchLua tool, as mEldritch will load all packages that are listed in it’s config files. Returns true if the package was added successfully, false if not.
table = pkg.list(pkg)
returns a table that contains a list of all files within the package file. The file must have been added using pkg.add(). Returns nil if the package was not found or had no contents.
ok = pkg.fileexists(file, pkgonly = false)
returns true if the file exists, false if not. If pkgonly is omitted or false, the file is searched for within packages and on the filesystem, otherwise it is searched for only in packages.

config

This library provides access to eldritch configuration. A handler function can be defined that is called when a configuration variable is not found at runtime.

int = config.hash(string)
creates a hash of the string and returns it
ok = config.load(filename)
loads a config file. This is mainly intended for the mEldritchLua tool, as mEldritch will load all config files that are listed in it’s config files. Returns true if the config file was loaded, false otherwise.
config.loadstring(string)
loads configuration from a string. Note that this does not load the configuration into the currently active context!
config.save(filename)
saves the current configuration to a file
val = config.getvar(name, context = "")
gets a variable from the configuration. Returns nil if .
config.setvar(name, context, value)
sets a variable to a value
config.registerhash(string)
registers a string for reverse hashing. Only available in mEldritchLua, not in mEldritch.
string = config.reversehash(hash)
tries to reverse a has code to the original string. This only works for strings that have been hashed before, either by using config.registerhash(), config.load() of an uncompiled config file, config.loadstring() or config.setvar(). Only available in mEldritchLua, not in mEldritch.

handlers

value = GETVAR(namehash, contexthash)
is a user defined function that gets called with the hash of the name and the context as arguments when a config variable can’t be found in the regular config options. This function may be present globally (in the empty context) and per context. If a variable is not found in the context, then first the GETVAR function in the context is tried. If that does not exist or returns nil, then the global GETVAR function is called, if it exists. If it does not exist or returns nil, the variable is considered unset.

stream

This library provides input/output streams. The input streams are intended to load resources from eldritch, and the output streams (in-memory only) are provided for dynamic resource loading through lua functions.

stream = stream.create()
returns a memory stream. Write to this stream and then return it from functions to be called from the configuration with a ‘=’ prefix. May be written to by textures or rooms saveto() method.
istream = stream.open(filename)
opens an input stream to a file within a package or on the filesystem. A stream returned from open can not be written to. Returns nil if the stream could not be opened. See also pkg.add().
stream:write(string)
writes string to stream. The write method is not available on streams that were opened with stream.open()
stream:read(len = auto)
reads data from the stream. If the len argument is omitted, we read as much data as is present. Otherwise len bytes are read. If you attempt to read more bytes from a stream than are present, read returns nil. If stream is at eof, read also returns nil.
size = stream:size()
returns the size of the stream
pos = stream:getpos()
returns the current position within the stream. Only one position os maintained for both read and write.
ok = stream:setpos(pos = 0)
sets the current position within the stream. If the pos argument is omitted, the position is reset to the beginning of the stream.
eof = stream:ateof()
returns true if the stream is at EOF, false if not.

filesystem

This library provides a few extra functions to interact with the filesystem.

table = fs.list(path)
returns a table with all objects in a directory. Returns nil if the directory was not found or could not be read or had no contents.
ok = fs.isfile(path)
returns true if the path exists and is a file, false otherwise
ok = fs.isdir(path)
returns true if the path exists and is a directory, false otherwise
path = fs.getexecdir()
returns the path to the current executable
name = fs.getexecname()
returns the name of the current executable
path = fs.getmoddir()
returns the path of the current mod, of the current working directory if not called from within a mod. Note that in the mEldritchLua tool there is no explicit support for mods so this will always return the current working directory.
path = fs.getcurrentdir()
returns the current working directory
fs.setcurrentdir(path)
changes the current working directory
fs.filename(path)
returns the filename portion of a path
fs.dirname(path)
returns the directory portion of a path
fs.extension(path)
returns the extension of a path
fs.basename(path)
returns the basename (filename without extension) of a path
path = fs.normalize(path)
returns a normalized version of the path

texture

This library provides access to textures, including the ability to create or modify them.

txt = texture.load(filename)
load a texture from a file on the filesytem or in a package. Can load bmp, tga, png. Returns nil if the texture could not be loaded. See also pkg.add().
txt = texture.create(width, height)
create a new empty texture size width x height
txt:copyrect(x, y, width, height, to, to_x, to_y)
copy a rectangle of pixels from texture txt top left x, y size width x height to texture to position to_x, to_y
txt:save(filename)
save a texture to a filename. Only png format supported.
txt:saveto(stream)
save a texture to s stream. This is used for dynamic resources through lua functions.
r, g, b, a = txt:getpixel(x, y)
reads rgba values from a pixel of the texture. The return values are nil if x, y is out of range for the texture.
txt:setpixel(x, y, r, g, b, a)
sets a pixel’s rgba values in the texture to r, g, b, a
txt.sizex, txt.sizey
dimension of the texture

room

This library provides access to rooms, including the ability to create or modify them. Voxel coordinates are in the range 0 <= x < room.sizex, 0 <= y < room.sizey, 0 <= z < room.sizez. X coordinates are along the West-East axis with 0 being west, y coordinates are along the North-South axis where 0 is south, and z coordinates are along the Up-Down axis where 0 is Down.

room = room.create()
creates a new, empty room with standard dimensions (12x12x8)
room = room.load(filename)
loads a room from a file on the filesystem or in a package. Returns nil if the room could not be loaded. See also pkg.add().
room:setvoxel(x, y, z, v)
sets the voxel at position x, y, z to value v. v must be in the range 0–255, where 0 is empty and 255 is invalid.
v = room:getvoxel(x, y, z)
returns the voxel at position x, y, z.
room:setspawner(x, y, z, name, orientation = North)
sets a spawner at position x, y, z with name and orientation. Name must be a predefined spawner name and must be defined at game run time, orientation is one of the 4 orientations n, w, s, e or 0, 1, 2, 3 respectively. All other values for orientation default to North (i.e. standard)
name, orientation, x, y, z = room:getspawner(x, y, z) or
name, orientation, x, y, z = room:getspawner(i)
gets name and orientation for either the spawner at position x, y, z or the i’th spawner, if it exists. returns nil if no spawner exists at the given position or index, or the name of the spawner and orientation (see above), and it’s coordinates. If you use the indexed form, i starts at 0 and continues until room:getspawner(i) returns nil.
room:setworlddef(name)
sets the world definition for a room. Note that this is only relevant for the room editor, it is not used anywhere else (except maybe in a script?)
hash = room:getworlddef()
returns the world definition stored in a room. For stock rooms, this will be 0, otherwise it will return a hash of the world definition name.
room:save(filename)
saves the room to a file
room:saveto(stream)
saves the room to a stream. This is used for dynamic resources through lua functions.
room.sizex, room.sizey, room.sizez
the dimensions of the room, should always be 12, 12, 8 respectively.

Examples

For examples check out the contents of Extras/Examples/Mods/LuaTest and Extras/Examples/Lua

TODO