VariablesWML
From Wesnoth
Contents |
Purpose
Variables are used to record information for later use.
For instance, assume that a choice a player makes in one scenario should affect a later scenario. With a variable, that choice can be recorded, and made available to the later scenario.
Overview
Each variable is given a name. A given variable name may contain only alphabetic characters, digits, and underscores.
A variable can be assigned, queried, and cleared.
- Assigning a value to a variable (usually with [set_variable]) stores that value in the variable. Every variable can be assigned an initial value at the beginning of a scenario by using the [variables] tag.
- Querying a variable returns the last value stored in it (or the empty string, if no value was).
- Clearing a variable makes Wesnoth forget about that variable. This is useful since Wesnoth must save all used variables when a game is saved. A variable can be cleared using [clear_variable].
In these operations, a variable is identified by its full name.
Kinds of Variables
Scalar
A scalar variable can store a single string or number. It is usually assigned using [set_variable] or with the {VARIABLE} macros, for example {VARIABLE foo (_"sample value")}
The full name of a scalar variable is simply its given name.
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.
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]. You can create your own arrays using [set_variable] like this:
[set_variable] name=my_awsome_array[0].x value=10 [/set_variable] [set_variable] name=my_awsome_array[1].x value=12 [/set_variable] [set_variable] name=my_awsome_array[2].x value=14 [/set_variable]
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 foo.length is the special variable that always stores the number of containers in foo. Hence, if the value stored in foo.length is 18, the last container is foo[17].
If you try to use an Array as if it were a Container, then it will simply use the first index[0]. So $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 or foo_3 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.)
Variable substitution
Variables can be queried in EventWML using [variable] inside an [if] or [while]. Also, when using EventWML, a scalar variable (or scalar variable inside another variable) can be substituted into the right-hand of an '=' assignment to an attribute. Finally, when using [set_variable], the substitution mode can be specified directly.
When providing attributes, there are 2 different substitution modes:
- literal
- the attribute value is used exactly as provided
- complex
- while the provided value contains a $, interpret what is between the rightmost $ and the next | as a full variable name to be queried, and replace $variablename| 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 precise 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.
The substitution mode used depends on the attribute being provided:
- literal
- [set_variable] literal=
- complex
- everywhere else (in EventWML)
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], ...
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
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
[/variable]
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.
More Examples
The implemention of UtilWML makes heavy use of variables, in particular the definition of {FOR_EACH} and {MODIFY_UNIT}. So does the implementation of Victory_Conditions#Victory_by_controlling_villages.
