Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added table documentation (since v3.50)

...

 

Operator / Delimiter / Constant

Type

Example

Result of example

Description

null

constant

null + 1

1

Null value, see above

false

constant

1 == 0

false

Integer value 0, useful in Boolean expressions

true

constant

null == 0

true

Integer value 1, useful in Boolean expressions

pi

constant

2 * pi

6.2831853rad

π as an angle (same as 180deg)

()

delimiter

(2 + 4) * (6 + 1)

42

Parentheses for arithmetic grouping

[]

delimiter

[1, 2, 2+1, 'string']

[1, 2, 3, 'string']

List of values (see below)

table[]delimitertable[$foo='bar', {1+1}=40+2]table[$foo='bar', {2}=42]Table of values (see below)

{}

delimiter

{101, 3}

'Some text'

Text lookup (page ID and text ID) from TextDB
(Note: Braces are also used for property lookups, see below)

+

unary

+21 * (+2)

42

Denotes positive number (no effect)

-

unary

-(21 * -2)

42

Negates the following number

not

unary

not (21 == 42)

true

Yields true if the following expression is false (equal to zero), false otherwise

typeof

unary

typeof null

typeof 0

typeof 'Hello world'

datatype.null

datatype.integer

datatype.string

Yields the data type of the following sub-expression

sin

unary

sin(30deg)

sin(pi)

0.5

1.0

Sine (function-style, parentheses required)

cos

unary

cos(60deg)

cos(pi)

0.5

0.0

Cosine (function-style, parentheses required)

sqrt

unary

sqrt(2)

1.414213LF

Square root (function-style, parentheses required)

exp

unary

exp(1)

2.71828LF

Exponential function (function-style, parentheses required)

log

unary

log(8) / log(2)

3.0LF

Natural logarithm (function-style, parentheses required)

^

binary

10 ^ 3

1000.0LF

Power

*

binary

21 * 2

42

Multiplication

/

binary

42 / 10
42.0 / 10.0

4
4.2

Division

%

binary

42 % 10

2

Modulus (remainder of integer division)

+

binary

1 + 1

'Hello' + ' world'

2

'Hello world'

Addition

String concatenation

-

binary

1 - 1

0

Subtraction

lt

&lt; (<)

binary

1 lt 3

1 &lt; 3

true

Less than

le

&lt;=

binary

1 le 3

1 &lt;= 3

true

Less than or equal to

gt

&gt; (>)

binary

1 gt 3

1 &gt; 3

false

Greater than

ge

&gt;=

binary

1 ge 3

1 &gt;= 3

false

Greater than or equal to

==

binary

1 + 1 == 2.0

true

Equal to

!=

binary

1 + 1 != 2.0

false

Not equal to

and

binary

true and false

false

Logical AND (short-circuit semantics)

or

binary

true or false

true

Logical OR (short-circuit semantics)

if ... then ...

if ... then ... else ...

ternary

if 1 == 2 then 'F'

if 1 == 2 then 'F' else 'T'

null

'T'

Conditional operator ("inline if")

 

...

A list can contain values of arbitrary data types, even mixed in the same list - so a list can actually contain other lists. However, some of the things that you can do with lists require that all contained elements are of a certain type. The contents of a list can be accessed via properties, see the next section about value properties. Lists can be empty, they are written as “[ ]”.

...

Lists are stored in variables as references, so multiple variables can refer to the same shared list: If you change a shared list through a variable, e.g. by changing the value of an element, you change it as well for all other variables. However, the operators == and != can also be used on two distinct lists to compare their elements.

Value properties

...


Tables

Tables are associative arrays - they are like lists, but you can assign values to (almost) arbitrary keys, not just to index numbers. A table is constructed within an expression using the table[] syntax, see above. See the next section about how to access the contents of a table.

Almost all values are allowed as table keys, but there are a few exceptions:

  • Strings must start with '$', like variables
  • null cannot be used as table key (but the number 0 is valid)
  • Lists, tables, groups and buildplans cannot be used as table keys

These restrictions only apply to the keys, there are no restrictions for values that you assign to them. For example:

  • table[] creates an empty table
  • table[{0} = null] creates a table that maps the number 0 to null
  • table[{'$foo'} = 'bar'] a table that maps the string '$foo' to the string 'bar'
  • table[$foo = 'bar'] exactly the same, just a shorter notation for string keys
  • table[foo = 'bar'] error, 'foo' does not start with a '$'
  • table[{1} = [], {2} = table[]] a table that maps 1 to an empty list and 2 to an empty table

Just like lists, tables are stored as references, so it's possible that multiple variables reference the same table (see above).


Value properties

Properties are a crucial concept in script expressions. In the previous sections you have seen mostly constant expressions, which are already evaluated when they are parsed at game start. For reading and writing variables and evaluating the game’s state, properties are used.

...

