This is the first installment of a multi-part series I’m doing on CubeScript. As the title suggests, I’m starting with a relatively abstract introduction.
What is CubeScript?
CubeScript is the console language of Cube-based games; it is used to write scripts that can be executed in-game. Scripts written in CubeScript can be anywhere from a single line to hundreds of lines in length (I’ve never seen thousands, but I guess that’s theoretically possible too :P).
While CubeScript shares many features with conventional programming languages, it has significant differences too. For example, one central focus of CubeScript is easy GUI design, a topic that will likely be covered in a later post.
A CubeScript script is basically just a series of syntactically valid statements. A statement will generally be either the invocation of a command or an assignment to a variable. For example, if you’ve ever executed the following in the console:
then you’ve used CubeScript; that’s a simple command. Command invocations follow a format wherein the command name is followed by the space-separated arguments to the command.
fov, for example, takes just one argument. A command like
bind, on the other hand, takes two: the key to bind, and the action to perform whenever that key is pushed.
Assignments are fairly straightforward too, especially if you’re familiar with conventional programming languages, as the format is largely the same. For example, if we want to store the value
42 in a variable
x, we would simply do:
x = 42
In the old days of CubeScript, assignment itself was actually done via the command
alias! There is little reason to use
= now, but it’s good to know in case you see it used in older scripts.
I should also mention that CubeScript scripts are typically placed in either
autoexec.cfg (in your Sauerbraten folder) or in their own
cfg file alongside
autoexec.cfg, whereupon they can be executed with the command
exec file.cfg from
autoexec.cfg. For larger scripts spanning multiple files, it is also possible to package the files in their own folder and use something like
Finally, CubeScript also supports comments, with a syntax similar to that of C/C++/Java:
// this is a comment
/* */-comments are not supported.
Now that we’ve covered what a CubeScript script actually is, we can go on to talk about more complicated things you can do in one. The first thing to go over is operators such as
/ etc. Now, it is important to note here that CubeScript uses polish/prefix notation, like Lisp, if you’re familiar with that family of languages. Therefore, something like
2 + 3 would, in CubeScript, be expressed as
(+ 2 3). (This is basically a result of the fact that operators such as
+ are just commands themselves, so they follow the same syntax as commands, but you probably don’t need to worry too much about that.) So, returning to our
x variable, let’s say we want to assign to
x the sum of
3, we’d simply do this:
x = (+ 2 3)
If you want to represent a more complicated expression like
(2 + 3) * 4, you have to do some nesting of the parenthesis:
x = (* (+ 2 3) 4)
(+ 2 3) is evaluated first, and its result is then multiplied by
Polish notation might take some getting used to at first, but once you get the hang of it, it’s really quite easy.
Next, we have to be able to access the values we’ve assigned to variables. This is done simply by prefixing the variable name with a
$. For example:
x = (+ 2 3) echo $x
would echo “5”. Of course, values of variables can be used in expressions being assigned to said variables. For instance, to increment
x by one:
x = (+ $x 1)
A more exhaustive list of operators can be found in the official documentation here, but they all work in essentially the same way.
Basic Control Flow
As with most other languages, CubeScript supports some basic control flow constructs such as if-else statements and loops.
In CubeScript, if-else statement follow this syntax:
if <condition> [ <if body> ] [ <else body> ]
if (= $x 42) [ echo "x is 42!" ] [ echo "x is not 42!" ]
The snippet above will echo “x is 42!” if
x is indeed 42, and will echo “x is not 42!” otherwise. Note that the else-portion is optional:
if <condition> [ <if body> ] is valid by itself:
if (= $x 42) [ echo "x is 42!" ]
Let’s move on to loops. The two most basic types of loops in CubeScript are associated with the commands
while should seem familiar if you’ve programmed in any conventional language before. It has a syntax of
while [ <condition> ] [ <body> ]
and will repeatedly execute
<body> so long as
<condition> is “true” (i.e. not zero). I’ll reuse the example used in the official docs for
while, because I think it’s a pretty good one:
i = 0 while [ (< $i 10) ] [ echo $i; i = (+ $i 1) ]
i = 0simply assigns the variable
ito zero, as we know.
- The condition
(< $i 10)returns 1 (“true”) if the value in
iis less than 10, and returns 0 (“false”) otherwise.
- The loop body does two things (the two statements composing the body are separated by a semicolon):
echo $ijust echoes the value of
i = (+ $i 1)increments the value of
i(just like the example with
So, in plain English, we can translate this snippet as “set
i to 0; while
i is less than 10, echo
i and increment it”. It shouldn’t be too hard to see now that all we will be doing here is echoing the integers from 0 up to 9.
The next kind of loop is, well,
loop, and it has this syntax:
loop <var> <N> [ <body> ]. In this case,
var is the name of some variable, and
N is a non-negative integer.
loop will set
var to 0, then execute
N times, and each time it will increment
var will take on the values from 0 to
N-1). Again I’ll use the example from the docs:
loop i 10 [ echo $i ]
This actually does the same thing as the
while snippet above: it just echoes the integers from 0 to 9 inclusive.
There are a few other loop constructs for looping over lists and strings. I’ll cover these in a future post.
This has been a very brief and, in many ways, high-level introduction to the wonderful world of CubeScript. I’ll apologize in advance to those of you who were already familiar with all this, but for those who were not, I hope you got something out of this overview, and that you’re now better prepared to delve into more complex topics in future posts.
In the near future, I’m planning to go over functions (i.e. the inner workings of
[ ] blocks), strings, lists, and GUI design. Let me know if I left anything out, and thanks for reading!