SyntaxWML
Tag and Attribute Structures
Basic Syntax
The Wesnoth Markup Language (WML) has a syntax containing two basic elements: tags and attributes. Furthermore, attributes consist of keys and values. For example:
[tag] key=value [/tag]
Tags are used to partition information, while the data is contained in the attributes. Keys define the type of data to be stored and values are the actual data stored. When this attribute is processed, the value of key for the tag that the attribute is in is set or changed to value. All text from '=' until the end of the line is considered to be part of value. Note that keys are not variables! Each predefined tag will accept a predefined set of keys, and changing the values of those keys will configure the behavior of that tag. Tag and key names (not values) may only contain alphanumerics and underscores: no +, -, or whitespaces are allowed. Tags also can be a child of another tag. For example:
[tag] key=value [tag] key=value [/tag] [/tag]
A top level tag is a tag that is not inside any other tag. Every tag describes something different about the game; different tags work differently. For information about how a certain tag works, see ReferenceWML.
A comment is any line that starts with a pound (#) sign, with certain exceptions (see PreprocessorRef). All the text after the pound sign will be ignored by the WML engine.
Please refer to ConventionsWML to make your code cleaner and more readable.
Special Syntaxes
Tag Amendment Syntax
[tag] key=value [/tag] [+tag] key=value [/tag]
- This +tag allows to adding or replace the attributes in the most recent [tag]. Any new keys in the +tag will be set to the given values, and keys that are the same will be replaced with the new values.
- Also, any child tags contained within the +tag will be appended to the children of the most recent [tag]. To be clear: none of those original child tags within the [tag] will be altered by this operation, since this is an "append" and not a "merge."
- Currently, you are not allowed to make tag amendments to a child tag after the parent tag has already closed. Using [+tag] syntax multiple times in a row will not allow you to amend the more inward scopes. However, this limitation may be removed in future versions of Wesnoth.
Multiple Assignment Syntax
[tag] key1,key2,key3=value1,value2,value3 [/tag]
- This is a multiple assignment. If there are extra keys, they will be set to an empty value. If there are extra values the last key will be set to the comma separated list of all remaining values. This would be the same as:
[tag] key1=value1 key2=value2 key3=value3 [/tag]
Special Attribute Values
Although an attribute's value can be just text corresponding to the function of its key, a value can also be encoded in many other ways, each with a specific purpose:
- key="value": a quoted value is a value surrounded by quotes. Note for single-line values this is completely unnecessary, but for multiple-line values this is required to avoid being processed as a single-line value. Quotes are sometimes used for clarity in single-line values.
- key= _ "value": a translatable value is a value that is intended to be translated (most notably seen in [story], [message], and the name= key in unit definitions). Note the quotes surrounding the value: they are required.
- key="value1" + "value2": the plus sign (+) may be used to concatenate two different strings. If you want to have a value that actually has a plus sign (+) in it, you need to enclose the string containing the + character in quotes. Note the quotes around the pre-concatenated values.
- key="quoted ""double quoted value"" value": double quotes can be used to create quote marks within a quoted value.
- key=$variable: a variable substitution sets the key to the value of the WML variable variable. See below for more information on WML-variable based values.
- key="$(formula-expression)": this sets the key to the value of the formula expression once processed. See FormulaAI for more information on Formula Basics, Data Types, and Built-in functions. Since formulas often need to use the plus sign (+), it is advisable to always enclose formula expressions in quotes.
Variables
Overview
A WML variable can be manipulated in three ways:
- Assigning a value to a variable stores that value in the variable. This is done with [set_variable] or the {VARIABLE} macro.
- Querying a variable returns the last value stored in it (or the empty string, if no value was). This is done by calling $variable.
- Clearing a variable makes the WML engine forget about that variable. This is useful since the WML engine must save all used variables when a game is saved. This is done with [clear_variable] or the {CLEAR_VARIABLE} macro.
Each variable is given a name. A given variable name may contain only alphanumerics and underscores. A variable in these operations is identified by its full name. For more information on macros, please refer to PreprocessorRef
Kinds of Variables
Scalar
A scalar variable can store a single string or number.=
[set_variable] name=my_variable value="sample value" [/set_variable]
The full name of a scalar variable is its given name, in this case my_variable. Note that the value of the variable can be translatable or even a formula expression.
Array
An array variable is a numbered sequence of container variables. There are some specific tags that assign array information, for example [store_unit] and [store_locations]. One could create an array using [set_variable] like this:
[set_variable] name=my_awesome_array[0].x value=10 [/set_variable] [set_variable] name=my_awesome_array[1].x value=12 [/set_variable] [set_variable] name=my_awesome_array[2].x value=14 [/set_variable]
However, when working with arrays, it is usually easier to make use of [set_variables]. This would be written as follows:
[set_variables] name=my_awesome_array [value] x=10 [/value] [value] x=12 [/value] [value] x=14 [/value] [/set_variables]
If foo is the name of an array, foo[0] is the full name of its first container variable, foo[1] the full name of its second, and so on. foo.length is the special variable that always stores the number of containers in the array foo. Hence, if the value stored in foo.length is 18, the last container in the array would be foo[17]. If you try to query an array as if it were a container, then it will simply use the first index[0]. Thus $foo.bar would be the same as $foo[0].bar
Note: Do not attempt to store a scalar value to the explicit index of an array, which is a container of scalar variables. Hence referring to a variable named foo[3] as if it were a scalar one is illegal; instead, you would use foo[3].value to store a scalar value. (While it may appear to work to an extent if you ignore this rule, it may also cause undefined behavior. For example, loading a text save of a game that contains such variables will fail with a WML error.)
Container
A container variable can store any number of scalar and/or array variables. There are tags to assign specific information, for instance [store_side]. To refer to a variable bar stored in a container foo you would write foo.bar. An explicit index inside an array is also considered a container.
Conditionals
Variables and be compared with and used in a conditional block by [variable] within an [if] or [while] tag. For more information, please refer to ConditionalActionsWML.
Variable Substitution
Whenever using a $ in front of a variable name, the content which has previously been put into this variable name is used instead of the name of the variable. For example:
[event] name=turn 1 [set_variable] name=my_variable value= _ "Konrad" [/set_variable] [message] speaker=Delfador message= _ "Hello, $my_variable|... How are you?" [/message] [/event]
The WML code above will cause Delfador to say "Hello, Konrad... How are you?" on turn 1.
When writing scenario events (EventWML), a scalar variable can generally be substituted into the right-hand of any key=value assignment. If the provided value contains a $, the WML engine with interpret what is between the rightmost $ and the next | as a full variable name to be queried, and replace $variable| with the result of this query.
In certain situations, the | that marks the end of the variable name to be queried can be omitted. The exact rule is: if there is no |, variable names span letters, digits, underlines, balanced square brackets and some periods. Doubled periods and some periods that would result in an illegal variable name will not be included. If the variable name ends up being empty (e.g. when using $|), then it will be replaced by just $, giving you an easy way to include a dollar sign in an interpolated string.
Literal Mode
There are a few places where the substitution mode is literal. In these places, attribute value are used exactly as provided, nothing is substituted, and the $ will not have special significance. The following places use the literal mode:
- value of literal= inside [set_variable]
- contents of [literal] inside [set_variables]
Automatically Stored Variables
- side_number: the number of the current player's side (may be empty during start or prestart events)
- turn_number: the number of the current turn (may be empty during start or prestart events)
- x1: this is the x-coordinate of the location where the most recent event was triggered
- y1: this is the y-coordinate of the location where the most recent event was triggered
- x2: this is the x-coordinate of the location that assisted in triggering the most recent event
- y2: this is the y-coordinate of the location that assisted in triggering the most recent event
- unit: inside an event, this is the unit at $x1,$y1
- second_unit: inside an event, this is the unit at $x2,$y2
- this_unit: inside a standard unit filter, this is the unit currently being considered for a possible match
- damage_inflicted: inside attacker_hits and defender_hits events, this is the amount of damage that was inflicted
- weapon: inside attack, attacker_hits, defender_hits, die and last_breath events, this is some information about the weapon that is/was being used by the unit at $x1,$y1. It contains the attributes from [attack], see UnitTypeWML.
- second_weapon: inside attack, attacker_hits, defender_hits, die and last_breath events, this is some information about the weapon that is/was being used by the unit at $x2,$y2. It contains the attributes from [attack], see UnitTypeWML.
Note: Automatically stored container and array variables are only stored once that one of their attributes is accessed for the first time. This means that one can sometimes get wrong results, for instance by killing the unit at $x1,$y1 as first action in a moveto event and then accessing $unit.something. This can be worked around by previously making a dummy access, such as adding 0 to hitpoints.
The [variables] tag
The [variables] tag is used in saved games to describe the current value of each variable, and in scenario files for assigning initial values to variables at scenario start.
A scalar variable is assigned using an attribute, where the attribute's key is the variable's given name, and the attribute's value is the value to be stored in the variable.
A container variable with given name foo is assigned using a [foo] tag that contains the definitions for the contained variables.
An array variable with given name foo is assigned using several [foo] tags, where the first tag describes foo[0], the second foo[1], ...
Storing variables inside units
Sometimes it is useful to store a custom WML variable inside a unit. Units stored with the [store_unit] command have a unit.variables sub-container where custom variables related to that unit may be saved. (Remember to [unstore_unit] for the changes to be kept.) One benefit of this approach is that the unit may then be filtered based on the value, for example:
[filter] [filter_wml] [variables] my_variable="test" [/variables] [/filter_wml] [/filter]
Variable Usage Examples
Consider a saved game with the following [variables] tag (or a freshly started scenario with that tag)
[variables] attitude_of_elves=hate attitude_of_dwarves=love attitude_of_humans=like current_opponent=elves [/variables]
Then,
[message] message="Oh, I see $current_opponent|! They surely $attitude_of_$current_opponent|| us!" [/message]
displays the message
Oh, I see elves! They surely hate us!
Consider another game with variables
[variables] our_side=1 their_side=2 [/variables]
where side 1 has 75 gold, and side 2 50 gold. Then,
[store_side] side=$our_side variable=we [/store_side] [store_side] side=$their_side variable=they [/store_side] [message] message=We have $we.gold gold, they have $they.gold gold. [/message] [if] [variable] name=we.gold greater_than=$they.gold [/variable] [then] [message] message=This should be easy! [/message] [/then] [else] [message] message=This will not be easy! [/message] [/else] [/if] [clear_variable] name=we [/clear_variable] [clear_variable] name=they [/clear_variable]
displays the messages
We have 75 gold, they have 50 gold. This should be easy!
If side 2 had 100 gold instead, the same code would display the messages
We have 75 gold, they have 100 gold. This will not be easy!
The code
[store_unit] [filter] canrecruit=yes side=1 [/filter] variable=leader [/store_unit] [message] message=Our leader's first attack does $leader[0].attack[0].damage damage per hit. [/message] [clear_variable] name=leader [/clear_variable]
always displays a true sentence.
You may find more complicated examples of variable use in the UsefulWMLFragments section.