You can look up a property by appending a dot and the key in curly braces:

  • [100, 200, 300, 400].{1} ⟹ 100 (reading the first element)

  • [100, 200, ['Hello ', 'world']].{3}.{2} ⟹ 'world' (second element of the inner list, which is the third element of the outer list)

  • [ [].{'count'} ⟹ 0

  • table[{21} = 42].{'count'21} 0 42

In most cases the property key is a fixed string, like “name” or “class”. You can write this like above:

  • [42].{'count'}

  • $ship.{'name'}

  • $ship.{'class'} 

  • table[$foo='bar'].{'$foo'}

But it is easier just to write the property key without braces, which is equivalent:

  • [0].count

  • $ship.name

  • $ship.class

  • table[$foo='bar'].$foo

(In this case, $ship is a variable. All variables start with a “$”, so they cannot be confused with keywords.)

A list has even more properties:

...

'random' returns a randomly chosen element, or null if the list is empty

...

a “$”, so they cannot be confused with keywords.)

A list has even more properties:

  • 'random' returns a randomly chosen element (which requires that the list is non-empty)

  • 'min' and 'max' return the minimum or maximum (all elements have to be numeric)

    • [1, 6, 8].min ⟹ 1

  • 'average' returns the average (but all element types have to be compatible)

    • [1, 6, 8].average ⟹ 5

  • 'indexof' is followed by another property, and the index of the first occurence of that key in the list is returned, or 0 if it’s not in the list

    • [1, 6, 8].indexof.{8} ⟹ 3

  • 'clone' creates a shallow copy of the list (i.e. lists that are contained as elements in the list are not copied, only the reference to them)

    • [1, 6, 8].min clone[1, 6, 8]

  • 'average' returns the average (but all element types have to be compatible)

    • [1, 6, 8].average ⟹ 5

  • 'indexof' is followed by another property, and the index of the first occurence of that key in the list is returned, or 0 if it’s not in the list

    • [1, 6, 8].indexof.{8} ⟹ 3

  • 'clone' creates a shallow copy of the list (i.e. lists that are contained as elements in the list are not copied, only the reference to them)

  • [1, 6, 8].clone ⟹ [1, 6, 8]

A table has different properties:

  • 'clone' creates a shallow copy of the table
  • 'keys' allows you to access data about the table's keys

However, 'keys' alone will not give you a result. 'keys' must be followed by another keyword to retrieve the desired information, for example:

  • $table.keys.list: Yields a list of all keys in the table
  • $table.keys.sorted: Yields a sorted list of all keys in the table (which requires that all keys are numeric)
  • $table.keys.random: A randomly chosen key (which requires that the table is non-empty)
Note

The string formatting syntax that you have seen above is also based on the property system. You basically pass a list as property key to a string. Braces around the brackets are not required, so 'foo'.[...] is just a convenient alternative notation for 'foo'.{[...]}.

Property lookup tests and suppressing errors

If you look up a property that does not exist, there will be an error, and the result will be null. To test whether a property exists, you can append a question mark “?” to the lookup, which yields true or false:

  • $list.{5} ⟹ The fifth element of a list - however, or error if the list $list has less than 5 elements (or if $list is not a list at all)and if it's also not a table with the key 5), there will be an error

  • $list.{5}? ⟹ true if the list exists and $list has the property 5, false otherwise

  • $table.$key? ⟹ Analogously, true if the $table has the string property '$key'

The question mark can even be applied to variables:

  • $list ⟹ The value stored under the name $list, or an error if there is no such variable

  • $list? ⟹ true if the variable exists, false otherwise

To look up the value of a property although it may not exist, you can use the at-sign “@” as prefix:

  • @$list.{5} ⟹ The fifth element if the list result of the $list lookup if $list exists and has a fifth element, null otherwisethe property 5, otherwise null (without error message)

  • @$list ⟹ The list if this variable exists, null otherwise

  • @$list.{5}.{1} ⟹ The first element of the fifth element of $list, if it exists, null otherwise

As you can see, an error is already prevented if any link in the property chain does not exist. But use the @ prefix with care, since error messages are really helpful for detecting problems in your scripts. The @ prefix only suppresses property-related error messages and does not change any in-game behaviour.

 

Static lookups

There are a few data types which are basically enumerations: They only consist of a set of named values, e.g. the “class” data type, which is used for the component classes that exist in the game. For all these static enumeration classes there is a lookup value of the same name, from which you can get the named values as properties by their name. So for the type “class”, there is a value “class” that can be used to access the classes.

...

The trick is that <set_value> not only works on variables, but also on list elements and table keys:

<set_value name="$list.{1}" exact="42" />
<set_value name="$table.$foo" exact="42" />

The operation insert is special, and it only works on lists. It inserts the value at the specified position (note that the position beyond the last element is also valid here):

...

To remove variables or list/table entries, use <remove_value>:

<remove_value name="$foo" />
<
remove_value name="$list.{1}" />
<remove_value name="$table.$foo" />

Removing an entry from a list shifts all following elements down by one. If you want to clear an entry without removing it from the list, just use <set_value> instead.

...