7.2. Data types
MScript supports the following data types:
There is no decicated boolean type. Instead, none
acts as false, and any other value acts as true when a boolean is expected. Functions that return a bool
usually return either 1
(true) or none
(false).
7.2.1. number
Used for properties that describe amounts, distances and volumes, but also for properties where a value can be selected from a list, because these are stored as numbers internally. Spawn flags are also stored as a number, in the special spawnflags
property. They are written the same both inside and outside expressions, for example 1
and -4.5
. Inside expressions, hexadecimal notation can also be used, for example, 31
can also be written as 0x1F
.
Numbers can be used in arithmetic operations and can be compared against each other. They do not have any member properties or functions. Numerical operations are mostly done with operators instead. All numbers are 64-bit floating point numbers (doubles).
See also: standard mathematics functions and standard trigonometry functions.
7.2.2. string
A string is a piece of text. Any property value that does not look like a number or a sequence of numbers is treated as a string. Within expressions strings must be surrounded by single quotes, to distinguish them from identifiers: 'targetname'
produces the literal text targetname
, whereas targetname
refers to the targetname property of the macro entity that is instantiating the current template.
Strings can be indexed in much the same way as arrays can, except that indexing returns a 1-character string instead of a number. Negative indexing is also supported, and indexes that do not exist produce the special value none
.
The following escape sequences are recognized: \'
(single quote), \"
(double quote), \\
(backslash), \0
(null-terminator), \a
(alert), \b
(backspace), \f
(form feed), \n
(newline), \r
(carriage return), \t
(horizontal tab), \v
(vertical tab), \xHH
(2-digit Unicode sequence) and \uHHHH
(4-digit Unicode sequence).
Properties
number length
Returns the number of characters in this string.
For example, 'hello'.length
returns 5
.
Indexing
string [number index]
Returns the character at the given index as a 1-character string, or none
if the index is out of range. Negative indexes start counting from the end of the string.
For example, 'hello'[-1]
returns 'o'
.
Member functions
- Comparisons and checks
- Substrings, trimming and replacing
- Changing case
- Splitting and joining
- Regular expressions
Comparisons and checks
bool equals(string str, bool ignore_case = false)
Checks whether this string is equal to the given string. Unlike the ==
operator, this function can also be used to do a case-insensitive comparison. Returns 1
(true) if the strings are equal, or none
if not.
For example, 'abc'.equals('ABC', 1)
returns 1
(true).
bool contains(string str, bool ignore_case = false)
Searches this string for the given string, and returns 1
(true) if the string is present, or none
if it is not. The search is case-sensitive by default.
For example, 'a small sentence'.contains('small')
returns 1
(true).
bool startswith(string str, bool ignore_case = false)
Checks whether this string starts with the given string. Returns 1
if true, or none
if not. The comparison is case-sensitive by default.
For example, 'firestorm'.startswith('fire')
returns 1
(true).
bool endswith(string str, bool ignore_case = false)
Checks whether this string ends with the given string. Returns 1
if true, or none
if not. The comparison is case-sensitive by default.
For example, 'firestorm'.endswith('orm')
returns 1
(true).
number|none index(string str, number offset = 0, bool ignore_case = false)
Returns the index of the first occurrence of the given string in this string, or none
if the given string could not be found. If an offset is specified, the search will start from that index, which can be useful for skipping earlier occurrences. Negative offsets are counted from the end of the string. The comparison is case-sensitive by default.
For example, 'ABCBCA'.index('C')
returns 2
.
number|none lastindex(string str, number offset = none, bool ignore_case = false)
Returns the index of the last occurrence of the given string in this string, or none
if the given string could not be found. If an offset is specified, the search will start from that index, which can be useful for skipping later occurrences. Negative offsets are counted from the end of the string. The comparison is case-sensitive by default.
For example, 'ABCBCA'.lastindex('C')
returns 4
.
number count(string str, number offset = none, bool ignore_case = false)
Returns the number of non-overlapping occurrences of the given string. If an offset is specified, the search will start from that index. Negative offsets are counted from the end of the string. The comparison is case-sensitive by default.
For example, 'ABCBCA'.count('A')
returns 2
, and 'ABCBCA'.count('b', 3, 1)
returns 1
.
Substrings, trimming and replacing
string substr(number offset, number length = none)
Returns the specified part of this string as a new string. A negative offset is counted from the end of the string. If no length is specified then the rest of the string is taken, starting from the given offset. An empty string is returned if the offset or length are out of range.
For example, 'hotel_room'.substr(6, 2)
returns 'ro'
.
string trim(string chars = none)
Returns a copy of this string, with specific characters removed from the start and end. Removes whitespace characters if no characters are specified.
For example, '_test_case_'.trim('_')
returns 'test_case'
.
string trimstart(string chars = none)
Returns a copy of this string, with specific characters removed from the start. Removes whitespace characters if no characters are specified.
For example, '_test_case_'.trimstart('_')
returns 'test_case_'
.
string trimend(string chars = none)
Returns a copy of this string, with specific characters removed from the end. Removes whitespace characters if no characters are specified.
For example, '_test_case_'.trimend('_')
returns '_test_case'
.
string replace(string str, string replacement, bool ignore_case = false)
Returns a copy of this string, with all occurrences of str
replaced with the given replacement. The comparison is case-sensitive by default.
For example, 'old is cold'.replace('old', 'new')
returns 'new is cnew'
.
Changing case
string upper()
Returns a copy of this string, with all characters turned into uppercase characters.
For example, 'Hello there'.upper()
returns 'HELLO THERE'
.
string lower()
Returns a copy of this string, with all characters turned into lowercase characters.
For example, 'This is GOOD'.upper()
returns 'this is good'
.
Splitting and joining
array split(any delimiters = none, number count = none)
Splits this string into multiple parts and returns those as an array of strings. The delimiter can be a single string or an array of strings. Any other value is treated as none
, and will result in splitting on whitespace. If a count is specified, then the resulting array will contain at most that many parts.
For example, 'apple;pear;banana;'.split(';')
returns ['apple', 'pear', 'banana', '']
.
array splitr(string pattern = none, number count = none)
Splits this string into multiple parts using a regular expression pattern. If not pattern is specified, the string will be split on whitespace. If a count is specified, then the resulting array will contain at most that many parts.
For example, 'apple---pear_-_banana orange'.splitr('[-_\\s]+')
returns ['apple', 'pear', 'banana', 'orange']
.
string join(array values)
Combines the string representation of the values in the given array, while inserting this string in-between each pair of values.
For example, ';'.join('apple', 'pear', 'banana')
returns 'apple;pear;banana'
.
Regular expressions
bool match(string pattern)
Returns 1
(true) if this string matches the given regular expression pattern, or none
(false) if it does not.
For example, 'env_beam'.match('^env_.*')
returns 1
.
array matches(string pattern)
Returns an array that contains all non-overlapping occurrences of the given regular expression in this string.
For example, 'This is a sentence.'.matches('\\w+')
returns ['This', 'is', 'a', 'sentence']
.
7.2.3. array
An array can store multiple values of different types. Property values that contain two or more numbers, separated by whitespace, are treated as an array. Within expressions, arrays must be surrounded by brackets and values must be separated by commas: [1, 2, 3]
. When an array is converted to text, the brackets and commas are omitted and the values are separated by spaces, to match the entity property format.
Arrays can be indexed, where a[0]
returns the first item, and a[a.length - 1]
returns the last item. Negative indexes are also supported: a[-1]
returns the last item, a[-a.length]
returns the first item. Indexes that are outside the range of the array will produce the special value none
.
See also: standard array functions.
Properties
number length
Returns the number of items in this array.
For example, ['A', 'B', 'C'].length
returns 3
.
Position, angles and colors
Arrays contain a few properties that don't make sense in all contexts, but they can be convenient when working with positions, angles and colors.
number|none x
number|none y
number|none z
These properties return the first, second and third item respectively, but only if they are a number. For example, [1, 2, 3].x
returns 1
, but ['A', 'B', 'C'].y
returns none
.
number|none pitch
number|none yaw
number|none roll
These properties also return the first, second and third item respectively, if they are a number.
number|none r
number|none g
number|none b
number|none brightness
Once more, these properties return the first, second, third and fourth items respectively, if they are a number.
Indexing
any [number index]
Returns the item at the given index, or none
if the index is out of range. Negative indexes start counting from the end of the array. For example, -1
will return the last item in the array.
For example, ['A, 'B', 'C'][1]
returns 'B'
.
Member functions
- Cutting and combining
- Searching
- Functional programming
- Numerical
Cutting and combining
array slice(number start, number end = none, number step = 1)
Returns a new array by taking specific items from this array. By default, the result will contain all items between the start index (inclusive) and the end index (exclusive). If no end is given, then items will be taken until the end of the array is reached. Both start and end index can be negative.
The step
argument lets you skip elements or invert the result. For example, a step
value of 2
will skip every second item, and a step
value of -1
will pick items in reversed order.
For example, ['A', 'B', 'C', 'D'].slice(1, 3)
returns ['B', 'C']
.
array skip(number count)
Returns a new array that contains all but the first count
items from this array.
For example, ['A', 'B', 'C'].skip(2)
returns ['C']
.
array take(number count)
Returns a new array that contains only the first count
items from this array.
For example, ['A', 'B', 'C'].take(2)
returns ['A', 'B']
.
any first()
Returns the first item from the array, or none
if the array is empty.
For example, ['A', 'B', 'C'].first()
returns 'A'
.
any last()
Returns the last item from the array, or none
if the array is empty.
For example, ['A', 'B', 'C'].first()
returns 'C'
.
array concat(array other)
Returns a new array with the items from the given array added at the end.
For example, ['A', 'B', 'C'].concat(['X', 'Y', 'Z'])
returns ['A', 'B', 'C', 'X', 'Y', 'Z']
.
array prepend(any value)
Returns a new array with the given value added at the start.
For example, ['A', 'B', 'C'].prepend('Z')
returns ['Z', 'A', 'B', 'C']
.
array append(any value)
Returns a new array with the given value added at the end.
For example, ['A', 'B', 'C'].append('Z')
returns ['A', 'B', 'C', 'Z']
.
array insert(number index, any value)
Returns a new array with the given value inserted at the given index. The index can be negative.
For example, ['A', 'B', 'C'].insert(2, 'Z')
returns ['A', 'B', 'Z', 'C']
.
Searching
bool contains(any value)
Searches the array for the given value, and returns 1
(true) if the value is present, or none
if it is not.
For example, ['B', 'A', 'B', 'A'].contains('C')
returns none
.
number index(any value, number offset = none)
Searches the array for the first occurrence of the given value and returns its index, or none
if the value was not found. An optional start offset can be given, which can be useful for finding subsequent occurrences. The offset can be negative.
For example, ['B', 'A', 'B', 'A'].index('A')
returns 1.
number lastindex(any value, number offset = none)
Searches the array for the last occurrence of the given value and returns its index, or none
if the value was not found. An optional start offset can be given, which can be useful for finding earlier occurrences. The offset can be negative.
For example, ['B', 'A', 'B', 'A'].lastindex('B')
returns 2
.
Functional programming
array map(function selector)
Calls the given selector function for every item in the array and returns a new array that contains the results.
selector
must either be a function that takes a single argument: (any value) => any
, or a function that takes two arguments: (any value, number index) => any
.
For example, ['apple', 'pear', 'banana'].map(s => s.length)
returns [5, 4, 6]
.
array filter(function predicate)
Returns a new array that only contains the items for which predicate
returned true.
predicate
must either be a function that takes a single argument: (any value) => bool
, or a function that takes two arguments: (any value, number index) => bool
.
For example, [2, 8, 5, 7].filter(n => n < 6)
returns [2, 5]
.
any reduce(function reducer, any start_value = none)
Reduces an array to a single value by calling reducer
for each item, passing the current result and item, and using the return value as the new result. The start value is used as the initial result.
reducer
must be a function that takes two arguments: (any result, any value) => any
.
For example, [4, 'times', 6].reduce((result, value) => result + ';' + value)
returns '4;times;6'
.
array groupby(function key_selector)
Groups items by calling key_selector
for each item to obtain its key, and creating a group for each distinct key. Returns an array of {any key, array values} objects, where key contains a key returned by a key_selector
call, and values contains all items from the original array that are associated with that key.
key_selector
must be a function that takes one argument: (any value) => any
.
For example, ['bear', 'lion', 'leopard'].groupby(s => s[0])
returns [{key: 'b', values: ['bear']}, {key: 'l', values: ['lion', 'leopard']}]
.
array zip(array other, function zipper)
Combines items from two arrays by calling zipper
with the first items from both arrays, then with the second items from both arrays, and so on, until one of the arrays is exhausted.
zipper
must be a function that takes two arguments: (any value, any otherValue) => any
.
For example, [1, 2, 3, 4].zip(['A', 'B', 'C'].zip((n, s) => n + s)
returns ['1A', '2B', '3C']
.
array sort(function sort_by)
Sorts an array in ascending order, based on the sorting values returned by sortby
.
sort_by
must be a function that takes one argument and that returns a number: (any value) => number
.
For example, ['red', 'green', 'blue'].sort(s => s.length)
returns ['red', 'blue', 'green']
.
array reverse()
Returns a reversed array.
For example, ['first', 'second', 'third'].reverse()
returns ['third', 'second', 'first']
.
bool any(function predicate = none)
Checks if any item in the array matches the given predicate, or if the array contains any items if no predicate is given.
predicate
can either be none
, or a function that takes one argument: (any value) => bool
.
For example, [4, 5, 6].any(n => n > 5)
returns 1
(true).
bool all(function predicate)
Checks if all items in the array match the given predicate.
predicate
can either be none
, or a function that takes one argument: (any value) => bool
.
For example, [4, 5, 6].any(n => n > 5)
returns none
(false).
Numerical
number|none max(funtion selector = none)
Returns the highest number from the array. An optional selector function can be provided to convert items to a number first. Returns none
if the array does not contain any numbers.
selector
can either be none
, or a function that takes one argument and that returns a number: (any value) => number
.
For example, [4, 8, 3].max()
returns 8
.
number|none min(function selector = none)
Returns the lowest number from the array. An optional selector function can be provided to convert items to a number first. Returns none
if the array does not contain any numbers.
selector
can either be none
, or a function that takes one argument and that returns a number: (any value) => number
.
For example, [4, 8, 3].min()
returns 3
.
number|none sum(function selector = none)
Returns the sum of all the numbers in the array. An optional selector function can be provided to convert items to a number first. Returns 0
if the array does not contain any numbers.
selector
can either be none
, or a function that takes one argument and that returns a number: (any value) => number
.
For example, [4, 8, 3].sum()
returns 15
.
7.2.4. object
An object is a collection of named values. It can be used to create more complex data types. An object is written as {field1: value1, field2: value2}
.
Objects do not have default properties or functions. Their fields act as properties instead.
See also: standard object functions.
7.2.5. function
A function is a piece of code that, when called, returns a value. For example, max(4, 5)
calls a function named max
, passing two numbers as arguments (inputs). The result of a function call is the value returned by the function. Functions can require multiple arguments, and some functions have optional arguments, but they always return a single value.
In MScript, functions are 'first-class citizens': just like other values, they can be passed to other functions, and stored in arrays and objects.
Sometimes it's useful to create an 'anonymous' function on the spot, for example when using the array.map
and array.filter
functions. An anonymous function can be created as following: (a, b) => a + b
, where the (a, b)
part defines the required arguments and the part after the =>
is the function 'body', the code that produces the function's output. For example, numbers_array.map(n => n * 2)
uses an anonymous function to multiply every number in numbers_array
by 2
.
See also: standard function functions.
7.2.6. none
none
is a special value that indicates the absence of a value. It is the only value that is treated as false in boolean situations.