...
<?xml version="1.0" encoding="utf-8"?>
<mdscript name="ScriptName" ...>
<cues>
<cue name="RootCue1"> [...]
</cue>
<cue name="RootCue2"> [...]
</cue>
</cues>
</mdscript>
Anchor cues cues
Cues
cues | |
cues |
Cues are the main ingredient of an MD script. A cue consists of a set of conditions and a set of actions. When the conditions are met, the cue is activated and the actions are performed. A cue can have child cues, or sub-cues: A sub-cue exists only when its parent cue has become active, so the activation of the parent cue initiates the condition checks of its child cues.
...
Note |
---|
This sub-section requires basic knowledge of script expressions, see the section below. |
In case of instances with sub-instances, you will often want to access a related instance from the current one. Like in the non-instance case, you can simply write the cue name in an expression to reference that cue. However, you should be aware of the pitfalls that are accompanied by this.
...
Conditions with results: If the instantiating cue has conditions with results, those results are stored in variables - but in the variables of the static cue, not of the instance! So in the <actions> you have to access the variables via the static keyword:
<debug_text text="static.$foo"/>
It may even be necessary to copy the variables over to the instance because the static variables can be overwritten by the next condition check:<set_value name="$foo" exact="static.$foo"/>
Resetting completed/cancelled instances: As explained above, sub-instances are only created when needed (when going to the waiting state) and are destroyed when they are not needed any more (when they are completed or cancelled, including all sub-cues). There are cases in which you want to access cues that don’t exist any more - it simply doesn’t work. In some cases you are safe: You can be sure that all your ancestors exist, and instantiating cues won’t be removed until they are cancelled. In some other cases you simply don’t know and have to check if the instance is already (or still) there.
Lifetime of instances: Do not make assumptions about when an instance is removed! Just looking at it in the Debug Manager keeps it alive for the time being. So, sometimes you could still have a completed instance that wouldn’t exist under other circumstances.
Anchor expressions expressions
Expressions
expressions | |
expressions |
Most of the attribute values in actions and conditions are interpreted as script expressions and parsed accordingly. An expression is a phrase that can be evaluated to a single value. The simplest expressions are actual numeric values and strings, so called literals:
...
Data type | Suffix | Examples | Description |
---|---|---|---|
null | (none) | null | Converted to non-null data type of value 0 when needed. |
integer | i | 42 | 32-bit signed integer. Default for integer literals, so the suffix is not required for them. |
largeint | L | 0x1ffffffffL | Large 64-bit signed integer. |
float | f | 3.14 0x100f | 32-bit float (single precision). Default for floating point literals, so the suffix is not required for them. |
largefloat | LF | 1.5e300 LF | Large 64-bit floating point number (double precision). |
money | ct (default) | 200Cr | Money in Credits or cents, always stored in cents. Do not forget to write Cr when working with Credits. |
length | m (default) km | 500m 2.3km | Length in metres or kilometres, respectively. A length value is always stored in metres. |
angle | rad (default) deg | 90deg 3.14159rad | Angle in radians or degrees, respectively. An angle value is always stored in radians. |
hitpoints | hp | 100hp | Hit points |
time | ms s (default) min h | 800ms 1.5s 10min 24h | Time in milliseconds, seconds, minutes, or hours, respectively. A time value is always stored in seconds. |
Note |
---|
All unit data types are floating point types, except for money, which is an integer data type. |
Anchor operators operators
Operators
operators | |
operators |
You can build expressions by combining sub-expressions with operators. For Boolean operations, expressions are considered “false” if they are equal to zero, “true” otherwise. The following operators, delimiters, and constants are supported:
...
Operator / Delimiter / Constant | Type | Example | Result of example | Description |
---|---|---|---|---|
null | constant |
|
| Null value, see above |
false | constant |
|
| Integer value 0, useful in Boolean expressions |
true | constant |
|
| Integer value 1, useful in Boolean expressions |
pi | constant |
|
| π as an angle (same as 180deg) |
() | delimiter |
|
| Parentheses for arithmetic grouping |
[] | delimiter |
|
| List of values (see below) |
table[] | delimiter | table[$foo='bar', {1+1}=40+2] | table[$foo='bar', {2}=42] | Table of values (see below) |
{} | delimiter |
|
| Text lookup (page ID and text ID) from TextDB |
+ | unary |
|
| Denotes positive number (no effect) |
- | unary |
|
| Negates the following number |
not | unary |
|
| Yields true if the following expression is false (equal to zero), false otherwise |
typeof | unary |
|
| Yields the data type of the following sub-expression |
sin | unary |
|
| Sine (function-style, parentheses required) |
cos | unary |
|
| Cosine (function-style, parentheses required) |
sqrt | unary |
|
| Square root (function-style, parentheses required) |
exp | unary |
|
| Exponential function (function-style, parentheses required) |
log | unary |
|
| Natural logarithm (function-style, parentheses required) |
^ | binary |
|
| Power |
* | binary |
|
| Multiplication |
/ | binary |
|
| Division |
% | binary |
|
| Modulus (remainder of integer division) |
+ | binary |
|
| Addition String concatenation |
- | binary |
|
| Subtraction |
lt < (<) | binary |
|
| Less than |
le <= | binary |
|
| Less than or equal to |
gt > (>) | binary |
|
| Greater than |
ge >= | binary |
|
| Greater than or equal to |
== | binary |
|
| Equal to |
!= | binary |
|
| Not equal to |
and | binary |
|
| Logical AND (short-circuit semantics) |
or | binary |
|
| Logical OR (short-circuit semantics) |
if ... then ... if ... then ... else ... | ternary |
|
| Conditional operator ("inline if") |
...
Of course a Boolean operation always results in true or false (integer 1 or 0).
Values of any type can be used as Boolean operands, e.g. for “and”. They will be interpreted as “true” if they are non-zero or non-numeric.
!= and == can be used with any data types, even non-numeric ones. When comparing two numeric values, they are converted using the rules above. Values of non-numeric types are never equal to null, or to any other numbers.
“and” and “or” use short-circuit semantics: The right side of the operation can be skipped if the left side already determines the outcome of the operation
Example:
false and $foo
⟹false
(the value of $foo is not checked at all)
Unlike != and ==, the comparison operators <, <=, >, >= are only supported for numeric values, difficulty levels, and attention levels. Comparing other non-numeric values will result in an error and an undefined result.
<, <=, >, >= cannot be used in XML directly, so lt, le, gt, ge are provided as alternatives. In some cases you won’t have to use them, though - using range checks with additional XML attributes can be more readable (see below).
Anchorstrings strings
Strings and formatting
strings | |
strings |
...
See also the section about value properties below.
Instead of ‘%1 %2 %3’, you can also use ‘%s %s %s’, which is also compatible with Lua string formatting in the UI system. However, this should only be used if you are sure that the order is the same in all supported languages. If you want to make translators aware that they can change the order of parameters, you should prefer '%1 %2 %3'.
...
- The "," and "." formatting modifiers only apply to numbers. They are ignored if used on values of other types.
- If "," is used without "." then any fractional digits are discarded.
- "." must be followed by a single digit (0-9). In case of ".0" any fractional digits are discarded (rounding towards zero, not half away from zero).
Info |
---|
There are also special methods to format money values and time values using the "formatted" property |
...
. |
Anchor lists lists
Lists
lists | |
lists |
Another example for a non-numeric value is a list: It is an ordered collection of other arbitrary values (called array or vector in other languages). It can be constructed within an expression using the [] syntax, see above. It may also be generated by special actions and conditions, and there are actions that can insert or remove values.
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 section about value properties. Lists can be empty, they these are written as “[ ]”.
Note |
---|
When accessing a list’s elements, the numbering is 1-based, so the first element has number 1. This is intuitive but different from 0-based numbering in most programming languages. |
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.
Anchor tables tables
Tables
tables | |
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 value properties for how to access the contents of a table. Creating and removing entries works similarly to lists, but instead of inserting, you simply assign a value to a table key. If the key does not exist yet, it will be created.
Almost all values are allowed as table keys, but there are a few exceptions:
...
Just like lists, tables are stored as references, so it's possible that multiple variables reference the same table (see above).
Anchor valueproperties valueproperties
Value properties
valueproperties | |
valueproperties |
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.
...
Data type (= value name) | Examples | Description |
---|---|---|
class | class.ship class.ship_xl class.space class.weapon | Component classes |
purpose | purpose.combat purpose.transportation | Purposes |
killmethod | killmethod.hitbybullet killmethod.hitbymissile | Ways to die (already used before destruction) |
datatype | datatype.float datatype.component datatype.class datatype.datatype | Script value datatypes (see typeof operator above) |
profile | profile.flat profile.increasing profile.bell | Probability distribution profile (see random ranges below) |
cuestate | cuestate.waiting cuestate.active cuestate.complete | Cue states (see above) |
level | level.easy level.medium level.veryhard | Mission difficulty levels (comparable with each other using lt, gt, etc.) |
attention | attention.insector attention.visible attention.adjacentzone | Attention levels (comparable with each other using lt, gt, etc.) |
ware | ware.ore ware.silicon | Wares |
race | race.argon race.boron | Races |
faction | faction.player faction.argongovernment | Factions |
Note | ||||||
---|---|---|---|---|---|---|
However, you should not compare the type to datatype.string because there are strings that have different data types. To check for a string you should use the datatype's property "isstring" instead. For example, to check if the variable $value is a string, use the following term:
|
Info |
---|
There is also the datatype “tag” with the lookup name “tag” - however, this is not an enumeration type. Looking up a value by name never fails, you actually create a tag value for a given name if it does not exist. For example, if you have a typo, like “tag.mision” instead of “tag.mission”, there won’t be an error because any name is valid for a tag, and the tag “mision” is created on its first use. |
...
There are many commonly used actions and conditions which share groups of attributes. The most important ones are explained here.
Anchor #valuecomparisons #valuecomparisons
Value comparisons
#valuecomparisons | |
#valuecomparisons |
There are many conditions and conditional actions that require a value comparison, for example the condition <check_value>:
...
Note |
---|
Values of most enumeration types cannot be compared via min or max (also not via lt, gt, etc.). The only data types that can be used with min and max are numbers and the enumeration types level and attention (see aboveBoolean operators). The exact attribute can be used with any type, and is equivalent to using the == operator. |
Anchor randomranges randomranges
Random ranges
randomranges | |
randomranges |
If an action requires a value, e.g. when you set a variable to a value, you can have some randomisation. To specify an exact value, e.g. in <set_value>, you can write this:
...
As you have seen above, you can easily access variables by writing their name (including $ prefix) in an expression. Namespaces define in which cue the variables are actually stored (and from which cue they are read).
Anchor createremovevariables createremovevariables
Creating and removing variables
createremovevariables | |
createremovevariables |
You can create variables with certain actions and conditions, such as the <set_value> action:
...
Warning |
---|
Although in general the expression “$foo == namespace.$foo” is true, there is one exception: When library parameters are evaluated in the referencing cue, variables are resolved using the parent’s namespace. However, the referencing cue creates a new namespace, so the namespace keyword already points to the library, not to the parent’s namespace. Example:
|
There are also special methods to format money values and time values using the "formatted" property.