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 my_variable "sample value"}
which is shorthand for:
[set_variable] name=my_variable value="sample value" [/set_variable]
The full name of a scalar variable is simply its given name, in this case my_variable.
Values such as "sample value" can also be marked as translatable (_"sample value") or even include special formula syntax ("$(1+2)"). For more details about WML syntax features, refer to SyntaxWML.
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_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 the [set_variables] command (note the extra 's' at the end). 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 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 testing
Variables can be tested by using [variable] inside an [if] or [while]. See ConditionalWML for more details.
Variable substitution (variable's $)
in short:
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=moveto
[set_variable]
name=my_var
value=my_value
[/set_variable]
[message]
speaker=narrator
message=_"my_var: $my_var|" # output: "my_var: my_value"
[/message]
[/event]
technical explanation:
When writing scenario events using EventWML, a scalar variable can generally be substituted into the right-hand of any key=value assignment, for example:
message="Hello, $my_variable"
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=
- [set_variables] [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], ...
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]
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.
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.
More Examples
The implemention of UtilWML makes heavy use of variables, in particular the definition of {FOR_EACH} and {MODIFY_UNIT}. You may find more complicated examples of variable use in the UsefulWMLFragments section.
