<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.wesnoth.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Celtic+Minstrel</id>
	<title>The Battle for Wesnoth Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.wesnoth.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Celtic+Minstrel"/>
	<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/Special:Contributions/Celtic_Minstrel"/>
	<updated>2026-05-24T12:59:05Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.16</generator>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GUIWidgetInstanceWML&amp;diff=75015</id>
		<title>GUIWidgetInstanceWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GUIWidgetInstanceWML&amp;diff=75015"/>
		<updated>2026-04-30T05:27:06Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Spacer */ Don't make external link to internal page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Widget instance ==&lt;br /&gt;
Inside a grid (which is inside all container widgets) a widget is&lt;br /&gt;
instantiated. With this instantiation some more variables of a widget can&lt;br /&gt;
be tuned. This page will describe what can be tuned.&lt;br /&gt;
&lt;br /&gt;
== Widget ==&lt;br /&gt;
All widgets placed in the cell have some keys in common, that can be used in any widget in addition to the widget-specific keys listed below.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| This value is used for the engine to identify 'special' items. This means that for example a text_box can get the proper initial value. This value should be unique or empty. Those special values are documented at the window definition that uses them. NOTE items starting with an underscore are used for composed widgets and these should be unique per composed widget.&lt;br /&gt;
|-&lt;br /&gt;
| definition&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;default&amp;quot;&lt;br /&gt;
| The id of the widget definition to use. This way it's possible to select a specific version of the widget e.g. a title label when the label is used as title.&lt;br /&gt;
|-&lt;br /&gt;
| linked_group&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The linked group the control belongs to.&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| Most widgets have some text associated with them, this field contain the value of that text. Some widgets use this value for other purposes, this is documented at the widget. E.g. an image uses the filename in this field.&lt;br /&gt;
|-&lt;br /&gt;
| use_markup&lt;br /&gt;
| | [[GUIVariable#bool|bool]]&lt;br /&gt;
| false&lt;br /&gt;
| Whether [https://docs.gtk.org/Pango/pango_markup.html Pango Markup] could be used to format the `label` of this widget (bold, italic, font color, alpha etc.)&lt;br /&gt;
|-&lt;br /&gt;
| tooltip&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If you hover over a widget a while (the time it takes can differ per widget) a short help can show up.This defines the text of that message. This field may not be empty when 'help' is set.&lt;br /&gt;
|-&lt;br /&gt;
| help&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If you hover over a widget and press F10 (or the key the user defined for the help tip) a help message can show up. This help message might be the same as the tooltip but in general (if used) this message should show more help. This defines the text of that message.&lt;br /&gt;
|-&lt;br /&gt;
| use_tooltip_on_label_overflow&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If the text on the label is truncated and the tooltip is empty the label can be used for the tooltip. If this variable is set to true this will happen.&lt;br /&gt;
|-&lt;br /&gt;
| debug_border_mode&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The mode for showing the debug border. This border shows the area reserved for a widget. This function is only meant for debugging and might not be available in all Wesnoth binaries. Available modes: &lt;br /&gt;
* '''0:''' no border. &lt;br /&gt;
* '''1:''' 1 pixel border. &lt;br /&gt;
* '''2:''' floodfill the widget area.&lt;br /&gt;
|-&lt;br /&gt;
| debug_border_color&lt;br /&gt;
| [[GUIVariable#color|color]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The color of the debug border.&lt;br /&gt;
|-&lt;br /&gt;
| size_text&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| Sets the minimum width of the widget depending on the text in it. (Note not implemented yet.)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Button ==&lt;br /&gt;
&lt;br /&gt;
[[File:Button.png|thumb|left|An example of a Button]]&lt;br /&gt;
&lt;br /&gt;
A button is a control that can be pushed to start an action or close a dialog.&lt;br /&gt;
&lt;br /&gt;
Instance of a button. When a button has a return value it sets the&lt;br /&gt;
return value for the window. Normally this closes the window and returns&lt;br /&gt;
this value to the caller. The return value can either be defined by the&lt;br /&gt;
user or determined from the id of the button. The return value has a&lt;br /&gt;
higher precedence as the one defined by the id. (Of course it's weird to&lt;br /&gt;
give a button an id and then override its return value.)&lt;br /&gt;
&lt;br /&gt;
When the button doesn't have a standard id, but you still want to use the&lt;br /&gt;
return value of that id, use return_value_id instead. This has a higher&lt;br /&gt;
precedence as return_value.&lt;br /&gt;
&lt;br /&gt;
List with the button specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Supported values for return_value_id:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!string&lt;br /&gt;
!value&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;ok&amp;quot;||-1||Equivalent to closing the dialog by pressing the Enter key&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;cancel&amp;quot;||-2||Equivalent to closing the dialog by pressing the Esc key&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;quit&amp;quot;||-2||An alias for cancel&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;&amp;quot;||N/A||Clears any previously set return_value_id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Combobox ==&lt;br /&gt;
{{DevFeature1.19|0}}&lt;br /&gt;
[[File:Combobox.png|frame|right|A Combobox with its list open]]&lt;br /&gt;
A widget with a text box and a dropdown list. Selecting an element from the list sets the value of the text box to that item of the list. The user can also manually enter a value in the text box.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! key !! type !! default !! description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The text of the combobox&lt;br /&gt;
|-&lt;br /&gt;
| max_input_length || [[GUIVariable#int|int]] || 0 || Maximum length of text in characters that can be entered into the combobox&lt;br /&gt;
|-&lt;br /&gt;
| hint_text || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Text that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| hint_image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image that is shown in the background when there is no input&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;combobox&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| value || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Value of the option. Defaults to &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; if unspecified.&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || User visible translatable name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| icon || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || WML path to the icon to be shown alongside the text in this option, if any.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Drawing ==&lt;br /&gt;
A drawing is widget with a fixed size and gives access to the canvas of the widget in the window instance. This allows special display only widgets.&lt;br /&gt;
&lt;br /&gt;
If either the width or the height is not zero the drawing functions as a&lt;br /&gt;
fixed size drawing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| [[GUIVariable#f_unsigned|f_unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The width of the drawing.&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| [[GUIVariable#f_unsigned|f_unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The height of the drawing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [draw] ===&lt;br /&gt;
A mandatory WML block (config) containing the drawing instructions, in the same format as [[GUICanvasWML]]. For an example, see this snippet from the [https://github.com/wesnoth/wesnoth/blob/9bd7614e89269b5456ee51ade3cc0af73efc99f5/data/gui/themes/default/dialogs/attack_predictions.cfg#L100 Attack predictions dialog].&lt;br /&gt;
&lt;br /&gt;
The variables available are the same as for the window resolution, see&lt;br /&gt;
[[GUIToolkitWML#Resolution_2|GUIToolkitWML]] for the list of&lt;br /&gt;
items.&lt;br /&gt;
&lt;br /&gt;
== Grid Listbox ==&lt;br /&gt;
List with the listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!ID (return value)&lt;br /&gt;
!Type&lt;br /&gt;
!Mandatory&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Horizontal listbox ==&lt;br /&gt;
A horizontal listbox is a control that holds several items of the same type.  Normally the items in a listbox are ordered in rows, this version orders them in columns instead.&lt;br /&gt;
&lt;br /&gt;
List with the horizontal listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!ID (return value)&lt;br /&gt;
!Type&lt;br /&gt;
!Mandatory&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In order to force widgets to be the same size inside a horizontal listbox,&lt;br /&gt;
the widgets need to be inside a linked_group.&lt;br /&gt;
&lt;br /&gt;
Inside the list section there are only the following widgets allowed&lt;br /&gt;
* grid (to nest)&lt;br /&gt;
* selectable widgets which are&lt;br /&gt;
** toggle_button&lt;br /&gt;
** toggle_panel&lt;br /&gt;
&lt;br /&gt;
== Image ==&lt;br /&gt;
An image shows a static image whose path is specified by its '''[[GUIWidgetInstanceWML#Widget|label]]''' key. Unlike other widgets, the '''label''' key here is not translatable since it specifies a path. The path is a standard WML path, i.e., &amp;lt;code&amp;gt;label=&amp;quot;units/konrad.png&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;label=&amp;quot;~add-ons/MyAddon/image/test.png&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It has no other extra fields.&lt;br /&gt;
&lt;br /&gt;
== Label ==&lt;br /&gt;
A label displays text provided via the '''[[GUIWidgetInstanceWML#Widget|label]]''' key that can be wrapped but no scrollbars are provided. For a version with scrollbars, see the [[GUIWidgetInstanceWML#Scroll_Label|Scroll Label]] widget.&lt;br /&gt;
&lt;br /&gt;
[[File:Title Label.png|frame|right|A Label with definition &amp;quot;title&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
List with the label specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| wrap || [[GUIVariable#bool|bool]] || false || Is wrapping enabled for the label.&lt;br /&gt;
|-&lt;br /&gt;
| characters_per_line || [[GUIVariable#unsigned|unsigned]] || 0 || Sets the maximum number of characters per line. This is only an approximate means of limiting the line's length, since the width of a character differs. E.g. iii is smaller than MMM. When the value is non-zero it also implies '''wrap''' is true. &lt;br /&gt;
When having long strings, wrapping them can increase readability. A rule of thumb is 66 characters per line is considered the optimum for a one column text.&lt;br /&gt;
|-&lt;br /&gt;
| text_alignment || [[GUIVariable#h_align|h_align]] || left || The way the text is aligned inside the canvas.&lt;br /&gt;
|-&lt;br /&gt;
| can_shrink || [[GUIVariable#bool|bool]] || false || Whether the label can shrink past its optimal size.&lt;br /&gt;
|-&lt;br /&gt;
| link_aware || [[GUIVariable#bool|bool]] || false || Whether the label is link aware. This means it is rendered with links highlighted, and responds to click events on those links.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Listbox ==&lt;br /&gt;
A listbox is a control that holds several items of the same type. Normally the items in a listbox are ordered in rows, this version might allow more options for ordering the items in the future.&lt;br /&gt;
&lt;br /&gt;
List with the listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In order to force widgets to be the same size inside a listbox, the widgets&lt;br /&gt;
need to be inside a linked_group.&lt;br /&gt;
&lt;br /&gt;
Inside the list section there are only the following widgets allowed&lt;br /&gt;
* grid (to nest)&lt;br /&gt;
* selectable widgets which are&lt;br /&gt;
** toggle_button&lt;br /&gt;
** toggle_panel&lt;br /&gt;
&lt;br /&gt;
== Matrix ==&lt;br /&gt;
List with the matrix specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Menu Button ==&lt;br /&gt;
[[File:Menu Button.png|thumb|left|A Menu Button with it's list open.]]&lt;br /&gt;
A button that shows a dropdown list when clicked. The user can select any one of the predefined options.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;menu_button&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| icon || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || WML path to the icon to be shown alongside the text in this option, if any.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Minimap ==&lt;br /&gt;
A minimap to show the gamemap, this only shows the map and has no interaction options. This version is used for map previews, there will be a another version which allows interaction.&lt;br /&gt;
&lt;br /&gt;
A minimap has no extra fields.&lt;br /&gt;
&lt;br /&gt;
== Multiline Text ==&lt;br /&gt;
{{DevFeature1.17|26}}&lt;br /&gt;
&lt;br /&gt;
Base class for a multiline text area.  Not to be used directly in a GUI, use the [[GUIWidgetInstanceWML#Scroll_Text|scroll_text]] widget instead.&lt;br /&gt;
&lt;br /&gt;
The following variables exist:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The initial text of the text box.&lt;br /&gt;
|-&lt;br /&gt;
| history&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The name of the history for the text box. A history saves the data entered in a text box between the games. With the up and down arrow it can be accessed. To create a new history item just add a new unique name for this field and the engine will handle the rest.&lt;br /&gt;
|-&lt;br /&gt;
| editable&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| &amp;quot;true&amp;quot;&lt;br /&gt;
| If the contents of the text box can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Multimenu Button ==&lt;br /&gt;
[[File:Multimenu Button.png|thumb|right|A Multimenu Button with its list open]]&lt;br /&gt;
A widget clicking on which shows a list from which one or more options can be selected.&lt;br /&gt;
&lt;br /&gt;
List with the multimenu_button specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value || [[GUIVariable#int|int]] || 0 || The return value.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_shown || [[GUIVariable#int|int]] || -1 || The maximum number of currently selected values to list on the button.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;multimenu_button&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| checkbox || [[GUIVariable#bool|bool]] || &amp;quot;&amp;quot; || Whether the checkbox alongside this option is selected or not.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Multi page ==&lt;br /&gt;
A multi page is a control that contains several 'pages' of which only one is visible. The pages can contain the same widgets containing the same 'kind' of data or look completely different.&lt;br /&gt;
&lt;br /&gt;
List with the multi page specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| page_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a multi page item looks. It must contain the grid definition for at least one page.&lt;br /&gt;
|-&lt;br /&gt;
| page_data&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the multi page. Every row must have the same number of columns as the 'page_definition'.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Panel ==&lt;br /&gt;
A panel is an item which can hold other items. The difference between a grid and a panel is that it's possible to define how a panel looks. A grid in an invisible container to just hold the items.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Password box ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The initial text of the password box.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Progress bar ==&lt;br /&gt;
A progress bar shows the progress of a certain object.&lt;br /&gt;
&lt;br /&gt;
A progress bar has no extra fields.&lt;br /&gt;
&lt;br /&gt;
== Repeating button ==&lt;br /&gt;
A repeating_button is a control that can be pushed down and repeat a certain action. Once the button is down every x milliseconds it is down a new down event is triggered.&lt;br /&gt;
&lt;br /&gt;
== Rich Label ==&lt;br /&gt;
{{DevFeature1.19|x}}&lt;br /&gt;
&lt;br /&gt;
A label that shows formatted text marked up with [[Help markup]]. It can show embedded images, links and tables inside text.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| text_alignment || [[GUIVariable#h_align|h_align]] || left || The way the text is aligned inside the canvas.&lt;br /&gt;
|-&lt;br /&gt;
| padding || [[GUIVariable#int|int]] || 5 || Internal padding, used in various spaces and between different types of elements (for example, between two float image, between a header and following text and so on).&lt;br /&gt;
|-&lt;br /&gt;
| link_aware || [[GUIVariable#bool|bool]] || true || Whether the label is link aware. This means it is rendered with links highlighted, and responds to click events on those links.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scroll Label ==&lt;br /&gt;
A scroll label is a label that wraps its text and also has a vertical scrollbar. This way a text can't be too long to be shown for this widget.&lt;br /&gt;
&lt;br /&gt;
List with the scroll label specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scroll Text ==&lt;br /&gt;
{{DevFeature1.19|x}}&lt;br /&gt;
&lt;br /&gt;
A multiline text area that shows a scrollbar if the text gets too long.&lt;br /&gt;
&lt;br /&gt;
List with the scrollbar container specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| editable&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| &amp;quot;true&amp;quot;&lt;br /&gt;
| If the contents of this scroll_text can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scrollbar panel ==&lt;br /&gt;
Instance of a scrollbar_panel.&lt;br /&gt;
&lt;br /&gt;
List with the scrollbar_panel specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a scrollbar_panel item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Size lock ==&lt;br /&gt;
Instance of the size_lock widget. This is a special container that forces the widget enclosed in the [widget] subtag to be of the size specified by the width and height. The [https://github.com/wesnoth/wesnoth/blob/9bd7614e89269b5456ee51ade3cc0af73efc99f5/data/gui/macros/_initial.cfg#L246 GUI_FORCE_WIDGET_SIZE] internal macro is a wrapper around this component.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| -&lt;br /&gt;
| The width the enclosed widget should be forced to (mandatory).&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| -&lt;br /&gt;
| The height the enclosed widget should be forced to (mandatory).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: Both &amp;lt;code&amp;gt;width&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;height&amp;lt;/code&amp;gt; are mandatory even if you want to fix either width or height as of 1.19.23.&lt;br /&gt;
&lt;br /&gt;
=== Subtag [widget] ===&lt;br /&gt;
The widget that should be force-sized.&lt;br /&gt;
&lt;br /&gt;
== Slider ==&lt;br /&gt;
&lt;br /&gt;
A slider is a control that can select a value by moving a grip on a groove.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| best_slider_length&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The best length for the sliding part.&lt;br /&gt;
|-&lt;br /&gt;
| minimum_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The minimum value the slider can have.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The maximum value the slider can have.&lt;br /&gt;
|-&lt;br /&gt;
| step_size&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The number of items the slider's value increases with one step.&lt;br /&gt;
|-&lt;br /&gt;
| value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The value of the slider.&lt;br /&gt;
|-&lt;br /&gt;
| minimum_value_label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If the minimum value is chosen there might be the need for a special value (eg off). When this key has a value that value will be shown if the minimum is selected.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_value_label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If the maximum value is chosen there might be the need for a special value (eg unlimited)). When this key has a value that value will be shown if the maximum is selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Spinner ==&lt;br /&gt;
{{DevFeature1.17|26}}&lt;br /&gt;
&lt;br /&gt;
[[File:Spinner.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
A textbox with two repeating buttons, which allow increasing/decreasing of the numerical value inside the textbox.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| wrap&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| 0&lt;br /&gt;
| Should the contents of the textbox wrap?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Spacer ==&lt;br /&gt;
A spacer is a dummy item to either fill in a widget since no empty items are allowed or to reserve a fixed space.&lt;br /&gt;
&lt;br /&gt;
If either the width or the height is non-zero the spacer functions as a&lt;br /&gt;
fixed size spacer.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| width || [[GUIVariable#f_unsigned|f_unsigned]] || 0 || The width of the spacer.&lt;br /&gt;
|-&lt;br /&gt;
| height || [[GUIVariable#f_unsigned|f_unsigned]] || 0 || The height of the spacer.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The variable available are the same as for the window resolution see&lt;br /&gt;
[[GUIToolkitWML#Resolution_2|GUIToolkitWML]] for the list of&lt;br /&gt;
items.&lt;br /&gt;
&lt;br /&gt;
== Tab Container ==&lt;br /&gt;
{{DevFeature1.19|0}}&lt;br /&gt;
&lt;br /&gt;
A container widget that can show its contents separated into various pages, each of which are accessible.&lt;br /&gt;
&lt;br /&gt;
It can contain one or more &amp;lt;code&amp;gt;[tab]&amp;lt;/code&amp;gt; tags inside it, each defining a tab's name, image (if any) and the contents of the tag, specified by the &amp;lt;code&amp;gt;[data]&amp;lt;/code&amp;gt; tag inside the &amp;lt;code&amp;gt;[tab]&amp;lt;/code&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
=== Subtag [tab] ===&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| name || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the tab&lt;br /&gt;
|-&lt;br /&gt;
| image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image for the tab to be shown alongside the name, if any&lt;br /&gt;
|-&lt;br /&gt;
| [data] || [[GUIVariable#grid|grid]] || empty grid || This subtag contains a grid that defines the contents for this tab.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Text box ==&lt;br /&gt;
A single line text entry widget.&lt;br /&gt;
&lt;br /&gt;
[[File:Text Box.png|frame|right|A Text Box]]&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || The initial text of the text box.&lt;br /&gt;
|-&lt;br /&gt;
| history || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The name of the history for the text box. A history saves the data entered in a text box between the games. With the up and down arrow it can be accessed. To create a new history item just add a new unique name for this field and the engine will handle the rest.&lt;br /&gt;
|-&lt;br /&gt;
| max_input_length || [[GUIVariable#int|int]] || 0 || Maximum length of text in characters that can be entered into the combobox&lt;br /&gt;
|-&lt;br /&gt;
| hint_text || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Text that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| hint_image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| editable || [[GUIVariable#bool|bool]] || &amp;quot;true&amp;quot; || If the contents of the text box can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Toggle button ==&lt;br /&gt;
Variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Toggle panel ==&lt;br /&gt;
A toggle panel is an item which can hold other items. The difference between&lt;br /&gt;
a grid and a panel is that it's possible to define how a panel looks. A grid&lt;br /&gt;
in an invisible container to just hold the items. The toggle panel is a&lt;br /&gt;
combination of the panel and a toggle button, it allows a toggle button with&lt;br /&gt;
its own grid.&lt;br /&gt;
&lt;br /&gt;
Variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id, see [[GUIToolkitWML#Button]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value, see [[GUIToolkitWML#Button]] for more information.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree view ==&lt;br /&gt;
A tree view is a control that holds several items of the same or different types. The items shown are called tree view nodes and when a node has children, these can be shown or hidden. Nodes that contain children need to provide a clickable button in order to fold or unfold the children.&lt;br /&gt;
&lt;br /&gt;
List with the tree view specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| indention_step_size&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The number of pixels every level of nodes is indented from the previous level.&lt;br /&gt;
|-&lt;br /&gt;
| node&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The tree view can contain multiple node sections. This part needs more documentation.&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| .&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| .&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If true, a tree with at least one item will always have something selected (except when items are being deleted). Although this is {{DevFeature1.19|21}}, the previous behavior is equivalent to setting this to true. The GUI doesn't provide a way to unselect items, the purpose of setting this to false is to add a landing page, as the campaign menu does.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
NOTE more documentation and examples are needed.&lt;br /&gt;
&lt;br /&gt;
== Vertical scrollbar ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Viewport ==&lt;br /&gt;
A viewport is an special widget used to view only a part of the widget it `holds'.&lt;br /&gt;
&lt;br /&gt;
List with the viewport specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grow_direction&lt;br /&gt;
| [[GUIVariable#grow_direction|grow_direction]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The direction in which new items grow.&lt;br /&gt;
|-&lt;br /&gt;
| parallel_items&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The number of items that are growing in parallel.&lt;br /&gt;
|-&lt;br /&gt;
| item_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The definition of a new item.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;br /&gt;
[[Category: GUI WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GUIWidgetInstanceWML&amp;diff=75014</id>
		<title>GUIWidgetInstanceWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GUIWidgetInstanceWML&amp;diff=75014"/>
		<updated>2026-04-30T05:26:01Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Subtag [draw] */ Don't make external link to internal page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Widget instance ==&lt;br /&gt;
Inside a grid (which is inside all container widgets) a widget is&lt;br /&gt;
instantiated. With this instantiation some more variables of a widget can&lt;br /&gt;
be tuned. This page will describe what can be tuned.&lt;br /&gt;
&lt;br /&gt;
== Widget ==&lt;br /&gt;
All widgets placed in the cell have some keys in common, that can be used in any widget in addition to the widget-specific keys listed below.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| This value is used for the engine to identify 'special' items. This means that for example a text_box can get the proper initial value. This value should be unique or empty. Those special values are documented at the window definition that uses them. NOTE items starting with an underscore are used for composed widgets and these should be unique per composed widget.&lt;br /&gt;
|-&lt;br /&gt;
| definition&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;default&amp;quot;&lt;br /&gt;
| The id of the widget definition to use. This way it's possible to select a specific version of the widget e.g. a title label when the label is used as title.&lt;br /&gt;
|-&lt;br /&gt;
| linked_group&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The linked group the control belongs to.&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| Most widgets have some text associated with them, this field contain the value of that text. Some widgets use this value for other purposes, this is documented at the widget. E.g. an image uses the filename in this field.&lt;br /&gt;
|-&lt;br /&gt;
| use_markup&lt;br /&gt;
| | [[GUIVariable#bool|bool]]&lt;br /&gt;
| false&lt;br /&gt;
| Whether [https://docs.gtk.org/Pango/pango_markup.html Pango Markup] could be used to format the `label` of this widget (bold, italic, font color, alpha etc.)&lt;br /&gt;
|-&lt;br /&gt;
| tooltip&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If you hover over a widget a while (the time it takes can differ per widget) a short help can show up.This defines the text of that message. This field may not be empty when 'help' is set.&lt;br /&gt;
|-&lt;br /&gt;
| help&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If you hover over a widget and press F10 (or the key the user defined for the help tip) a help message can show up. This help message might be the same as the tooltip but in general (if used) this message should show more help. This defines the text of that message.&lt;br /&gt;
|-&lt;br /&gt;
| use_tooltip_on_label_overflow&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If the text on the label is truncated and the tooltip is empty the label can be used for the tooltip. If this variable is set to true this will happen.&lt;br /&gt;
|-&lt;br /&gt;
| debug_border_mode&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The mode for showing the debug border. This border shows the area reserved for a widget. This function is only meant for debugging and might not be available in all Wesnoth binaries. Available modes: &lt;br /&gt;
* '''0:''' no border. &lt;br /&gt;
* '''1:''' 1 pixel border. &lt;br /&gt;
* '''2:''' floodfill the widget area.&lt;br /&gt;
|-&lt;br /&gt;
| debug_border_color&lt;br /&gt;
| [[GUIVariable#color|color]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The color of the debug border.&lt;br /&gt;
|-&lt;br /&gt;
| size_text&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| Sets the minimum width of the widget depending on the text in it. (Note not implemented yet.)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Button ==&lt;br /&gt;
&lt;br /&gt;
[[File:Button.png|thumb|left|An example of a Button]]&lt;br /&gt;
&lt;br /&gt;
A button is a control that can be pushed to start an action or close a dialog.&lt;br /&gt;
&lt;br /&gt;
Instance of a button. When a button has a return value it sets the&lt;br /&gt;
return value for the window. Normally this closes the window and returns&lt;br /&gt;
this value to the caller. The return value can either be defined by the&lt;br /&gt;
user or determined from the id of the button. The return value has a&lt;br /&gt;
higher precedence as the one defined by the id. (Of course it's weird to&lt;br /&gt;
give a button an id and then override its return value.)&lt;br /&gt;
&lt;br /&gt;
When the button doesn't have a standard id, but you still want to use the&lt;br /&gt;
return value of that id, use return_value_id instead. This has a higher&lt;br /&gt;
precedence as return_value.&lt;br /&gt;
&lt;br /&gt;
List with the button specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Supported values for return_value_id:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!string&lt;br /&gt;
!value&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;ok&amp;quot;||-1||Equivalent to closing the dialog by pressing the Enter key&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;cancel&amp;quot;||-2||Equivalent to closing the dialog by pressing the Esc key&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;quit&amp;quot;||-2||An alias for cancel&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;&amp;quot;||N/A||Clears any previously set return_value_id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Combobox ==&lt;br /&gt;
{{DevFeature1.19|0}}&lt;br /&gt;
[[File:Combobox.png|frame|right|A Combobox with its list open]]&lt;br /&gt;
A widget with a text box and a dropdown list. Selecting an element from the list sets the value of the text box to that item of the list. The user can also manually enter a value in the text box.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! key !! type !! default !! description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The text of the combobox&lt;br /&gt;
|-&lt;br /&gt;
| max_input_length || [[GUIVariable#int|int]] || 0 || Maximum length of text in characters that can be entered into the combobox&lt;br /&gt;
|-&lt;br /&gt;
| hint_text || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Text that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| hint_image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image that is shown in the background when there is no input&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;combobox&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| value || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Value of the option. Defaults to &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; if unspecified.&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || User visible translatable name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| icon || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || WML path to the icon to be shown alongside the text in this option, if any.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Drawing ==&lt;br /&gt;
A drawing is widget with a fixed size and gives access to the canvas of the widget in the window instance. This allows special display only widgets.&lt;br /&gt;
&lt;br /&gt;
If either the width or the height is not zero the drawing functions as a&lt;br /&gt;
fixed size drawing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| [[GUIVariable#f_unsigned|f_unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The width of the drawing.&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| [[GUIVariable#f_unsigned|f_unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The height of the drawing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [draw] ===&lt;br /&gt;
A mandatory WML block (config) containing the drawing instructions, in the same format as [[GUICanvasWML]]. For an example, see this snippet from the [https://github.com/wesnoth/wesnoth/blob/9bd7614e89269b5456ee51ade3cc0af73efc99f5/data/gui/themes/default/dialogs/attack_predictions.cfg#L100 Attack predictions dialog].&lt;br /&gt;
&lt;br /&gt;
The variables available are the same as for the window resolution, see&lt;br /&gt;
[[GUIToolkitWML#Resolution_2|GUIToolkitWML]] for the list of&lt;br /&gt;
items.&lt;br /&gt;
&lt;br /&gt;
== Grid Listbox ==&lt;br /&gt;
List with the listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!ID (return value)&lt;br /&gt;
!Type&lt;br /&gt;
!Mandatory&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Horizontal listbox ==&lt;br /&gt;
A horizontal listbox is a control that holds several items of the same type.  Normally the items in a listbox are ordered in rows, this version orders them in columns instead.&lt;br /&gt;
&lt;br /&gt;
List with the horizontal listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!ID (return value)&lt;br /&gt;
!Type&lt;br /&gt;
!Mandatory&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In order to force widgets to be the same size inside a horizontal listbox,&lt;br /&gt;
the widgets need to be inside a linked_group.&lt;br /&gt;
&lt;br /&gt;
Inside the list section there are only the following widgets allowed&lt;br /&gt;
* grid (to nest)&lt;br /&gt;
* selectable widgets which are&lt;br /&gt;
** toggle_button&lt;br /&gt;
** toggle_panel&lt;br /&gt;
&lt;br /&gt;
== Image ==&lt;br /&gt;
An image shows a static image whose path is specified by its '''[[GUIWidgetInstanceWML#Widget|label]]''' key. Unlike other widgets, the '''label''' key here is not translatable since it specifies a path. The path is a standard WML path, i.e., &amp;lt;code&amp;gt;label=&amp;quot;units/konrad.png&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;label=&amp;quot;~add-ons/MyAddon/image/test.png&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It has no other extra fields.&lt;br /&gt;
&lt;br /&gt;
== Label ==&lt;br /&gt;
A label displays text provided via the '''[[GUIWidgetInstanceWML#Widget|label]]''' key that can be wrapped but no scrollbars are provided. For a version with scrollbars, see the [[GUIWidgetInstanceWML#Scroll_Label|Scroll Label]] widget.&lt;br /&gt;
&lt;br /&gt;
[[File:Title Label.png|frame|right|A Label with definition &amp;quot;title&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
List with the label specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| wrap || [[GUIVariable#bool|bool]] || false || Is wrapping enabled for the label.&lt;br /&gt;
|-&lt;br /&gt;
| characters_per_line || [[GUIVariable#unsigned|unsigned]] || 0 || Sets the maximum number of characters per line. This is only an approximate means of limiting the line's length, since the width of a character differs. E.g. iii is smaller than MMM. When the value is non-zero it also implies '''wrap''' is true. &lt;br /&gt;
When having long strings, wrapping them can increase readability. A rule of thumb is 66 characters per line is considered the optimum for a one column text.&lt;br /&gt;
|-&lt;br /&gt;
| text_alignment || [[GUIVariable#h_align|h_align]] || left || The way the text is aligned inside the canvas.&lt;br /&gt;
|-&lt;br /&gt;
| can_shrink || [[GUIVariable#bool|bool]] || false || Whether the label can shrink past its optimal size.&lt;br /&gt;
|-&lt;br /&gt;
| link_aware || [[GUIVariable#bool|bool]] || false || Whether the label is link aware. This means it is rendered with links highlighted, and responds to click events on those links.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Listbox ==&lt;br /&gt;
A listbox is a control that holds several items of the same type. Normally the items in a listbox are ordered in rows, this version might allow more options for ordering the items in the future.&lt;br /&gt;
&lt;br /&gt;
List with the listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In order to force widgets to be the same size inside a listbox, the widgets&lt;br /&gt;
need to be inside a linked_group.&lt;br /&gt;
&lt;br /&gt;
Inside the list section there are only the following widgets allowed&lt;br /&gt;
* grid (to nest)&lt;br /&gt;
* selectable widgets which are&lt;br /&gt;
** toggle_button&lt;br /&gt;
** toggle_panel&lt;br /&gt;
&lt;br /&gt;
== Matrix ==&lt;br /&gt;
List with the matrix specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Menu Button ==&lt;br /&gt;
[[File:Menu Button.png|thumb|left|A Menu Button with it's list open.]]&lt;br /&gt;
A button that shows a dropdown list when clicked. The user can select any one of the predefined options.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;menu_button&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| icon || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || WML path to the icon to be shown alongside the text in this option, if any.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Minimap ==&lt;br /&gt;
A minimap to show the gamemap, this only shows the map and has no interaction options. This version is used for map previews, there will be a another version which allows interaction.&lt;br /&gt;
&lt;br /&gt;
A minimap has no extra fields.&lt;br /&gt;
&lt;br /&gt;
== Multiline Text ==&lt;br /&gt;
{{DevFeature1.17|26}}&lt;br /&gt;
&lt;br /&gt;
Base class for a multiline text area.  Not to be used directly in a GUI, use the [[GUIWidgetInstanceWML#Scroll_Text|scroll_text]] widget instead.&lt;br /&gt;
&lt;br /&gt;
The following variables exist:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The initial text of the text box.&lt;br /&gt;
|-&lt;br /&gt;
| history&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The name of the history for the text box. A history saves the data entered in a text box between the games. With the up and down arrow it can be accessed. To create a new history item just add a new unique name for this field and the engine will handle the rest.&lt;br /&gt;
|-&lt;br /&gt;
| editable&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| &amp;quot;true&amp;quot;&lt;br /&gt;
| If the contents of the text box can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Multimenu Button ==&lt;br /&gt;
[[File:Multimenu Button.png|thumb|right|A Multimenu Button with its list open]]&lt;br /&gt;
A widget clicking on which shows a list from which one or more options can be selected.&lt;br /&gt;
&lt;br /&gt;
List with the multimenu_button specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value || [[GUIVariable#int|int]] || 0 || The return value.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_shown || [[GUIVariable#int|int]] || -1 || The maximum number of currently selected values to list on the button.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;multimenu_button&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| checkbox || [[GUIVariable#bool|bool]] || &amp;quot;&amp;quot; || Whether the checkbox alongside this option is selected or not.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Multi page ==&lt;br /&gt;
A multi page is a control that contains several 'pages' of which only one is visible. The pages can contain the same widgets containing the same 'kind' of data or look completely different.&lt;br /&gt;
&lt;br /&gt;
List with the multi page specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| page_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a multi page item looks. It must contain the grid definition for at least one page.&lt;br /&gt;
|-&lt;br /&gt;
| page_data&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the multi page. Every row must have the same number of columns as the 'page_definition'.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Panel ==&lt;br /&gt;
A panel is an item which can hold other items. The difference between a grid and a panel is that it's possible to define how a panel looks. A grid in an invisible container to just hold the items.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Password box ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The initial text of the password box.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Progress bar ==&lt;br /&gt;
A progress bar shows the progress of a certain object.&lt;br /&gt;
&lt;br /&gt;
A progress bar has no extra fields.&lt;br /&gt;
&lt;br /&gt;
== Repeating button ==&lt;br /&gt;
A repeating_button is a control that can be pushed down and repeat a certain action. Once the button is down every x milliseconds it is down a new down event is triggered.&lt;br /&gt;
&lt;br /&gt;
== Rich Label ==&lt;br /&gt;
{{DevFeature1.19|x}}&lt;br /&gt;
&lt;br /&gt;
A label that shows formatted text marked up with [[Help markup]]. It can show embedded images, links and tables inside text.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| text_alignment || [[GUIVariable#h_align|h_align]] || left || The way the text is aligned inside the canvas.&lt;br /&gt;
|-&lt;br /&gt;
| padding || [[GUIVariable#int|int]] || 5 || Internal padding, used in various spaces and between different types of elements (for example, between two float image, between a header and following text and so on).&lt;br /&gt;
|-&lt;br /&gt;
| link_aware || [[GUIVariable#bool|bool]] || true || Whether the label is link aware. This means it is rendered with links highlighted, and responds to click events on those links.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scroll Label ==&lt;br /&gt;
A scroll label is a label that wraps its text and also has a vertical scrollbar. This way a text can't be too long to be shown for this widget.&lt;br /&gt;
&lt;br /&gt;
List with the scroll label specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scroll Text ==&lt;br /&gt;
{{DevFeature1.19|x}}&lt;br /&gt;
&lt;br /&gt;
A multiline text area that shows a scrollbar if the text gets too long.&lt;br /&gt;
&lt;br /&gt;
List with the scrollbar container specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| editable&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| &amp;quot;true&amp;quot;&lt;br /&gt;
| If the contents of this scroll_text can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scrollbar panel ==&lt;br /&gt;
Instance of a scrollbar_panel.&lt;br /&gt;
&lt;br /&gt;
List with the scrollbar_panel specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a scrollbar_panel item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Size lock ==&lt;br /&gt;
Instance of the size_lock widget. This is a special container that forces the widget enclosed in the [widget] subtag to be of the size specified by the width and height. The [https://github.com/wesnoth/wesnoth/blob/9bd7614e89269b5456ee51ade3cc0af73efc99f5/data/gui/macros/_initial.cfg#L246 GUI_FORCE_WIDGET_SIZE] internal macro is a wrapper around this component.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| -&lt;br /&gt;
| The width the enclosed widget should be forced to (mandatory).&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| -&lt;br /&gt;
| The height the enclosed widget should be forced to (mandatory).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: Both &amp;lt;code&amp;gt;width&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;height&amp;lt;/code&amp;gt; are mandatory even if you want to fix either width or height as of 1.19.23.&lt;br /&gt;
&lt;br /&gt;
=== Subtag [widget] ===&lt;br /&gt;
The widget that should be force-sized.&lt;br /&gt;
&lt;br /&gt;
== Slider ==&lt;br /&gt;
&lt;br /&gt;
A slider is a control that can select a value by moving a grip on a groove.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| best_slider_length&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The best length for the sliding part.&lt;br /&gt;
|-&lt;br /&gt;
| minimum_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The minimum value the slider can have.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The maximum value the slider can have.&lt;br /&gt;
|-&lt;br /&gt;
| step_size&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The number of items the slider's value increases with one step.&lt;br /&gt;
|-&lt;br /&gt;
| value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The value of the slider.&lt;br /&gt;
|-&lt;br /&gt;
| minimum_value_label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If the minimum value is chosen there might be the need for a special value (eg off). When this key has a value that value will be shown if the minimum is selected.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_value_label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If the maximum value is chosen there might be the need for a special value (eg unlimited)). When this key has a value that value will be shown if the maximum is selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Spinner ==&lt;br /&gt;
{{DevFeature1.17|26}}&lt;br /&gt;
&lt;br /&gt;
[[File:Spinner.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
A textbox with two repeating buttons, which allow increasing/decreasing of the numerical value inside the textbox.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| wrap&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| 0&lt;br /&gt;
| Should the contents of the textbox wrap?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Spacer ==&lt;br /&gt;
A spacer is a dummy item to either fill in a widget since no empty items are allowed or to reserve a fixed space.&lt;br /&gt;
&lt;br /&gt;
If either the width or the height is non-zero the spacer functions as a&lt;br /&gt;
fixed size spacer.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| width || [[GUIVariable#f_unsigned|f_unsigned]] || 0 || The width of the spacer.&lt;br /&gt;
|-&lt;br /&gt;
| height || [[GUIVariable#f_unsigned|f_unsigned]] || 0 || The height of the spacer.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The variable available are the same as for the window resolution see&lt;br /&gt;
http://www.wesnoth.org/wiki/GUIToolkitWML#Resolution_2 for the list of&lt;br /&gt;
items.&lt;br /&gt;
&lt;br /&gt;
== Tab Container ==&lt;br /&gt;
{{DevFeature1.19|0}}&lt;br /&gt;
&lt;br /&gt;
A container widget that can show its contents separated into various pages, each of which are accessible.&lt;br /&gt;
&lt;br /&gt;
It can contain one or more &amp;lt;code&amp;gt;[tab]&amp;lt;/code&amp;gt; tags inside it, each defining a tab's name, image (if any) and the contents of the tag, specified by the &amp;lt;code&amp;gt;[data]&amp;lt;/code&amp;gt; tag inside the &amp;lt;code&amp;gt;[tab]&amp;lt;/code&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
=== Subtag [tab] ===&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| name || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the tab&lt;br /&gt;
|-&lt;br /&gt;
| image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image for the tab to be shown alongside the name, if any&lt;br /&gt;
|-&lt;br /&gt;
| [data] || [[GUIVariable#grid|grid]] || empty grid || This subtag contains a grid that defines the contents for this tab.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Text box ==&lt;br /&gt;
A single line text entry widget.&lt;br /&gt;
&lt;br /&gt;
[[File:Text Box.png|frame|right|A Text Box]]&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || The initial text of the text box.&lt;br /&gt;
|-&lt;br /&gt;
| history || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The name of the history for the text box. A history saves the data entered in a text box between the games. With the up and down arrow it can be accessed. To create a new history item just add a new unique name for this field and the engine will handle the rest.&lt;br /&gt;
|-&lt;br /&gt;
| max_input_length || [[GUIVariable#int|int]] || 0 || Maximum length of text in characters that can be entered into the combobox&lt;br /&gt;
|-&lt;br /&gt;
| hint_text || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Text that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| hint_image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| editable || [[GUIVariable#bool|bool]] || &amp;quot;true&amp;quot; || If the contents of the text box can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Toggle button ==&lt;br /&gt;
Variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Toggle panel ==&lt;br /&gt;
A toggle panel is an item which can hold other items. The difference between&lt;br /&gt;
a grid and a panel is that it's possible to define how a panel looks. A grid&lt;br /&gt;
in an invisible container to just hold the items. The toggle panel is a&lt;br /&gt;
combination of the panel and a toggle button, it allows a toggle button with&lt;br /&gt;
its own grid.&lt;br /&gt;
&lt;br /&gt;
Variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id, see [[GUIToolkitWML#Button]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value, see [[GUIToolkitWML#Button]] for more information.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree view ==&lt;br /&gt;
A tree view is a control that holds several items of the same or different types. The items shown are called tree view nodes and when a node has children, these can be shown or hidden. Nodes that contain children need to provide a clickable button in order to fold or unfold the children.&lt;br /&gt;
&lt;br /&gt;
List with the tree view specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| indention_step_size&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The number of pixels every level of nodes is indented from the previous level.&lt;br /&gt;
|-&lt;br /&gt;
| node&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The tree view can contain multiple node sections. This part needs more documentation.&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| .&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| .&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If true, a tree with at least one item will always have something selected (except when items are being deleted). Although this is {{DevFeature1.19|21}}, the previous behavior is equivalent to setting this to true. The GUI doesn't provide a way to unselect items, the purpose of setting this to false is to add a landing page, as the campaign menu does.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
NOTE more documentation and examples are needed.&lt;br /&gt;
&lt;br /&gt;
== Vertical scrollbar ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Viewport ==&lt;br /&gt;
A viewport is an special widget used to view only a part of the widget it `holds'.&lt;br /&gt;
&lt;br /&gt;
List with the viewport specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grow_direction&lt;br /&gt;
| [[GUIVariable#grow_direction|grow_direction]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The direction in which new items grow.&lt;br /&gt;
|-&lt;br /&gt;
| parallel_items&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The number of items that are growing in parallel.&lt;br /&gt;
|-&lt;br /&gt;
| item_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The definition of a new item.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;br /&gt;
[[Category: GUI WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GUIWidgetInstanceWML&amp;diff=75013</id>
		<title>GUIWidgetInstanceWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GUIWidgetInstanceWML&amp;diff=75013"/>
		<updated>2026-04-30T05:25:40Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Subtag [draw] */ Don't make external link to internal page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Widget instance ==&lt;br /&gt;
Inside a grid (which is inside all container widgets) a widget is&lt;br /&gt;
instantiated. With this instantiation some more variables of a widget can&lt;br /&gt;
be tuned. This page will describe what can be tuned.&lt;br /&gt;
&lt;br /&gt;
== Widget ==&lt;br /&gt;
All widgets placed in the cell have some keys in common, that can be used in any widget in addition to the widget-specific keys listed below.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| This value is used for the engine to identify 'special' items. This means that for example a text_box can get the proper initial value. This value should be unique or empty. Those special values are documented at the window definition that uses them. NOTE items starting with an underscore are used for composed widgets and these should be unique per composed widget.&lt;br /&gt;
|-&lt;br /&gt;
| definition&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;default&amp;quot;&lt;br /&gt;
| The id of the widget definition to use. This way it's possible to select a specific version of the widget e.g. a title label when the label is used as title.&lt;br /&gt;
|-&lt;br /&gt;
| linked_group&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The linked group the control belongs to.&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| Most widgets have some text associated with them, this field contain the value of that text. Some widgets use this value for other purposes, this is documented at the widget. E.g. an image uses the filename in this field.&lt;br /&gt;
|-&lt;br /&gt;
| use_markup&lt;br /&gt;
| | [[GUIVariable#bool|bool]]&lt;br /&gt;
| false&lt;br /&gt;
| Whether [https://docs.gtk.org/Pango/pango_markup.html Pango Markup] could be used to format the `label` of this widget (bold, italic, font color, alpha etc.)&lt;br /&gt;
|-&lt;br /&gt;
| tooltip&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If you hover over a widget a while (the time it takes can differ per widget) a short help can show up.This defines the text of that message. This field may not be empty when 'help' is set.&lt;br /&gt;
|-&lt;br /&gt;
| help&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If you hover over a widget and press F10 (or the key the user defined for the help tip) a help message can show up. This help message might be the same as the tooltip but in general (if used) this message should show more help. This defines the text of that message.&lt;br /&gt;
|-&lt;br /&gt;
| use_tooltip_on_label_overflow&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If the text on the label is truncated and the tooltip is empty the label can be used for the tooltip. If this variable is set to true this will happen.&lt;br /&gt;
|-&lt;br /&gt;
| debug_border_mode&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The mode for showing the debug border. This border shows the area reserved for a widget. This function is only meant for debugging and might not be available in all Wesnoth binaries. Available modes: &lt;br /&gt;
* '''0:''' no border. &lt;br /&gt;
* '''1:''' 1 pixel border. &lt;br /&gt;
* '''2:''' floodfill the widget area.&lt;br /&gt;
|-&lt;br /&gt;
| debug_border_color&lt;br /&gt;
| [[GUIVariable#color|color]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The color of the debug border.&lt;br /&gt;
|-&lt;br /&gt;
| size_text&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| Sets the minimum width of the widget depending on the text in it. (Note not implemented yet.)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Button ==&lt;br /&gt;
&lt;br /&gt;
[[File:Button.png|thumb|left|An example of a Button]]&lt;br /&gt;
&lt;br /&gt;
A button is a control that can be pushed to start an action or close a dialog.&lt;br /&gt;
&lt;br /&gt;
Instance of a button. When a button has a return value it sets the&lt;br /&gt;
return value for the window. Normally this closes the window and returns&lt;br /&gt;
this value to the caller. The return value can either be defined by the&lt;br /&gt;
user or determined from the id of the button. The return value has a&lt;br /&gt;
higher precedence as the one defined by the id. (Of course it's weird to&lt;br /&gt;
give a button an id and then override its return value.)&lt;br /&gt;
&lt;br /&gt;
When the button doesn't have a standard id, but you still want to use the&lt;br /&gt;
return value of that id, use return_value_id instead. This has a higher&lt;br /&gt;
precedence as return_value.&lt;br /&gt;
&lt;br /&gt;
List with the button specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Supported values for return_value_id:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!string&lt;br /&gt;
!value&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;ok&amp;quot;||-1||Equivalent to closing the dialog by pressing the Enter key&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;cancel&amp;quot;||-2||Equivalent to closing the dialog by pressing the Esc key&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;quit&amp;quot;||-2||An alias for cancel&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;&amp;quot;||N/A||Clears any previously set return_value_id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Combobox ==&lt;br /&gt;
{{DevFeature1.19|0}}&lt;br /&gt;
[[File:Combobox.png|frame|right|A Combobox with its list open]]&lt;br /&gt;
A widget with a text box and a dropdown list. Selecting an element from the list sets the value of the text box to that item of the list. The user can also manually enter a value in the text box.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! key !! type !! default !! description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The text of the combobox&lt;br /&gt;
|-&lt;br /&gt;
| max_input_length || [[GUIVariable#int|int]] || 0 || Maximum length of text in characters that can be entered into the combobox&lt;br /&gt;
|-&lt;br /&gt;
| hint_text || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Text that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| hint_image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image that is shown in the background when there is no input&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;combobox&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| value || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Value of the option. Defaults to &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; if unspecified.&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || User visible translatable name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| icon || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || WML path to the icon to be shown alongside the text in this option, if any.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Drawing ==&lt;br /&gt;
A drawing is widget with a fixed size and gives access to the canvas of the widget in the window instance. This allows special display only widgets.&lt;br /&gt;
&lt;br /&gt;
If either the width or the height is not zero the drawing functions as a&lt;br /&gt;
fixed size drawing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| [[GUIVariable#f_unsigned|f_unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The width of the drawing.&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| [[GUIVariable#f_unsigned|f_unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The height of the drawing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [draw] ===&lt;br /&gt;
A mandatory WML block (config) containing the drawing instructions, in the same format as [https://wiki.wesnoth.org/GUICanvasWML GUICanvasWML]. For an example, see this snippet from the [https://github.com/wesnoth/wesnoth/blob/9bd7614e89269b5456ee51ade3cc0af73efc99f5/data/gui/themes/default/dialogs/attack_predictions.cfg#L100 Attack predictions dialog].&lt;br /&gt;
&lt;br /&gt;
The variables available are the same as for the window resolution, see&lt;br /&gt;
[[GUIToolkitWML#Resolution_2|GUIToolkitWML]] for the list of&lt;br /&gt;
items.&lt;br /&gt;
&lt;br /&gt;
== Grid Listbox ==&lt;br /&gt;
List with the listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!ID (return value)&lt;br /&gt;
!Type&lt;br /&gt;
!Mandatory&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Horizontal listbox ==&lt;br /&gt;
A horizontal listbox is a control that holds several items of the same type.  Normally the items in a listbox are ordered in rows, this version orders them in columns instead.&lt;br /&gt;
&lt;br /&gt;
List with the horizontal listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!ID (return value)&lt;br /&gt;
!Type&lt;br /&gt;
!Mandatory&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIToolkitWML#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIToolkitWML#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIToolkitWML#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIToolkitWML#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In order to force widgets to be the same size inside a horizontal listbox,&lt;br /&gt;
the widgets need to be inside a linked_group.&lt;br /&gt;
&lt;br /&gt;
Inside the list section there are only the following widgets allowed&lt;br /&gt;
* grid (to nest)&lt;br /&gt;
* selectable widgets which are&lt;br /&gt;
** toggle_button&lt;br /&gt;
** toggle_panel&lt;br /&gt;
&lt;br /&gt;
== Image ==&lt;br /&gt;
An image shows a static image whose path is specified by its '''[[GUIWidgetInstanceWML#Widget|label]]''' key. Unlike other widgets, the '''label''' key here is not translatable since it specifies a path. The path is a standard WML path, i.e., &amp;lt;code&amp;gt;label=&amp;quot;units/konrad.png&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;label=&amp;quot;~add-ons/MyAddon/image/test.png&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It has no other extra fields.&lt;br /&gt;
&lt;br /&gt;
== Label ==&lt;br /&gt;
A label displays text provided via the '''[[GUIWidgetInstanceWML#Widget|label]]''' key that can be wrapped but no scrollbars are provided. For a version with scrollbars, see the [[GUIWidgetInstanceWML#Scroll_Label|Scroll Label]] widget.&lt;br /&gt;
&lt;br /&gt;
[[File:Title Label.png|frame|right|A Label with definition &amp;quot;title&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
List with the label specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| wrap || [[GUIVariable#bool|bool]] || false || Is wrapping enabled for the label.&lt;br /&gt;
|-&lt;br /&gt;
| characters_per_line || [[GUIVariable#unsigned|unsigned]] || 0 || Sets the maximum number of characters per line. This is only an approximate means of limiting the line's length, since the width of a character differs. E.g. iii is smaller than MMM. When the value is non-zero it also implies '''wrap''' is true. &lt;br /&gt;
When having long strings, wrapping them can increase readability. A rule of thumb is 66 characters per line is considered the optimum for a one column text.&lt;br /&gt;
|-&lt;br /&gt;
| text_alignment || [[GUIVariable#h_align|h_align]] || left || The way the text is aligned inside the canvas.&lt;br /&gt;
|-&lt;br /&gt;
| can_shrink || [[GUIVariable#bool|bool]] || false || Whether the label can shrink past its optimal size.&lt;br /&gt;
|-&lt;br /&gt;
| link_aware || [[GUIVariable#bool|bool]] || false || Whether the label is link aware. This means it is rendered with links highlighted, and responds to click events on those links.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Listbox ==&lt;br /&gt;
A listbox is a control that holds several items of the same type. Normally the items in a listbox are ordered in rows, this version might allow more options for ordering the items in the future.&lt;br /&gt;
&lt;br /&gt;
List with the listbox specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| header&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional header. (This grid will automatically get the id _header_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| []&lt;br /&gt;
| Defines the grid for the optional footer. (This grid will automatically get the id _footer_grid.)&lt;br /&gt;
|-&lt;br /&gt;
| list_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a listbox item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|-&lt;br /&gt;
| list_data&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the listbox. Every row must have the same number of columns as the 'list_definition'.&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, less than one row can be selected.&lt;br /&gt;
|-&lt;br /&gt;
| has_maximum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If false, more than one row can be selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In order to force widgets to be the same size inside a listbox, the widgets&lt;br /&gt;
need to be inside a linked_group.&lt;br /&gt;
&lt;br /&gt;
Inside the list section there are only the following widgets allowed&lt;br /&gt;
* grid (to nest)&lt;br /&gt;
* selectable widgets which are&lt;br /&gt;
** toggle_button&lt;br /&gt;
** toggle_panel&lt;br /&gt;
&lt;br /&gt;
== Matrix ==&lt;br /&gt;
List with the matrix specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Menu Button ==&lt;br /&gt;
[[File:Menu Button.png|thumb|left|A Menu Button with it's list open.]]&lt;br /&gt;
A button that shows a dropdown list when clicked. The user can select any one of the predefined options.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;menu_button&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| icon || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || WML path to the icon to be shown alongside the text in this option, if any.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Minimap ==&lt;br /&gt;
A minimap to show the gamemap, this only shows the map and has no interaction options. This version is used for map previews, there will be a another version which allows interaction.&lt;br /&gt;
&lt;br /&gt;
A minimap has no extra fields.&lt;br /&gt;
&lt;br /&gt;
== Multiline Text ==&lt;br /&gt;
{{DevFeature1.17|26}}&lt;br /&gt;
&lt;br /&gt;
Base class for a multiline text area.  Not to be used directly in a GUI, use the [[GUIWidgetInstanceWML#Scroll_Text|scroll_text]] widget instead.&lt;br /&gt;
&lt;br /&gt;
The following variables exist:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The initial text of the text box.&lt;br /&gt;
|-&lt;br /&gt;
| history&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The name of the history for the text box. A history saves the data entered in a text box between the games. With the up and down arrow it can be accessed. To create a new history item just add a new unique name for this field and the engine will handle the rest.&lt;br /&gt;
|-&lt;br /&gt;
| editable&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| &amp;quot;true&amp;quot;&lt;br /&gt;
| If the contents of the text box can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Multimenu Button ==&lt;br /&gt;
[[File:Multimenu Button.png|thumb|right|A Multimenu Button with its list open]]&lt;br /&gt;
A widget clicking on which shows a list from which one or more options can be selected.&lt;br /&gt;
&lt;br /&gt;
List with the multimenu_button specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value || [[GUIVariable#int|int]] || 0 || The return value.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_shown || [[GUIVariable#int|int]] || -1 || The maximum number of currently selected values to list on the button.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Subtag [option] ===&lt;br /&gt;
Specifies the initial list of options to be shown in the &amp;lt;code&amp;gt;multimenu_button&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the option.&lt;br /&gt;
|-&lt;br /&gt;
| tooltip || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Tooltip that is shown when the mouse hovers above this option.&lt;br /&gt;
|-&lt;br /&gt;
| checkbox || [[GUIVariable#bool|bool]] || &amp;quot;&amp;quot; || Whether the checkbox alongside this option is selected or not.&lt;br /&gt;
|-&lt;br /&gt;
| details || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Short description about this option.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Multi page ==&lt;br /&gt;
A multi page is a control that contains several 'pages' of which only one is visible. The pages can contain the same widgets containing the same 'kind' of data or look completely different.&lt;br /&gt;
&lt;br /&gt;
List with the multi page specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| page_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a multi page item looks. It must contain the grid definition for at least one page.&lt;br /&gt;
|-&lt;br /&gt;
| page_data&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| []&lt;br /&gt;
| A grid alike section which stores the initial data for the multi page. Every row must have the same number of columns as the 'page_definition'.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Panel ==&lt;br /&gt;
A panel is an item which can hold other items. The difference between a grid and a panel is that it's possible to define how a panel looks. A grid in an invisible container to just hold the items.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Password box ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The initial text of the password box.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Progress bar ==&lt;br /&gt;
A progress bar shows the progress of a certain object.&lt;br /&gt;
&lt;br /&gt;
A progress bar has no extra fields.&lt;br /&gt;
&lt;br /&gt;
== Repeating button ==&lt;br /&gt;
A repeating_button is a control that can be pushed down and repeat a certain action. Once the button is down every x milliseconds it is down a new down event is triggered.&lt;br /&gt;
&lt;br /&gt;
== Rich Label ==&lt;br /&gt;
{{DevFeature1.19|x}}&lt;br /&gt;
&lt;br /&gt;
A label that shows formatted text marked up with [[Help markup]]. It can show embedded images, links and tables inside text.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| text_alignment || [[GUIVariable#h_align|h_align]] || left || The way the text is aligned inside the canvas.&lt;br /&gt;
|-&lt;br /&gt;
| padding || [[GUIVariable#int|int]] || 5 || Internal padding, used in various spaces and between different types of elements (for example, between two float image, between a header and following text and so on).&lt;br /&gt;
|-&lt;br /&gt;
| link_aware || [[GUIVariable#bool|bool]] || true || Whether the label is link aware. This means it is rendered with links highlighted, and responds to click events on those links.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scroll Label ==&lt;br /&gt;
A scroll label is a label that wraps its text and also has a vertical scrollbar. This way a text can't be too long to be shown for this widget.&lt;br /&gt;
&lt;br /&gt;
List with the scroll label specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scroll Text ==&lt;br /&gt;
{{DevFeature1.19|x}}&lt;br /&gt;
&lt;br /&gt;
A multiline text area that shows a scrollbar if the text gets too long.&lt;br /&gt;
&lt;br /&gt;
List with the scrollbar container specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| editable&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| &amp;quot;true&amp;quot;&lt;br /&gt;
| If the contents of this scroll_text can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Scrollbar panel ==&lt;br /&gt;
Instance of a scrollbar_panel.&lt;br /&gt;
&lt;br /&gt;
List with the scrollbar_panel specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| This defines how a scrollbar_panel item looks. It must contain the grid definition for 1 row of the list.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Size lock ==&lt;br /&gt;
Instance of the size_lock widget. This is a special container that forces the widget enclosed in the [widget] subtag to be of the size specified by the width and height. The [https://github.com/wesnoth/wesnoth/blob/9bd7614e89269b5456ee51ade3cc0af73efc99f5/data/gui/macros/_initial.cfg#L246 GUI_FORCE_WIDGET_SIZE] internal macro is a wrapper around this component.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| -&lt;br /&gt;
| The width the enclosed widget should be forced to (mandatory).&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| -&lt;br /&gt;
| The height the enclosed widget should be forced to (mandatory).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: Both &amp;lt;code&amp;gt;width&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;height&amp;lt;/code&amp;gt; are mandatory even if you want to fix either width or height as of 1.19.23.&lt;br /&gt;
&lt;br /&gt;
=== Subtag [widget] ===&lt;br /&gt;
The widget that should be force-sized.&lt;br /&gt;
&lt;br /&gt;
== Slider ==&lt;br /&gt;
&lt;br /&gt;
A slider is a control that can select a value by moving a grip on a groove.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| best_slider_length&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The best length for the sliding part.&lt;br /&gt;
|-&lt;br /&gt;
| minimum_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The minimum value the slider can have.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The maximum value the slider can have.&lt;br /&gt;
|-&lt;br /&gt;
| step_size&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The number of items the slider's value increases with one step.&lt;br /&gt;
|-&lt;br /&gt;
| value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The value of the slider.&lt;br /&gt;
|-&lt;br /&gt;
| minimum_value_label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If the minimum value is chosen there might be the need for a special value (eg off). When this key has a value that value will be shown if the minimum is selected.&lt;br /&gt;
|-&lt;br /&gt;
| maximum_value_label&lt;br /&gt;
| [[GUIVariable#t_string|t_string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| If the maximum value is chosen there might be the need for a special value (eg unlimited)). When this key has a value that value will be shown if the maximum is selected.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Spinner ==&lt;br /&gt;
{{DevFeature1.17|26}}&lt;br /&gt;
&lt;br /&gt;
[[File:Spinner.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
A textbox with two repeating buttons, which allow increasing/decreasing of the numerical value inside the textbox.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| wrap&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| 0&lt;br /&gt;
| Should the contents of the textbox wrap?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Spacer ==&lt;br /&gt;
A spacer is a dummy item to either fill in a widget since no empty items are allowed or to reserve a fixed space.&lt;br /&gt;
&lt;br /&gt;
If either the width or the height is non-zero the spacer functions as a&lt;br /&gt;
fixed size spacer.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| width || [[GUIVariable#f_unsigned|f_unsigned]] || 0 || The width of the spacer.&lt;br /&gt;
|-&lt;br /&gt;
| height || [[GUIVariable#f_unsigned|f_unsigned]] || 0 || The height of the spacer.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The variable available are the same as for the window resolution see&lt;br /&gt;
http://www.wesnoth.org/wiki/GUIToolkitWML#Resolution_2 for the list of&lt;br /&gt;
items.&lt;br /&gt;
&lt;br /&gt;
== Tab Container ==&lt;br /&gt;
{{DevFeature1.19|0}}&lt;br /&gt;
&lt;br /&gt;
A container widget that can show its contents separated into various pages, each of which are accessible.&lt;br /&gt;
&lt;br /&gt;
It can contain one or more &amp;lt;code&amp;gt;[tab]&amp;lt;/code&amp;gt; tags inside it, each defining a tab's name, image (if any) and the contents of the tag, specified by the &amp;lt;code&amp;gt;[data]&amp;lt;/code&amp;gt; tag inside the &amp;lt;code&amp;gt;[tab]&amp;lt;/code&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
=== Subtag [tab] ===&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| name || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || Name of the tab&lt;br /&gt;
|-&lt;br /&gt;
| image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image for the tab to be shown alongside the name, if any&lt;br /&gt;
|-&lt;br /&gt;
| [data] || [[GUIVariable#grid|grid]] || empty grid || This subtag contains a grid that defines the contents for this tab.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Text box ==&lt;br /&gt;
A single line text entry widget.&lt;br /&gt;
&lt;br /&gt;
[[File:Text Box.png|frame|right|A Text Box]]&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key !!type !!default !!description&lt;br /&gt;
|-&lt;br /&gt;
| label || [[GUIVariable#t_string|t_string]] || &amp;quot;&amp;quot; || The initial text of the text box.&lt;br /&gt;
|-&lt;br /&gt;
| history || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || The name of the history for the text box. A history saves the data entered in a text box between the games. With the up and down arrow it can be accessed. To create a new history item just add a new unique name for this field and the engine will handle the rest.&lt;br /&gt;
|-&lt;br /&gt;
| max_input_length || [[GUIVariable#int|int]] || 0 || Maximum length of text in characters that can be entered into the combobox&lt;br /&gt;
|-&lt;br /&gt;
| hint_text || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Text that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| hint_image || [[GUIVariable#string|string]] || &amp;quot;&amp;quot; || Image that is shown in the background when there is no input&lt;br /&gt;
|-&lt;br /&gt;
| editable || [[GUIVariable#bool|bool]] || &amp;quot;true&amp;quot; || If the contents of the text box can be edited.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Toggle button ==&lt;br /&gt;
Variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Toggle panel ==&lt;br /&gt;
A toggle panel is an item which can hold other items. The difference between&lt;br /&gt;
a grid and a panel is that it's possible to define how a panel looks. A grid&lt;br /&gt;
in an invisible container to just hold the items. The toggle panel is a&lt;br /&gt;
combination of the panel and a toggle button, it allows a toggle button with&lt;br /&gt;
its own grid.&lt;br /&gt;
&lt;br /&gt;
Variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grid&lt;br /&gt;
| [[GUIVariable#grid|grid]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| Defines the grid with the widgets to place on the panel.&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#string|string]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| The return value id, see [[GUIToolkitWML#Button]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
| return_value&lt;br /&gt;
| [[GUIVariable#int|int]]&lt;br /&gt;
| 0&lt;br /&gt;
| The return value, see [[GUIToolkitWML#Button]] for more information.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tree view ==&lt;br /&gt;
A tree view is a control that holds several items of the same or different types. The items shown are called tree view nodes and when a node has children, these can be shown or hidden. Nodes that contain children need to provide a clickable button in order to fold or unfold the children.&lt;br /&gt;
&lt;br /&gt;
List with the tree view specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| vertical_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| horizontal_scrollbar_mode&lt;br /&gt;
| [[GUIVariable#scrollbar_mode|scrollbar_mode]]&lt;br /&gt;
| initial_auto&lt;br /&gt;
| Determines whether or not to show the scrollbar.&lt;br /&gt;
|-&lt;br /&gt;
| indention_step_size&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| 0&lt;br /&gt;
| The number of pixels every level of nodes is indented from the previous level.&lt;br /&gt;
|-&lt;br /&gt;
| node&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The tree view can contain multiple node sections. This part needs more documentation.&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| .&lt;br /&gt;
|-&lt;br /&gt;
| return_value_id&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| &amp;quot;&amp;quot;&lt;br /&gt;
| .&lt;br /&gt;
|-&lt;br /&gt;
| has_minimum&lt;br /&gt;
| [[GUIVariable#bool|bool]]&lt;br /&gt;
| true&lt;br /&gt;
| If true, a tree with at least one item will always have something selected (except when items are being deleted). Although this is {{DevFeature1.19|21}}, the previous behavior is equivalent to setting this to true. The GUI doesn't provide a way to unselect items, the purpose of setting this to false is to add a landing page, as the campaign menu does.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
NOTE more documentation and examples are needed.&lt;br /&gt;
&lt;br /&gt;
== Vertical scrollbar ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Viewport ==&lt;br /&gt;
A viewport is an special widget used to view only a part of the widget it `holds'.&lt;br /&gt;
&lt;br /&gt;
List with the viewport specific variables:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!key&lt;br /&gt;
!type&lt;br /&gt;
!default&lt;br /&gt;
!description&lt;br /&gt;
|-&lt;br /&gt;
| grow_direction&lt;br /&gt;
| [[GUIVariable#grow_direction|grow_direction]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The direction in which new items grow.&lt;br /&gt;
|-&lt;br /&gt;
| parallel_items&lt;br /&gt;
| [[GUIVariable#unsigned|unsigned]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The number of items that are growing in parallel.&lt;br /&gt;
|-&lt;br /&gt;
| item_definition&lt;br /&gt;
| [[GUIVariable#section|section]]&lt;br /&gt;
| mandatory&lt;br /&gt;
| The definition of a new item.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;br /&gt;
[[Category: GUI WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=LuaAPI/stringx&amp;diff=74917</id>
		<title>LuaAPI/stringx</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=LuaAPI/stringx&amp;diff=74917"/>
		<updated>2026-03-22T01:16:29Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Note that ipairs works too&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;stringx&amp;lt;/tt&amp;gt; module contains additional string support functions. It also registers itself as the string metatable so that these functions can be called directly on strings.&lt;br /&gt;
&lt;br /&gt;
In addition, it permits extracting characters from a string by indexing with an integer. Basically, &amp;lt;syntaxhighlight lang=lua inline&amp;gt;str[n]&amp;lt;/syntaxhighlight&amp;gt; is a shorthand for &amp;lt;syntaxhighlight lang=lua inline&amp;gt;str:sub(n,n)&amp;lt;/syntaxhighlight&amp;gt;. This means negative indices count from the end of the string, and invalid indices output an empty string. It also means you can use &amp;lt;syntaxhighlight lang=lua inline&amp;gt;ipairs(str)&amp;lt;/syntaxhighlight&amp;gt; to iterate over the characters of the string.&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
=== stringx.split ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.split'''(''str'', [''separator''] , [''options'']) &amp;amp;rarr; ''list of strings''&lt;br /&gt;
* ''str'':'''split'''([''separator''] , [''options'']) &amp;amp;rarr; ''list of strings''&lt;br /&gt;
&lt;br /&gt;
Splits a string on a separator character, which currently must be a single character and defaults to &amp;lt;syntaxhighlight lang=lua inline&amp;gt;','&amp;lt;/syntaxhighlight&amp;gt;. The optional ''options'' table controls how the string is split (beyond the basic option of the separator character). It can contain the following keys:&lt;br /&gt;
&lt;br /&gt;
* '''remove_empty''': If true, empty strings are omitted from the result. If the options table is omitted, this will default to true; otherwise, it will default to false.&lt;br /&gt;
* '''strip_spaces''': Spaces surrounding the separator character are stripped. If the options table is omitted, this will default to true; otherwise, it will default to false.&lt;br /&gt;
* '''escape''': Specify a single character as the &amp;quot;escape&amp;quot; character. If a separator character is preceded by this character, then it will not be considered for splitting. The escape character is not removed from the result strings. This option is incompatible with the quote options. For example: &amp;lt;syntaxhighlight lang=lua inline&amp;gt;{escape = [[\]]}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* '''quote''': Specify one or more quote characters. Any separators within the matching instances of the quotes will not be considered for splitting. For example: &amp;lt;syntaxhighlight lang=lua inline&amp;gt;{quote = [['&amp;quot;]]}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* '''quote_left''', '''quote_right''': As above, but you can separately specify opening and closing versions of each quote. The first left quote will match the first right quote, the second left quote will match the second right quote, and so on. For example: &amp;lt;syntaxhighlight lang=lua inline&amp;gt;{quote_left = '([', quote_right = ')]'&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* '''expand_anim''': If true, expand the progressive string syntax of [[AnimationWML]]. This option is compatible with the quote options, but since the progressive string syntax treats square brackets as special characters, they may not be specified as quote characters with this option.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- TODO: Add examples for each of the main options --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stringx.escaped_split ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.escaped_split'''(''str'', [''separator'', [''escape'']]) &amp;amp;rarr; ''list of strings''&lt;br /&gt;
* ''str'':'''escaped_split'''([''separator'', [''escape'']]) &amp;amp;rarr; ''list of strings''&lt;br /&gt;
&lt;br /&gt;
A convenient shorthand for specifying the '''escape''' option in '''stringx.split'''. The separator and escape default to &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;\&amp;lt;/tt&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
=== stringx.quoted_split ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.quoted_split'''(''str'', [''separator'', [''quotes'', [''quotes'']]]) &amp;amp;rarr; ''list of strings''&lt;br /&gt;
* ''str'':'''quoted_split'''([''separator'', [''quotes'', [''quotes'']]]) &amp;amp;rarr; ''list of strings''&lt;br /&gt;
&lt;br /&gt;
A convenient shorthand for specifying quote options in '''stringx.split'''. If two quote parameters are passed, they are in the order left, right. The separator defaults to &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; and the quotes default to &amp;lt;tt&amp;gt;(&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== stringx.anim_split ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.anim_split'''(''str'', [''separator'']) &amp;amp;rarr; ''list of strings''&lt;br /&gt;
* ''str'':'''anim_split'''([''separator'']) &amp;amp;rarr; ''list of strings''&lt;br /&gt;
&lt;br /&gt;
A convenient shorthand for specifying the '''expand_anim''' option in '''stringx.split'''. The separator defaults to &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== stringx.parenthetical_split ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.parenthetical_split'''(''str'', ''left_parens'', ''right_parens'') &amp;amp;rarr; ''list of strings''&lt;br /&gt;
* ''str'':'''parenthetical_split'''(''left_parens'', ''right_parens'') &amp;amp;rarr; ''list of strings''&lt;br /&gt;
&lt;br /&gt;
Splits a string into parenthesized portions and portions between the parenthesized portions. With multiple parenthesis types, only the toplevel type at a given point participates in the split. The parentheses default to &amp;lt;tt&amp;gt;(&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- TODO: Demonstrate by example --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stringx.map_split ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.map_split'''(''str'', [''item separator'', [''key-value separator'', [''options'']]) &amp;amp;rarr; ''string map''&lt;br /&gt;
* ''str'':'''map_split'''([''item separator'', [''key-value separator'', [''options'']]) &amp;amp;rarr; ''string map''&lt;br /&gt;
&lt;br /&gt;
Splits a string into key-value pairs based on the two separators, which currently must each be a single character. The item separator defaults to &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; and the key-value separator defaults to &amp;lt;tt&amp;gt;:&amp;lt;/tt&amp;gt;. The options table supports the following keys:&lt;br /&gt;
&lt;br /&gt;
* '''remove_empty''', '''strip_spaces''': Same as in [[#stringx.split|stringx.split]] above.&lt;br /&gt;
* '''default''': Used as the value if any item is missing the ''key_value_separator''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- TODO: Demonstrate by example --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stringx.join ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.join'''(''list of strings'', [''separator'']) &amp;amp;rarr; ''string''&lt;br /&gt;
* ''separator'':'''join'''(''list of strings'') &amp;amp;rarr; ''string''&lt;br /&gt;
&lt;br /&gt;
Joins a list of strings into a single string using the specified separator string. Accepts its arguments in either order. If omitted, the separator defaults to &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== stringx.join_map ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.join_map'''(''string map'', [''item separator'', [''key-value separator'']]) &amp;amp;rarr; ''string''&lt;br /&gt;
* ''item_separator'':'''join_map'''(''string map'', [''key-value separator'']) &amp;amp;rarr; ''string''&lt;br /&gt;
&lt;br /&gt;
Joins a map of strings into a single string using the specified separators. Keys will be output in lexicographical order. Accepts its arguments in any order, with the caveat that the ''item separator'' must appear before the ''key-value separator''. If omitted, the item separator defaults to &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; and the key-value separator defaults to &amp;lt;tt&amp;gt;:&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== stringx.ends_with ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* '''stringx.ends_with'''(''string'', ''suffix'') &amp;amp;rarr; ''boolean''&lt;br /&gt;
&lt;br /&gt;
Determines whether the string ends with the specified suffix.&lt;br /&gt;
&lt;br /&gt;
=== stringx.starts_with ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* '''stringx.starts_with'''(''string'', ''prefix'') &amp;amp;rarr; ''boolean''&lt;br /&gt;
&lt;br /&gt;
Determines whether the string starts with the specified prefix.&lt;br /&gt;
&lt;br /&gt;
=== stringx.vformat ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.vformat'''(''format_string'', ''values'') &amp;amp;rarr; ''formatted string''&lt;br /&gt;
* ''string'':'''vformat'''(''values'') &amp;amp;rarr; ''formatted string''&lt;br /&gt;
&lt;br /&gt;
Similar to '''string.format''' but using Wesnoth's variable substitution syntax, and also supporting translatable strings. Any valid WML table can be passed as the values, though typically you will only need key-value pairs. You could also substitute WML variables into a string by passing '''wml.all_variables''' as the second parameter.&lt;br /&gt;
&lt;br /&gt;
This function preserves the translatability of the input format string.&lt;br /&gt;
&lt;br /&gt;
=== stringx.format_conjunct_list ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.format_conjunct_list'''(''empty'', ''list_of_strings'') &amp;amp;rarr; ''formatted string''&lt;br /&gt;
&lt;br /&gt;
Formats a list of usually-translatable strings into a localized list string of the form &amp;quot;A, B, and C&amp;quot;. If the list contains no elements, returns ''empty''.&lt;br /&gt;
&lt;br /&gt;
=== stringx.format_disjunct_list ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.format_disjunct_list'''(''empty'', ''list_of_strings'') &amp;amp;rarr; ''formatted string''&lt;br /&gt;
&lt;br /&gt;
Formats a list of usually-translatable strings into a localized list string of the form &amp;quot;A, B, or C&amp;quot;. If the list contains no elements, returns ''empty''.&lt;br /&gt;
&lt;br /&gt;
=== stringx.trim ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.trim'''(''str'') &amp;amp;rarr; ''trimmed string''&lt;br /&gt;
* ''str'':'''trim'''() &amp;amp;rarr; ''trimmed string''&lt;br /&gt;
&lt;br /&gt;
Strips out any leading and trailing whitespace from the string and returns the resulting string.&lt;br /&gt;
&lt;br /&gt;
=== stringx.parse_range ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.parse_range'''(''range string'') &amp;amp;rarr; ''start'', ''end''&lt;br /&gt;
* ''range'':'''parse_range'''() &amp;amp;rarr; ''start'', ''end''&lt;br /&gt;
&lt;br /&gt;
Parses a range of the form &amp;lt;syntaxhighlight lang=lua inline&amp;gt;&amp;quot;1-5&amp;quot;&amp;lt;/syntaxhighlight&amp;gt; and returns the endpoints of the range as two separate values.&lt;br /&gt;
&lt;br /&gt;
=== stringx.iter_range ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.iter_range'''(''range string'') &amp;amp;rarr; ''iterator'' &amp;amp;rArr; ''integer''&lt;br /&gt;
* ''range'':'''iter_range'''() &amp;amp;rarr; ''iterator'' &amp;amp;rArr; ''integer''&lt;br /&gt;
&lt;br /&gt;
Iterate over a range of the form &amp;lt;syntaxhighlight lang=lua inline&amp;gt;&amp;quot;1-5&amp;quot;&amp;lt;/syntaxhighlight&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
for i in stringx.iter_range &amp;quot;1-3&amp;quot; do&lt;br /&gt;
  print(i)&lt;br /&gt;
end&lt;br /&gt;
-- Output:&lt;br /&gt;
-- 1&lt;br /&gt;
-- 2&lt;br /&gt;
-- 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stringx.iter_ranges ===&lt;br /&gt;
&lt;br /&gt;
* '''stringx.iter_ranges'''(''range strings'') &amp;amp;rarr; ''iterator'' &amp;amp;rArr; ''integer''&lt;br /&gt;
* ''ranges'':'''iter_ranges'''() &amp;amp;rarr; ''iterator'' &amp;amp;rArr; ''integer''&lt;br /&gt;
&lt;br /&gt;
Iterates over a sequence of comma-separated ranges. If the ranges overlap, numbers will be yielded more than once.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
for i in stringx.iter_ranges &amp;quot;1-3,7-9&amp;quot; do&lt;br /&gt;
  print(i)&lt;br /&gt;
end&lt;br /&gt;
-- Output:&lt;br /&gt;
-- 1&lt;br /&gt;
-- 2&lt;br /&gt;
-- 3&lt;br /&gt;
-- 7&lt;br /&gt;
-- 8&lt;br /&gt;
-- 9&lt;br /&gt;
for i in stringx.iter_ranges &amp;quot;1-3,3-6&amp;quot; do&lt;br /&gt;
  print(i)&lt;br /&gt;
end&lt;br /&gt;
-- Output:&lt;br /&gt;
-- 1&lt;br /&gt;
-- 2&lt;br /&gt;
-- 3&lt;br /&gt;
-- 3&lt;br /&gt;
-- 4&lt;br /&gt;
-- 5&lt;br /&gt;
-- 6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74911</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74911"/>
		<updated>2026-03-19T07:45:09Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Progressive Values */ Add new section covering AnimationWML's progressive values&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is [https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form Extended Backus-Naur form]:&lt;br /&gt;
&lt;br /&gt;
* Every rule is of the form &amp;lt;tt&amp;gt;nonterminal = rule ;&amp;lt;/tt&amp;gt; with a terminating semicolon.&lt;br /&gt;
* Comments are enclosed in &amp;lt;tt&amp;gt;(* these *)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Literal values are enclosed in either double or single quotes. There is no special syntax inside quotes.&lt;br /&gt;
* &amp;lt;tt&amp;gt;(...)&amp;lt;/tt&amp;gt; can be used for grouping.&lt;br /&gt;
* &amp;lt;tt&amp;gt;N * A&amp;lt;/tt&amp;gt; where N is a number means &amp;quot;exactly N instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;[A]&amp;lt;/tt&amp;gt; means &amp;quot;zero or one instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;{A}&amp;lt;/tt&amp;gt; means &amp;quot;zero or more instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A , B&amp;lt;/tt&amp;gt; means &amp;quot;A followed by B&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A | B&amp;lt;/tt&amp;gt; means &amp;quot;either A or B&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A - B&amp;lt;/tt&amp;gt; means &amp;quot;A but not B&amp;quot;.]&lt;br /&gt;
* Some special values are enclosed in &amp;lt;tt&amp;gt;?...?&amp;lt;/tt&amp;gt;. This document uses the following special values:&lt;br /&gt;
** &amp;lt;tt&amp;gt;?newline?&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;?tab?&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;?space?&amp;lt;/tt&amp;gt; represent the named non-printable characters.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?unicode?&amp;lt;/tt&amp;gt; represents any valid Unicode character.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?digit?&amp;lt;/tt&amp;gt; represents any decimal digit.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?hexdigit?&amp;lt;/tt&amp;gt; represents any hexadecimal digit.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?letter?&amp;lt;/tt&amp;gt; represents any ASCII Latin letter in either uppercase or lowercase.&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = ?digit? , {?digit?} ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {?unicode? - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {?unicode? - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {?unicode? - '&amp;gt;' | '&amp;gt;' , ?unicode? - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = ?letter? | ?digit? | '_' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , ?digit? , {?digit?} , ']' ;&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = ?unicode? - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Context-free Grammars ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of a [[Context-free grammar]] used for random text generation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
grammar = production , {production} ;&lt;br /&gt;
production = symbol , '=' , alternative , {'|' , alternative} , ?newline? ;&lt;br /&gt;
symbol = symbol_char , {symbol_char} ;&lt;br /&gt;
symbol_char = ?letter? | ?digit? | '_' ; (* Unsure on this, need to check it *)&lt;br /&gt;
alternative = {terminal} ;&lt;br /&gt;
terminal = '{' , symbol , '}' | '{!}' | '{(}' | '{)}' | (?unicode? - '}') ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wfl_comment = '#' , {wfl_comment_char} , '#' ;&lt;br /&gt;
wfl_comment_char = ?unicode? - '#' ;&lt;br /&gt;
wfl_file_run = 'wfl' , wfl_string , wfl_file_content , 'wflend' ;&lt;br /&gt;
wfl_file_content = {?any token? - 'wflend'} ;&lt;br /&gt;
wfl_document = {wfl_function_definition} , wfl_formula ;&lt;br /&gt;
wfl_function_definition = 'def' , wfl_name , '(' , [wfl_function_args] , ')' , wfl_formula , ';' ;&lt;br /&gt;
wfl_function_args = wfl_function_arg , {',' , wfl_function_arg} ;&lt;br /&gt;
wfl_function_arg = wfl_name , ['*'] ;&lt;br /&gt;
wfl_formula = ['not'] , where_expression | bracketed_expression ;&lt;br /&gt;
bracketed_expression = '(' , wfl_formula , ')' ;&lt;br /&gt;
where_expression = (boolean_or_expression | bracketed_expression) , {'where' , wfl_variables} ;&lt;br /&gt;
wfl_variables = wfl_variable , {',' , wfl_variable} ;&lt;br /&gt;
wfl_variable = wfl_name , '=' , wfl_formula ;&lt;br /&gt;
boolean_or_expression = (boolean_and_expression | bracketed_expression) , {'or' , wfl_formula} ;&lt;br /&gt;
boolean_and_expression = (comparison_expression | bracketed_expression) , {'and' , wfl_formula} ;&lt;br /&gt;
comparison_expression = (containment_expression | bracketed_expression) , {comparison_op , wfl_formula} ;&lt;br /&gt;
comparison_op = '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;=' ;&lt;br /&gt;
containment_expression = (range_expression | bracketed_expression) , {'in' , wfl_formula} ;&lt;br /&gt;
range_expression = (additive_expression | bracketed_expression) , {'~' , wfl_formula} ;&lt;br /&gt;
additive_expression = [negation_op] , (multiplicative_expression | bracketed_expression) , {additive_op , wfl_formula} ;&lt;br /&gt;
negation_op = '-' | '+' ;&lt;br /&gt;
additive_op = '-' | '+' | '..' ;&lt;br /&gt;
multiplicative_expression := (exponent_expression | bracketed_expression) , {multiplicative_op , wfl_formula} ;&lt;br /&gt;
muliplicative_op = '*' | '/' | '%' ;&lt;br /&gt;
exponent_expression = {wfl_formula , '^'} , (dice_expression | bracketed_expression) ;&lt;br /&gt;
dice_expression = (dot_expression | bracketed_expression) , {'d' , wfl_formula} ;&lt;br /&gt;
dot_expression = (wfl_value | bracketed_expression) , {'.' , wfl_formula} ;&lt;br /&gt;
wfl_value = 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call ;&lt;br /&gt;
wfl_name = wfl_id_char , {wfl_id_char} ;&lt;br /&gt;
wfl_id_char = ?letter? | '_' ; (* Note: digits are NOT allowed! *)&lt;br /&gt;
wfl_number = ?digit? , {?digit?} , ['.' , ?digit? , {?digit?}] ;&lt;br /&gt;
wfl_string = &amp;quot;'&amp;quot; , {wfl_string_char | wfl_string_subst | wfl_string_escape} , &amp;quot;'&amp;quot; ;&lt;br /&gt;
wfl_string_char = ?unicode? - (&amp;quot;'&amp;quot; | &amp;quot;[&amp;quot;) ;&lt;br /&gt;
wfl_string_subst = '[' , wfl_formula , ']' ;&lt;br /&gt;
wfl_string_escape = &amp;quot;[']&amp;quot; | '[(]' | '[)]' ;&lt;br /&gt;
wfl_container = '[' , ['-&amp;gt;' | wfl_expression_list | wfl_key_value_list] , ']' ;&lt;br /&gt;
wfl_expression_list = wfl_formula , {',' , wfl_formula} ;&lt;br /&gt;
wfl_key_value_list = wml_key_value , {',' , wml_key_value} ;&lt;br /&gt;
wml_key_value = wfl_formula , '-&amp;gt;' , wfl_formula ;&lt;br /&gt;
wfl_function_call = wfl_name , '(' , [wfl_expression_list] , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Help Markup ==&lt;br /&gt;
&lt;br /&gt;
This grammar defines the [[help markup]] used in Wesnoth help topics and GUI2 rich labels. It's ''almost'' HTML and ''almost'' XMl but not quite either.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
document = {text | tag} ;&lt;br /&gt;
text = {literal | entity | escape} ;&lt;br /&gt;
literal = ?unicode? - ('&amp;lt;' , '&amp;amp;' , '\') ;&lt;br /&gt;
escape = '\' , ?unicode? ;&lt;br /&gt;
entity = '&amp;amp;#' , ?digit? , {?digit?} , ';'&lt;br /&gt;
       | '&amp;amp;#x' , ?hexdigit? , {?hexdigit?} , ';'&lt;br /&gt;
       | '&amp;amp;' , name , ';'&lt;br /&gt;
       ;&lt;br /&gt;
tag = '&amp;lt;' , name , {attribute} , '/' '&amp;gt;' (* Self-closing tag, XML-style *)&lt;br /&gt;
    | '&amp;lt;' , name , {attribute} , '&amp;gt;' , document , '&amp;lt;/' , name , '&amp;gt;' (* HTML-style tag, nestable *)&lt;br /&gt;
    | '&amp;lt;' , name , '&amp;gt;' , {attribute} , [text] , '&amp;lt;/' , name , '&amp;gt;' (* Old-style tag, not nestable *)&lt;br /&gt;
    ;&lt;br /&gt;
attribute = name , ['=' , attribute_value] ;&lt;br /&gt;
attribute_value = {?unicode? - (&amp;quot;'&amp;quot; | '&amp;quot;' | ?space?)} (* Unquoted value *)&lt;br /&gt;
                | &amp;quot;'&amp;quot; , text - &amp;quot;'&amp;quot; , &amp;quot;'&amp;quot;&lt;br /&gt;
                | '&amp;quot;' , text - '&amp;quot;' , '&amp;quot;'&lt;br /&gt;
                ;&lt;br /&gt;
name = name_char , {name_char} ;&lt;br /&gt;
name_char = ?letter? | ?digit? | '_'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Progressive Values ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes progressive strings and numbers used by animation frames.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
range_integer = digits , ['~' , digits] , [timing] ;&lt;br /&gt;
progressive_integer = range_integer , {',' , range_integer} ;&lt;br /&gt;
&lt;br /&gt;
range_real = digits , ['.' , digits] , ['~' , digits , [',' , digits]] , [timing] ;&lt;br /&gt;
progressive_real = range_real , {',' , range_real} ;&lt;br /&gt;
&lt;br /&gt;
range_string = {literal | expansion_list} , [timing | ':' , expansion_list] ;&lt;br /&gt;
progressive_string = range_string , {',' , range_string} ;&lt;br /&gt;
literal = ?unicode? - ('[' | ',' | ':') ; (* Colon actually might be permitted, not sure *)&lt;br /&gt;
expansion_list = '[' , expansion , {',' , expansion} , ']' ;&lt;br /&gt;
expansion = range_integer | digits , '*' , digits ;&lt;br /&gt;
&lt;br /&gt;
digits = digit , {digit} ;&lt;br /&gt;
timing = ':' , digits ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74910</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74910"/>
		<updated>2026-03-19T07:26:04Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Simplify a few very basic productions with special symbols&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is [https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form Extended Backus-Naur form]:&lt;br /&gt;
&lt;br /&gt;
* Every rule is of the form &amp;lt;tt&amp;gt;nonterminal = rule ;&amp;lt;/tt&amp;gt; with a terminating semicolon.&lt;br /&gt;
* Comments are enclosed in &amp;lt;tt&amp;gt;(* these *)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Literal values are enclosed in either double or single quotes. There is no special syntax inside quotes.&lt;br /&gt;
* &amp;lt;tt&amp;gt;(...)&amp;lt;/tt&amp;gt; can be used for grouping.&lt;br /&gt;
* &amp;lt;tt&amp;gt;N * A&amp;lt;/tt&amp;gt; where N is a number means &amp;quot;exactly N instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;[A]&amp;lt;/tt&amp;gt; means &amp;quot;zero or one instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;{A}&amp;lt;/tt&amp;gt; means &amp;quot;zero or more instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A , B&amp;lt;/tt&amp;gt; means &amp;quot;A followed by B&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A | B&amp;lt;/tt&amp;gt; means &amp;quot;either A or B&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A - B&amp;lt;/tt&amp;gt; means &amp;quot;A but not B&amp;quot;.]&lt;br /&gt;
* Some special values are enclosed in &amp;lt;tt&amp;gt;?...?&amp;lt;/tt&amp;gt;. This document uses the following special values:&lt;br /&gt;
** &amp;lt;tt&amp;gt;?newline?&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;?tab?&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;?space?&amp;lt;/tt&amp;gt; represent the named non-printable characters.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?unicode?&amp;lt;/tt&amp;gt; represents any valid Unicode character.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?digit?&amp;lt;/tt&amp;gt; represents any decimal digit.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?hexdigit?&amp;lt;/tt&amp;gt; represents any hexadecimal digit.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?letter?&amp;lt;/tt&amp;gt; represents any ASCII Latin letter in either uppercase or lowercase.&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = ?digit? , {?digit?} ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {?unicode? - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {?unicode? - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {?unicode? - '&amp;gt;' | '&amp;gt;' , ?unicode? - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = ?letter? | ?digit? | '_' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , ?digit? , {?digit?} , ']' ;&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = ?unicode? - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Context-free Grammars ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of a [[Context-free grammar]] used for random text generation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
grammar = production , {production} ;&lt;br /&gt;
production = symbol , '=' , alternative , {'|' , alternative} , ?newline? ;&lt;br /&gt;
symbol = symbol_char , {symbol_char} ;&lt;br /&gt;
symbol_char = ?letter? | ?digit? | '_' ; (* Unsure on this, need to check it *)&lt;br /&gt;
alternative = {terminal} ;&lt;br /&gt;
terminal = '{' , symbol , '}' | '{!}' | '{(}' | '{)}' | (?unicode? - '}') ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wfl_comment = '#' , {wfl_comment_char} , '#' ;&lt;br /&gt;
wfl_comment_char = ?unicode? - '#' ;&lt;br /&gt;
wfl_file_run = 'wfl' , wfl_string , wfl_file_content , 'wflend' ;&lt;br /&gt;
wfl_file_content = {?any token? - 'wflend'} ;&lt;br /&gt;
wfl_document = {wfl_function_definition} , wfl_formula ;&lt;br /&gt;
wfl_function_definition = 'def' , wfl_name , '(' , [wfl_function_args] , ')' , wfl_formula , ';' ;&lt;br /&gt;
wfl_function_args = wfl_function_arg , {',' , wfl_function_arg} ;&lt;br /&gt;
wfl_function_arg = wfl_name , ['*'] ;&lt;br /&gt;
wfl_formula = ['not'] , where_expression | bracketed_expression ;&lt;br /&gt;
bracketed_expression = '(' , wfl_formula , ')' ;&lt;br /&gt;
where_expression = (boolean_or_expression | bracketed_expression) , {'where' , wfl_variables} ;&lt;br /&gt;
wfl_variables = wfl_variable , {',' , wfl_variable} ;&lt;br /&gt;
wfl_variable = wfl_name , '=' , wfl_formula ;&lt;br /&gt;
boolean_or_expression = (boolean_and_expression | bracketed_expression) , {'or' , wfl_formula} ;&lt;br /&gt;
boolean_and_expression = (comparison_expression | bracketed_expression) , {'and' , wfl_formula} ;&lt;br /&gt;
comparison_expression = (containment_expression | bracketed_expression) , {comparison_op , wfl_formula} ;&lt;br /&gt;
comparison_op = '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;=' ;&lt;br /&gt;
containment_expression = (range_expression | bracketed_expression) , {'in' , wfl_formula} ;&lt;br /&gt;
range_expression = (additive_expression | bracketed_expression) , {'~' , wfl_formula} ;&lt;br /&gt;
additive_expression = [negation_op] , (multiplicative_expression | bracketed_expression) , {additive_op , wfl_formula} ;&lt;br /&gt;
negation_op = '-' | '+' ;&lt;br /&gt;
additive_op = '-' | '+' | '..' ;&lt;br /&gt;
multiplicative_expression := (exponent_expression | bracketed_expression) , {multiplicative_op , wfl_formula} ;&lt;br /&gt;
muliplicative_op = '*' | '/' | '%' ;&lt;br /&gt;
exponent_expression = {wfl_formula , '^'} , (dice_expression | bracketed_expression) ;&lt;br /&gt;
dice_expression = (dot_expression | bracketed_expression) , {'d' , wfl_formula} ;&lt;br /&gt;
dot_expression = (wfl_value | bracketed_expression) , {'.' , wfl_formula} ;&lt;br /&gt;
wfl_value = 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call ;&lt;br /&gt;
wfl_name = wfl_id_char , {wfl_id_char} ;&lt;br /&gt;
wfl_id_char = ?letter? | '_' ; (* Note: digits are NOT allowed! *)&lt;br /&gt;
wfl_number = ?digit? , {?digit?} , ['.' , ?digit? , {?digit?}] ;&lt;br /&gt;
wfl_string = &amp;quot;'&amp;quot; , {wfl_string_char | wfl_string_subst | wfl_string_escape} , &amp;quot;'&amp;quot; ;&lt;br /&gt;
wfl_string_char = ?unicode? - (&amp;quot;'&amp;quot; | &amp;quot;[&amp;quot;) ;&lt;br /&gt;
wfl_string_subst = '[' , wfl_formula , ']' ;&lt;br /&gt;
wfl_string_escape = &amp;quot;[']&amp;quot; | '[(]' | '[)]' ;&lt;br /&gt;
wfl_container = '[' , ['-&amp;gt;' | wfl_expression_list | wfl_key_value_list] , ']' ;&lt;br /&gt;
wfl_expression_list = wfl_formula , {',' , wfl_formula} ;&lt;br /&gt;
wfl_key_value_list = wml_key_value , {',' , wml_key_value} ;&lt;br /&gt;
wml_key_value = wfl_formula , '-&amp;gt;' , wfl_formula ;&lt;br /&gt;
wfl_function_call = wfl_name , '(' , [wfl_expression_list] , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Help Markup ==&lt;br /&gt;
&lt;br /&gt;
This grammar defines the [[help markup]] used in Wesnoth help topics and GUI2 rich labels. It's ''almost'' HTML and ''almost'' XMl but not quite either.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
document = {text | tag} ;&lt;br /&gt;
text = {literal | entity | escape} ;&lt;br /&gt;
literal = ?unicode? - ('&amp;lt;' , '&amp;amp;' , '\') ;&lt;br /&gt;
escape = '\' , ?unicode? ;&lt;br /&gt;
entity = '&amp;amp;#' , ?digit? , {?digit?} , ';'&lt;br /&gt;
       | '&amp;amp;#x' , ?hexdigit? , {?hexdigit?} , ';'&lt;br /&gt;
       | '&amp;amp;' , name , ';'&lt;br /&gt;
       ;&lt;br /&gt;
tag = '&amp;lt;' , name , {attribute} , '/' '&amp;gt;' (* Self-closing tag, XML-style *)&lt;br /&gt;
    | '&amp;lt;' , name , {attribute} , '&amp;gt;' , document , '&amp;lt;/' , name , '&amp;gt;' (* HTML-style tag, nestable *)&lt;br /&gt;
    | '&amp;lt;' , name , '&amp;gt;' , {attribute} , [text] , '&amp;lt;/' , name , '&amp;gt;' (* Old-style tag, not nestable *)&lt;br /&gt;
    ;&lt;br /&gt;
attribute = name , ['=' , attribute_value] ;&lt;br /&gt;
attribute_value = {?unicode? - (&amp;quot;'&amp;quot; | '&amp;quot;' | ?space?)} (* Unquoted value *)&lt;br /&gt;
                | &amp;quot;'&amp;quot; , text - &amp;quot;'&amp;quot; , &amp;quot;'&amp;quot;&lt;br /&gt;
                | '&amp;quot;' , text - '&amp;quot;' , '&amp;quot;'&lt;br /&gt;
                ;&lt;br /&gt;
name = name_char , {name_char} ;&lt;br /&gt;
name_char = ?letter? | ?digit? | '_'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74909</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74909"/>
		<updated>2026-03-19T07:19:56Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Summarize EBNF syntax at the top of the page, including the special extended syntax I'm using.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is [https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form Extended Backus-Naur form]:&lt;br /&gt;
&lt;br /&gt;
* Every rule is of the form &amp;lt;tt&amp;gt;nonterminal = rule ;&amp;lt;/tt&amp;gt; with a terminating semicolon.&lt;br /&gt;
* Comments are enclosed in &amp;lt;tt&amp;gt;(* these *)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Literal values are enclosed in either double or single quotes. There is no special syntax inside quotes.&lt;br /&gt;
* &amp;lt;tt&amp;gt;(...)&amp;lt;/tt&amp;gt; can be used for grouping.&lt;br /&gt;
* &amp;lt;tt&amp;gt;N * A&amp;lt;/tt&amp;gt; where N is a number means &amp;quot;exactly N instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;[A]&amp;lt;/tt&amp;gt; means &amp;quot;zero or one instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;{A}&amp;lt;/tt&amp;gt; means &amp;quot;zero or more instances of A&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A , B&amp;lt;/tt&amp;gt; means &amp;quot;A followed by B&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A | B&amp;lt;/tt&amp;gt; means &amp;quot;either A or B&amp;quot;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;A - B&amp;lt;/tt&amp;gt; means &amp;quot;A but not B&amp;quot;.]&lt;br /&gt;
* Some special values are enclosed in &amp;lt;tt&amp;gt;?...?&amp;lt;/tt&amp;gt;. This document uses the following special values:&lt;br /&gt;
** &amp;lt;tt&amp;gt;?newline?&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;?tab?&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;?space?&amp;lt;/tt&amp;gt; represent the named non-printable characters.&lt;br /&gt;
** &amp;lt;tt&amp;gt;?unicode?&amp;lt;/tt&amp;gt; represents any valid Unicode character.&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {?unicode? - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {?unicode? - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {?unicode? - '&amp;gt;' | '&amp;gt;' , ?unicode? - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = lowercase | uppercase | digit | '_' ;&lt;br /&gt;
lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'&lt;br /&gt;
          | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' ;&lt;br /&gt;
uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'&lt;br /&gt;
          | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , digit , {digit} , ']' ; (* as is digit *)&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = ?unicode? - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Context-free Grammars ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of a [[Context-free grammar]] used for random text generation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
grammar = production , {production} ;&lt;br /&gt;
production = symbol , '=' , alternative , {'|' , alternative} , ?newline? ;&lt;br /&gt;
symbol = symbol_char , {symbol_char} ;&lt;br /&gt;
symbol_char = lowercase | uppercase | digit | '_' ; (* Unsure on this, need to check it *)&lt;br /&gt;
alternative = {terminal} ;&lt;br /&gt;
terminal = '{' , symbol , '}' | '{!}' | '{(}' | '{)}' | (?unicode? - '}') ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wfl_comment = '#' , {wfl_comment_char} , '#' ;&lt;br /&gt;
wfl_comment_char = ?unicode? - '#' ;&lt;br /&gt;
wfl_file_run = 'wfl' , wfl_string , wfl_file_content , 'wflend' ;&lt;br /&gt;
wfl_file_content = {?any token? - 'wflend'} ;&lt;br /&gt;
wfl_document = {wfl_function_definition} , wfl_formula ;&lt;br /&gt;
wfl_function_definition = 'def' , wfl_name , '(' , [wfl_function_args] , ')' , wfl_formula , ';' ;&lt;br /&gt;
wfl_function_args = wfl_function_arg , {',' , wfl_function_arg} ;&lt;br /&gt;
wfl_function_arg = wfl_name , ['*'] ;&lt;br /&gt;
wfl_formula = ['not'] , where_expression | bracketed_expression ;&lt;br /&gt;
bracketed_expression = '(' , wfl_formula , ')' ;&lt;br /&gt;
where_expression = (boolean_or_expression | bracketed_expression) , {'where' , wfl_variables} ;&lt;br /&gt;
wfl_variables = wfl_variable , {',' , wfl_variable} ;&lt;br /&gt;
wfl_variable = wfl_name , '=' , wfl_formula ;&lt;br /&gt;
boolean_or_expression = (boolean_and_expression | bracketed_expression) , {'or' , wfl_formula} ;&lt;br /&gt;
boolean_and_expression = (comparison_expression | bracketed_expression) , {'and' , wfl_formula} ;&lt;br /&gt;
comparison_expression = (containment_expression | bracketed_expression) , {comparison_op , wfl_formula} ;&lt;br /&gt;
comparison_op = '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;=' ;&lt;br /&gt;
containment_expression = (range_expression | bracketed_expression) , {'in' , wfl_formula} ;&lt;br /&gt;
range_expression = (additive_expression | bracketed_expression) , {'~' , wfl_formula} ;&lt;br /&gt;
additive_expression = [negation_op] , (multiplicative_expression | bracketed_expression) , {additive_op , wfl_formula} ;&lt;br /&gt;
negation_op = '-' | '+' ;&lt;br /&gt;
additive_op = '-' | '+' | '..' ;&lt;br /&gt;
multiplicative_expression := (exponent_expression | bracketed_expression) , {multiplicative_op , wfl_formula} ;&lt;br /&gt;
muliplicative_op = '*' | '/' | '%' ;&lt;br /&gt;
exponent_expression = {wfl_formula , '^'} , (dice_expression | bracketed_expression) ;&lt;br /&gt;
dice_expression = (dot_expression | bracketed_expression) , {'d' , wfl_formula} ;&lt;br /&gt;
dot_expression = (wfl_value | bracketed_expression) , {'.' , wfl_formula} ;&lt;br /&gt;
wfl_value = 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call ;&lt;br /&gt;
wfl_name = wfl_id_char , {wfl_id_char} ;&lt;br /&gt;
wfl_id_char = lowercase | uppercase | '_' ; (* Note: digits are NOT allowed! *)&lt;br /&gt;
wfl_number = digit , {digit} , ['.' , digit , {digit}] ;&lt;br /&gt;
wfl_string = &amp;quot;'&amp;quot; , {wfl_string_char | wfl_string_subst | wfl_string_escape} , &amp;quot;'&amp;quot; ;&lt;br /&gt;
wfl_string_char = ?unicode? - (&amp;quot;'&amp;quot; | &amp;quot;[&amp;quot;) ;&lt;br /&gt;
wfl_string_subst = '[' , wfl_formula , ']' ;&lt;br /&gt;
wfl_string_escape = &amp;quot;[']&amp;quot; | '[(]' | '[)]' ;&lt;br /&gt;
wfl_container = '[' , ['-&amp;gt;' | wfl_expression_list | wfl_key_value_list] , ']' ;&lt;br /&gt;
wfl_expression_list = wfl_formula , {',' , wfl_formula} ;&lt;br /&gt;
wfl_key_value_list = wml_key_value , {',' , wml_key_value} ;&lt;br /&gt;
wml_key_value = wfl_formula , '-&amp;gt;' , wfl_formula ;&lt;br /&gt;
wfl_function_call = wfl_name , '(' , [wfl_expression_list] , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Help Markup ==&lt;br /&gt;
&lt;br /&gt;
This grammar defines the [[help markup]] used in Wesnoth help topics and GUI2 rich labels. It's ''almost'' HTML and ''almost'' XMl but not quite either.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
document = {text | tag} ;&lt;br /&gt;
text = {literal | entity | escape} ;&lt;br /&gt;
literal = ?unicode? - ('&amp;lt;' , '&amp;amp;' , '\') ;&lt;br /&gt;
escape = '\' , ?unicode? ;&lt;br /&gt;
entity = '&amp;amp;#' , digit , {digit} , ';'&lt;br /&gt;
       | '&amp;amp;#x' , hexdigit , {hexdigit} , ';'&lt;br /&gt;
       | '&amp;amp;' , name , ';'&lt;br /&gt;
       ;&lt;br /&gt;
tag = '&amp;lt;' , name , {attribute} , '/' '&amp;gt;' (* Self-closing tag, XML-style *)&lt;br /&gt;
    | '&amp;lt;' , name , {attribute} , '&amp;gt;' , document , '&amp;lt;/' , name , '&amp;gt;' (* HTML-style tag, nestable *)&lt;br /&gt;
    | '&amp;lt;' , name , '&amp;gt;' , {attribute} , [text] , '&amp;lt;/' , name , '&amp;gt;' (* Old-style tag, not nestable *)&lt;br /&gt;
    ;&lt;br /&gt;
attribute = name , ['=' , attribute_value] ;&lt;br /&gt;
attribute_value = {?unicode? - (&amp;quot;'&amp;quot; | '&amp;quot;' | ?space?)} (* Unquoted value *)&lt;br /&gt;
                | &amp;quot;'&amp;quot; , text - &amp;quot;'&amp;quot; , &amp;quot;'&amp;quot;&lt;br /&gt;
                | '&amp;quot;' , text - '&amp;quot;' , '&amp;quot;'&lt;br /&gt;
                ;&lt;br /&gt;
name = name_char , {name_char} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
hexdigit = digit | 'a' | 'A' | 'b' | 'B' | 'c' | 'C' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F' ;&lt;br /&gt;
name_char = lower | upper | digit | '_'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74908</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74908"/>
		<updated>2026-03-19T07:11:29Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Help Markup */ Add a new section describing Help markup&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is [https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form Extended Backus-Naur form].&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {char - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {char - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {char - '&amp;gt;' | '&amp;gt;' , char - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = lowercase | uppercase | digit | '_' ;&lt;br /&gt;
lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'&lt;br /&gt;
          | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' ;&lt;br /&gt;
uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'&lt;br /&gt;
          | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , digit , {digit} , ']' ; (* as is digit *)&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = char - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Context-free Grammars ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of a [[Context-free grammar]] used for random text generation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
grammar = production , {production} ;&lt;br /&gt;
production = symbol , '=' , alternative , {'|' , alternative} , ?newline? ;&lt;br /&gt;
symbol = symbol_char , {symbol_char} ;&lt;br /&gt;
symbol_char = lowercase | uppercase | digit | '_' ; (* Unsure on this, need to check it *)&lt;br /&gt;
alternative = {terminal} ;&lt;br /&gt;
terminal = '{' , symbol , '}' | '{!}' | '{(}' | '{)}' | (?any unicode character? - '}') ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wfl_comment = '#' , {wfl_comment_char} , '#' ;&lt;br /&gt;
wfl_comment_char = char - '#' ;&lt;br /&gt;
wfl_file_run = 'wfl' , wfl_string , wfl_file_content , 'wflend' ;&lt;br /&gt;
wfl_file_content = {?any token? - 'wflend'} ;&lt;br /&gt;
wfl_document = {wfl_function_definition} , wfl_formula ;&lt;br /&gt;
wfl_function_definition = 'def' , wfl_name , '(' , [wfl_function_args] , ')' , wfl_formula , ';' ;&lt;br /&gt;
wfl_function_args = wfl_function_arg , {',' , wfl_function_arg} ;&lt;br /&gt;
wfl_function_arg = wfl_name , ['*'] ;&lt;br /&gt;
wfl_formula = ['not'] , where_expression | bracketed_expression ;&lt;br /&gt;
bracketed_expression = '(' , wfl_formula , ')' ;&lt;br /&gt;
where_expression = (boolean_or_expression | bracketed_expression) , {'where' , wfl_variables} ;&lt;br /&gt;
wfl_variables = wfl_variable , {',' , wfl_variable} ;&lt;br /&gt;
wfl_variable = wfl_name , '=' , wfl_formula ;&lt;br /&gt;
boolean_or_expression = (boolean_and_expression | bracketed_expression) , {'or' , wfl_formula} ;&lt;br /&gt;
boolean_and_expression = (comparison_expression | bracketed_expression) , {'and' , wfl_formula} ;&lt;br /&gt;
comparison_expression = (containment_expression | bracketed_expression) , {comparison_op , wfl_formula} ;&lt;br /&gt;
comparison_op = '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;=' ;&lt;br /&gt;
containment_expression = (range_expression | bracketed_expression) , {'in' , wfl_formula} ;&lt;br /&gt;
range_expression = (additive_expression | bracketed_expression) , {'~' , wfl_formula} ;&lt;br /&gt;
additive_expression = [negation_op] , (multiplicative_expression | bracketed_expression) , {additive_op , wfl_formula} ;&lt;br /&gt;
negation_op = '-' | '+' ;&lt;br /&gt;
additive_op = '-' | '+' | '..' ;&lt;br /&gt;
multiplicative_expression := (exponent_expression | bracketed_expression) , {multiplicative_op , wfl_formula} ;&lt;br /&gt;
muliplicative_op = '*' | '/' | '%' ;&lt;br /&gt;
exponent_expression = {wfl_formula , '^'} , (dice_expression | bracketed_expression) ;&lt;br /&gt;
dice_expression = (dot_expression | bracketed_expression) , {'d' , wfl_formula} ;&lt;br /&gt;
dot_expression = (wfl_value | bracketed_expression) , {'.' , wfl_formula} ;&lt;br /&gt;
wfl_value = 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call ;&lt;br /&gt;
wfl_name = wfl_id_char , {wfl_id_char} ;&lt;br /&gt;
wfl_id_char = lowercase | uppercase | '_' ; (* Note: digits are NOT allowed! *)&lt;br /&gt;
wfl_number = digit , {digit} , ['.' , digit , {digit}] ;&lt;br /&gt;
wfl_string = &amp;quot;'&amp;quot; , {wfl_string_char | wfl_string_subst | wfl_string_escape} , &amp;quot;'&amp;quot; ;&lt;br /&gt;
wfl_string_char = char - (&amp;quot;'&amp;quot; | &amp;quot;[&amp;quot;) ;&lt;br /&gt;
wfl_string_subst = '[' , wfl_formula , ']' ;&lt;br /&gt;
wfl_string_escape = &amp;quot;[']&amp;quot; | '[(]' | '[)]' ;&lt;br /&gt;
wfl_container = '[' , ['-&amp;gt;' | wfl_expression_list | wfl_key_value_list] , ']' ;&lt;br /&gt;
wfl_expression_list = wfl_formula , {',' , wfl_formula} ;&lt;br /&gt;
wfl_key_value_list = wml_key_value , {',' , wml_key_value} ;&lt;br /&gt;
wml_key_value = wfl_formula , '-&amp;gt;' , wfl_formula ;&lt;br /&gt;
wfl_function_call = wfl_name , '(' , [wfl_expression_list] , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Help Markup ==&lt;br /&gt;
&lt;br /&gt;
This grammar defines the [[help markup]] used in Wesnoth help topics and GUI2 rich labels. It's ''almost'' HTML and ''almost'' XMl but not quite either.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
document = {text | tag} ;&lt;br /&gt;
text = {literal | entity | escape} ;&lt;br /&gt;
literal = ?any unicode character? - ('&amp;lt;' , '&amp;amp;' , '\') ;&lt;br /&gt;
escape = '\' , ?any unicode character? ;&lt;br /&gt;
entity = '&amp;amp;#' , digit , {digit} , ';'&lt;br /&gt;
       | '&amp;amp;#x' , hexdigit , {hexdigit} , ';'&lt;br /&gt;
       | '&amp;amp;' , name , ';'&lt;br /&gt;
       ;&lt;br /&gt;
tag = '&amp;lt;' , name , {attribute} , '/' '&amp;gt;' (* Self-closing tag, XML-style *)&lt;br /&gt;
    | '&amp;lt;' , name , {attribute} , '&amp;gt;' , document , '&amp;lt;/' , name , '&amp;gt;' (* HTML-style tag, nestable *)&lt;br /&gt;
    | '&amp;lt;' , name , '&amp;gt;' , {attribute} , [text] , '&amp;lt;/' , name , '&amp;gt;' (* Old-style tag, not nestable *)&lt;br /&gt;
    ;&lt;br /&gt;
attribute = name , ['=' , attribute_value] ;&lt;br /&gt;
attribute_value = {?any unicode character? - (&amp;quot;'&amp;quot; | '&amp;quot;' | ?space?)} (* Unquoted value *)&lt;br /&gt;
                | &amp;quot;'&amp;quot; , text - &amp;quot;'&amp;quot; , &amp;quot;'&amp;quot;&lt;br /&gt;
                | '&amp;quot;' , text - '&amp;quot;' , '&amp;quot;'&lt;br /&gt;
                ;&lt;br /&gt;
name = name_char , {name_char} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
hexdigit = digit | 'a' | 'A' | 'b' | 'B' | 'c' | 'C' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F' ;&lt;br /&gt;
name_char = lower | upper | digit | '_'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74907</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74907"/>
		<updated>2026-03-19T06:57:33Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Context-free Grammars */ Add new section covering Context-free grammar&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is [https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form Extended Backus-Naur form].&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {char - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {char - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {char - '&amp;gt;' | '&amp;gt;' , char - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = lowercase | uppercase | digit | '_' ;&lt;br /&gt;
lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'&lt;br /&gt;
          | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' ;&lt;br /&gt;
uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'&lt;br /&gt;
          | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , digit , {digit} , ']' ; (* as is digit *)&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = char - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Context-free Grammars ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of a [[Context-free grammar]] used for random text generation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
grammar = production , {production} ;&lt;br /&gt;
production = symbol , '=' , alternative , {'|' , alternative} , ?newline? ;&lt;br /&gt;
symbol = symbol_char , {symbol_char} ;&lt;br /&gt;
symbol_char = lowercase | uppercase | digit | '_' ; (* Unsure on this, need to check it *)&lt;br /&gt;
alternative = {terminal} ;&lt;br /&gt;
terminal = '{' , symbol , '}' | '{!}' | '{(}' | '{)}' | (?any unicode character? - '}') ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wfl_comment = '#' , {wfl_comment_char} , '#' ;&lt;br /&gt;
wfl_comment_char = char - '#' ;&lt;br /&gt;
wfl_file_run = 'wfl' , wfl_string , wfl_file_content , 'wflend' ;&lt;br /&gt;
wfl_file_content = {?any token? - 'wflend'} ;&lt;br /&gt;
wfl_document = {wfl_function_definition} , wfl_formula ;&lt;br /&gt;
wfl_function_definition = 'def' , wfl_name , '(' , [wfl_function_args] , ')' , wfl_formula , ';' ;&lt;br /&gt;
wfl_function_args = wfl_function_arg , {',' , wfl_function_arg} ;&lt;br /&gt;
wfl_function_arg = wfl_name , ['*'] ;&lt;br /&gt;
wfl_formula = ['not'] , where_expression | bracketed_expression ;&lt;br /&gt;
bracketed_expression = '(' , wfl_formula , ')' ;&lt;br /&gt;
where_expression = (boolean_or_expression | bracketed_expression) , {'where' , wfl_variables} ;&lt;br /&gt;
wfl_variables = wfl_variable , {',' , wfl_variable} ;&lt;br /&gt;
wfl_variable = wfl_name , '=' , wfl_formula ;&lt;br /&gt;
boolean_or_expression = (boolean_and_expression | bracketed_expression) , {'or' , wfl_formula} ;&lt;br /&gt;
boolean_and_expression = (comparison_expression | bracketed_expression) , {'and' , wfl_formula} ;&lt;br /&gt;
comparison_expression = (containment_expression | bracketed_expression) , {comparison_op , wfl_formula} ;&lt;br /&gt;
comparison_op = '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;=' ;&lt;br /&gt;
containment_expression = (range_expression | bracketed_expression) , {'in' , wfl_formula} ;&lt;br /&gt;
range_expression = (additive_expression | bracketed_expression) , {'~' , wfl_formula} ;&lt;br /&gt;
additive_expression = [negation_op] , (multiplicative_expression | bracketed_expression) , {additive_op , wfl_formula} ;&lt;br /&gt;
negation_op = '-' | '+' ;&lt;br /&gt;
additive_op = '-' | '+' | '..' ;&lt;br /&gt;
multiplicative_expression := (exponent_expression | bracketed_expression) , {multiplicative_op , wfl_formula} ;&lt;br /&gt;
muliplicative_op = '*' | '/' | '%' ;&lt;br /&gt;
exponent_expression = {wfl_formula , '^'} , (dice_expression | bracketed_expression) ;&lt;br /&gt;
dice_expression = (dot_expression | bracketed_expression) , {'d' , wfl_formula} ;&lt;br /&gt;
dot_expression = (wfl_value | bracketed_expression) , {'.' , wfl_formula} ;&lt;br /&gt;
wfl_value = 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call ;&lt;br /&gt;
wfl_name = wfl_id_char , {wfl_id_char} ;&lt;br /&gt;
wfl_id_char = lowercase | uppercase | '_' ; (* Note: digits are NOT allowed! *)&lt;br /&gt;
wfl_number = digit , {digit} , ['.' , digit , {digit}] ;&lt;br /&gt;
wfl_string = &amp;quot;'&amp;quot; , {wfl_string_char | wfl_string_subst | wfl_string_escape} , &amp;quot;'&amp;quot; ;&lt;br /&gt;
wfl_string_char = char - (&amp;quot;'&amp;quot; | &amp;quot;[&amp;quot;) ;&lt;br /&gt;
wfl_string_subst = '[' , wfl_formula , ']' ;&lt;br /&gt;
wfl_string_escape = &amp;quot;[']&amp;quot; | '[(]' | '[)]' ;&lt;br /&gt;
wfl_container = '[' , ['-&amp;gt;' | wfl_expression_list | wfl_key_value_list] , ']' ;&lt;br /&gt;
wfl_expression_list = wfl_formula , {',' , wfl_formula} ;&lt;br /&gt;
wfl_key_value_list = wml_key_value , {',' , wml_key_value} ;&lt;br /&gt;
wml_key_value = wfl_formula , '-&amp;gt;' , wfl_formula ;&lt;br /&gt;
wfl_function_call = wfl_name , '(' , [wfl_expression_list] , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74906</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74906"/>
		<updated>2026-03-19T06:38:12Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Remove &amp;quot;Under Construction&amp;quot; note&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is [https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form Extended Backus-Naur form].&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {char - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {char - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {char - '&amp;gt;' | '&amp;gt;' , char - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = lowercase | uppercase | digit | '_' ;&lt;br /&gt;
lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'&lt;br /&gt;
          | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' ;&lt;br /&gt;
uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'&lt;br /&gt;
          | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , digit , {digit} , ']' ; (* as is digit *)&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = char - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wfl_comment = '#' , {wfl_comment_char} , '#' ;&lt;br /&gt;
wfl_comment_char = char - '#' ;&lt;br /&gt;
wfl_file_run = 'wfl' , wfl_string , wfl_file_content , 'wflend' ;&lt;br /&gt;
wfl_file_content = {?any token? - 'wflend'} ;&lt;br /&gt;
wfl_document = {wfl_function_definition} , wfl_formula ;&lt;br /&gt;
wfl_function_definition = 'def' , wfl_name , '(' , [wfl_function_args] , ')' , wfl_formula , ';' ;&lt;br /&gt;
wfl_function_args = wfl_function_arg , {',' , wfl_function_arg} ;&lt;br /&gt;
wfl_function_arg = wfl_name , ['*'] ;&lt;br /&gt;
wfl_formula = ['not'] , where_expression | bracketed_expression ;&lt;br /&gt;
bracketed_expression = '(' , wfl_formula , ')' ;&lt;br /&gt;
where_expression = (boolean_or_expression | bracketed_expression) , {'where' , wfl_variables} ;&lt;br /&gt;
wfl_variables = wfl_variable , {',' , wfl_variable} ;&lt;br /&gt;
wfl_variable = wfl_name , '=' , wfl_formula ;&lt;br /&gt;
boolean_or_expression = (boolean_and_expression | bracketed_expression) , {'or' , wfl_formula} ;&lt;br /&gt;
boolean_and_expression = (comparison_expression | bracketed_expression) , {'and' , wfl_formula} ;&lt;br /&gt;
comparison_expression = (containment_expression | bracketed_expression) , {comparison_op , wfl_formula} ;&lt;br /&gt;
comparison_op = '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;=' ;&lt;br /&gt;
containment_expression = (range_expression | bracketed_expression) , {'in' , wfl_formula} ;&lt;br /&gt;
range_expression = (additive_expression | bracketed_expression) , {'~' , wfl_formula} ;&lt;br /&gt;
additive_expression = [negation_op] , (multiplicative_expression | bracketed_expression) , {additive_op , wfl_formula} ;&lt;br /&gt;
negation_op = '-' | '+' ;&lt;br /&gt;
additive_op = '-' | '+' | '..' ;&lt;br /&gt;
multiplicative_expression := (exponent_expression | bracketed_expression) , {multiplicative_op , wfl_formula} ;&lt;br /&gt;
muliplicative_op = '*' | '/' | '%' ;&lt;br /&gt;
exponent_expression = {wfl_formula , '^'} , (dice_expression | bracketed_expression) ;&lt;br /&gt;
dice_expression = (dot_expression | bracketed_expression) , {'d' , wfl_formula} ;&lt;br /&gt;
dot_expression = (wfl_value | bracketed_expression) , {'.' , wfl_formula} ;&lt;br /&gt;
wfl_value = 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call ;&lt;br /&gt;
wfl_name = wfl_id_char , {wfl_id_char} ;&lt;br /&gt;
wfl_id_char = lowercase | uppercase | '_' ; (* Note: digits are NOT allowed! *)&lt;br /&gt;
wfl_number = digit , {digit} , ['.' , digit , {digit}] ;&lt;br /&gt;
wfl_string = &amp;quot;'&amp;quot; , {wfl_string_char | wfl_string_subst | wfl_string_escape} , &amp;quot;'&amp;quot; ;&lt;br /&gt;
wfl_string_char = char - (&amp;quot;'&amp;quot; | &amp;quot;[&amp;quot;) ;&lt;br /&gt;
wfl_string_subst = '[' , wfl_formula , ']' ;&lt;br /&gt;
wfl_string_escape = &amp;quot;[']&amp;quot; | '[(]' | '[)]' ;&lt;br /&gt;
wfl_container = '[' , ['-&amp;gt;' | wfl_expression_list | wfl_key_value_list] , ']' ;&lt;br /&gt;
wfl_expression_list = wfl_formula , {',' , wfl_formula} ;&lt;br /&gt;
wfl_key_value_list = wml_key_value , {',' , wml_key_value} ;&lt;br /&gt;
wml_key_value = wfl_formula , '-&amp;gt;' , wfl_formula ;&lt;br /&gt;
wfl_function_call = wfl_name , '(' , [wfl_expression_list] , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74905</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74905"/>
		<updated>2026-03-19T06:37:52Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Wesnoth Formula Language */ Rewrite in EBNF&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;----&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This page is currently undergoing reconstruction. Information on the page may become misleading or occasionally wrong for brief periods of time.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is [https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form Extended Backus-Naur form].&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {char - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {char - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {char - '&amp;gt;' | '&amp;gt;' , char - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = lowercase | uppercase | digit | '_' ;&lt;br /&gt;
lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'&lt;br /&gt;
          | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' ;&lt;br /&gt;
uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'&lt;br /&gt;
          | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , digit , {digit} , ']' ; (* as is digit *)&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = char - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wfl_comment = '#' , {wfl_comment_char} , '#' ;&lt;br /&gt;
wfl_comment_char = char - '#' ;&lt;br /&gt;
wfl_file_run = 'wfl' , wfl_string , wfl_file_content , 'wflend' ;&lt;br /&gt;
wfl_file_content = {?any token? - 'wflend'} ;&lt;br /&gt;
wfl_document = {wfl_function_definition} , wfl_formula ;&lt;br /&gt;
wfl_function_definition = 'def' , wfl_name , '(' , [wfl_function_args] , ')' , wfl_formula , ';' ;&lt;br /&gt;
wfl_function_args = wfl_function_arg , {',' , wfl_function_arg} ;&lt;br /&gt;
wfl_function_arg = wfl_name , ['*'] ;&lt;br /&gt;
wfl_formula = ['not'] , where_expression | bracketed_expression ;&lt;br /&gt;
bracketed_expression = '(' , wfl_formula , ')' ;&lt;br /&gt;
where_expression = (boolean_or_expression | bracketed_expression) , {'where' , wfl_variables} ;&lt;br /&gt;
wfl_variables = wfl_variable , {',' , wfl_variable} ;&lt;br /&gt;
wfl_variable = wfl_name , '=' , wfl_formula ;&lt;br /&gt;
boolean_or_expression = (boolean_and_expression | bracketed_expression) , {'or' , wfl_formula} ;&lt;br /&gt;
boolean_and_expression = (comparison_expression | bracketed_expression) , {'and' , wfl_formula} ;&lt;br /&gt;
comparison_expression = (containment_expression | bracketed_expression) , {comparison_op , wfl_formula} ;&lt;br /&gt;
comparison_op = '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;=' ;&lt;br /&gt;
containment_expression = (range_expression | bracketed_expression) , {'in' , wfl_formula} ;&lt;br /&gt;
range_expression = (additive_expression | bracketed_expression) , {'~' , wfl_formula} ;&lt;br /&gt;
additive_expression = [negation_op] , (multiplicative_expression | bracketed_expression) , {additive_op , wfl_formula} ;&lt;br /&gt;
negation_op = '-' | '+' ;&lt;br /&gt;
additive_op = '-' | '+' | '..' ;&lt;br /&gt;
multiplicative_expression := (exponent_expression | bracketed_expression) , {multiplicative_op , wfl_formula} ;&lt;br /&gt;
muliplicative_op = '*' | '/' | '%' ;&lt;br /&gt;
exponent_expression = {wfl_formula , '^'} , (dice_expression | bracketed_expression) ;&lt;br /&gt;
dice_expression = (dot_expression | bracketed_expression) , {'d' , wfl_formula} ;&lt;br /&gt;
dot_expression = (wfl_value | bracketed_expression) , {'.' , wfl_formula} ;&lt;br /&gt;
wfl_value = 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call ;&lt;br /&gt;
wfl_name = wfl_id_char , {wfl_id_char} ;&lt;br /&gt;
wfl_id_char = lowercase | uppercase | '_' ; (* Note: digits are NOT allowed! *)&lt;br /&gt;
wfl_number = digit , {digit} , ['.' , digit , {digit}] ;&lt;br /&gt;
wfl_string = &amp;quot;'&amp;quot; , {wfl_string_char | wfl_string_subst | wfl_string_escape} , &amp;quot;'&amp;quot; ;&lt;br /&gt;
wfl_string_char = char - (&amp;quot;'&amp;quot; | &amp;quot;[&amp;quot;) ;&lt;br /&gt;
wfl_string_subst = '[' , wfl_formula , ']' ;&lt;br /&gt;
wfl_string_escape = &amp;quot;[']&amp;quot; | '[(]' | '[)]' ;&lt;br /&gt;
wfl_container = '[' , ['-&amp;gt;' | wfl_expression_list | wfl_key_value_list] , ']' ;&lt;br /&gt;
wfl_expression_list = wfl_formula , {',' , wfl_formula} ;&lt;br /&gt;
wfl_key_value_list = wml_key_value , {',' , wml_key_value} ;&lt;br /&gt;
wml_key_value = wfl_formula , '-&amp;gt;' , wfl_formula ;&lt;br /&gt;
wfl_function_call = wfl_name , '(' , [wfl_expression_list] , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74904</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74904"/>
		<updated>2026-03-19T06:17:19Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Update opening blurb&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;----&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This page is currently undergoing reconstruction. Information on the page may become misleading or occasionally wrong for brief periods of time.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is [https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form Extended Backus-Naur form].&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {char - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {char - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {char - '&amp;gt;' | '&amp;gt;' , char - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = lowercase | uppercase | digit | '_' ;&lt;br /&gt;
lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'&lt;br /&gt;
          | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' ;&lt;br /&gt;
uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'&lt;br /&gt;
          | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , digit , {digit} , ']' ; (* as is digit *)&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = char - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
 wfl_comment := '#' [^#]* '#'&lt;br /&gt;
 wfl_file_run := 'wfl' wfl_string «any token»* 'wflend'&lt;br /&gt;
 wfl_document := wfl_function_definition* wfl_formula&lt;br /&gt;
 wfl_function_definition := 'def' wfl_name '(' wfl_function_args ')' wfl_formula ';'&lt;br /&gt;
 wfl_function_args := (wfl_function_arg (',' wfl_function_arg)*)?&lt;br /&gt;
 wfl_function_arg := wfl_name '*'?&lt;br /&gt;
 wfl_formula := 'not'? where_expression&lt;br /&gt;
 wfl_formula := bracketed_expression&lt;br /&gt;
 bracketed_expression := '(' wfl_formula ')'&lt;br /&gt;
 where_expression := (boolean_or_expression | bracketed_expression) ('where' wfl_variables)*&lt;br /&gt;
 wfl_variables := wfl_variable (',' wfl_variable)*&lt;br /&gt;
 wfl_variable := wfl_name '=' wfl_formula&lt;br /&gt;
 boolean_or_expression := (boolean_and_expression | bracketed_expression) ('or' wfl_formula)*&lt;br /&gt;
 boolean_and_expression := (comparison_expression | bracketed_expression) ('and' wfl_formula)*&lt;br /&gt;
 comparison_expression := (containment_expression | bracketed_expression) (comparison_op wfl_formula)*&lt;br /&gt;
 comparison_op := '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;='&lt;br /&gt;
 containment_expression := (range_expression | bracketed_expression) ('in' wfl_formula)*&lt;br /&gt;
 range_expression := (additive_expression | bracketed_expression) ('~' wfl_formula)*&lt;br /&gt;
 additive_expression := negation_opt? (multiplicative_expression | bracketed_expression) (additive_op wfl_formula)*&lt;br /&gt;
 negation_op := '-' | '+'&lt;br /&gt;
 additive_op := '-' | '+' | '..'&lt;br /&gt;
 multiplicative_expression := (exponent_expression | bracketed_expression) (multiplicative_op wfl_formula)*&lt;br /&gt;
 muliplicative_op := '*' | '/' | '%'&lt;br /&gt;
 exponent_expression := (wfl_formula '^')* (dice_expression | bracketed_expression)&lt;br /&gt;
 dice_expression := (dot_expression | bracketed_expression) ('d' wfl_formula)*&lt;br /&gt;
 dot_expression := (wfl_value | bracketed_expression) ('.' wfl_formula)*&lt;br /&gt;
 wfl_value := 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call&lt;br /&gt;
 wfl_name := [a-zA-Z_]+&lt;br /&gt;
 wfl_number := [0-9]+ ('.' [0-9]+)?&lt;br /&gt;
 wfl_string := &amp;quot;'&amp;quot; ([^'[]+ | wfl_string_subst | wfl_string_escape)* &amp;quot;'&amp;quot;&lt;br /&gt;
 wfl_string_subst := '[' wfl_formula ']'&lt;br /&gt;
 wfl_string_escape := &amp;quot;[']&amp;quot; | '[(]' | '[)]'&lt;br /&gt;
 wfl_container := '[' ('-&amp;gt;' | wfl_expression_list | wfl_key_value_list)? ']'&lt;br /&gt;
 wfl_expression_list := wfl_formula (',' wfl_formula)*&lt;br /&gt;
 wfl_key_value_list := wfl_formula '-&amp;gt;' wfl_formula (',' wfl_formula '-&amp;gt;' wfl_formula)*&lt;br /&gt;
 wfl_function_call := wfl_name '(' wfl_expression_list? ')'&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74903</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74903"/>
		<updated>2026-03-19T06:10:30Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* WML Substitutions */ Rewrite in EBNF&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;----&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This page is currently undergoing reconstruction. Information on the page may become misleading or occasionally wrong for brief periods of time.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is regular-expression-like (which is not quite the same as regex-like!), with the following conventions:&lt;br /&gt;
&lt;br /&gt;
* Literal values are enclosed in either 'single quotes' or &amp;quot;double quotes&amp;quot;.&lt;br /&gt;
* Square brackets enclose character classes, with initial ^ inverting them&lt;br /&gt;
* Whitespace within an expression (unless quoted) is used only for readability or to separate non-terminals&lt;br /&gt;
* The meta-characters * + ? | have the same meaning as is typical in regular expressions&lt;br /&gt;
* The sequence «tab» represents a tab character, and «nl» represents an end-of-line character or character sequence&lt;br /&gt;
* Multiple definitions of a non-terminal are equivalent to alternation (ie, x:=4 and x:=7 combine to produce x:=4|7)&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {char - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {char - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {char - '&amp;gt;' | '&amp;gt;' , char - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = lowercase | uppercase | digit | '_' ;&lt;br /&gt;
lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'&lt;br /&gt;
          | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' ;&lt;br /&gt;
uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'&lt;br /&gt;
          | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_substitution = wml_var | wml_formula | '$|' ;&lt;br /&gt;
wml_var = '$' , wml_var_path , [wml_var_default | '|'] ;&lt;br /&gt;
wml_var_path = {wml_var_name , [wml_var_index] , '.'} , wml_var_name ;&lt;br /&gt;
wml_var_name = wml_id_char, {wml_id_char} ; (* wml_id_char is defined in the WML grammar, above *)&lt;br /&gt;
wml_var_index = '[' , digit , {digit} , ']' ; (* as is digit *)&lt;br /&gt;
wml_var_default = '?' , default_char, {default_char} , '|' ;&lt;br /&gt;
default_char = char - '|' ;&lt;br /&gt;
wml_formula = '$' , '(' , wfl_document , ')' ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
 wfl_comment := '#' [^#]* '#'&lt;br /&gt;
 wfl_file_run := 'wfl' wfl_string «any token»* 'wflend'&lt;br /&gt;
 wfl_document := wfl_function_definition* wfl_formula&lt;br /&gt;
 wfl_function_definition := 'def' wfl_name '(' wfl_function_args ')' wfl_formula ';'&lt;br /&gt;
 wfl_function_args := (wfl_function_arg (',' wfl_function_arg)*)?&lt;br /&gt;
 wfl_function_arg := wfl_name '*'?&lt;br /&gt;
 wfl_formula := 'not'? where_expression&lt;br /&gt;
 wfl_formula := bracketed_expression&lt;br /&gt;
 bracketed_expression := '(' wfl_formula ')'&lt;br /&gt;
 where_expression := (boolean_or_expression | bracketed_expression) ('where' wfl_variables)*&lt;br /&gt;
 wfl_variables := wfl_variable (',' wfl_variable)*&lt;br /&gt;
 wfl_variable := wfl_name '=' wfl_formula&lt;br /&gt;
 boolean_or_expression := (boolean_and_expression | bracketed_expression) ('or' wfl_formula)*&lt;br /&gt;
 boolean_and_expression := (comparison_expression | bracketed_expression) ('and' wfl_formula)*&lt;br /&gt;
 comparison_expression := (containment_expression | bracketed_expression) (comparison_op wfl_formula)*&lt;br /&gt;
 comparison_op := '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;='&lt;br /&gt;
 containment_expression := (range_expression | bracketed_expression) ('in' wfl_formula)*&lt;br /&gt;
 range_expression := (additive_expression | bracketed_expression) ('~' wfl_formula)*&lt;br /&gt;
 additive_expression := negation_opt? (multiplicative_expression | bracketed_expression) (additive_op wfl_formula)*&lt;br /&gt;
 negation_op := '-' | '+'&lt;br /&gt;
 additive_op := '-' | '+' | '..'&lt;br /&gt;
 multiplicative_expression := (exponent_expression | bracketed_expression) (multiplicative_op wfl_formula)*&lt;br /&gt;
 muliplicative_op := '*' | '/' | '%'&lt;br /&gt;
 exponent_expression := (wfl_formula '^')* (dice_expression | bracketed_expression)&lt;br /&gt;
 dice_expression := (dot_expression | bracketed_expression) ('d' wfl_formula)*&lt;br /&gt;
 dot_expression := (wfl_value | bracketed_expression) ('.' wfl_formula)*&lt;br /&gt;
 wfl_value := 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call&lt;br /&gt;
 wfl_name := [a-zA-Z_]+&lt;br /&gt;
 wfl_number := [0-9]+ ('.' [0-9]+)?&lt;br /&gt;
 wfl_string := &amp;quot;'&amp;quot; ([^'[]+ | wfl_string_subst | wfl_string_escape)* &amp;quot;'&amp;quot;&lt;br /&gt;
 wfl_string_subst := '[' wfl_formula ']'&lt;br /&gt;
 wfl_string_escape := &amp;quot;[']&amp;quot; | '[(]' | '[)]'&lt;br /&gt;
 wfl_container := '[' ('-&amp;gt;' | wfl_expression_list | wfl_key_value_list)? ']'&lt;br /&gt;
 wfl_expression_list := wfl_formula (',' wfl_formula)*&lt;br /&gt;
 wfl_key_value_list := wfl_formula '-&amp;gt;' wfl_formula (',' wfl_formula '-&amp;gt;' wfl_formula)*&lt;br /&gt;
 wfl_function_call := wfl_name '(' wfl_expression_list? ')'&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74902</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74902"/>
		<updated>2026-03-19T06:03:31Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* WML */ Rewrite in EBNF&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;----&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This page is currently undergoing reconstruction. Information on the page may become misleading or occasionally wrong for brief periods of time.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is regular-expression-like (which is not quite the same as regex-like!), with the following conventions:&lt;br /&gt;
&lt;br /&gt;
* Literal values are enclosed in either 'single quotes' or &amp;quot;double quotes&amp;quot;.&lt;br /&gt;
* Square brackets enclose character classes, with initial ^ inverting them&lt;br /&gt;
* Whitespace within an expression (unless quoted) is used only for readability or to separate non-terminals&lt;br /&gt;
* The meta-characters * + ? | have the same meaning as is typical in regular expressions&lt;br /&gt;
* The sequence «tab» represents a tab character, and «nl» represents an end-of-line character or character sequence&lt;br /&gt;
* Multiple definitions of a non-terminal are equivalent to alternation (ie, x:=4 and x:=7 combine to produce x:=4|7)&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
wml_doc = {wml_tag | wml_attribute} ;&lt;br /&gt;
wml_tag = '[' , ['+'] , wml_name , ']' , wml_doc , '[/' , wml_name , ']' ;&lt;br /&gt;
wml_name = wml_id_char , {wml_id_char} ;&lt;br /&gt;
wml_attribute = [textdomain] , wml_key_sequence , '=' , wml_value , ?newline? ;&lt;br /&gt;
wml_key_sequence = wml_name , {',' , wml_name} ;&lt;br /&gt;
wml_value = wml_value_component , {'+' , [?newline? , [textdomain]] , wml_value_component} ;&lt;br /&gt;
wml_value_component = text | ['_'] , (string | raw_string) ;&lt;br /&gt;
text = {char - '+' | '&amp;quot;' | ?newline?} ;&lt;br /&gt;
string = '&amp;quot;' . {char - '&amp;quot;' | '&amp;quot;&amp;quot;'} , '&amp;quot;' ;&lt;br /&gt;
raw_string = '&amp;lt;&amp;lt;' , {char - '&amp;gt;' | '&amp;gt;' , char - '&amp;gt;'} , '&amp;gt;&amp;gt;' ;&lt;br /&gt;
textdomain = '#textdomain' domain_char , {domain_char} , ?newline? ;&lt;br /&gt;
wml_id_char = lowercase | uppercase | digit | '_' ;&lt;br /&gt;
lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm'&lt;br /&gt;
          | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' ;&lt;br /&gt;
uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'&lt;br /&gt;
          | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
domain_char = wml_id_char | '-' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
 wml_substitution := wml_var | wml_formula | '$|'&lt;br /&gt;
 wml_var := '$' wml_var_path (wml_var_default | '|')?&lt;br /&gt;
 wml_var_path := (wml_var_name wml_var_index? '.')* wml_var_name&lt;br /&gt;
 wml_var_name := [a-zA-Z0-9_]+&lt;br /&gt;
 wml_var_index := '[' [0-9]+ ']'&lt;br /&gt;
 wml_var_default := '?' [^|]+ '|'&lt;br /&gt;
 wml_formula := '$' '(' wfl_document ')'&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
 wfl_comment := '#' [^#]* '#'&lt;br /&gt;
 wfl_file_run := 'wfl' wfl_string «any token»* 'wflend'&lt;br /&gt;
 wfl_document := wfl_function_definition* wfl_formula&lt;br /&gt;
 wfl_function_definition := 'def' wfl_name '(' wfl_function_args ')' wfl_formula ';'&lt;br /&gt;
 wfl_function_args := (wfl_function_arg (',' wfl_function_arg)*)?&lt;br /&gt;
 wfl_function_arg := wfl_name '*'?&lt;br /&gt;
 wfl_formula := 'not'? where_expression&lt;br /&gt;
 wfl_formula := bracketed_expression&lt;br /&gt;
 bracketed_expression := '(' wfl_formula ')'&lt;br /&gt;
 where_expression := (boolean_or_expression | bracketed_expression) ('where' wfl_variables)*&lt;br /&gt;
 wfl_variables := wfl_variable (',' wfl_variable)*&lt;br /&gt;
 wfl_variable := wfl_name '=' wfl_formula&lt;br /&gt;
 boolean_or_expression := (boolean_and_expression | bracketed_expression) ('or' wfl_formula)*&lt;br /&gt;
 boolean_and_expression := (comparison_expression | bracketed_expression) ('and' wfl_formula)*&lt;br /&gt;
 comparison_expression := (containment_expression | bracketed_expression) (comparison_op wfl_formula)*&lt;br /&gt;
 comparison_op := '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;='&lt;br /&gt;
 containment_expression := (range_expression | bracketed_expression) ('in' wfl_formula)*&lt;br /&gt;
 range_expression := (additive_expression | bracketed_expression) ('~' wfl_formula)*&lt;br /&gt;
 additive_expression := negation_opt? (multiplicative_expression | bracketed_expression) (additive_op wfl_formula)*&lt;br /&gt;
 negation_op := '-' | '+'&lt;br /&gt;
 additive_op := '-' | '+' | '..'&lt;br /&gt;
 multiplicative_expression := (exponent_expression | bracketed_expression) (multiplicative_op wfl_formula)*&lt;br /&gt;
 muliplicative_op := '*' | '/' | '%'&lt;br /&gt;
 exponent_expression := (wfl_formula '^')* (dice_expression | bracketed_expression)&lt;br /&gt;
 dice_expression := (dot_expression | bracketed_expression) ('d' wfl_formula)*&lt;br /&gt;
 dot_expression := (wfl_value | bracketed_expression) ('.' wfl_formula)*&lt;br /&gt;
 wfl_value := 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call&lt;br /&gt;
 wfl_name := [a-zA-Z_]+&lt;br /&gt;
 wfl_number := [0-9]+ ('.' [0-9]+)?&lt;br /&gt;
 wfl_string := &amp;quot;'&amp;quot; ([^'[]+ | wfl_string_subst | wfl_string_escape)* &amp;quot;'&amp;quot;&lt;br /&gt;
 wfl_string_subst := '[' wfl_formula ']'&lt;br /&gt;
 wfl_string_escape := &amp;quot;[']&amp;quot; | '[(]' | '[)]'&lt;br /&gt;
 wfl_container := '[' ('-&amp;gt;' | wfl_expression_list | wfl_key_value_list)? ']'&lt;br /&gt;
 wfl_expression_list := wfl_formula (',' wfl_formula)*&lt;br /&gt;
 wfl_key_value_list := wfl_formula '-&amp;gt;' wfl_formula (',' wfl_formula '-&amp;gt;' wfl_formula)*&lt;br /&gt;
 wfl_function_call := wfl_name '(' wfl_expression_list? ')'&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74901</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74901"/>
		<updated>2026-03-19T05:49:48Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* WML Preprocessor */ Rewrite in EBNF&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;----&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This page is currently undergoing reconstruction. Information on the page may become misleading or occasionally wrong for brief periods of time.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is regular-expression-like (which is not quite the same as regex-like!), with the following conventions:&lt;br /&gt;
&lt;br /&gt;
* Literal values are enclosed in either 'single quotes' or &amp;quot;double quotes&amp;quot;.&lt;br /&gt;
* Square brackets enclose character classes, with initial ^ inverting them&lt;br /&gt;
* Whitespace within an expression (unless quoted) is used only for readability or to separate non-terminals&lt;br /&gt;
* The meta-characters * + ? | have the same meaning as is typical in regular expressions&lt;br /&gt;
* The sequence «tab» represents a tab character, and «nl» represents an end-of-line character or character sequence&lt;br /&gt;
* Multiple definitions of a non-terminal are equivalent to alternation (ie, x:=4 and x:=7 combine to produce x:=4|7)&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=ebnf&amp;gt;&lt;br /&gt;
preproc_doc = {preproc_directive | preproc_line} ;&lt;br /&gt;
preproc_directive = simple_directive | macro_definition | if_block ;&lt;br /&gt;
preproc_line = {preproc_text} , ['&amp;lt;'] , [comment] , ?newline? ;&lt;br /&gt;
preproc_text = preproc_char | '&amp;lt;' , preproc_char | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;' | macro_inclusion ;&lt;br /&gt;
preproc_char = char - ('&amp;lt;' | '{' | '#' | ?newline?) ;&lt;br /&gt;
macro_free_text = {macro_free_char | '&amp;gt;' , macro_free_char} ;&lt;br /&gt;
macro_free_char = char - '&amp;gt;' ; (* Note: this can include newlines! *)&lt;br /&gt;
macro_inclusion = '{' , macro_name , {req_ws , macro_argument} , '}' ;&lt;br /&gt;
macro_name = macro_name_char , {macro_name_char}&lt;br /&gt;
macro_name_char = char - ('}' | ws) ;&lt;br /&gt;
macro_argument = macro_component , {macro_component}&lt;br /&gt;
macro_component = macro_name&lt;br /&gt;
                | macro_inclusion&lt;br /&gt;
                | '(' , [preproc_doc] , ')'&lt;br /&gt;
                | ['_'] , opt_ws , '&amp;quot;' , {quoted_char | macro_inclusion} , '&amp;quot;'&lt;br /&gt;
                | '&amp;lt;&amp;lt;' , macro_free_text , '&amp;gt;&amp;gt;'&lt;br /&gt;
                ;&lt;br /&gt;
quoted_char = char - ( '}' | '&amp;quot;' ) | '&amp;quot;&amp;quot;' ;&lt;br /&gt;
comment = opt_ws , '#' , {comment_char} , ?newline? ;&lt;br /&gt;
comment_char = char - ?newline? ;&lt;br /&gt;
ws = ?space? | ?tab?&lt;br /&gt;
opt_ws = {ws}&lt;br /&gt;
req_ws = ws , {ws}&lt;br /&gt;
simple_directive = '#undef' , req_ws , macro_name , opt_ws , ?newline?&lt;br /&gt;
                 | ('#warning' | '#error') req_ws , {comment_char} , ?newline? ;&lt;br /&gt;
macro_definition = '#define' , req_ws , macro_name , {req_ws macro_name} , ?newline? , {opt_arg_definition} , {macro_content} , '#enddef' , ?newline? ;&lt;br /&gt;
macro_content = simple_directive | if_block | preproc_line ;&lt;br /&gt;
opt_arg_definition = '#arg' , req_ws , macro_name , ?newline? , {macro_content} , '#endarg' , ?newline? ;&lt;br /&gt;
if_block = (ifdef_header | ifver_header | ifhave_header) , ?newline? , preproc_doc ['#else' , ?newline? , preproc_doc] '#endif' , ?newline? ;&lt;br /&gt;
ifdef_header = ('#ifdef' | '#ifndef') , req_ws , macro_name ;&lt;br /&gt;
ifver_header = ('#ifver' | '#ifnver') , req_ws , macro_name , opt_ws , comparison_op , opt_ws , version_string ;&lt;br /&gt;
ifhave_header = ('#ifhave' | '#ifnhave') , req_ws , comment_char ;&lt;br /&gt;
comparison_op = '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;' ;&lt;br /&gt;
version_string = integer , ['.' , integer] ;&lt;br /&gt;
integer = digit , {digit} ;&lt;br /&gt;
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;&lt;br /&gt;
char = ?any unicode character? ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
 wml_doc := (wml_tag | wml_attribute)*&lt;br /&gt;
 wml_tag := '[' '+'? wml_name ']' wml_doc '[/' wml_name ']'&lt;br /&gt;
 wml_name := [a-zA-Z0-9_]+&lt;br /&gt;
 wml_attribute := textdomain? wml_key_sequence '=' wml_value «nl»&lt;br /&gt;
 wml_key_sequence := wml_name (',' wml_name)*&lt;br /&gt;
 wml_value := wml_value_component ('+' («nl» textdomain?)? wml_value_component)*&lt;br /&gt;
 wml_value_component := text | '_'? string | '_'? raw_string&lt;br /&gt;
 &lt;br /&gt;
 text := [^+«nl»&amp;quot;]*&lt;br /&gt;
 string := '&amp;quot;' ([^&amp;quot;] | '&amp;quot;&amp;quot;')* '&amp;quot;'&lt;br /&gt;
 raw_string := '&amp;lt;&amp;lt;' ([^&amp;gt;] | &amp;gt;[^&amp;gt;])* '&amp;gt;&amp;gt;'&lt;br /&gt;
 textdomain := '#textdomain' [a-zA-Z0-9_-]+ «nl»&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
 wml_substitution := wml_var | wml_formula | '$|'&lt;br /&gt;
 wml_var := '$' wml_var_path (wml_var_default | '|')?&lt;br /&gt;
 wml_var_path := (wml_var_name wml_var_index? '.')* wml_var_name&lt;br /&gt;
 wml_var_name := [a-zA-Z0-9_]+&lt;br /&gt;
 wml_var_index := '[' [0-9]+ ']'&lt;br /&gt;
 wml_var_default := '?' [^|]+ '|'&lt;br /&gt;
 wml_formula := '$' '(' wfl_document ')'&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
 wfl_comment := '#' [^#]* '#'&lt;br /&gt;
 wfl_file_run := 'wfl' wfl_string «any token»* 'wflend'&lt;br /&gt;
 wfl_document := wfl_function_definition* wfl_formula&lt;br /&gt;
 wfl_function_definition := 'def' wfl_name '(' wfl_function_args ')' wfl_formula ';'&lt;br /&gt;
 wfl_function_args := (wfl_function_arg (',' wfl_function_arg)*)?&lt;br /&gt;
 wfl_function_arg := wfl_name '*'?&lt;br /&gt;
 wfl_formula := 'not'? where_expression&lt;br /&gt;
 wfl_formula := bracketed_expression&lt;br /&gt;
 bracketed_expression := '(' wfl_formula ')'&lt;br /&gt;
 where_expression := (boolean_or_expression | bracketed_expression) ('where' wfl_variables)*&lt;br /&gt;
 wfl_variables := wfl_variable (',' wfl_variable)*&lt;br /&gt;
 wfl_variable := wfl_name '=' wfl_formula&lt;br /&gt;
 boolean_or_expression := (boolean_and_expression | bracketed_expression) ('or' wfl_formula)*&lt;br /&gt;
 boolean_and_expression := (comparison_expression | bracketed_expression) ('and' wfl_formula)*&lt;br /&gt;
 comparison_expression := (containment_expression | bracketed_expression) (comparison_op wfl_formula)*&lt;br /&gt;
 comparison_op := '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;='&lt;br /&gt;
 containment_expression := (range_expression | bracketed_expression) ('in' wfl_formula)*&lt;br /&gt;
 range_expression := (additive_expression | bracketed_expression) ('~' wfl_formula)*&lt;br /&gt;
 additive_expression := negation_opt? (multiplicative_expression | bracketed_expression) (additive_op wfl_formula)*&lt;br /&gt;
 negation_op := '-' | '+'&lt;br /&gt;
 additive_op := '-' | '+' | '..'&lt;br /&gt;
 multiplicative_expression := (exponent_expression | bracketed_expression) (multiplicative_op wfl_formula)*&lt;br /&gt;
 muliplicative_op := '*' | '/' | '%'&lt;br /&gt;
 exponent_expression := (wfl_formula '^')* (dice_expression | bracketed_expression)&lt;br /&gt;
 dice_expression := (dot_expression | bracketed_expression) ('d' wfl_formula)*&lt;br /&gt;
 dot_expression := (wfl_value | bracketed_expression) ('.' wfl_formula)*&lt;br /&gt;
 wfl_value := 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call&lt;br /&gt;
 wfl_name := [a-zA-Z_]+&lt;br /&gt;
 wfl_number := [0-9]+ ('.' [0-9]+)?&lt;br /&gt;
 wfl_string := &amp;quot;'&amp;quot; ([^'[]+ | wfl_string_subst | wfl_string_escape)* &amp;quot;'&amp;quot;&lt;br /&gt;
 wfl_string_subst := '[' wfl_formula ']'&lt;br /&gt;
 wfl_string_escape := &amp;quot;[']&amp;quot; | '[(]' | '[)]'&lt;br /&gt;
 wfl_container := '[' ('-&amp;gt;' | wfl_expression_list | wfl_key_value_list)? ']'&lt;br /&gt;
 wfl_expression_list := wfl_formula (',' wfl_formula)*&lt;br /&gt;
 wfl_key_value_list := wfl_formula '-&amp;gt;' wfl_formula (',' wfl_formula '-&amp;gt;' wfl_formula)*&lt;br /&gt;
 wfl_function_call := wfl_name '(' wfl_expression_list? ')'&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74900</id>
		<title>GrammarWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=GrammarWML&amp;diff=74900"/>
		<updated>2026-03-19T04:37:18Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Add an &amp;quot;under construction&amp;quot; notice&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;----&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This page is currently undergoing reconstruction. Information on the page may become misleading or occasionally wrong for brief periods of time.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{WML Tags}}&lt;br /&gt;
This page contains a formal grammar of the Wesnoth domain-specific languages, including WML and its preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is regular-expression-like (which is not quite the same as regex-like!), with the following conventions:&lt;br /&gt;
&lt;br /&gt;
* Literal values are enclosed in either 'single quotes' or &amp;quot;double quotes&amp;quot;.&lt;br /&gt;
* Square brackets enclose character classes, with initial ^ inverting them&lt;br /&gt;
* Whitespace within an expression (unless quoted) is used only for readability or to separate non-terminals&lt;br /&gt;
* The meta-characters * + ? | have the same meaning as is typical in regular expressions&lt;br /&gt;
* The sequence «tab» represents a tab character, and «nl» represents an end-of-line character or character sequence&lt;br /&gt;
* Multiple definitions of a non-terminal are equivalent to alternation (ie, x:=4 and x:=7 combine to produce x:=4|7)&lt;br /&gt;
&lt;br /&gt;
== WML Preprocessor ==&lt;br /&gt;
&lt;br /&gt;
The WML preprocessor knows little of the grammar of the WML language itself; it is primarily just a text-substitution engine. Currently this is just a draft and may not be entirely accurate.&lt;br /&gt;
&lt;br /&gt;
 preproc_doc := (preproc_directive | preproc_line)*&lt;br /&gt;
 preproc_directive := simple_directive | macro_definition | if_block&lt;br /&gt;
 preproc_line := (preproc_text | '&amp;lt;&amp;lt;' macro_free_text '&amp;gt;&amp;gt;' | macro_inclusion)* comment? «nl»&lt;br /&gt;
 preproc_text := (preproc_char | '&amp;lt;' preproc_char)* '&amp;lt;'?&lt;br /&gt;
 preproc_char := [^&amp;lt;{#«nl»]&lt;br /&gt;
 macro_free_text := (macro_free_char | '&amp;gt;' macro_free_char)*&lt;br /&gt;
 macro_free_char := [^&amp;gt;]&lt;br /&gt;
 macro_inclusion := '{' ([^}]+ | macro_function) '}'&lt;br /&gt;
 macro_function := macro_name_char+ (macro_argument)*&lt;br /&gt;
 macro_name_char := [^} «tab»]&lt;br /&gt;
 macro_argument := (macro_name_char | macro_inclusion)+&lt;br /&gt;
 macro_argument := '(' preproc_doc? ')' | '_'? '&amp;quot;' ([^}&amp;quot;]&lt;br /&gt;
 macro_argument := ('&amp;quot;&amp;quot;' | macro_inclusion)* '&amp;quot;'&lt;br /&gt;
 macro_argument := '&amp;lt;&amp;lt;' macro_free_text '&amp;gt;&amp;gt;'&lt;br /&gt;
 comment := '#' [^«nl»]+ «nl»&lt;br /&gt;
 ws := ' ' | «tab»&lt;br /&gt;
 simple_directive := '#undef' ws+ macro_name_char+ ws* «nl»&lt;br /&gt;
 simple_directive := ('#warning' | '#error') ws+ [^«nl»]* «nl»&lt;br /&gt;
 macro_definition := '#define' ws+ macro_name_char+ (ws+ macro_name_char+)* «nl» (opt_arg_definition)* (simple_directive | if_block | preproc_line)+ '#enddef' «nl»&lt;br /&gt;
 opt_arg_definition := '#arg' ws+ macro_name_char+ «nl» (simple_directive | if_block | preproc_line)+ '#endarg' «nl»&lt;br /&gt;
 if_block := (ifdef_header | ifver_header | ifhave_header) «nl» preproc_doc ('#else' «nl» preproc_doc)? '#endif' «nl»&lt;br /&gt;
 ifdef_header := ('#ifdef' | '#ifndef') ws+ macro_name_char+&lt;br /&gt;
 ifver_header := ('#ifver' | '#ifnver') ws+ macro_name_char+ ws* comparison_op ws* version_string&lt;br /&gt;
 ifhave_header := ('#ifhave' | '#ifnhave') ws+ [^«nl»]+&lt;br /&gt;
 comparison_op := '&amp;lt;' | '&amp;lt;=' | '==' | '!=' | '&amp;gt;=' | '&amp;gt;'&lt;br /&gt;
 version_string := integer ('.' integer)*&lt;br /&gt;
 integer := [0-9]+&lt;br /&gt;
&lt;br /&gt;
== WML ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes WML '''after''' the preprocessor is finished with it, and as such does not account for macros, preprocessor directives, or comments. It also assumes tokenization has already occurred and thus does not specify whitespace, except for newlines. Note that it omits the requirement for opening and closing tags to match.&lt;br /&gt;
&lt;br /&gt;
 wml_doc := (wml_tag | wml_attribute)*&lt;br /&gt;
 wml_tag := '[' '+'? wml_name ']' wml_doc '[/' wml_name ']'&lt;br /&gt;
 wml_name := [a-zA-Z0-9_]+&lt;br /&gt;
 wml_attribute := textdomain? wml_key_sequence '=' wml_value «nl»&lt;br /&gt;
 wml_key_sequence := wml_name (',' wml_name)*&lt;br /&gt;
 wml_value := wml_value_component ('+' («nl» textdomain?)? wml_value_component)*&lt;br /&gt;
 wml_value_component := text | '_'? string | '_'? raw_string&lt;br /&gt;
 &lt;br /&gt;
 text := [^+«nl»&amp;quot;]*&lt;br /&gt;
 string := '&amp;quot;' ([^&amp;quot;] | '&amp;quot;&amp;quot;')* '&amp;quot;'&lt;br /&gt;
 raw_string := '&amp;lt;&amp;lt;' ([^&amp;gt;] | &amp;gt;[^&amp;gt;])* '&amp;gt;&amp;gt;'&lt;br /&gt;
 textdomain := '#textdomain' [a-zA-Z0-9_-]+ «nl»&lt;br /&gt;
&lt;br /&gt;
== WML Substitutions ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of WML substitutions, the syntax used to specify that variables should be substituted into the value of a WML attribute. The grammar here describes a single placeholder, without regard to the fact that they can be nested. Thus, parsing a string using this grammar would only succeed if done from right to left ''while'' performing the substitutions.&lt;br /&gt;
&lt;br /&gt;
 wml_substitution := wml_var | wml_formula | '$|'&lt;br /&gt;
 wml_var := '$' wml_var_path (wml_var_default | '|')?&lt;br /&gt;
 wml_var_path := (wml_var_name wml_var_index? '.')* wml_var_name&lt;br /&gt;
 wml_var_name := [a-zA-Z0-9_]+&lt;br /&gt;
 wml_var_index := '[' [0-9]+ ']'&lt;br /&gt;
 wml_var_default := '?' [^|]+ '|'&lt;br /&gt;
 wml_formula := '$' '(' wfl_document ')'&lt;br /&gt;
&lt;br /&gt;
== Wesnoth Formula Language ==&lt;br /&gt;
&lt;br /&gt;
This grammar describes the syntax of the [[Wesnoth Formula Language]]. Though it specifies the format of comments and file markers, they are not integrated into the main grammar since it treats the equivalently to whitespace. The grammar may not be completely accurate to the actual in-game parser.&lt;br /&gt;
&lt;br /&gt;
 wfl_comment := '#' [^#]* '#'&lt;br /&gt;
 wfl_file_run := 'wfl' wfl_string «any token»* 'wflend'&lt;br /&gt;
 wfl_document := wfl_function_definition* wfl_formula&lt;br /&gt;
 wfl_function_definition := 'def' wfl_name '(' wfl_function_args ')' wfl_formula ';'&lt;br /&gt;
 wfl_function_args := (wfl_function_arg (',' wfl_function_arg)*)?&lt;br /&gt;
 wfl_function_arg := wfl_name '*'?&lt;br /&gt;
 wfl_formula := 'not'? where_expression&lt;br /&gt;
 wfl_formula := bracketed_expression&lt;br /&gt;
 bracketed_expression := '(' wfl_formula ')'&lt;br /&gt;
 where_expression := (boolean_or_expression | bracketed_expression) ('where' wfl_variables)*&lt;br /&gt;
 wfl_variables := wfl_variable (',' wfl_variable)*&lt;br /&gt;
 wfl_variable := wfl_name '=' wfl_formula&lt;br /&gt;
 boolean_or_expression := (boolean_and_expression | bracketed_expression) ('or' wfl_formula)*&lt;br /&gt;
 boolean_and_expression := (comparison_expression | bracketed_expression) ('and' wfl_formula)*&lt;br /&gt;
 comparison_expression := (containment_expression | bracketed_expression) (comparison_op wfl_formula)*&lt;br /&gt;
 comparison_op := '=' | '!=' | '&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;='&lt;br /&gt;
 containment_expression := (range_expression | bracketed_expression) ('in' wfl_formula)*&lt;br /&gt;
 range_expression := (additive_expression | bracketed_expression) ('~' wfl_formula)*&lt;br /&gt;
 additive_expression := negation_opt? (multiplicative_expression | bracketed_expression) (additive_op wfl_formula)*&lt;br /&gt;
 negation_op := '-' | '+'&lt;br /&gt;
 additive_op := '-' | '+' | '..'&lt;br /&gt;
 multiplicative_expression := (exponent_expression | bracketed_expression) (multiplicative_op wfl_formula)*&lt;br /&gt;
 muliplicative_op := '*' | '/' | '%'&lt;br /&gt;
 exponent_expression := (wfl_formula '^')* (dice_expression | bracketed_expression)&lt;br /&gt;
 dice_expression := (dot_expression | bracketed_expression) ('d' wfl_formula)*&lt;br /&gt;
 dot_expression := (wfl_value | bracketed_expression) ('.' wfl_formula)*&lt;br /&gt;
 wfl_value := 'functions' | wfl_name | wfl_number | wfl_string | wfl_container | wfl_function_call&lt;br /&gt;
 wfl_name := [a-zA-Z_]+&lt;br /&gt;
 wfl_number := [0-9]+ ('.' [0-9]+)?&lt;br /&gt;
 wfl_string := &amp;quot;'&amp;quot; ([^'[]+ | wfl_string_subst | wfl_string_escape)* &amp;quot;'&amp;quot;&lt;br /&gt;
 wfl_string_subst := '[' wfl_formula ']'&lt;br /&gt;
 wfl_string_escape := &amp;quot;[']&amp;quot; | '[(]' | '[)]'&lt;br /&gt;
 wfl_container := '[' ('-&amp;gt;' | wfl_expression_list | wfl_key_value_list)? ']'&lt;br /&gt;
 wfl_expression_list := wfl_formula (',' wfl_formula)*&lt;br /&gt;
 wfl_key_value_list := wfl_formula '-&amp;gt;' wfl_formula (',' wfl_formula '-&amp;gt;' wfl_formula)*&lt;br /&gt;
 wfl_function_call := wfl_name '(' wfl_expression_list? ')'&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Download/zh-Hans&amp;diff=74884</id>
		<title>Download/zh-Hans</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Download/zh-Hans&amp;diff=74884"/>
		<updated>2026-03-02T13:00:54Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Update version numbers and delete some obsolete information (references to MacCompileStuff, Download_Xdeltas, Eclipse plugin) -- I'm not sure how accurate the rest of this info is, but I doubt the core of this page changes THAT drastically over time&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Translations}}&lt;br /&gt;
欢迎来到韦诺之战下载页。韦诺之战项目团队官方发布源代码及适用于Windows、OS X、OpenPandora和多种Linux发行版的二进制构建版本。BT种子是非官方的。&lt;br /&gt;
&lt;br /&gt;
如果适用于您的操作系统的最新的二进制可执行文件尚未提供，请过几天再来此处查看是否已提供。打包者们已被告知本次发布的相关情况，请保持耐心。在此期间，请阅读[[FAQ#A_new_version_is_out.2C_but_where_is_the_download_for_.5BWindows.2C_Mac_OS.2C_etc..5D.3F|常见问题]]。&lt;br /&gt;
&lt;br /&gt;
韦诺之战也在[http://brew.sh/ Homebrew]以及[http://www.macports.org/ Macports]上提供。Macports上只有稳定版本。Homebrew 上有稳定发布版，开发发布版，同时也会构建最“前沿”的主开发分支。&lt;br /&gt;
__NOTOC__&lt;br /&gt;
== 稳定版 （1.18 分支） ==&lt;br /&gt;
稳定版是希望作为稳定且平衡的游戏版本来使用。1.19分支的每一个版本都相互兼容。&lt;br /&gt;
&lt;br /&gt;
版本1.18.6是最新的稳定版。这个版本推荐给绝大多数玩家，因为1.18在线多人游戏社区很庞大，而且用户自制战役服务器上也有很好的内容可供选择。&lt;br /&gt;
&lt;br /&gt;
==== 源代码 ====&lt;br /&gt;
* [[CompilingWesnoth|编译指导]] - 如何编译源代码&lt;br /&gt;
{{StableDownload|当前版本|先前版本|当前源代码包的md5sum值|微软视窗操作系统|麦金塔操作系统}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* 有许多二进制文件对应于不同的Linux发行版。不是所有的文件都已及时更新到最新版。请查阅[[WesnothBinariesLinux|Linux二进制文件页]]寻找对应于你的发行版的二进制包信息。&lt;br /&gt;
&lt;br /&gt;
==== 杂项 ====&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ 当前和所有先前版本的SourceForge页]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== 开发版（1.19分支） ==&lt;br /&gt;
版本1.19.x 是最新的开发版，拥有升级的图像和令人兴奋的新特性。然而，在开发版里可能有偶尔的错误或性能问题，因为总是有着很多大的修改。为了平衡和稳定地游戏，强烈推荐你使用1.18.x分支的最新版。开发版是推荐给程序员和战役开发者，也给那些想要预览韦诺新特性的人。熟悉SVN和编译的人可以从[[WesnothRepository]]中检出最新的开发版。&lt;br /&gt;
&lt;br /&gt;
==== Source code 源代码 ====&lt;br /&gt;
* [[CompilingWesnoth|编译指导]] - 如何编译源代码&lt;br /&gt;
{{DevDownload|当前版本|先前版本|当前源代码包的md5sum值|微软视窗操作系统|麦金塔操作系统}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* 有许多二进制文件对应于不同的Linux发行版。不是所有的都已及时更新到最新版。请查阅[[WesnothBinariesLinux|Linux二进制包页]]寻找对应于你的发行版的二进制包信息。&lt;br /&gt;
&lt;br /&gt;
==== 杂项 ====&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ 当前和所有先前版本的SourceForge页]&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 许可 ==&lt;br /&gt;
'''主要文章：[[Wesnoth:Copyrights|版权声明]]&lt;br /&gt;
&lt;br /&gt;
本程序为自由软件；您可依据[http://www.fsf.org Free Software Foundation|自由软件基金会]所发表的[http://www.fsf.org/copyleft/gpl.html GNU General Public License version 2|GNU通用公共许可证第2版]条款规定，就本程序再为发布与／或修改。&lt;br /&gt;
本程序是基于使用目的而加以发布，然而不负任何担保责任；亦无对适售性或特定目的适用性所为的默示性担保。详情请参照GNU通用公共授权。&lt;br /&gt;
&lt;br /&gt;
== 参见 ==&lt;br /&gt;
* [http://changelog.wesnoth.org 更新日志]&lt;br /&gt;
* [[WesnothRepository]] - 版本库中最前沿的版本&lt;br /&gt;
&lt;br /&gt;
[[Category:Building and Installing]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Download/ukr&amp;diff=74883</id>
		<title>Download/ukr</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Download/ukr&amp;diff=74883"/>
		<updated>2026-03-02T12:59:28Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Update version numbers and delete some obsolete information (references to MacCompileStuff, Download_Xdeltas, Eclipse plugin) -- I'm not sure how accurate the rest of this info is, but I doubt the core of this page changes THAT drastically over time&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Translations}}&lt;br /&gt;
Ласкаво просимо на сторінку завантаження «Битви за Веснот». Команда проекту BfW офіційно постачає джерельний код та бінарні пакети для Windows, OS X, OpenPandora, та різних дистрибутивів Linux. Торренти є неофіційними.&lt;br /&gt;
&lt;br /&gt;
Якщо виконувані файли останньої версії гри для вашої ОС ще не доступні, то, можливо, вони з'являться на цій сторінці через деякий час. Спробуйте перевірити через кілька днів. Люди, що займаються зборкою, знають про реліз, тому, будь ласка, запасіться терпінням. Тим часом, можете прочитати [[FAQ#A_new_version_is_out.2C_but_where_is_the_download_for_.5BWindows.2C_Mac_OS.2C_etc..5D.3F|FAQ]].&lt;br /&gt;
&lt;br /&gt;
Wesnoth також доступний для OS X від [http://brew.sh/ Homebrew] і [http://www.macports.org/ MacPorts]. В MacPorts є тільки стабільна версія. В Homebrew є стабільний та розробницький релізи.&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
Перейти до: [[Download/ua#Стабільні_версії_.28гілка_1.10.29|Стабільна гілка]] | [[Download/ua#Розробка_.28гілка_1.11.29|Гілка розробки]]&lt;br /&gt;
&lt;br /&gt;
== Стабільні версії (гілка 1.18) ==&lt;br /&gt;
Стабільні файли пропонується використовувати в тому випадку, якщо потрібна стабільна і одночасно збалансована версія гри. Всі версії гілки 1.18 сумісні одина з одною.&lt;br /&gt;
&lt;br /&gt;
Версія 1.10.7 на даний момент є попередньою стабільною версією. Ця версія рекомендується для більшості гравців, оскільки в багатокористувацькій грі співтовариство 1.10 дуже велике і створений користувачами сервер кампаній пропонує багатий вибір контенту.&lt;br /&gt;
&lt;br /&gt;
==== Джерельний код ====&lt;br /&gt;
* [[CompilingWesnoth|Керівництво з компіляції]] - як зкомпілювати джерельний код.&lt;br /&gt;
{{StableDownload|Поточна версія|Попередня версія|md5sum джерельних кодів поточної версії}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Існують пакети для безлічі різних дистрибутивів GNU / Linux. Не всі з них оновлюються з виходом нового релізу гри. Будь ласка, ознайомтеся з [[WesnothBinariesLinux|Сторінка збірок для Linux]] для того, щоб дізнатися більше про збірки для вашого дистрибутива.&lt;br /&gt;
&lt;br /&gt;
==== Додатково ====&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ Сторінка на SourceForge дпоточної та всіх попередніх версій]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Розробка (гілка 1.11) ==&lt;br /&gt;
1.11.x - це нова версія, що розробляється в даний момент, яка може похвалитися вдосконаленою графікою і новими хвилюючими можливостями. Однак, у версіях розробки можуть бути баги або проблеми продуктивності через великі зміни, що постійно вносяться в код. Для збалансованої та стабільної гри рекомендується використовувати найбільш свіжу версію гілки 1.18.x. Ця версія рекомендується як для кодерів і розробників кампаній, так і для тих, хто хоче побачити, що чекає Веснот в майбутньому. Люди, знайомі з системою контролю версій і компіляцією, можуть стежити за розробкою тут: [[WesnothRepository]].&lt;br /&gt;
&lt;br /&gt;
==== Джерельний код ====&lt;br /&gt;
* [[CompilingWesnoth| Керівництво з компіляції]] - як зкомпілювати джерельний код.&lt;br /&gt;
{{DevDownload|Поточна версія|Попередня версія|md5sum джерельних кодів поточної версії}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Існують пакети для безлічі різних дистрибутивів GNU / Linux. Не всі з них оновлюються з виходом нового релізу гри. Будь ласка, ознайомтеся з [[WesnothBinariesLinux|Сторінка збірок для Linux]] для того, щоб дізнатися більше про збірки для вашого дистрибутива.&lt;br /&gt;
&lt;br /&gt;
==== Додатково ====&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ Сторінка на SourceForge для поточної та всіх попередніх версій]&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
== Ліцензія ==&lt;br /&gt;
''Головна стаття: [[Wesnoth:Copyrights]]&lt;br /&gt;
&lt;br /&gt;
Ця програма є вільним програмним забезпеченням; ви можете розповсюджувати та / або змінювати його відповідно до умов [http://www.fsf.org/copyleft/gpl.html GNU General Public License версії 2], опублікованій на сайті [http://www.fsf.org Free Software Foundation].&lt;br /&gt;
Ця програма поширюється в надії, що вона буде корисна, але без будь-якої гарантії; навіть без гарантій щодо товарного стану й придатності для конкретної мети. Дивіться GNU General Public License для більш докладної інформації.&lt;br /&gt;
&lt;br /&gt;
== Дивіться також ==&lt;br /&gt;
* [http://changelog.wesnoth.org Список змін]&lt;br /&gt;
* [[WesnothRepository]] - найновіша версія з репозиторію&lt;br /&gt;
&lt;br /&gt;
[[Category:Building and Installing]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Download/ru&amp;diff=74882</id>
		<title>Download/ru</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Download/ru&amp;diff=74882"/>
		<updated>2026-03-02T12:58:35Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Update version numbers and delete some obsolete information (references to MacCompileStuff, Download_Xdeltas, Eclipse plugin) -- I'm not sure how accurate the rest of this info is, but I doubt the core of this page changes THAT drastically over time&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Translations}}&lt;br /&gt;
Добро пожаловать на страницу загрузки «Битвы за Веснот». Команда проекта BFW официально поставляет только исходный код, бинарные пакеты же предоставлены добровольцами сообщества и размещаются на этой странице. Торренты тоже официально не поддерживаются.&lt;br /&gt;
&lt;br /&gt;
Если сборки последней версии игры для вашей ОС еще не доступны, то, возможно, они появятся на этой странице спустя какое-то время. Попробуйте проверить через несколько дней. Люди, занимающиеся сборкой, знают о релизе, поэтому, пожалуйста, запаситесь терпением. А тем временем можете прочесть  [[FAQ#A_new_version_is_out.2C_but_where_is_the_download_for_.5BWindows.2C_Mac_OS.2C_etc..5D.3F|FAQ]].&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== Стабильные версии (ветка 1.18) ==&lt;br /&gt;
Стабильные файлы предлагается использовать в том случае, если нужна стабильная и одновременно сбалансированная версия игры. Все версии ветки 1.18 совместимы друг с другом.&lt;br /&gt;
&lt;br /&gt;
Версия 1.18.1 на данный момент является последней стабильной версией. Эта версия рекомендуется для большинства игроков, поскольку в многопользовательской игре сообщество 1.18 очень большое и созданный пользователями сервер кампаний предлагает богатый выбор контента. &lt;br /&gt;
&lt;br /&gt;
==== Исходный код ====&lt;br /&gt;
* [[CompilingWesnoth|Гайд по компилированию]] - как откомпилировать исходный код&lt;br /&gt;
{{StableDownload|Текущая версия|Предыдущая версия|md5sum для исходников текущей версии}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Существуют пакеты для множества различных дистрибутивов GNU/Linux. Не все из них обновляются с выходом нового релиза игры. Пожалуйста, ознакомьтесь с [[WesnothBinariesLinux|Страница сборок для Linux]] для того, чтобы узнать больше информации о сборках для вашего дистрибутива.&lt;br /&gt;
&lt;br /&gt;
==== Дополнительно ====&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ Страница на SourceForge для текущей и всех предыдущих версий]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Разработка (ветка 1.13) ==&lt;br /&gt;
1.13.x - это новая, разрабатываемая в настоящий момент версия, которая может похвастаться усовершенствованной графикой и новыми волнующими возможностями. Однако в версиях разработки могут быть баги или проблемы производительности из-за крупных изменений, постоянно вводимых в код. Для сбалансированной и стабильной игры рекомендуется использовать наиболее свежую версию ветки 1.12.x. Эта версия рекомендуется как для кодеров и разработчиков кампаний, так и для тех, кто хочет увидеть, что ждет Веснот в будущем. Люди, знакомые с системой контроля версий и компилированием, могут следить за разработкой здесь: [[WesnothRepository]].&lt;br /&gt;
&lt;br /&gt;
==== Исходный код ====&lt;br /&gt;
* [[CompilingWesnoth|Гайд по компилированию]] - как откомпилировать исходный код&lt;br /&gt;
{{DevDownload|Текущая версия|Предыдущая версия|md5sum для исходников текущей версии}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Существуют пакеты для множества различных дистрибутивов GNU/Linux. Не все из них обновляются с выходом нового релиза игры. Пожалуйста, ознакомьтесь с [[WesnothBinariesLinux|Страница сборок для Linux]] для того, чтобы узнать больше информации о сборках для вашего дистрибутива.&lt;br /&gt;
&lt;br /&gt;
==== Дополнительно ====&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ Страница на SourceForge для текущей и всех предыдущих версий]&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
== Лицензия ==&lt;br /&gt;
''Main article: [[Wesnoth:Copyrights]]&lt;br /&gt;
&lt;br /&gt;
This program is free software; you can redistribute it and/or modify it under the terms of the [http://www.fsf.org/copyleft/gpl.html GNU General Public License version 2], as published by the [http://www.fsf.org Free Software Foundation].&lt;br /&gt;
This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU General Public License for more details.&lt;br /&gt;
&lt;br /&gt;
== Смотрите также ==&lt;br /&gt;
* [http://changelog.wesnoth.org Список изменений]&lt;br /&gt;
* [[WesnothRepository]] - новейшая версия из репозитория&lt;br /&gt;
&lt;br /&gt;
[[Category:Building and Installing]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Download/fr&amp;diff=74881</id>
		<title>Download/fr</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Download/fr&amp;diff=74881"/>
		<updated>2026-03-02T12:57:11Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Delete some obsolete information (references to MacCompileStuff, Download_Xdeltas, Eclipse plugin) -- I'm not sure how accurate the rest of this info is, but I doubt the core of this page changes THAT drastically over time&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Translations}}&lt;br /&gt;
''Traduction en cours''&lt;br /&gt;
&lt;br /&gt;
''Atention : la version anglaise de cette page est la plus fiable''&lt;br /&gt;
&lt;br /&gt;
Bienvenue sur la page de téléchargement de ''La bataille pour Wesnoth''. L'équipe du projet publie officiellement le code source et les paquets binaires pour Windows, macOs, et différentes distributions GNU/Linux. &lt;br /&gt;
&lt;br /&gt;
Si les derniers binaire ne sont pas disponible pour votre système d'exploitation, vous pouvez venir vérifier dans quelques jours si ce n'est toujours pas le cas. Les mainteneurs des paquets sont au courant des sorties, merci d'être patient. En attendant, vous pouvez lire la [[FAQ#A_new_version_is_out.2C_but_where_is_the_download_for_.5BWindows.2C_Mac_OS_X.2C_etc..5D.3F|FAQ (en)]].&lt;br /&gt;
&lt;br /&gt;
La bataille pour Wesnoth est également disponible pour OS X chez [http://brew.sh/ Homebrew] et [http://www.macports.org/ Macports]. Chez Macports, il n'y a que la version stable. Chez Homebrew vous pouvez trouver la branche stable et celle de développement, vous pouvez aussi compiler la branche principale &amp;quot;bleeding edge&amp;quot;  depuis le [[WesnothRepository|dépôt Git(en)]].&lt;br /&gt;
__NOTOC__&lt;br /&gt;
== Branche Stable  ==&lt;br /&gt;
Cette version est conseillée à la plupart des joueurs puisqu'elle offre une expérience de jeu la plus testée et équilibrée, et n'a que peu de mises à jour de  correction de bugs. Chaque version de la branche stable sont compatibles entres elles. La communauté de joueurs en ligne est aussi la plus importante et le serveur d'extensions dispose d'un vaste choix de jeux suplémentaires.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Code source ====&lt;br /&gt;
* [[CompilingWesnoth|Compiling Guide]] - Comment compiler le code source en anglais.&lt;br /&gt;
{{StableDownload}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
*Il existe des paquets binaires pour plusieurs distributions différentes. Il ne sont pas toujours à jour avec les versions en vigueur. Vous pouvez lire la page [[WesnothBinariesLinux|Linux binary page]] pour plus d'information sur les paquets correspondant à votre distribution.&lt;br /&gt;
&lt;br /&gt;
==== Divers ====&lt;br /&gt;
* [[Download_Xdeltas#Stable_Version_1.14.x|Xdelta for the source code]]&lt;br /&gt;
* [https://sourceforge.net/projects/wesnoth/files/ SourceForge page for current and all previous versions]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
==  Branche de Développement ==&lt;br /&gt;
L'actuelle branche de développement est dotée de nouvelles fonctionnalitées passionnantes.&lt;br /&gt;
Par contre, elle rencontre des bugs occasionnel ou des problèmes de performances. Les auteurs, les codeurs et les joueurs qui veulent avoir un aperçu du future de Wesnoth peuvent utiliser cette version.&lt;br /&gt;
&lt;br /&gt;
Les personnes habituées aux systèmes de contrôle de version et à compiler le jeu peuvent suivre le développement de Wesnoth de plus près en utilisant le [[WesnothRepository|Dépot git(en)]] à la place.&lt;br /&gt;
&lt;br /&gt;
==== Source code ====&lt;br /&gt;
* [[CompilingWesnoth|Compiling Guide]] - Comment compiler le code source&lt;br /&gt;
{{DevDownload}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* There are binaries for many different GNU/Linux distributions. Not all are always up to date with the current release. Please have a look at the [[WesnothBinariesLinux|Linux binary page]] for more information about the binaries for your distribution.&lt;br /&gt;
&lt;br /&gt;
==== Miscellaneous ====&lt;br /&gt;
* [https://sourceforge.net/projects/wesnoth/files/ SourceForge page for current and all previous versions]&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== License ==&lt;br /&gt;
''Page principale: [[Wesnoth:Copyrights]]''&lt;br /&gt;
&lt;br /&gt;
Ce programme est un logiciel libre; vous pouvez le distribuer et/ou le modifier selon les termes de la licence&lt;br /&gt;
[https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License version 2], comme publiée par la [https://www.fsf.org Free Software Foundation], ou choisir une version plus récente.&lt;br /&gt;
&lt;br /&gt;
Ce programme est proposé en espérant qu'il sera utile, mais sans garantie; sans même la garantie commerciale ou une garantie de conformité. Allez voir La licence publique générale GNU pour plus de détails.&lt;br /&gt;
&lt;br /&gt;
Certaines ressources du jeu sont fournies selon les termes de la licence [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0 license].&lt;br /&gt;
&lt;br /&gt;
== Voir aussi ==&lt;br /&gt;
* [https://changelog.wesnoth.org/1.14 Changelog for the stable version]&lt;br /&gt;
* [https://changelog.wesnoth.org Changelog for the development version]&lt;br /&gt;
* [[WesnothRepository]] - bleeding edge version from the repository&lt;br /&gt;
&lt;br /&gt;
[[Category:Building and Installing]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Download/de&amp;diff=74880</id>
		<title>Download/de</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Download/de&amp;diff=74880"/>
		<updated>2026-03-02T12:55:58Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Delete obsolete link to Download_Xdeltas&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Translations}}&lt;br /&gt;
Willkommen auf der Battle for Wesnoth-Downloadseite. Das BfW-Team veröffentlicht offiziell nur den Quelltext. Binärpakete werden nur von Freiwilligen aus der Gemeinschaft zur Verfügung gestellt und hier angeboten.&lt;br /&gt;
&lt;br /&gt;
Wenn die neuesten Binärpakete für dein Betriebssystem momentan noch nicht verfügbar sind, überprüfe einfach alle paar Tage ob du sie hier finden kannst. Die jeweilig Verantwortlichen wurden informiert, bitte habe etwas Geduld. In der Zwischenzeit kannst du die [[/FAQ/de#Eine_neue_Version_wurde_ver.C3.B6ffentlicht.2C_aber_wo_kann_man_die_.5BWindows.2C_Mac_OS_X.2C_usw..5D-Version_herunterladen.3F|FAQ-Seite]] lesen.&lt;br /&gt;
__NOTOC__&lt;br /&gt;
Springen zu: [[Download/de#Hauptversion (1.18-Zweig)|Hauptversion]] | [[Download/de#Entwicklungsversion (1.19-Zweig)|Entwicklungsversion]]&lt;br /&gt;
&lt;br /&gt;
== Hauptversion (1.18-Zweig) ==&lt;br /&gt;
Die Hauptversion ist eine stabile und ziemlich ausgewogene Version des Spiels. Alle Versionen des 1.18-Zweigs sind miteinander kompatibel.&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
Version 1.18.0 ist die neueste Hauptversion. Diese Version ist für die meisten Spieler zu empfehlen, da die 1.18-Mehrspielergemeinschaft riesig ist und der Erweiterungsserver eine ordentliche Auswahl anbietet.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Quelltext ====&lt;br /&gt;
* [[CompilingWesnoth|Kompilierungsanleitung]] - wie man den Quelltext kompiliert&lt;br /&gt;
{{StableDownload|Neueste Version|Vorherige Version|md5sum für den aktuellen Quelltext}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Es gibt Binärpakete für viele verschiedene GNU/Linux-Distributionen. Nicht alle sind immer auf dem Stand der neuesten Version. Für mehr Informationen über die Binärpakete für deine Distribution lies bitte die [[WesnothBinariesLinux|entsprechende Seite]].&lt;br /&gt;
&lt;br /&gt;
==== Verschiedenes ====&lt;br /&gt;
* [http://web.archive.org/web/20200412113411/https://wiki.wesnoth.org/Download_Xdeltas#Stable_Version_1.18.x Xdelta für den Quelltext]&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ SourceForge-Seite für die aktuellen und alle vorherigen Versionen]&lt;br /&gt;
&lt;br /&gt;
== Entwicklungsversion (1.19-Zweig) ==&lt;br /&gt;
Version 1.19.x ist die neueste Entwicklungsversion, die verbesserte Grafik und neue aufregende Inhalte vorstellt. Allerdigs können auch Programmierfehler oder andere Probleme auftreten, da schwerwiegende Änderungen stattfinden.&lt;br /&gt;
&lt;br /&gt;
Um ausgewogen und stabil zu spielen solltest du die neueste Version des 1.18-Zweigs benutzen. Diese Version hingegen ist Programmierern und Kampagnenentwicklern zu empfehlen, ebenso wie denen, die wissen wollen, wie Wesnoth zukünftig aussehen wird.&lt;br /&gt;
&lt;br /&gt;
Wer mit Versionskontrolle und Kompilierung vertraut ist, kann der aktuellen Entwicklung durch das Überprüfen von [[WesnothRepository]] folgen.&lt;br /&gt;
&lt;br /&gt;
==== Quelltext ====&lt;br /&gt;
* [[CompilingWesnoth|Kompilierungsanleitung]] - wie man den Quellext kompiliert&lt;br /&gt;
{{DevDownload|Neueste Version|Vorherige Version|md5sum für den aktuellen Quelltext}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Es gibt Binärpakete für viele verschiedene GNU/Linux-Distributionen. Nicht alle sind immer auf dem Stand der neuesten Version. Für mehr Informationen über die Binärpakete für deine Distribution lies bitte die [[WesnothBinariesLinux|entsprechende Seite]].&lt;br /&gt;
&lt;br /&gt;
==== Verschiedenes ====&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ SourceForge-Seite für die aktuelle und alle vorherigen Versionen]&lt;br /&gt;
&lt;br /&gt;
== Lizenz ==&lt;br /&gt;
''Hauptartikel: [[Wesnoth:Copyrights]]&lt;br /&gt;
&lt;br /&gt;
Dieses Programm ist freie Software; du kannst es weitervertreiben und/oder modifizieren, solange das unter den Bedingungen der [http://www.fsf.org/copyleft/gpl.html GNU General Public License version 2] bleibt, veröffentlicht von der [http://www.fsf.org Free Software Foundation].&lt;br /&gt;
Dieses Programm wird mit der Hoffnung vertrieben, dass es nützlich ist, allerdings ohne Garantie; ohne die auch nur angedeutete Garantie auf Marktgängigkeit oder Eignung für eine bestimmte Absicht. Siehe die GNU Allgemeine Öffentliche Lizenz für mehr Informationen.&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* [http://changelog.wesnoth.org Versionshistorie]&lt;br /&gt;
* [[WesnothRepository]] - bleeding-edge-Version von Quelle&lt;br /&gt;
&lt;br /&gt;
[[Category:Building and Installing]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Download/es&amp;diff=74879</id>
		<title>Download/es</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Download/es&amp;diff=74879"/>
		<updated>2026-03-02T12:55:30Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Update version numbers and delete some obsolete information (references to MacCompileStuff, Download_Xdeltas, Eclipse plugin) -- I'm not sure how accurate the rest of this info is, but I doubt the core of this page changes THAT drastically over time&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Translations}} __NOTOC__&lt;br /&gt;
Bienvenidos a la página de descargas de ''La Batalla por Wesnoth''. El equipo de ''La Batalla por Wesnoth'' sólo publica de forma oficial el código fuente y paquetes para Windows, macOS y varias distribuciones de Linux.&lt;br /&gt;
&lt;br /&gt;
Si la última versión de los binarios no está disponible para tu sistema operativo, por favor vuelve a comprobar en unos días si ya lo está. Se ha informado convenientemente a los empaquetadores, así que debes ser paciente. Durante la espera puedes leer las [[FAQ#A_new_version_is_out.2C_but_where_is_the_download_for_.5BWindows.2C_Mac_OS_X.2C_etc..5D.3F | preguntas frecuentes]] a este respecto.&lt;br /&gt;
&lt;br /&gt;
== Estable (serie 1.18) ==&lt;br /&gt;
&amp;lt;b&amp;gt;1.18.x&amp;lt;/b&amp;gt; es la serie estable actual. Éstas publicaciones son recomendadas para la mayoría de los jugadores, ya que proporcionan una experiencia de juego probada y balanceada con actualizaciones ocasionales con parches de defectos. Cada versión en esta serie es compatible con las otras. La comunidad en línea de jugadores para esta serie también es la más grande y el servidor de complementos tiene una vasta selección de contenido.&lt;br /&gt;
&lt;br /&gt;
==== Código fuente ====&lt;br /&gt;
* [[CompilingWesnoth|Guía de compilación]] - cómo compilar el código fuente&lt;br /&gt;
{{StableDownload|Versión actual|Versión anterior}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Existen binarios para muchas distribuciones diferentes de GNU/Linux. No siempre están todos actualizados a la última publicación. Por favor, echa un vistazo a la [[WesnothBinariesLinux | página de binarios para Linux]] para obtener más información sobre los binarios para tu distribución.&lt;br /&gt;
&lt;br /&gt;
==== Miscelánea ====&lt;br /&gt;
* [[Download_Xdeltas#Stable_Version_1.18.x|Xdelta para el código fuente]]&lt;br /&gt;
* [https://sourceforge.net/projects/wesnoth/files/ Página de SourceForge para la versión actual y todas las anteriores]&lt;br /&gt;
&lt;br /&gt;
== Desarrollo (serie 1.19) ==&lt;br /&gt;
&amp;lt;b&amp;gt;1.19.x&amp;lt;/b&amp;gt; es la serie de desarrollo actual, presentando nuevas y emocionantes características. Sin embargo, es posible que presente defectos o problemas de rendimiento en ocasiones. Creadores de contenido, desarrolladores y jugadores que deseen darle un vistazo al futuro de Wesnoth podrían estar interesados en probar esta serie.&lt;br /&gt;
&lt;br /&gt;
Aquellos que estén familiarizados con el uso de sistemas de control de versiones y compilar el juego a partir de su código fuente pueden seguir de más cerca aún el desarrollo de Wesnoth usando el [[WesnothRepository|repositorio Git]] en vez de las publicaciones de esta serie.&lt;br /&gt;
&lt;br /&gt;
==== Código fuente ====&lt;br /&gt;
* [[CompilingWesnoth | Guía de compilación]] - cómo compilar el código fuente&lt;br /&gt;
{{DevDownload|Versión actual|Versión anterior}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Existen binarios para muchas distribuciones diferentes de GNU/Linux. No siempre están todos actualizados a la última publicación. Por favor, echa un vistazo a la [[WesnothBinariesLinux | página de binarios para Linux]] para obtener más información sobre los binarios para tu distribución.&lt;br /&gt;
&lt;br /&gt;
==== Miscelánea ====&lt;br /&gt;
* [https://sourceforge.net/projects/wesnoth/files/ Página de SourceForge para la versión actual y todas las anteriores]&lt;br /&gt;
&lt;br /&gt;
== Licencia ==&lt;br /&gt;
''Artículo principal: [[Wesnoth:Copyrights]]''&lt;br /&gt;
&lt;br /&gt;
Este programa es software libre; puedes redistribuirlo o modificarlo bajo los términos de la [https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, versión 2], publicada por la [https://www.fsf.org Free Software Foundation]. Este programa se distribuye con la esperanza de que sea útil, pero sin ninguna garantía; incluso sin la garantía implícita de comerciabilidad o aptitud para un propósito particular. Vea la Licencia Pública General de GNU para más detalles.&lt;br /&gt;
&lt;br /&gt;
== Véase también ==&lt;br /&gt;
* [http://changelog.wesnoth.org Registro de cambios]&lt;br /&gt;
* [[WesnothRepository | Repositorio de Wesnoth]] - Obtener la última versión desde el repositorio&lt;br /&gt;
&lt;br /&gt;
[[Category:Building and Installing]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Download/de&amp;diff=74878</id>
		<title>Download/de</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Download/de&amp;diff=74878"/>
		<updated>2026-03-02T12:53:06Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Update version numbers and delete some obsolete information (references to MacCompileStuff and the Eclipse plugin) -- I'm not sure how accurate the rest of this info is, but I doubt the core of this page changes THAT drastically over time&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Translations}}&lt;br /&gt;
Willkommen auf der Battle for Wesnoth-Downloadseite. Das BfW-Team veröffentlicht offiziell nur den Quelltext. Binärpakete werden nur von Freiwilligen aus der Gemeinschaft zur Verfügung gestellt und hier angeboten.&lt;br /&gt;
&lt;br /&gt;
Wenn die neuesten Binärpakete für dein Betriebssystem momentan noch nicht verfügbar sind, überprüfe einfach alle paar Tage ob du sie hier finden kannst. Die jeweilig Verantwortlichen wurden informiert, bitte habe etwas Geduld. In der Zwischenzeit kannst du die [[/FAQ/de#Eine_neue_Version_wurde_ver.C3.B6ffentlicht.2C_aber_wo_kann_man_die_.5BWindows.2C_Mac_OS_X.2C_usw..5D-Version_herunterladen.3F|FAQ-Seite]] lesen.&lt;br /&gt;
__NOTOC__&lt;br /&gt;
Springen zu: [[Download/de#Hauptversion (1.18-Zweig)|Hauptversion]] | [[Download/de#Entwicklungsversion (1.19-Zweig)|Entwicklungsversion]]&lt;br /&gt;
&lt;br /&gt;
== Hauptversion (1.18-Zweig) ==&lt;br /&gt;
Die Hauptversion ist eine stabile und ziemlich ausgewogene Version des Spiels. Alle Versionen des 1.18-Zweigs sind miteinander kompatibel.&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
Version 1.18.0 ist die neueste Hauptversion. Diese Version ist für die meisten Spieler zu empfehlen, da die 1.18-Mehrspielergemeinschaft riesig ist und der Erweiterungsserver eine ordentliche Auswahl anbietet.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Quelltext ====&lt;br /&gt;
* [[CompilingWesnoth|Kompilierungsanleitung]] - wie man den Quelltext kompiliert&lt;br /&gt;
{{StableDownload|Neueste Version|Vorherige Version|md5sum für den aktuellen Quelltext}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Es gibt Binärpakete für viele verschiedene GNU/Linux-Distributionen. Nicht alle sind immer auf dem Stand der neuesten Version. Für mehr Informationen über die Binärpakete für deine Distribution lies bitte die [[WesnothBinariesLinux|entsprechende Seite]].&lt;br /&gt;
&lt;br /&gt;
==== Verschiedenes ====&lt;br /&gt;
* [http://web.archive.org/web/20200412113411/https://wiki.wesnoth.org/Download_Xdeltas#Stable_Version_1.18.x Xdelta für den Quelltext]&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ SourceForge-Seite für die aktuellen und alle vorherigen Versionen]&lt;br /&gt;
&lt;br /&gt;
== Entwicklungsversion (1.19-Zweig) ==&lt;br /&gt;
Version 1.19.x ist die neueste Entwicklungsversion, die verbesserte Grafik und neue aufregende Inhalte vorstellt. Allerdigs können auch Programmierfehler oder andere Probleme auftreten, da schwerwiegende Änderungen stattfinden.&lt;br /&gt;
&lt;br /&gt;
Um ausgewogen und stabil zu spielen solltest du die neueste Version des 1.18-Zweigs benutzen. Diese Version hingegen ist Programmierern und Kampagnenentwicklern zu empfehlen, ebenso wie denen, die wissen wollen, wie Wesnoth zukünftig aussehen wird.&lt;br /&gt;
&lt;br /&gt;
Wer mit Versionskontrolle und Kompilierung vertraut ist, kann der aktuellen Entwicklung durch das Überprüfen von [[WesnothRepository]] folgen.&lt;br /&gt;
&lt;br /&gt;
==== Quelltext ====&lt;br /&gt;
* [[CompilingWesnoth|Kompilierungsanleitung]] - wie man den Quellext kompiliert&lt;br /&gt;
{{DevDownload|Neueste Version|Vorherige Version|md5sum für den aktuellen Quelltext}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* Es gibt Binärpakete für viele verschiedene GNU/Linux-Distributionen. Nicht alle sind immer auf dem Stand der neuesten Version. Für mehr Informationen über die Binärpakete für deine Distribution lies bitte die [[WesnothBinariesLinux|entsprechende Seite]].&lt;br /&gt;
&lt;br /&gt;
==== Verschiedenes ====&lt;br /&gt;
* [http://web.archive.org/web/20200412113411/https://wiki.wesnoth.org/Download_Xdeltas#Development_Version_1.19.x Xdelta für den Quelltext]&lt;br /&gt;
* [http://sourceforge.net/projects/wesnoth/files/ SourceForge-Seite für die aktuelle und alle vorherigen Versionen]&lt;br /&gt;
&lt;br /&gt;
== Lizenz ==&lt;br /&gt;
''Hauptartikel: [[Wesnoth:Copyrights]]&lt;br /&gt;
&lt;br /&gt;
Dieses Programm ist freie Software; du kannst es weitervertreiben und/oder modifizieren, solange das unter den Bedingungen der [http://www.fsf.org/copyleft/gpl.html GNU General Public License version 2] bleibt, veröffentlicht von der [http://www.fsf.org Free Software Foundation].&lt;br /&gt;
Dieses Programm wird mit der Hoffnung vertrieben, dass es nützlich ist, allerdings ohne Garantie; ohne die auch nur angedeutete Garantie auf Marktgängigkeit oder Eignung für eine bestimmte Absicht. Siehe die GNU Allgemeine Öffentliche Lizenz für mehr Informationen.&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* [http://changelog.wesnoth.org Versionshistorie]&lt;br /&gt;
* [[WesnothRepository]] - bleeding-edge-Version von Quelle&lt;br /&gt;
&lt;br /&gt;
[[Category:Building and Installing]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Download&amp;diff=74877</id>
		<title>Download</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Download&amp;diff=74877"/>
		<updated>2026-03-02T12:49:03Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Add the translations toolbar&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to the ''Battle for Wesnoth'' downloads page. The BfW project team officially releases the source code and builds for Windows, macOS, and various Linux distributions.&lt;br /&gt;
&lt;br /&gt;
If the latest binaries are not currently available for your OS, please check back in a few days to see if they have been placed here. Packagers have been informed of the release, please be patient.  In the meantime, read the [[FAQ#A_new_version_is_out.2C_but_where_is_the_download_for_.5BWindows.2C_Mac_OS_X.2C_etc..5D.3F|FAQ]].&lt;br /&gt;
&lt;br /&gt;
{{Translations}}&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
== Stable (1.18 branch) ==&lt;br /&gt;
&amp;lt;b&amp;gt;1.18.x&amp;lt;/b&amp;gt; is the current stable branch. These releases are recommended for most players, as they provide a well-tested and balanced game experience with only occasional bug-fix updates. Each version of this branch is compatible with each other. The online player community for it is also the largest and the add-ons server has a vast selection of content.&lt;br /&gt;
{{StableDownload}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* There are binaries for many different GNU/Linux distributions. Not all are always up to date with the current release. Please have a look at the [[WesnothBinariesLinux|Linux binary page]] for more information about the binaries for your distribution.&lt;br /&gt;
&lt;br /&gt;
==== Miscellaneous ====&lt;br /&gt;
* [https://sourceforge.net/projects/wesnoth/files/ SourceForge page for current and all previous versions]&lt;br /&gt;
&lt;br /&gt;
== Development (1.19 branch) ==&lt;br /&gt;
&amp;lt;b&amp;gt;1.19.x&amp;lt;/b&amp;gt; is the current development branch, boasting new exciting features. However, there may be occasional bugs or performance problems in these releases. Content creators, coders, and players who want to preview the future of Wesnoth may be interested in checking out our work in this branch.&lt;br /&gt;
&lt;br /&gt;
People familiar with version control systems and building the game from source may follow Wesnoth development even more closely using the [[WesnothRepository|Git repository]] instead.&lt;br /&gt;
{{DevDownload}}&lt;br /&gt;
&lt;br /&gt;
==== GNU/Linux ====&lt;br /&gt;
* There are binaries for many different GNU/Linux distributions. Not all are always up to date with the current release. Please have a look at the [[WesnothBinariesLinux|Linux binary page]] for more information about the binaries for your distribution.&lt;br /&gt;
&lt;br /&gt;
==== Miscellaneous ====&lt;br /&gt;
* [https://sourceforge.net/projects/wesnoth/files/ SourceForge page for current and all previous versions]&lt;br /&gt;
&lt;br /&gt;
== License ==&lt;br /&gt;
''Main article: [[Wesnoth:Copyrights]]''&lt;br /&gt;
&lt;br /&gt;
This program is free software; you can redistribute it and/or modify it under the terms of the [https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License version 3], as published by the [https://www.fsf.org Free Software Foundation], or at your option, any later version.&lt;br /&gt;
&lt;br /&gt;
This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU General Public License for more details.&lt;br /&gt;
&lt;br /&gt;
Some assets included with the game are provided under the terms of the [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0 license].&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [https://changelog.wesnoth.org/1.18 Changelog for the stable version]&lt;br /&gt;
* [https://changelog.wesnoth.org Changelog for the development version]&lt;br /&gt;
* [[WesnothRepository]] - bleeding edge version from the repository&lt;br /&gt;
&lt;br /&gt;
[[Category:Building and Installing]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=VariablesWML&amp;diff=74856</id>
		<title>VariablesWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=VariablesWML&amp;diff=74856"/>
		<updated>2026-02-22T07:03:13Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Undo revision 74848 by Sapient (talk) -- Who are we do prescribe what may be done?&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WML Tags}}&lt;br /&gt;
Variables in WML are used to store data for later retrieval. Each variable is identified by its name. Once created, a variable persists until the end of a campaign or scenario unless explicitly cleared.&lt;br /&gt;
Variable names can contain only alphanumerics and underscores and are case-sensitive. Though technically permitted, it is recommended not to use an underscore as the first character of a variable name.&lt;br /&gt;
&lt;br /&gt;
The three basic manipulations of WML variables are assigning a value, querying the value, and clearing the variable.&lt;br /&gt;
* [[#Assigning Variables|'''Assigning to a variable''']]: stores a value in the variable, either creating a new variable or modifying a variable that already exists.&lt;br /&gt;
* [[#Reading Variables|'''Querying a variable''']]: retrieves the last value stored in the variable (usually returning an empty string if no value was stored).&lt;br /&gt;
* [[#Clearing Variables|'''Clearing a variable''']]: makes the WML engine forget about that variable. This is useful for reducing overhead, since all used variables are stored in saved games.&lt;br /&gt;
&lt;br /&gt;
== Kinds of Variables ==&lt;br /&gt;
=== Scalar ===&lt;br /&gt;
A scalar variable can store a single string, number, or boolean value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[set_variable]&lt;br /&gt;
    name=my_variable&lt;br /&gt;
    value=&amp;quot;sample value&amp;quot;&lt;br /&gt;
[/set_variable]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 ([[SyntaxWML#Special_Attribute_Values|Special Attribute Values]]).&lt;br /&gt;
&lt;br /&gt;
=== Container ===&lt;br /&gt;
A container variable can store any number of scalar variables, as well as nested containers. There are tags to assign specific information, for instance [store_side]. To refer to a variable &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; stored in a container &amp;lt;code&amp;gt;foo&amp;lt;/code&amp;gt; you would write &amp;lt;code&amp;gt;foo.bar&amp;lt;/code&amp;gt;. This works even if one of the variable names is entirely numeric.&lt;br /&gt;
&lt;br /&gt;
=== Array ===&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[set_variable]&lt;br /&gt;
    name=my_awesome_array[0].x&lt;br /&gt;
    value=10&lt;br /&gt;
[/set_variable]&lt;br /&gt;
[set_variable]&lt;br /&gt;
    name=my_awesome_array[1].x&lt;br /&gt;
    value=12&lt;br /&gt;
[/set_variable]&lt;br /&gt;
[set_variable]&lt;br /&gt;
    name=my_awesome_array[2].x&lt;br /&gt;
    value=14&lt;br /&gt;
[/set_variable]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However, when working with arrays, it is usually easier to make use of [set_variables]. This would be written as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[set_variables]&lt;br /&gt;
    name=my_awesome_array&lt;br /&gt;
    [value]&lt;br /&gt;
        x=10&lt;br /&gt;
    [/value]&lt;br /&gt;
    [value]&lt;br /&gt;
        x=12&lt;br /&gt;
    [/value]&lt;br /&gt;
    [value]&lt;br /&gt;
        x=14&lt;br /&gt;
    [/value]&lt;br /&gt;
[/set_variables]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Arrays are indexed from 0, which means that if &amp;lt;code&amp;gt;foo&amp;lt;/code&amp;gt; is the name of an array, &amp;lt;code&amp;gt;foo[0]&amp;lt;/code&amp;gt; is the full name of its first container variable, &amp;lt;code&amp;gt;foo[1]&amp;lt;/code&amp;gt; the full name of its second, and so on.&lt;br /&gt;
&lt;br /&gt;
For an array variable, &amp;lt;code&amp;gt;foo.length&amp;lt;/code&amp;gt; is the special variable that always stores the number of containers in the array &amp;lt;code&amp;gt;foo&amp;lt;/code&amp;gt;. Hence, if the value stored in &amp;lt;code&amp;gt;foo.length&amp;lt;/code&amp;gt; is 18, the last container in the array would be &amp;lt;code&amp;gt;foo[17]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you try to query an array as if it were a container, then it will simply use the first index. Thus &amp;lt;code&amp;gt;$foo.bar&amp;lt;/code&amp;gt; would be the same as &amp;lt;code&amp;gt;$foo[0].bar&amp;lt;/code&amp;gt;. An explicit index inside an array is also considered a container.&lt;br /&gt;
&lt;br /&gt;
''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 &amp;lt;code&amp;gt;foo[3]&amp;lt;/code&amp;gt; as if it were a scalar one is illegal; instead, you would use &amp;lt;code&amp;gt;foo[3].value&amp;lt;/code&amp;gt; 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 save of a game that contains such variables will fail with a WML error.)&lt;br /&gt;
&lt;br /&gt;
=== Global ===&lt;br /&gt;
&lt;br /&gt;
Most WML variables are global variables, and unless they are explicitly cleared, they will continue to exist across all events and scenarios until a campaign ends. Variables created with '''[set_variable]''', '''[set_variables]''', or any of the [store_something] styled WML tags such as '''[store_unit]''' may all used to create or modify global variables. Likewise, [[#Variable Substitution|variable substitution]] and the '''[variable]''' conditional tag may be used to read global variables.&lt;br /&gt;
&lt;br /&gt;
=== Unit ===&lt;br /&gt;
&lt;br /&gt;
Unit variables may be stored on a specific unit in a special '''variables''' child container. That means that, if desired, every unit could have a variable with the same name, and it wouldn't conflict with a global variable of the same name. Note that they are not global only in the sense that they are &amp;quot;namespaced&amp;quot; and not in the sense that they cannot be accessed globally.&lt;br /&gt;
&lt;br /&gt;
Unit variables can be read after storing a unit then can be created by setting data in the '''variables''' child container and unstoring the unit. A one-step way of creating unit variables is possible with '''[modify_unit]''', but to read the variables you still usually need to use '''[store_unit]'''. You can read them from [[Wesnoth Formula Language|formulas]] (eg in [[StandardUnitFilter]] or [[AbilitiesWML]]) and the '''[filter_wml][variables]''' tag in [[StandardUnitFilter]], or as mentioned you can use '''[store_unit]''' to copy the unit along with all its variables into a global variable which can then be accessed normally – for example with a unit stored to the variable &amp;lt;code&amp;gt;my_unit&amp;lt;/code&amp;gt;, you could access the scalar unit variable &amp;lt;code&amp;gt;my_stamina&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;$my_unit.variables.my_stamina&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If modifying unit variables after storing the unit, always remember to [[DirectActionsWML#.5Bunstore_unit.5D|[unstore_unit]]] for the changes to be kept.&lt;br /&gt;
&lt;br /&gt;
An example of how you can filter on a unit variable in [[StandardUnitFilter]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[filter]&lt;br /&gt;
  [filter_wml]&lt;br /&gt;
    [variables]&lt;br /&gt;
      my_variable=&amp;quot;test&amp;quot;&lt;br /&gt;
    [/variables]&lt;br /&gt;
  [/filter_wml]&lt;br /&gt;
[/filter]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Side ===&lt;br /&gt;
&lt;br /&gt;
Side variables are stored on a specific side. That means that, if desired, every side could have a variable with the same name, and it doesn't conflict with a global variable of the same name. Note that they are not global only in the sense that they are &amp;quot;namespaced&amp;quot; and not in the sense that they cannot be accessed globally.&lt;br /&gt;
&lt;br /&gt;
Side variables can be created with '''[modify_side]''', but there is currently no way to read them directly in WML. You can read them from [[Wesnoth Formula Language|formulas]] (eg in [[StandardSideFilter]]), or you can use '''[store_side]''' to copy the side along with all its variables into a global variable which can then be accessed normally – if you call the variable &amp;lt;code&amp;gt;my_side&amp;lt;/code&amp;gt;, then you could access the scalar side variable &amp;lt;code&amp;gt;wood_amount&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;$my_side.variables.wood_amount&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Since there is no '''[unstore_side]''' tag, don't modify the variables in a stored side. Instead, use [[DirectActionsWML#.5Bmodify_side.5D|[modify_side]]] for the changes to be kept.&lt;br /&gt;
&lt;br /&gt;
== Assigning Variables ==&lt;br /&gt;
&lt;br /&gt;
Variables can be created and modified using [[ActionWML]] or [[LuaAPI/wml#wml.variables|Lua]]. There are several ways to do this:&lt;br /&gt;
&lt;br /&gt;
* The '''[set_variable]''' tag can assign or modify a scalar variable using a wide variety of operations.&lt;br /&gt;
* The '''[set_variables]''' tag can assign or modify a container or array variable using a wide variety of operations.&lt;br /&gt;
* The '''[variables]''' tag can be used to set up a large number of variables all at once.&lt;br /&gt;
* The '''{VARIABLE}''' macro can assign a new scalar variable with a given value.&lt;br /&gt;
* The '''{VARIABLE_OP}''' macro can modify an existing scalar variable using a wide variety of operations.&lt;br /&gt;
* There are several ways to assign variables from Lua. They won't be covered here, however.&lt;br /&gt;
&lt;br /&gt;
=== The [set_variable] tag ===&lt;br /&gt;
&lt;br /&gt;
The '''[[InternalActionsWML#.5Bset_variable.5D|[set_variable]]]''' tag can be directly used as ActionWML to work with global variables, or it can be placed in the '''[modify_unit]''' or '''[modify_side]''' ActionWML tags to work with unit or side variables, respectively. See the documentation of these tags for details.&lt;br /&gt;
&lt;br /&gt;
=== The [set_variables] tag ===&lt;br /&gt;
&lt;br /&gt;
As of 1.18.0, the '''[[InternalActionsWML#.5Bset_variables.5D|[set_variables]]]''' tag can only be used as ActionWML. Support for placing it in '''[modify_unit]''' and '''[modify_side]''' is planned. See the documentation of these tags for details.&lt;br /&gt;
&lt;br /&gt;
=== The [variables] tag ===&lt;br /&gt;
&lt;br /&gt;
Unlike the others, the '''[variables]''' tag cannot be directly used as ActionWML. It can be used in a number of other places, however:&lt;br /&gt;
&lt;br /&gt;
* Placed in a scenario tag to assign initial global variables at scenario start.&lt;br /&gt;
* Placed in a '''[side]''' tag to assign initial side variables at scenario start.&lt;br /&gt;
* Placed in a '''[unit]''' tag to assign initial unit variables when the unit is spawned.&lt;br /&gt;
* Placed in '''[leader]''' with the same meaning as in '''[unit]'''.&lt;br /&gt;
* Placed in '''[modify_unit]''' and '''[modify_side]''' ActionWML to adjust the values of several variables at once using &amp;quot;merge mode&amp;quot; (see '''[set_variables]''' documentation for the explanation of how this works).&lt;br /&gt;
* Seen in saved games to describe the current value of each variable when the game was saved.&lt;br /&gt;
&lt;br /&gt;
When using the '''[variables]''' tag, 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.&lt;br /&gt;
&lt;br /&gt;
A container variable with given name ''foo'' is assigned using a [foo] tag that contains the definitions for the contained variables.&lt;br /&gt;
&lt;br /&gt;
An array variable with given name ''foo'' is assigned using several [foo] tags, where the first tag describes foo[0], the second foo[1], ...&lt;br /&gt;
&lt;br /&gt;
== Reading Variables ==&lt;br /&gt;
&lt;br /&gt;
Variables can be queried in a variety of ways, including substitutions, [[ConditionalWML]], [[Wesnoth Formula Language]], and Lua. The Lua methods won't be covered here, however.&lt;br /&gt;
&lt;br /&gt;
=== Conditionals ===&lt;br /&gt;
&lt;br /&gt;
Variables may be compared by using '''[variable]''' within an [if] or [while] tag. The '''{VARIABLE_CONDITIONAL}''' macro can also be used for this purpose. For more information, please refer to [[ConditionalActionsWML]].&lt;br /&gt;
&lt;br /&gt;
=== Filters ===&lt;br /&gt;
&lt;br /&gt;
In [[StandardUnitFilter|unit filters]], the '''[variables]''' tag can be used in '''[filter_wml]''' to check the value of unit variables, respectively.&lt;br /&gt;
&lt;br /&gt;
Both unit filters and [[StandardSideFilter|side filters]] also support querying variables via WFL. The details of how this works is not covered here, however.&lt;br /&gt;
&lt;br /&gt;
=== Variable Substitution ===&lt;br /&gt;
&lt;br /&gt;
When writing scenario events ([[EventWML]]) and filters, a scalar variable can generally be substituted in the right-hand side of any '''key=value''' assignment. To do this, enclose the full variable name to be queried between a dollar sign (&amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt;) and a pipe (&amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;). The variable name should be the entire dot-separated path, where each component is an identifier (consisting of English letters, Arabic digits, and underscores) optionally followed by a pair of square brackets containing either a number or another substitution. The number represents the array index. When such a substitution appears in the text, the content which has previously been put into this variable name is used instead of the name of the variable.&lt;br /&gt;
&lt;br /&gt;
In certain situations, the &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt; that marks the end of the variable name to be queried can be omitted. The exact rule is: if there is no &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;, variable names span identifier characters (as defined in the preceding paragraph), balanced square brackets and some periods. Doubled periods, final periods (followed by a non-identifier character), 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 &amp;lt;code&amp;gt;$|&amp;lt;/code&amp;gt;), then it will be replaced by just &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt;, giving you an easy way to include a dollar sign in an interpolated string.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|2}} If you want to substitute a default value when the variable is uninitialized or empty, add a question mark (&amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt;) followed by the default value after the variable name, eg &amp;lt;code&amp;gt;$varname?default text|&amp;lt;/code&amp;gt;. In this case, the pipe (&amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;) is required. The default text can be anything at all, as long as it doesn't contain a pipe. (There exists no mechanism to escape a pipe so it can be included in the default text.)&lt;br /&gt;
&lt;br /&gt;
A dollar sign at the end of a string or followed by a character that's not an identifier will be left alone. If it's followed by a pipe, the pipe will be removed.&lt;br /&gt;
&lt;br /&gt;
Variable substitutions (and also formula substitutions, see [[SyntaxWML#formula substitution|here]] for more details) in a string are processed one at a time from right to left. That is, the engine finds the last dollar sign, substitutes that variable in, and then moves on to the next one in the resulting string. This means that the result of one variable substitution can affect the next one.&lt;br /&gt;
&lt;br /&gt;
For example, consider the substitution &amp;lt;code&amp;gt;$house_$colour|.title&amp;lt;/code&amp;gt;. First the &amp;quot;colour&amp;quot; variable is substituted in. If it contains &amp;quot;blue&amp;quot;, the result is &amp;lt;code&amp;gt;$house_blue.title&amp;lt;/code&amp;gt;, so the game will then look for a container variable called &amp;quot;house_blue&amp;quot; and substitute in its &amp;quot;title&amp;quot; key. On the other hand, if the &amp;quot;colour&amp;quot; variable contains &amp;quot;red&amp;quot;, the result of the first substitution is &amp;lt;code&amp;gt;$house_red.title&amp;lt;/code&amp;gt;, so the engine will instead look for a container variable called &amp;quot;house_red&amp;quot; and substitute in ''its'' &amp;quot;title&amp;quot; key.&lt;br /&gt;
&lt;br /&gt;
The most common use-case for this is using a scalar variable to index an array variable, for example &amp;lt;code&amp;gt;$houses[$n].title&amp;lt;/code&amp;gt;. In cases where substitution will occur more than once, such as a nested event, it can also be used to delay substitution to the second phase by simply adding a pipe directly after the dollar sign. The first round of substitution will remove the pipe and stop there (moving on to the next substitution left of it, if any), and then the second round of substitution will detect the variable and replace it.&lt;br /&gt;
&lt;br /&gt;
Here's a more complete example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
    name=turn 1&lt;br /&gt;
    [set_variable]&lt;br /&gt;
        name=my_variable&lt;br /&gt;
        value= _ &amp;quot;Konrad&amp;quot;&lt;br /&gt;
    [/set_variable]&lt;br /&gt;
    [message]&lt;br /&gt;
        speaker=Delfador&lt;br /&gt;
        message= _ &amp;quot;Hello, $my_variable|... How are you?&amp;quot;&lt;br /&gt;
    [/message]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The WML code above will cause Delfador to say &amp;quot;Hello, Konrad... How are you?&amp;quot; on turn 1.&lt;br /&gt;
&lt;br /&gt;
==== Literal Mode ====&lt;br /&gt;
&lt;br /&gt;
There are a few places where the substitution mode is literal. In these places, attribute values are used exactly as provided, nothing is substituted, and the &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; will not have special significance. The following places use the literal mode:&lt;br /&gt;
* The value of '''literal=''' inside [set_variable]&lt;br /&gt;
* The contents of '''[literal]''' inside [set_variables]&lt;br /&gt;
* The special [[SyntaxWML#The_.5Bvariables.5D_tag|[variables]]] tag, when used to give initial values to many variables upon scenario start&lt;br /&gt;
* In general, anything that's not nested inside '''[event]''', '''[command]''', '''[tunnel]''', '''[story]''', or a filter. For example, the '''[unit_type]''' tag cannot use variable substitution (except in filters).&lt;br /&gt;
&lt;br /&gt;
=== [insert_tag] ===&lt;br /&gt;
&lt;br /&gt;
The '''[insert_tag]''' tag inserts a variable as WML. In other words, the value of the passed [[VariablesWML#Container|container variable]] will be injected into the game as if they had been written out in WML form.&lt;br /&gt;
&lt;br /&gt;
This works in any tag that permits sub-tags and supports variable substitution. That means that, like variable substitution, it will ''not'' work in places that use [[#Literal Mode|literal mode]].&lt;br /&gt;
&lt;br /&gt;
*'''name''': The [&amp;quot;name&amp;quot;] to be given to the tag. This must be a tag which would be valid at the place where [insert_tag] is used, for anything to happen. (For example, if used as ActionWML, it should be a [[ActionWML]] tag name, and it may be a recognized subtag such as &amp;quot;option&amp;quot; when used within a [message]).&lt;br /&gt;
&lt;br /&gt;
*'''variable''': The name of the container variable which will have its value inserted into the tag. If the container variable is a WML array, [insert_tag] will insert a different tag for each of its elements.&lt;br /&gt;
&lt;br /&gt;
Here's an example of its use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
    name=moveto&lt;br /&gt;
    &lt;br /&gt;
    [set_variable]&lt;br /&gt;
        name=temp.speaker&lt;br /&gt;
        value=Konrad&lt;br /&gt;
    [/set_variable]&lt;br /&gt;
    &lt;br /&gt;
    [set_variable]&lt;br /&gt;
        name=temp.message&lt;br /&gt;
        value= _ &amp;quot;Yo Kalenz!&amp;quot;&lt;br /&gt;
    [/set_variable]    &lt;br /&gt;
    &lt;br /&gt;
    [insert_tag]&lt;br /&gt;
        name=message&lt;br /&gt;
        variable=temp&lt;br /&gt;
    [/insert_tag]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is effectively identical to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
    name=moveto&lt;br /&gt;
    &lt;br /&gt;
    [message]&lt;br /&gt;
        speaker=Konrad&lt;br /&gt;
        message= _ &amp;quot;Yo Kalenz!&amp;quot;&lt;br /&gt;
    [/message]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Clearing Variables ==&lt;br /&gt;
&lt;br /&gt;
This is done with {{tag|InternalActionsWML|clear_variable}} or the &amp;lt;tt&amp;gt;{CLEAR_VARIABLE}&amp;lt;/tt&amp;gt; [[PreprocessorRef|macro]]. It can also be done from Lua.&lt;br /&gt;
&lt;br /&gt;
Like '''[set_variable]''', the '''[clear_variable]''' tag can either be used as ActionWML or placed inside '''[modify_unit]''' or '''[modify_side]'''.&lt;br /&gt;
&lt;br /&gt;
== Automatically Stored Variables ==&lt;br /&gt;
* '''side_number''': the number of the current player's side (may be empty during start or prestart events)&lt;br /&gt;
* '''turn_number''': the number of the current turn (may be empty during start or prestart events)&lt;br /&gt;
* '''x1''': this is the x-coordinate of the location where the most recent event was triggered&lt;br /&gt;
* '''y1''': this is the y-coordinate of the location where the most recent event was triggered&lt;br /&gt;
* '''x2''': this is the x-coordinate of the location that assisted in triggering the most recent event&lt;br /&gt;
* '''y2''': this is the y-coordinate of the location that assisted in triggering the most recent event&lt;br /&gt;
* '''unit''': inside an event, this is the unit at $x1,$y1&lt;br /&gt;
* '''second_unit''': inside an event, this is the unit at $x2,$y2&lt;br /&gt;
* '''this_unit''': inside a standard unit filter, this is the unit currently being considered for a possible match&lt;br /&gt;
* '''other_unit''': inside some standard unit filters, this is an adjacent unit relevant to the match&lt;br /&gt;
* '''damage_inflicted''': inside attacker_hits and defender_hits events, this is the amount of damage that was inflicted&lt;br /&gt;
* '''weapon''': inside attack, attack_end, attacker_hits, attacker_misses, defender_hits, defender_misses, 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]].&lt;br /&gt;
* '''second_weapon''': inside attack, attack_end, attacker_hits, attacker_misses, defender_hits, defender_misses, 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]].&lt;br /&gt;
* '''owner_side''': inside a capture event, this contains the number of the previous owner (0 if previously unowned)&lt;br /&gt;
* '''teleport_unit''': inside the [[AbilitiesWML#Extra_tags_used_by_the_.5Bteleport.5D_ability|[tunnel]]] tag used by a teleport ability, this is the unit with that ability&lt;br /&gt;
&lt;br /&gt;
Note: Automatically stored container and array variables are only stored once one of their attributes is accessed for the first time. This means that one can sometimes get incorrect 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.&lt;br /&gt;
&lt;br /&gt;
== Variable Usage Examples ==&lt;br /&gt;
Consider a saved game with the following [variables] tag (or a freshly started scenario with that tag)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[variables]&lt;br /&gt;
    attitude_of_elves=hate&lt;br /&gt;
    attitude_of_dwarves=love&lt;br /&gt;
    attitude_of_humans=like&lt;br /&gt;
    current_opponent=elves&lt;br /&gt;
[/variables]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then,&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[message]&lt;br /&gt;
   message=&amp;quot;Oh, I see $current_opponent|! They surely $attitude_of_$current_opponent|| us!&amp;quot;&lt;br /&gt;
[/message]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
displays the message&lt;br /&gt;
 Oh, I see elves! They surely hate us!&lt;br /&gt;
&lt;br /&gt;
Consider another game with variables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[variables]&lt;br /&gt;
    our_side=1&lt;br /&gt;
    their_side=2&lt;br /&gt;
[/variables]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
where side 1 has 75 gold, and side 2 50 gold. Then, &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[store_side]&lt;br /&gt;
    side=$our_side&lt;br /&gt;
    variable=we&lt;br /&gt;
[/store_side]&lt;br /&gt;
[store_side]&lt;br /&gt;
    side=$their_side&lt;br /&gt;
    variable=they&lt;br /&gt;
[/store_side]&lt;br /&gt;
[message]&lt;br /&gt;
    message=We have $we.gold gold, they have $they.gold gold.&lt;br /&gt;
[/message]&lt;br /&gt;
[if]&lt;br /&gt;
    [variable]&lt;br /&gt;
        name=we.gold&lt;br /&gt;
        greater_than=$they.gold&lt;br /&gt;
    [/variable]&lt;br /&gt;
    [then]&lt;br /&gt;
        [message]&lt;br /&gt;
            message=This should be easy!&lt;br /&gt;
        [/message]&lt;br /&gt;
    [/then]&lt;br /&gt;
    [else]&lt;br /&gt;
        [message]&lt;br /&gt;
            message=This will not be easy!&lt;br /&gt;
        [/message]&lt;br /&gt;
    [/else]&lt;br /&gt;
[/if]&lt;br /&gt;
[clear_variable]&lt;br /&gt;
    name=we&lt;br /&gt;
[/clear_variable]&lt;br /&gt;
[clear_variable]&lt;br /&gt;
    name=they&lt;br /&gt;
[/clear_variable]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
displays the messages&lt;br /&gt;
 We have 75 gold, they have 50 gold.&lt;br /&gt;
 This should be easy!&lt;br /&gt;
If side 2 had 100 gold instead, the same code would display the messages&lt;br /&gt;
 We have 75 gold, they have 100 gold.&lt;br /&gt;
 This will not be easy!&lt;br /&gt;
&lt;br /&gt;
The code&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;wml&amp;quot;&amp;gt;&lt;br /&gt;
[store_unit]&lt;br /&gt;
    [filter]&lt;br /&gt;
        canrecruit=yes&lt;br /&gt;
        side=1&lt;br /&gt;
    [/filter]&lt;br /&gt;
    variable=leader&lt;br /&gt;
[/store_unit]&lt;br /&gt;
[message]&lt;br /&gt;
    message=Our leader's first attack does $leader[0].attack[0].damage damage per hit.&lt;br /&gt;
[/message]&lt;br /&gt;
[clear_variable]&lt;br /&gt;
    name=leader&lt;br /&gt;
[/clear_variable]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
always displays a true sentence.&lt;br /&gt;
&lt;br /&gt;
You may find more complicated examples of variable use in the [[UsefulWMLFragments]] section.&lt;br /&gt;
&lt;br /&gt;
== Tutorial ==&lt;br /&gt;
&lt;br /&gt;
* [[/How_to_use_variables|How to use variables]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&amp;diff=74836</id>
		<title>LuaAPI/types/widget</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&amp;diff=74836"/>
		<updated>2026-02-16T03:47:19Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Widget Length */ Add stacked_widget&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;tright&amp;quot;&amp;gt; __TOC__ &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''widget''' userdata offers access to a widget of a GUI2 dialog. While there is only one type of widget userdata that covers all widgets including the window itself, the properties of a widget userdata are different for each type of widget. Indexing a widget's userdata can either be used to access a child widget or to set or get a property of a widget. Some properties are read-only or write-only; the properties depend on the type of the widget.&lt;br /&gt;
&lt;br /&gt;
An example of accessing a child widget:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
function preshow(dialog)&lt;br /&gt;
  local okay_button = dialog.okay_button&lt;br /&gt;
  -- okay_button is now a handle to the the widget's child with the id 'okay_button' &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Widget Attributes ==&lt;br /&gt;
&lt;br /&gt;
=== selected ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected''' &amp;amp;harr; ''boolean''&lt;br /&gt;
* Available on: '''[toggle_button]''', '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
Whether the item is selected or not. Note that this should only be used for widgets that have only 2 states. In particular, there exist 3-State toggle_buttons (for example in listbox headers). For those, selected_index must be used instead.&lt;br /&gt;
&lt;br /&gt;
=== selected_index ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected_index''' &amp;amp;harr; ''index''&lt;br /&gt;
* Available on: '''[listbox]''', '''[multi_page]''', '''[stacked_widget]''', '''[menu_button]''', '''[toggle_button]''', '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
The selected index of the item. For '''[toggle_button]''' and '''[toggle_panel]''', this is the same as '''selected''' only encoded as a number (1 for false or 2 for true) instead of a boolean.&lt;br /&gt;
&lt;br /&gt;
For a  '''[listbox]'''with '''has_maximum=false''' and more than one item selected, reading '''selected_index''' will return the first selected index.&lt;br /&gt;
&lt;br /&gt;
For a '''[stacked_widget]''', only the layer specified by '''selected_index''' will be displayed and receive events (callbacks will only be triggered on the selected layer).&lt;br /&gt;
A '''selected_index''' of 0 represents all layers being selected, with events only being received by the layer with the highest index.  Note that term ''selected'' for the ''layer'' of a stacked_widget is not the same as the '''selected''' ''widget'' attribute.&lt;br /&gt;
&lt;br /&gt;
=== text ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''text''' &amp;amp;harr; ''text''&lt;br /&gt;
* Available on: '''[text_box]'''&lt;br /&gt;
&lt;br /&gt;
The text of the textbox.&lt;br /&gt;
&lt;br /&gt;
=== value ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''value''' &amp;amp;harr; ''position''&lt;br /&gt;
* Available on: '''[slider]'''&lt;br /&gt;
&lt;br /&gt;
The current position of the slider.&lt;br /&gt;
&lt;br /&gt;
=== percentage ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''percentage''' &amp;amp;harr; ''position''&lt;br /&gt;
* Available on: '''[progress_bar]'''&lt;br /&gt;
&lt;br /&gt;
The current position of the progress bar, between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
=== selected_item_path ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected_item_path''' &amp;amp;rarr; ''array of indices''&lt;br /&gt;
* Available on: '''[tree_view]'''&lt;br /&gt;
&lt;br /&gt;
A table describing the currently selected node. If for example, in the following treeview, Item 9 is selected, the result will be {2,1,3}.&lt;br /&gt;
&lt;br /&gt;
 +Section1&lt;br /&gt;
  +Subsection11&lt;br /&gt;
   *Item1&lt;br /&gt;
   *Item2&lt;br /&gt;
   *Item3&lt;br /&gt;
  +Subsection12&lt;br /&gt;
   *Item4&lt;br /&gt;
   *Item5&lt;br /&gt;
   *Item6&lt;br /&gt;
 +Section2&lt;br /&gt;
  +Subsection21&lt;br /&gt;
   *Item7&lt;br /&gt;
   *Item8&lt;br /&gt;
   *Item9&lt;br /&gt;
  +Subsection22&lt;br /&gt;
   *Item10&lt;br /&gt;
   *Item11&lt;br /&gt;
   *Item12&lt;br /&gt;
&lt;br /&gt;
=== path ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''path''' &amp;amp;rarr; ''array of indices''&lt;br /&gt;
* Available on: '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
A table describing this node in the overall treeview. See [[#selected_item_path|selected_item_path]] for the meaning of the table..&lt;br /&gt;
&lt;br /&gt;
=== unfolded ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''unfolded''' &amp;amp;larr; ''boolean''&lt;br /&gt;
* Available on: '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
Control whether a tree node is currently expanded or not.&lt;br /&gt;
&lt;br /&gt;
=== unit ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''unit''' &amp;amp;larr; ''unit or unit type''&lt;br /&gt;
* Available on: '''[unit_preview_pane]'''&lt;br /&gt;
&lt;br /&gt;
Change the displayed unit or unit type in the preview pane.&lt;br /&gt;
&lt;br /&gt;
=== item_count ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''item_count''' &amp;amp;rarr; ''number of items''&lt;br /&gt;
* Available on: '''[multi_page]''', '''[listbox]'''&lt;br /&gt;
&lt;br /&gt;
The number of items in the container widget.&lt;br /&gt;
&lt;br /&gt;
=== use_markup ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''use_markup''' &amp;amp;rarr; ''boolean''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]'''&lt;br /&gt;
&lt;br /&gt;
Sets whether the widget's label will parse [[Pango formatting]].&lt;br /&gt;
&lt;br /&gt;
=== label ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''label''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]''', '''[image]'''&lt;br /&gt;
&lt;br /&gt;
The widget's label. Technically this is a special string used in the widget's wml definition. It usually does what one would expect, but also sets the image for '''image''' widgets.  For '''[text_box]''', use '''text''' for initial values.&lt;br /&gt;
&lt;br /&gt;
=== marked_up_text ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''marked_up_text''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]'''&lt;br /&gt;
&lt;br /&gt;
Shortcut for setting label and use_markup=yes.&lt;br /&gt;
&lt;br /&gt;
=== enabled ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''enabled''' &amp;amp;larr; ''boolean''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
=== tooltip ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''tooltip''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
=== visible ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''visible''' &amp;amp;larr; ''visibility string''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
Determines whether the widget is visible onscreen. The following visibility statuses are recognized:&lt;br /&gt;
{| clasS=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! String value !! Boolean shorthand !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| visible || true || The widget is visible and handles events.&lt;br /&gt;
|-&lt;br /&gt;
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.&lt;br /&gt;
|-&lt;br /&gt;
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== type ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''type''' &amp;amp;rarr; ''string''&lt;br /&gt;
* Available on: All widgets&lt;br /&gt;
&lt;br /&gt;
Returns a string specifying the type of the widget.&lt;br /&gt;
&lt;br /&gt;
== Widget Callbacks ==&lt;br /&gt;
&lt;br /&gt;
=== on_modified ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_modified''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: Most widgets, in particular '''[slider]''', '''[toggle_button]''', '''[listbox]''', '''[menu_button]''', '''[text_box]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user changes the value of the widget.&lt;br /&gt;
&lt;br /&gt;
=== on_left_click ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_left_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: All widgets&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on the widget.&lt;br /&gt;
&lt;br /&gt;
=== on_double_click ===&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_double_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user double clicks on the widget. Non-toggle panel widgets can be wrapped in a toggle panel to make use of this event handler.&lt;br /&gt;
&lt;br /&gt;
=== on_button_click ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_button_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: '''[button]''', '''[repeating_button]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on the button. This can differ from '''on_left_click''', depending on the type of widget. For example, on a '''[repeating_button]''' it will fire multiple times if the user holds the mouse button down.&lt;br /&gt;
&lt;br /&gt;
=== on_link_click ===&lt;br /&gt;
{{DevFeature1.19|9}}&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_link_click''' &amp;amp;larr; '''function'''(''dest'')&lt;br /&gt;
* Available on: '''[rich_label]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on a '''&amp;lt;ref&amp;gt;''' link inside a '''[rich_label]'''. The first argument '''dest''' is the target of the link.&lt;br /&gt;
&lt;br /&gt;
== Widget Length ==&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* '''#'''''widget''&lt;br /&gt;
* Available on: '''[listbox]''', '''[multi_page]''', '''[tree_view]''', '''[tree_view_node]''', {{DevFeature1.19|6}} '''[stacked_widget]'''&lt;br /&gt;
&lt;br /&gt;
Returns the total number of children in the specified container widget – for example, the number of rows in a list box, or the number of pages in a multi-page.&lt;br /&gt;
&lt;br /&gt;
== Widget Methods ==&lt;br /&gt;
&lt;br /&gt;
Any function defined in the [[LuaAPI/gui/widget|gui.widget]] module and taking a widget as its first parameter can be called as a method of a widget. This includes any functions that are added to the module by user code. Note that these methods are available even if the widget itself doesn't support that function, so in some cases it may be necessary to check '''widget.type''' before calling the method.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=LuaAPI/gui/widget&amp;diff=74835</id>
		<title>LuaAPI/gui/widget</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=LuaAPI/gui/widget&amp;diff=74835"/>
		<updated>2026-02-16T03:45:46Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* clear_items */ Fix name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The '''gui.widget''' module contains functions for managing widgets in custom GUI2 dialogs. Since these functions take a [[LuaAPI/types/widget|widget userdata]] as the first parameter, they can only be used in the preshow or postshow of a GUI2 dialog (directly or indirectly). However, the table is available at all times, and additional methods can be installed here for unusual needs.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The '''gui.widget.set_callback''' is a compatibility wrapper and is unsupported. It may be removed without warning. Callbacks should be bound by assigning the appropriate callback key on the widget.&lt;br /&gt;
&lt;br /&gt;
=== focus ===&lt;br /&gt;
&lt;br /&gt;
* '''gui.widget.focus'''(''widget'')&lt;br /&gt;
* ''widget'':'''focus'''()&lt;br /&gt;
&lt;br /&gt;
Switches the keyboard focus to the widget. This is often useful for dialogs containing a central listbox, so that it can be controlled with the keyboard as soon as it is displayed.&lt;br /&gt;
&lt;br /&gt;
=== set_canvas ===&lt;br /&gt;
&lt;br /&gt;
* '''gui.widget.set_canvas'''(''widget'', ''layer index'', ''content'')&lt;br /&gt;
* ''widget'':'''set_canvas'''(''layer index'', ''content'')&lt;br /&gt;
&lt;br /&gt;
Sets the WML passed as the second argument as the canvas content (index given by the first argument) of the widget. The content of the WML table depends on which shape is used:&lt;br /&gt;
&lt;br /&gt;
* [[GUICanvasWML#Circle|Circle]]&lt;br /&gt;
* [[GUICanvasWML#Image|Image]]&lt;br /&gt;
* [[GUICanvasWML#Line|Line]]&lt;br /&gt;
* [[GUICanvasWML#Bounded_Shape|common attributes of rectangles, round rectangles and text]]&lt;br /&gt;
* [[GUICanvasWML#Rectangle|Rectangle]]&lt;br /&gt;
* [[GUICanvasWML#Rounded_Rectangle|Rounded Rectangle]]&lt;br /&gt;
* [[GUICanvasWML#Text|Text]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
-- draw two rectangles in the upper-left corner of the window (assume dialog is the window widget)&lt;br /&gt;
dialog:set_canvas(2, {&lt;br /&gt;
    wml.tag.rectangle { x = 20, y = 20, w = 20, h = 20, fill_color= &amp;quot;0,0,255,255&amp;quot; },&lt;br /&gt;
    wml.tag.rectangle { x = 30, y = 30, w = 20, h = 20, fill_color = &amp;quot;255,0,0,255&amp;quot; }&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The meaning of the canvas index depends on the chosen widget. It may be the disabled / enabled states of the widget, or its background / foreground planes, or... For instance, overwriting canvas 1 of the window with an empty canvas causes the window to become transparent.&lt;br /&gt;
&lt;br /&gt;
=== add_item ===&lt;br /&gt;
&lt;br /&gt;
* '''gui.widget.add_item'''(''widget'', [''position'']) &amp;amp;rarr; ''the new item'', ''position''&lt;br /&gt;
* ''widget'':'''add_item'''([''position'']) &amp;amp;rarr; ''the new item'', ''position''&lt;br /&gt;
&lt;br /&gt;
Add an item to a container widget, for example a listbox. Returns the created item as a [[LuaAPI/types/widget|widget userdata]].&lt;br /&gt;
&lt;br /&gt;
=== add_item_of_type ===&lt;br /&gt;
&lt;br /&gt;
* '''gui.widget.add_item_of_type'''(''widget'', ''category'', [''position'']) &amp;amp;rarr; ''the new item'', ''position''&lt;br /&gt;
* ''widget'':'''add_item_of_type'''(''category'', [''position'']) &amp;amp;rarr; ''the new item'', ''position''&lt;br /&gt;
&lt;br /&gt;
Add an item to a widget which is a heterogeneous container of different types of widgets, in particular multi_pages and treeviews.&lt;br /&gt;
&lt;br /&gt;
=== remove_items_at ===&lt;br /&gt;
&lt;br /&gt;
* '''gui.widget.remove_items_at'''(''widget'', ''position'', ''count'')&lt;br /&gt;
* ''widget'':'''remove_items_at'''(''position'', ''count'')&lt;br /&gt;
&lt;br /&gt;
Removes one or more elements of a container type widget (like treeviews), starting at the given index. If 0 is passed as the count, all elements from that point to the end are removed. Otherwise, the specified number of elements are removed.&lt;br /&gt;
&lt;br /&gt;
=== clear_items ===&lt;br /&gt;
{{DevFeature1.19|5}}&lt;br /&gt;
&lt;br /&gt;
* '''gui.widget.clear_items'''(''widget'')&lt;br /&gt;
* ''widget'':'''clear_items'''()&lt;br /&gt;
&lt;br /&gt;
Removes all elements of a container type widget.&lt;br /&gt;
&lt;br /&gt;
=== find ===&lt;br /&gt;
&lt;br /&gt;
* '''gui.widget.find'''(''root widget'', ...)&lt;br /&gt;
* ''widget'':'''find'''(...)&lt;br /&gt;
&lt;br /&gt;
Finds a child widget of the widget of the given path. For example, here it searches for the widget with the id 'preview_panel' of the second item of the widget with the id 'unit_list':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
dialog:find('unit_list', 2, 'preview_panel')&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is more or less equivalent to the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
dialog.unit_list[2].preview_panel&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However, if the path comes from a variable, the functional form may be more convenient:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
dialog:find(table.unpack(path))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== close ===&lt;br /&gt;
&lt;br /&gt;
* '''gui.widget.close'''(''dialog'')&lt;br /&gt;
* ''widget'':'''close'''()&lt;br /&gt;
&lt;br /&gt;
Closes the dialog.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&amp;diff=74834</id>
		<title>LuaAPI/types/widget</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&amp;diff=74834"/>
		<updated>2026-02-16T03:43:51Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Widget Callbacks */ Capitalization&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;tright&amp;quot;&amp;gt; __TOC__ &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''widget''' userdata offers access to a widget of a GUI2 dialog. While there is only one type of widget userdata that covers all widgets including the window itself, the properties of a widget userdata are different for each type of widget. Indexing a widget's userdata can either be used to access a child widget or to set or get a property of a widget. Some properties are read-only or write-only; the properties depend on the type of the widget.&lt;br /&gt;
&lt;br /&gt;
An example of accessing a child widget:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
function preshow(dialog)&lt;br /&gt;
  local okay_button = dialog.okay_button&lt;br /&gt;
  -- okay_button is now a handle to the the widget's child with the id 'okay_button' &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Widget Attributes ==&lt;br /&gt;
&lt;br /&gt;
=== selected ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected''' &amp;amp;harr; ''boolean''&lt;br /&gt;
* Available on: '''[toggle_button]''', '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
Whether the item is selected or not. Note that this should only be used for widgets that have only 2 states. In particular, there exist 3-State toggle_buttons (for example in listbox headers). For those, selected_index must be used instead.&lt;br /&gt;
&lt;br /&gt;
=== selected_index ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected_index''' &amp;amp;harr; ''index''&lt;br /&gt;
* Available on: '''[listbox]''', '''[multi_page]''', '''[stacked_widget]''', '''[menu_button]''', '''[toggle_button]''', '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
The selected index of the item. For '''[toggle_button]''' and '''[toggle_panel]''', this is the same as '''selected''' only encoded as a number (1 for false or 2 for true) instead of a boolean.&lt;br /&gt;
&lt;br /&gt;
For a  '''[listbox]'''with '''has_maximum=false''' and more than one item selected, reading '''selected_index''' will return the first selected index.&lt;br /&gt;
&lt;br /&gt;
For a '''[stacked_widget]''', only the layer specified by '''selected_index''' will be displayed and receive events (callbacks will only be triggered on the selected layer).&lt;br /&gt;
A '''selected_index''' of 0 represents all layers being selected, with events only being received by the layer with the highest index.  Note that term ''selected'' for the ''layer'' of a stacked_widget is not the same as the '''selected''' ''widget'' attribute.&lt;br /&gt;
&lt;br /&gt;
=== text ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''text''' &amp;amp;harr; ''text''&lt;br /&gt;
* Available on: '''[text_box]'''&lt;br /&gt;
&lt;br /&gt;
The text of the textbox.&lt;br /&gt;
&lt;br /&gt;
=== value ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''value''' &amp;amp;harr; ''position''&lt;br /&gt;
* Available on: '''[slider]'''&lt;br /&gt;
&lt;br /&gt;
The current position of the slider.&lt;br /&gt;
&lt;br /&gt;
=== percentage ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''percentage''' &amp;amp;harr; ''position''&lt;br /&gt;
* Available on: '''[progress_bar]'''&lt;br /&gt;
&lt;br /&gt;
The current position of the progress bar, between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
=== selected_item_path ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected_item_path''' &amp;amp;rarr; ''array of indices''&lt;br /&gt;
* Available on: '''[tree_view]'''&lt;br /&gt;
&lt;br /&gt;
A table describing the currently selected node. If for example, in the following treeview, Item 9 is selected, the result will be {2,1,3}.&lt;br /&gt;
&lt;br /&gt;
 +Section1&lt;br /&gt;
  +Subsection11&lt;br /&gt;
   *Item1&lt;br /&gt;
   *Item2&lt;br /&gt;
   *Item3&lt;br /&gt;
  +Subsection12&lt;br /&gt;
   *Item4&lt;br /&gt;
   *Item5&lt;br /&gt;
   *Item6&lt;br /&gt;
 +Section2&lt;br /&gt;
  +Subsection21&lt;br /&gt;
   *Item7&lt;br /&gt;
   *Item8&lt;br /&gt;
   *Item9&lt;br /&gt;
  +Subsection22&lt;br /&gt;
   *Item10&lt;br /&gt;
   *Item11&lt;br /&gt;
   *Item12&lt;br /&gt;
&lt;br /&gt;
=== path ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''path''' &amp;amp;rarr; ''array of indices''&lt;br /&gt;
* Available on: '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
A table describing this node in the overall treeview. See [[#selected_item_path|selected_item_path]] for the meaning of the table..&lt;br /&gt;
&lt;br /&gt;
=== unfolded ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''unfolded''' &amp;amp;larr; ''boolean''&lt;br /&gt;
* Available on: '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
Control whether a tree node is currently expanded or not.&lt;br /&gt;
&lt;br /&gt;
=== unit ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''unit''' &amp;amp;larr; ''unit or unit type''&lt;br /&gt;
* Available on: '''[unit_preview_pane]'''&lt;br /&gt;
&lt;br /&gt;
Change the displayed unit or unit type in the preview pane.&lt;br /&gt;
&lt;br /&gt;
=== item_count ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''item_count''' &amp;amp;rarr; ''number of items''&lt;br /&gt;
* Available on: '''[multi_page]''', '''[listbox]'''&lt;br /&gt;
&lt;br /&gt;
The number of items in the container widget.&lt;br /&gt;
&lt;br /&gt;
=== use_markup ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''use_markup''' &amp;amp;rarr; ''boolean''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]'''&lt;br /&gt;
&lt;br /&gt;
Sets whether the widget's label will parse [[Pango formatting]].&lt;br /&gt;
&lt;br /&gt;
=== label ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''label''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]''', '''[image]'''&lt;br /&gt;
&lt;br /&gt;
The widget's label. Technically this is a special string used in the widget's wml definition. It usually does what one would expect, but also sets the image for '''image''' widgets.  For '''[text_box]''', use '''text''' for initial values.&lt;br /&gt;
&lt;br /&gt;
=== marked_up_text ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''marked_up_text''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]'''&lt;br /&gt;
&lt;br /&gt;
Shortcut for setting label and use_markup=yes.&lt;br /&gt;
&lt;br /&gt;
=== enabled ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''enabled''' &amp;amp;larr; ''boolean''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
=== tooltip ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''tooltip''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
=== visible ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''visible''' &amp;amp;larr; ''visibility string''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
Determines whether the widget is visible onscreen. The following visibility statuses are recognized:&lt;br /&gt;
{| clasS=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! String value !! Boolean shorthand !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| visible || true || The widget is visible and handles events.&lt;br /&gt;
|-&lt;br /&gt;
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.&lt;br /&gt;
|-&lt;br /&gt;
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== type ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''type''' &amp;amp;rarr; ''string''&lt;br /&gt;
* Available on: All widgets&lt;br /&gt;
&lt;br /&gt;
Returns a string specifying the type of the widget.&lt;br /&gt;
&lt;br /&gt;
== Widget Callbacks ==&lt;br /&gt;
&lt;br /&gt;
=== on_modified ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_modified''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: Most widgets, in particular '''[slider]''', '''[toggle_button]''', '''[listbox]''', '''[menu_button]''', '''[text_box]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user changes the value of the widget.&lt;br /&gt;
&lt;br /&gt;
=== on_left_click ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_left_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: All widgets&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on the widget.&lt;br /&gt;
&lt;br /&gt;
=== on_double_click ===&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_double_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user double clicks on the widget. Non-toggle panel widgets can be wrapped in a toggle panel to make use of this event handler.&lt;br /&gt;
&lt;br /&gt;
=== on_button_click ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_button_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: '''[button]''', '''[repeating_button]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on the button. This can differ from '''on_left_click''', depending on the type of widget. For example, on a '''[repeating_button]''' it will fire multiple times if the user holds the mouse button down.&lt;br /&gt;
&lt;br /&gt;
=== on_link_click ===&lt;br /&gt;
{{DevFeature1.19|9}}&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_link_click''' &amp;amp;larr; '''function'''(''dest'')&lt;br /&gt;
* Available on: '''[rich_label]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on a '''&amp;lt;ref&amp;gt;''' link inside a '''[rich_label]'''. The first argument '''dest''' is the target of the link.&lt;br /&gt;
&lt;br /&gt;
== Widget Length ==&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* '''#'''''widget''&lt;br /&gt;
* Available on: '''[listbox]''', '''[multi_page]''', '''[tree_view]''', '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
Returns the total number of children in the specified container widget – for example, the number of rows in a list box, or the number of pages in a multi-page.&lt;br /&gt;
&lt;br /&gt;
== Widget Methods ==&lt;br /&gt;
&lt;br /&gt;
Any function defined in the [[LuaAPI/gui/widget|gui.widget]] module and taking a widget as its first parameter can be called as a method of a widget. This includes any functions that are added to the module by user code. Note that these methods are available even if the widget itself doesn't support that function, so in some cases it may be necessary to check '''widget.type''' before calling the method.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&amp;diff=74833</id>
		<title>LuaAPI/types/widget</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&amp;diff=74833"/>
		<updated>2026-02-16T03:43:39Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Widget Methods */ Capitalization&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;tright&amp;quot;&amp;gt; __TOC__ &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''widget''' userdata offers access to a widget of a GUI2 dialog. While there is only one type of widget userdata that covers all widgets including the window itself, the properties of a widget userdata are different for each type of widget. Indexing a widget's userdata can either be used to access a child widget or to set or get a property of a widget. Some properties are read-only or write-only; the properties depend on the type of the widget.&lt;br /&gt;
&lt;br /&gt;
An example of accessing a child widget:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
function preshow(dialog)&lt;br /&gt;
  local okay_button = dialog.okay_button&lt;br /&gt;
  -- okay_button is now a handle to the the widget's child with the id 'okay_button' &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Widget Attributes ==&lt;br /&gt;
&lt;br /&gt;
=== selected ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected''' &amp;amp;harr; ''boolean''&lt;br /&gt;
* Available on: '''[toggle_button]''', '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
Whether the item is selected or not. Note that this should only be used for widgets that have only 2 states. In particular, there exist 3-State toggle_buttons (for example in listbox headers). For those, selected_index must be used instead.&lt;br /&gt;
&lt;br /&gt;
=== selected_index ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected_index''' &amp;amp;harr; ''index''&lt;br /&gt;
* Available on: '''[listbox]''', '''[multi_page]''', '''[stacked_widget]''', '''[menu_button]''', '''[toggle_button]''', '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
The selected index of the item. For '''[toggle_button]''' and '''[toggle_panel]''', this is the same as '''selected''' only encoded as a number (1 for false or 2 for true) instead of a boolean.&lt;br /&gt;
&lt;br /&gt;
For a  '''[listbox]'''with '''has_maximum=false''' and more than one item selected, reading '''selected_index''' will return the first selected index.&lt;br /&gt;
&lt;br /&gt;
For a '''[stacked_widget]''', only the layer specified by '''selected_index''' will be displayed and receive events (callbacks will only be triggered on the selected layer).&lt;br /&gt;
A '''selected_index''' of 0 represents all layers being selected, with events only being received by the layer with the highest index.  Note that term ''selected'' for the ''layer'' of a stacked_widget is not the same as the '''selected''' ''widget'' attribute.&lt;br /&gt;
&lt;br /&gt;
=== text ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''text''' &amp;amp;harr; ''text''&lt;br /&gt;
* Available on: '''[text_box]'''&lt;br /&gt;
&lt;br /&gt;
The text of the textbox.&lt;br /&gt;
&lt;br /&gt;
=== value ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''value''' &amp;amp;harr; ''position''&lt;br /&gt;
* Available on: '''[slider]'''&lt;br /&gt;
&lt;br /&gt;
The current position of the slider.&lt;br /&gt;
&lt;br /&gt;
=== percentage ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''percentage''' &amp;amp;harr; ''position''&lt;br /&gt;
* Available on: '''[progress_bar]'''&lt;br /&gt;
&lt;br /&gt;
The current position of the progress bar, between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
=== selected_item_path ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected_item_path''' &amp;amp;rarr; ''array of indices''&lt;br /&gt;
* Available on: '''[tree_view]'''&lt;br /&gt;
&lt;br /&gt;
A table describing the currently selected node. If for example, in the following treeview, Item 9 is selected, the result will be {2,1,3}.&lt;br /&gt;
&lt;br /&gt;
 +Section1&lt;br /&gt;
  +Subsection11&lt;br /&gt;
   *Item1&lt;br /&gt;
   *Item2&lt;br /&gt;
   *Item3&lt;br /&gt;
  +Subsection12&lt;br /&gt;
   *Item4&lt;br /&gt;
   *Item5&lt;br /&gt;
   *Item6&lt;br /&gt;
 +Section2&lt;br /&gt;
  +Subsection21&lt;br /&gt;
   *Item7&lt;br /&gt;
   *Item8&lt;br /&gt;
   *Item9&lt;br /&gt;
  +Subsection22&lt;br /&gt;
   *Item10&lt;br /&gt;
   *Item11&lt;br /&gt;
   *Item12&lt;br /&gt;
&lt;br /&gt;
=== path ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''path''' &amp;amp;rarr; ''array of indices''&lt;br /&gt;
* Available on: '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
A table describing this node in the overall treeview. See [[#selected_item_path|selected_item_path]] for the meaning of the table..&lt;br /&gt;
&lt;br /&gt;
=== unfolded ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''unfolded''' &amp;amp;larr; ''boolean''&lt;br /&gt;
* Available on: '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
Control whether a tree node is currently expanded or not.&lt;br /&gt;
&lt;br /&gt;
=== unit ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''unit''' &amp;amp;larr; ''unit or unit type''&lt;br /&gt;
* Available on: '''[unit_preview_pane]'''&lt;br /&gt;
&lt;br /&gt;
Change the displayed unit or unit type in the preview pane.&lt;br /&gt;
&lt;br /&gt;
=== item_count ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''item_count''' &amp;amp;rarr; ''number of items''&lt;br /&gt;
* Available on: '''[multi_page]''', '''[listbox]'''&lt;br /&gt;
&lt;br /&gt;
The number of items in the container widget.&lt;br /&gt;
&lt;br /&gt;
=== use_markup ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''use_markup''' &amp;amp;rarr; ''boolean''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]'''&lt;br /&gt;
&lt;br /&gt;
Sets whether the widget's label will parse [[Pango formatting]].&lt;br /&gt;
&lt;br /&gt;
=== label ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''label''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]''', '''[image]'''&lt;br /&gt;
&lt;br /&gt;
The widget's label. Technically this is a special string used in the widget's wml definition. It usually does what one would expect, but also sets the image for '''image''' widgets.  For '''[text_box]''', use '''text''' for initial values.&lt;br /&gt;
&lt;br /&gt;
=== marked_up_text ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''marked_up_text''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]'''&lt;br /&gt;
&lt;br /&gt;
Shortcut for setting label and use_markup=yes.&lt;br /&gt;
&lt;br /&gt;
=== enabled ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''enabled''' &amp;amp;larr; ''boolean''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
=== tooltip ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''tooltip''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
=== visible ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''visible''' &amp;amp;larr; ''visibility string''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
Determines whether the widget is visible onscreen. The following visibility statuses are recognized:&lt;br /&gt;
{| clasS=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! String value !! Boolean shorthand !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| visible || true || The widget is visible and handles events.&lt;br /&gt;
|-&lt;br /&gt;
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.&lt;br /&gt;
|-&lt;br /&gt;
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== type ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''type''' &amp;amp;rarr; ''string''&lt;br /&gt;
* Available on: All widgets&lt;br /&gt;
&lt;br /&gt;
Returns a string specifying the type of the widget.&lt;br /&gt;
&lt;br /&gt;
== Widget callbacks ==&lt;br /&gt;
&lt;br /&gt;
=== on_modified ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_modified''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: Most widgets, in particular '''[slider]''', '''[toggle_button]''', '''[listbox]''', '''[menu_button]''', '''[text_box]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user changes the value of the widget.&lt;br /&gt;
&lt;br /&gt;
=== on_left_click ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_left_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: All widgets&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on the widget.&lt;br /&gt;
&lt;br /&gt;
=== on_double_click ===&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_double_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user double clicks on the widget. Non-toggle panel widgets can be wrapped in a toggle panel to make use of this event handler.&lt;br /&gt;
&lt;br /&gt;
=== on_button_click ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_button_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: '''[button]''', '''[repeating_button]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on the button. This can differ from '''on_left_click''', depending on the type of widget. For example, on a '''[repeating_button]''' it will fire multiple times if the user holds the mouse button down.&lt;br /&gt;
&lt;br /&gt;
=== on_link_click ===&lt;br /&gt;
{{DevFeature1.19|9}}&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_link_click''' &amp;amp;larr; '''function'''(''dest'')&lt;br /&gt;
* Available on: '''[rich_label]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on a '''&amp;lt;ref&amp;gt;''' link inside a '''[rich_label]'''. The first argument '''dest''' is the target of the link.&lt;br /&gt;
&lt;br /&gt;
== Widget Length ==&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* '''#'''''widget''&lt;br /&gt;
* Available on: '''[listbox]''', '''[multi_page]''', '''[tree_view]''', '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
Returns the total number of children in the specified container widget – for example, the number of rows in a list box, or the number of pages in a multi-page.&lt;br /&gt;
&lt;br /&gt;
== Widget Methods ==&lt;br /&gt;
&lt;br /&gt;
Any function defined in the [[LuaAPI/gui/widget|gui.widget]] module and taking a widget as its first parameter can be called as a method of a widget. This includes any functions that are added to the module by user code. Note that these methods are available even if the widget itself doesn't support that function, so in some cases it may be necessary to check '''widget.type''' before calling the method.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&amp;diff=74832</id>
		<title>LuaAPI/types/widget</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=LuaAPI/types/widget&amp;diff=74832"/>
		<updated>2026-02-16T03:43:23Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Widget Length */ New section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;tright&amp;quot;&amp;gt; __TOC__ &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''widget''' userdata offers access to a widget of a GUI2 dialog. While there is only one type of widget userdata that covers all widgets including the window itself, the properties of a widget userdata are different for each type of widget. Indexing a widget's userdata can either be used to access a child widget or to set or get a property of a widget. Some properties are read-only or write-only; the properties depend on the type of the widget.&lt;br /&gt;
&lt;br /&gt;
An example of accessing a child widget:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
function preshow(dialog)&lt;br /&gt;
  local okay_button = dialog.okay_button&lt;br /&gt;
  -- okay_button is now a handle to the the widget's child with the id 'okay_button' &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Widget Attributes ==&lt;br /&gt;
&lt;br /&gt;
=== selected ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected''' &amp;amp;harr; ''boolean''&lt;br /&gt;
* Available on: '''[toggle_button]''', '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
Whether the item is selected or not. Note that this should only be used for widgets that have only 2 states. In particular, there exist 3-State toggle_buttons (for example in listbox headers). For those, selected_index must be used instead.&lt;br /&gt;
&lt;br /&gt;
=== selected_index ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected_index''' &amp;amp;harr; ''index''&lt;br /&gt;
* Available on: '''[listbox]''', '''[multi_page]''', '''[stacked_widget]''', '''[menu_button]''', '''[toggle_button]''', '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
The selected index of the item. For '''[toggle_button]''' and '''[toggle_panel]''', this is the same as '''selected''' only encoded as a number (1 for false or 2 for true) instead of a boolean.&lt;br /&gt;
&lt;br /&gt;
For a  '''[listbox]'''with '''has_maximum=false''' and more than one item selected, reading '''selected_index''' will return the first selected index.&lt;br /&gt;
&lt;br /&gt;
For a '''[stacked_widget]''', only the layer specified by '''selected_index''' will be displayed and receive events (callbacks will only be triggered on the selected layer).&lt;br /&gt;
A '''selected_index''' of 0 represents all layers being selected, with events only being received by the layer with the highest index.  Note that term ''selected'' for the ''layer'' of a stacked_widget is not the same as the '''selected''' ''widget'' attribute.&lt;br /&gt;
&lt;br /&gt;
=== text ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''text''' &amp;amp;harr; ''text''&lt;br /&gt;
* Available on: '''[text_box]'''&lt;br /&gt;
&lt;br /&gt;
The text of the textbox.&lt;br /&gt;
&lt;br /&gt;
=== value ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''value''' &amp;amp;harr; ''position''&lt;br /&gt;
* Available on: '''[slider]'''&lt;br /&gt;
&lt;br /&gt;
The current position of the slider.&lt;br /&gt;
&lt;br /&gt;
=== percentage ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''percentage''' &amp;amp;harr; ''position''&lt;br /&gt;
* Available on: '''[progress_bar]'''&lt;br /&gt;
&lt;br /&gt;
The current position of the progress bar, between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
=== selected_item_path ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''selected_item_path''' &amp;amp;rarr; ''array of indices''&lt;br /&gt;
* Available on: '''[tree_view]'''&lt;br /&gt;
&lt;br /&gt;
A table describing the currently selected node. If for example, in the following treeview, Item 9 is selected, the result will be {2,1,3}.&lt;br /&gt;
&lt;br /&gt;
 +Section1&lt;br /&gt;
  +Subsection11&lt;br /&gt;
   *Item1&lt;br /&gt;
   *Item2&lt;br /&gt;
   *Item3&lt;br /&gt;
  +Subsection12&lt;br /&gt;
   *Item4&lt;br /&gt;
   *Item5&lt;br /&gt;
   *Item6&lt;br /&gt;
 +Section2&lt;br /&gt;
  +Subsection21&lt;br /&gt;
   *Item7&lt;br /&gt;
   *Item8&lt;br /&gt;
   *Item9&lt;br /&gt;
  +Subsection22&lt;br /&gt;
   *Item10&lt;br /&gt;
   *Item11&lt;br /&gt;
   *Item12&lt;br /&gt;
&lt;br /&gt;
=== path ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''path''' &amp;amp;rarr; ''array of indices''&lt;br /&gt;
* Available on: '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
A table describing this node in the overall treeview. See [[#selected_item_path|selected_item_path]] for the meaning of the table..&lt;br /&gt;
&lt;br /&gt;
=== unfolded ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''unfolded''' &amp;amp;larr; ''boolean''&lt;br /&gt;
* Available on: '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
Control whether a tree node is currently expanded or not.&lt;br /&gt;
&lt;br /&gt;
=== unit ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''unit''' &amp;amp;larr; ''unit or unit type''&lt;br /&gt;
* Available on: '''[unit_preview_pane]'''&lt;br /&gt;
&lt;br /&gt;
Change the displayed unit or unit type in the preview pane.&lt;br /&gt;
&lt;br /&gt;
=== item_count ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''item_count''' &amp;amp;rarr; ''number of items''&lt;br /&gt;
* Available on: '''[multi_page]''', '''[listbox]'''&lt;br /&gt;
&lt;br /&gt;
The number of items in the container widget.&lt;br /&gt;
&lt;br /&gt;
=== use_markup ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''use_markup''' &amp;amp;rarr; ''boolean''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]'''&lt;br /&gt;
&lt;br /&gt;
Sets whether the widget's label will parse [[Pango formatting]].&lt;br /&gt;
&lt;br /&gt;
=== label ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''label''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]''', '''[image]'''&lt;br /&gt;
&lt;br /&gt;
The widget's label. Technically this is a special string used in the widget's wml definition. It usually does what one would expect, but also sets the image for '''image''' widgets.  For '''[text_box]''', use '''text''' for initial values.&lt;br /&gt;
&lt;br /&gt;
=== marked_up_text ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''marked_up_text''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets, in particular '''[label]''', '''[button]'''&lt;br /&gt;
&lt;br /&gt;
Shortcut for setting label and use_markup=yes.&lt;br /&gt;
&lt;br /&gt;
=== enabled ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''enabled''' &amp;amp;larr; ''boolean''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
=== tooltip ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''tooltip''' &amp;amp;larr; ''text''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
=== visible ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''visible''' &amp;amp;larr; ''visibility string''&lt;br /&gt;
* Available on: Most widgets&lt;br /&gt;
&lt;br /&gt;
Determines whether the widget is visible onscreen. The following visibility statuses are recognized:&lt;br /&gt;
{| clasS=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! String value !! Boolean shorthand !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| visible || true || The widget is visible and handles events.&lt;br /&gt;
|-&lt;br /&gt;
| hidden || || The widget is not visible, doesn't handle events, but still takes up space on the dialog grid.&lt;br /&gt;
|-&lt;br /&gt;
| invisible || false || The widget is not visible, doesn't handle events, and does not take up space on the dialog grid.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== type ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''type''' &amp;amp;rarr; ''string''&lt;br /&gt;
* Available on: All widgets&lt;br /&gt;
&lt;br /&gt;
Returns a string specifying the type of the widget.&lt;br /&gt;
&lt;br /&gt;
== Widget callbacks ==&lt;br /&gt;
&lt;br /&gt;
=== on_modified ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_modified''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: Most widgets, in particular '''[slider]''', '''[toggle_button]''', '''[listbox]''', '''[menu_button]''', '''[text_box]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user changes the value of the widget.&lt;br /&gt;
&lt;br /&gt;
=== on_left_click ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_left_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: All widgets&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on the widget.&lt;br /&gt;
&lt;br /&gt;
=== on_double_click ===&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_double_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: '''[toggle_panel]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user double clicks on the widget. Non-toggle panel widgets can be wrapped in a toggle panel to make use of this event handler.&lt;br /&gt;
&lt;br /&gt;
=== on_button_click ===&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_button_click''' &amp;amp;larr; '''function'''()&lt;br /&gt;
* Available on: '''[button]''', '''[repeating_button]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on the button. This can differ from '''on_left_click''', depending on the type of widget. For example, on a '''[repeating_button]''' it will fire multiple times if the user holds the mouse button down.&lt;br /&gt;
&lt;br /&gt;
=== on_link_click ===&lt;br /&gt;
{{DevFeature1.19|9}}&lt;br /&gt;
&lt;br /&gt;
* ''widget''.'''on_link_click''' &amp;amp;larr; '''function'''(''dest'')&lt;br /&gt;
* Available on: '''[rich_label]'''&lt;br /&gt;
&lt;br /&gt;
Triggers when the user clicks on a '''&amp;lt;ref&amp;gt;''' link inside a '''[rich_label]'''. The first argument '''dest''' is the target of the link.&lt;br /&gt;
&lt;br /&gt;
== Widget Length ==&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* '''#'''''widget''&lt;br /&gt;
* Available on: '''[listbox]''', '''[multi_page]''', '''[tree_view]''', '''[tree_view_node]'''&lt;br /&gt;
&lt;br /&gt;
Returns the total number of children in the specified container widget – for example, the number of rows in a list box, or the number of pages in a multi-page.&lt;br /&gt;
&lt;br /&gt;
== Widget methods ==&lt;br /&gt;
&lt;br /&gt;
Any function defined in the [[LuaAPI/gui/widget|gui.widget]] module and taking a widget as its first parameter can be called as a method of a widget. This includes any functions that are added to the module by user code. Note that these methods are available even if the widget itself doesn't support that function, so in some cases it may be necessary to check '''widget.type''' before calling the method.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=AbilitiesWML&amp;diff=74819</id>
		<title>AbilitiesWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=AbilitiesWML&amp;diff=74819"/>
		<updated>2026-02-11T05:35:28Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Common keys and tags for every weapon special */ Link to the section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
==  Abilities and their effects ==&lt;br /&gt;
&lt;br /&gt;
There are two types of abilities: ones that apply to units (called ''abilities'') and ones that only apply when using a particular attack (called ''specials'' or ''weapon specials'').  A unit may have multiple abilities and an attack can have multiple specials.&lt;br /&gt;
&lt;br /&gt;
Each ability or special defines an effect based on one to three units. Most abilities apply to a single unit, and '''[filter_self]''' can be used to determine when the ability is active. Weapon specials apply to two units, which can be filtered either as &amp;quot;attacker&amp;quot; and &amp;quot;defender&amp;quot; (with the obvious meaning) or as &amp;quot;self&amp;quot; and &amp;quot;other&amp;quot; – the unit that possesses the special, and that unit's opponent. When filtering on the &amp;quot;other&amp;quot; unit, you use '''[filter_opponent]'''.&lt;br /&gt;
&lt;br /&gt;
Leadership-style abilities are a more complex case, as they involve three units. Like a weapon special, there is an attacker and defender, but there is also a third unit that could be referred to as the &amp;quot;teacher&amp;quot;. The &amp;quot;teacher&amp;quot; is the unit that possesses the ability, so it is referred to as &amp;quot;self&amp;quot; in the ability. A leadership ability works by temporarily granting a weapon special to either the attacker or the defender. The unit that benefits from this is referred to as the &amp;quot;student&amp;quot;, while the unit that does not benefit is simply the &amp;quot;other&amp;quot; unit. When filtering on the &amp;quot;other&amp;quot; unit, you use '''[filter_opponent]''', while the student can be filtered with '''[filter_student]'''.&lt;br /&gt;
&lt;br /&gt;
== The ''[abilities]'' tag ==&lt;br /&gt;
&lt;br /&gt;
The following tags are used to describe an ability in WML:&lt;br /&gt;
&lt;br /&gt;
* '''[heals]''': modifies the hitpoints of a unit at the beginning of the healer's turn&lt;br /&gt;
* '''[regenerate]''': modifies the hitpoints of a unit at the beginning of the unit's turn&lt;br /&gt;
* '''[resistance]''': modifies the resistance of a unit to damage&lt;br /&gt;
* '''[leadership]''': modifies the damage of a unit&lt;br /&gt;
* '''[skirmisher]''': negates enemy zones of control&lt;br /&gt;
* '''[illuminates]''': modifies the time of day adjacent to the affected units&lt;br /&gt;
* '''[teleport]''': allows the unit to teleport&lt;br /&gt;
* '''[hides]''': renders the unit invisible to enemies&lt;br /&gt;
* {{DevFeature1.15|0}} All [[#The_.5Bspecials.5D_tag|weapon specials]] except for '''[plague]''', '''[heal_on_hit]''', and '''[swarm]''' can be placed in the '''[abilities]''' tag. These [[#Extra_tags_and_keys_used_by_weapon_specials_as_abilities|&amp;quot;weapon specials as abilities&amp;quot;]] will give the weapon special to all attacks the unit has.&lt;br /&gt;
* '''[defense]''' {{DevFeature1.19|16}}: modifies the chances of being hit by the opponent's weapon, this value can be modified by the parry attribute, the accuracy attribute of the opponent's weapon, or by their special weapon '''[chance_to_hit]'''. Be careful, the more you increase the value, the less chance the opponent has of hitting you. Using same standard numerical attributes as '''[attacks]''' .&lt;br /&gt;
* Any other tag is valid (for example '''[dummy]'''), but will result in an ability that does nothing but report it's there. '''Note:''' a dummy ability must have an id for the name and description to display.&lt;br /&gt;
* {{DevFeature1.15|3}} All the engine [[#The_.5Bspecials.5D_tag|weapon specials]] can be placed in the [abilities] tag now.&lt;br /&gt;
&lt;br /&gt;
=== Available formula variables in Abilities and Weapon Specials  ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|?}} When using formulas in abilities and weapon specials, the following formula variables are available:&lt;br /&gt;
* '''self''': (unit) the unit that has the ability&lt;br /&gt;
* '''student''': (unit) for leadership-like abilities this is the unit that is adjacent to the unit that has the ability; if affect_self=yes, this is also unit who has ability.&lt;br /&gt;
* '''attacker''': (unit) for attack-related abilities and weapon specials, this is the attacking unit during the attack.&lt;br /&gt;
* '''defender''': (unit) for attack-related abilities and weapon specials, this is the defending unit during the attack.&lt;br /&gt;
* '''other''': (unit) the unit whose stats get modified from the ability. For abilities without 'apply_to=opponent' this is always the same as 'student'.&lt;br /&gt;
&lt;br /&gt;
=== Common keys and tags for every ability ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|?}} All keys inside any ability that expects a numeric value will also accept formulas using &lt;br /&gt;
[[Wesnoth Formula Language]]. In order to use a formula in these keys, you must enclose it in parentheses. However, do '''not''' precede those parentheses with a dollar sign like &amp;lt;code&amp;gt;$(...)&amp;lt;/code&amp;gt;, since that will erase the &amp;lt;tt&amp;gt;self&amp;lt;/tt&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the (translatable) name of the ability. If omitted, the ability will be a hidden ability.&lt;br /&gt;
* '''female_name''': the (translatable) name of the ability when possessed by a female unit. Defaults to ''name'' if not specified.&lt;br /&gt;
* '''name_inactive''': the (translatable) name of the ability when inactive. Defaults to ''name'' if not specified; if the ability is supposed to be not displayed when inactive, you must explicitly set ''name_inactive'' to an empty string (nothing after the equals sign).&lt;br /&gt;
* '''female_name_inactive''': the (translatable) name of the ability when inactive and possessed by a female unit. Defaults to ''name_inactive'' if not specified. You should thus set ''female_name'' as well!&lt;br /&gt;
* '''description''': the (translatable) description of the ability.&lt;br /&gt;
* '''description_inactive''': the (translatable) description of the ability when inactive. Defaults to ''description'' if not specified.&lt;br /&gt;
* '''special_note''' {{DevFeature1.15|14}} Translatable string, which will be displayed in the unit’s help. See also [[UnitTypeWML#Special_Notes]].&lt;br /&gt;
* '''affect_self''': if equal to 'yes' (default), the ability will affect the unit that has it.&lt;br /&gt;
* '''affect_allies''': if equal to 'yes', the ability will affect units from the same and allied sides in the specified adjacent hexes. If set to 'no' it will not affect own or allied sides. If not set (default) it will affect units on the same side but not from allied sides.&lt;br /&gt;
* '''affect_enemies''': if equal to 'yes' (default is 'no'), the ability will affect enemies in the specified adjacent hexes.&lt;br /&gt;
* '''id''': this ability will not be cumulative with other abilities using this id. Must be present if cumulative is anything other than 'yes'.&lt;br /&gt;
* '''unique_id''': {{DevFeature1.19|18}} A unique identifier for this ability, used for the registry under [[UnitsWML#.5Babilities.5D|[units][abilities]]]. If not defined, falls back to '''id'''. Used to add this ability via '''abilities_list''' key in '''[unit_type]''' or '''[effect]apply_to=new_ability'''.&lt;br /&gt;
* '''halo_image''': {{DevFeature1.17|22}} if used, the halo specified showed on unit affected by ability.&lt;br /&gt;
* '''overlay_image''': {{DevFeature1.17|22}} if used, the overlay specified showed on unit affected by ability.&lt;br /&gt;
* '''halo_image_self''': {{DevFeature1.17|22}} if used, the halo specified showed on unit who has ability when active.&lt;br /&gt;
* '''overlay_image_self''': {{DevFeature1.17|22}} if used, the overlay specified showed on unit who has ability when active.&lt;br /&gt;
* '''[filter]''': [[StandardUnitFilter]] If the unit owning the ability does not match this filter, the ability will be inactive.&lt;br /&gt;
* {{anchor|affect_adjacent|'''[affect_adjacent]'''}}: an adjacent unit that does not match this filter will not receive its effects. There can be multiple [affect_adjacent] tags in a single ability; a unit needs to match any one of these to receive the effects. The side requirement of matching units is defined by the '''affect_allies''' and '''affect_enemies''' keys. If there are no [affect_adjacent] tags, then no adjacent units will receive the effects.&lt;br /&gt;
** '''adjacent''': a comma separated list of any combination of these directions: '''n''','''ne''','''se''','''s''','''sw''','''nw'''. (See [[StandardLocationFilter#Directions|notes]])&lt;br /&gt;
** '''[filter]''': a [[StandardUnitFilter]]. {{DevFeature1.13|2}} The variable $other_unit refers to the unit owning the ability.&lt;br /&gt;
** '''radius''': {{DevFeature1.19|13}} set to 1 by default, it determines the range within which units can be affected beyond immediately adjacent units, if the value is equal to 'full-map', the area is the entire map.&lt;br /&gt;
* '''[filter_self]''': if the owner of the ability does not match this filter, it will not receive the effects of the ability. [filter_self] takes a [[StandardUnitFilter]] as argument.&lt;br /&gt;
* '''[filter_adjacent]''': if an adjacent unit does not match this filter, the ability will not be active and no-one will receive its affects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). In fact, it's really a shorthand for a [filter_adjacent] nested within [filter]. The variables $this_unit and {{DevFeature1.13|2}} $other_unit both work as you'd expect. Multiple [filter_adjacent] can be provided, all of which must pass for the ability to activate. {{DevFeature1.19|18}} '''filter_adjacent''' is deprecated and will likely be removed in version 1.21, since a version already exists in the [[StandardUnitFilter]].&lt;br /&gt;
* '''[filter_adjacent_location]''': like [filter_adjacent], but filters on locations instead of units. This is a shorthand for [filter][filter_location][filter_adjacent_location]. {{DevFeature1.19|18}} '''filter_adjacent_location''' is deprecated and will likely be removed in version 1.21, since a version already exists in the [[StandardUnitFilter]].&lt;br /&gt;
* {{anchor|filter_base_value|'''[filter_base_value]'''}}: filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', etc. If several keys are used all have to match.&lt;br /&gt;
* '''[event]''': [[EventWML]]. {{DevFeature1.19|4}} An [event] to be included into any scenario where a unit with this ability appears in. Note that such events get included when a unit with this ability first appears in the scenario, not automatically when the scenario begins (meaning that ''name=prestart'' events, for example, would usually never trigger). See [[WML_Abilities|WML Abilities]]. Shortcut of [unit_type][event].&lt;br /&gt;
&lt;br /&gt;
=== Common keys and tags for abilities with a value ===&lt;br /&gt;
&lt;br /&gt;
The '''[leadership]''', '''[heals]''', '''[regenerate]''',and '''[illuminates]''' abilities take values that specify how those abilities modify their respective base values.&lt;br /&gt;
&lt;br /&gt;
* '''value''': the value to be used. Available inside translatable strings as '''$value'''.&lt;br /&gt;
* '''add''': the number to add to the base value. Note the interaction with '''sub''' in [[#Common_calculations]]. Available inside translatable strings as '''$add'''.&lt;br /&gt;
* '''sub''': the number to subtract from the base value. Available inside translatable strings as '''$sub'''.&lt;br /&gt;
* '''multiply''': this multiplies the base value. Available inside translatable strings as '''$multiply'''.&lt;br /&gt;
* '''divide''': this divides the base value. Available inside translatable strings as '''$divide'''.&lt;br /&gt;
* '''max_value''': {{DevFeature1.19|2}}  maximum special value. Default: no limit. Available inside translatable strings as '''$max_value'''.&lt;br /&gt;
* '''min_value''': {{DevFeature1.19|2}}  minimum special value. Default: no limit. Available inside translatable strings as '''$min_value'''.&lt;br /&gt;
* '''priority''': {{DevFeature1.19|19}}  This attribute allows a higher-priority ability to use as its base the value returned by a lower-priority ability of the same type; for example a negative priority will cause the value to be calculated before checking whether the mainline marksman ability should override it. The value is arbitrary, but generally -10 is chosen to allow for another (not yet known) ability to be placed in between the known ones. Default: 0.&lt;br /&gt;
* '''cumulative''': if set to 'yes', the [leadership] value will be added to another [leadership] value= same if have same id=, for other abilities, the highest value between value= or base_value will be chosen.&lt;br /&gt;
* '''[filter_base_value]''': filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', '''less_than''', '''greater_than''', '''less_than_equal_to''', '''greater_than_equal_to'''.&lt;br /&gt;
&lt;br /&gt;
==== Common calculations ====&lt;br /&gt;
&lt;br /&gt;
Several abilities and weapon specials take the keys '''add''', '''sub''', '''multiply''' and '''divide'''.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}} '''add''' and '''sub''' work independently.&lt;br /&gt;
&lt;br /&gt;
Prior to 1.19.4:&lt;br /&gt;
&lt;br /&gt;
* If '''add''' and '''sub''' are used in the same ability, the '''add''' is ignored&lt;br /&gt;
* If '''add''' and '''sub''' are used in separate abilities with the same id, or with the default id that's used when no id is specified, then the order in which the abilities are encountered controls the calculation, which may change depending on units' positions on the map.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[heals]'' and ''[regenerate]'' abilities ===&lt;br /&gt;
* '''value''': the amount healed.&lt;br /&gt;
* '''poison''': When the healed unit is poisoned, then unit takes usual poison damage instead. Interaction with poison can be changed with these values:&lt;br /&gt;
** ''cured'' - stops poison damage and heals the poison instead of healing&lt;br /&gt;
** ''slowed'' - stops poison damage instead of healing&lt;br /&gt;
&lt;br /&gt;
* Use common keys and tags for abilities with a value.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys and tags used by the ''[resistance]'' ability ===&lt;br /&gt;
&lt;br /&gt;
* '''value''': set resistance to this value.&lt;br /&gt;
* '''max_value''': maximum resistance value. Default: 0%. {{DevFeature1.17|24}} Default: no limit.&lt;br /&gt;
* '''min_value''': {{DevFeature1.19|0}} minimum resistance value. Default: no limit.&lt;br /&gt;
* Use common keys and tags for abilities with a value&lt;br /&gt;
* '''apply_to''': a list of damage types; if left out, the ability applies to all types.&lt;br /&gt;
* '''active_on''': one of 'defense' or 'offense'; if left out, the ability is active on both.&lt;br /&gt;
These keys affect the actual resistance (e.g. -20%), not the damage modifier normally used in [resistance] (e.g. 120).&lt;br /&gt;
* '''[filter_weapon]''': {{DevFeature1.15|0}} If present, the resistance ability only takes effect when the owner of the ability uses a matching weapon.&lt;br /&gt;
* '''[filter_second_weapon]''': {{DevFeature1.15|0}} If present, the resistance ability only takes effect when the opponent uses a matching weapon.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys and tags used by the ''[defense]'' ability ===&lt;br /&gt;
* '''value''': set defense to this value. Warning, the chance to be hit decrease when value of ability increase.&lt;br /&gt;
* Use common keys and tags for abilities with a value&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[leadership]'' ability ===&lt;br /&gt;
&lt;br /&gt;
* '''value''': the percentage bonus to damage.&lt;br /&gt;
* Use common keys and tags for abilities with a value&lt;br /&gt;
''Note:'' cumulative leadership with '''cumulative=yes''' and '''value=''' doesn't work in 1.16 (but fixed in 1.17.12 and later). To work around use '''add=''' or '''sub=''' key (it doesn't require cumulative) (https://github.com/wesnoth/wesnoth/issues/6466 ). If you want each instance of a ''[leadership]'' with the same id to be added you will be able to reuse '''cumulative=yes''' in 1.17.12 and later, otherwise, if you want to add the value of another ''[leadership]'' only once even with the same id in several copies, use '''add'''.&lt;br /&gt;
* '''[filter_weapon]''': {{DevFeature1.15|0}} If present, the leadership ability only takes effect when the owner of the ability uses a matching weapon.&lt;br /&gt;
* '''[filter_second_weapon]''': {{DevFeature1.15|0}} If present, the leadership ability only takes effect when the opponent uses a matching weapon.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[illuminates]'' ability ===&lt;br /&gt;
&lt;br /&gt;
Because this ability changes the terrain instead of units on it, affect_self, affect_allies, affect_enemies and [filter_adjacent] have no effect. If you use [affect_adjacent] the terrain under and adjacent to adjacent unit will be changed.&lt;br /&gt;
* '''value''': the percentage bonus to lawful units. Units with '''alignment=lawful''' do +''value'' % damage when under the influence of a unit with this ability. Units with '''alignment=chaotic''' do -''value'' % damage. Units with '''alignment=neutral''' are unaffected by this ability. Units with '''alignment=liminal''' do -(abs(''value'')) % damage. ''value'' can be a negative number; this is useful if you want to give Chaotic units an advantage instead of Lawful ones. &lt;br /&gt;
* Use Common keys and tags for abilities with a value&lt;br /&gt;
* '''max_value''': the maximum percentage bonus given. Cannot be less than 0. Defaults to 0 if not present.&lt;br /&gt;
* '''min_value''': the minimum percentage bonus given. Cannot be greater than 0. Defaults to 0 if not present.&lt;br /&gt;
* '''radius''': {{DevFeature1.19|15}} defines the radius of the ability, by default only the terrain the user is on and adjacent hexes are affected, but this can now be extended to a radius defined by '''radius''' ; if '''radius'''=all_map then the whole map will be affected.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[hides]'' ability ===&lt;br /&gt;
&lt;br /&gt;
* '''alert''': the displayed text when the unit is discovered. Default &amp;quot;Ambushed!&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Extra tags used by the ''[teleport]'' ability ===&lt;br /&gt;
&lt;br /&gt;
* '''[tunnel]''' - a [[DirectActionsWML#.5Btunnel.5D|tunnel tag]] (without the remove key) defining the tunneling source and target hexes, and maybe other conditions. (It automatically applies only to the unit with the ability.)  You may use $teleport_unit inside the [tunnel][source] and [tunnel][target] tag for filtering purposes.&lt;br /&gt;
&lt;br /&gt;
=== Extra tags and keys used by weapon specials as abilities ===&lt;br /&gt;
&lt;br /&gt;
* {{anchor|filter_student|'''[filter_student]'''}}: {{DevFeature1.15|0}} If present, only the unit matching this filter, either the possessor of the ability if affect_self=yes, or an adjacent unit matching '''[filter_adjacent]''' will be affected. &lt;br /&gt;
* '''[filter_adjacent_student]''': {{DevFeature1.19|10}} if an adjacent unit to student does not match this filter, the ability will not be active and no-one will receive its affects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). In fact, it's really a shorthand for a [filter_adjacent] nested within [filter_student]. The variables $this_unit and $other_unit both work as you'd expect. Multiple [filter_adjacent_student] can be provided, all of which must pass for the ability to activate.&lt;br /&gt;
** '''radius''': {{DevFeature1.19|13}} determines the distance of units that can be filtered and not just adjacent units, '''radius''' is set to 1 by default. {{DevFeature1.19|18}} '''[filter_adjacent_student]''' is removed because having multiple shorthands requires giving them specific names for abilities used as weapons, and it's even simpler to use the [[StandardUnitFilter]].&lt;br /&gt;
* '''[filter_adjacent_student_location]''': {{DevFeature1.19|10}} like [filter_adjacent_student], but filters on locations instead of units. This is a shorthand for [filter_student][filter_location][filter_adjacent_location]. {{DevFeature1.19|18}} '''[filter_adjacent_student_location]''' is removed because having multiple shorthands requires giving them specific names for abilities used as weapons, and it's even simpler to use the [[StandardUnitFilter]].&lt;br /&gt;
* '''overwrite_specials''': {{DevFeature1.15|13}} If present, allows a special abilities weapon with a numerical value to impose its value and ignore values of abilities or specials of the same type. If '''overwrite_specials=one_side''', the specials and abilities used by the opponent of the unit affected by the ability with this key and applied to it will not be affected. If '''overwrite_specials=both_sides''', all non-key-carrying abilities and all specials of the same type affecting the recipient unit will be affected, even if used by the opponent (used in the macro FORCE_CHANCE_TO_HIT).&lt;br /&gt;
* {{anchor|overwrite|'''[overwrite]'''}}: {{DevFeature1.17|22}} Part of '''overwrite_specials'''. Allows more flexibility in determining which specials should take priority over other specials of the same type.&lt;br /&gt;
** '''priority''': A numeric value to use when determining which special should be used if multiple specials of the same type have the '''overwrite_specials''' attribute. Default is 0.&lt;br /&gt;
** {{anchor|filter_specials|'''[experimental_filter_specials]'''}}: [[StandardAbilityFilter]] Further attributes to filter specials by to determine if it should take priority over other specials. Accepts the same attributes as [experimental_filter_ability].&lt;br /&gt;
** '''description_affected''': {{DevFeature1.17|13}} becomes the '''description''' of the weapon special, without changing the '''description''' of the ability&lt;br /&gt;
** '''name_affected''': {{DevFeature1.17|13}} becomes the '''name''' of the weapon special, without changing the '''name''' of the ability&lt;br /&gt;
* Other keys and tags appropriate to the specific weapon special.&lt;br /&gt;
&lt;br /&gt;
=== Macros for common abilities ===&lt;br /&gt;
&lt;br /&gt;
[https://www.wesnoth.org/macro-reference.html#file:abilities.cfg macro reference]&lt;br /&gt;
* ABILITY_AMBUSH&lt;br /&gt;
* ABILITY_CURES&lt;br /&gt;
* ABILITY_HEALS&lt;br /&gt;
* ABILITY_ILLUMINATES&lt;br /&gt;
* ABILITY_LEADERSHIP_LEVEL_1 to ABILITY_LEADERSHIP_LEVEL_5&lt;br /&gt;
* {{DevFeature1.13|2}} ABILITY_LEADERSHIP (replaces the above leadership macros, which are now deprecated)&lt;br /&gt;
* ABILITY_NIGHTSTALK&lt;br /&gt;
* ABILITY_REGENERATES&lt;br /&gt;
* ABILITY_SKIRMISHER&lt;br /&gt;
* ABILITY_STEADFAST&lt;br /&gt;
* ABILITY_SUBMERGE&lt;br /&gt;
* ABILITY_TELEPORT&lt;br /&gt;
&lt;br /&gt;
== The ''[specials]'' tag ==&lt;br /&gt;
&lt;br /&gt;
The '''[specials]''' tag goes inside the '''[attack]''' tag. It can contain the following tags:&lt;br /&gt;
&lt;br /&gt;
* '''[attacks]''': modifies the number of attacks of a weapon, in using '''value''', '''add''', '''sub''', '''multiply''' or '''divide''' attributes&lt;br /&gt;
* '''[berserk]''': pushes the attack for more than one combat round, using '''value''' attribute, '''value''' is 1 by default&lt;br /&gt;
* '''[chance_to_hit]''': modifies the chance to hit of a weapon, using same standard numerical attributes as '''[attacks]'''&lt;br /&gt;
* '''[damage]''': modifies the damage of a weapon, using same attributes as '''[attacks]''' and '''[chance_to_hit]'''&lt;br /&gt;
* '''[damage_type]''' {{DevFeature1.17|23}}: changes the damage type of a weapon&lt;br /&gt;
* '''[defense]''' {{DevFeature1.19|15}}: modifies the chances of being hit by the opponent's weapon, this value can be modified by the parry attribute, the accuracy attribute of the opponent's weapon, or by their special weapon '''[chance_to_hit]'''. Be careful, the more you increase the value, the less chance the opponent has of hitting you. Using same standard numerical attributes as '''[attacks]''' {{DevFeature1.19|16}} [defense] is no longer a weapon special but an ability.&lt;br /&gt;
* '''[disable]''': disables the weapon&lt;br /&gt;
* '''[drains]''': heals the attacker '''value''' percentage of the damage dealt, using same attributes as '''[attacks]''' and '''[chance_to_hit]''', '''value''' is 50 by default&lt;br /&gt;
* '''[firststrike]''': forces the weapon to always strike first&lt;br /&gt;
* '''[heal_on_hit]''': heals the attacker when an attack connects, using same attributes as '''[attacks]''' and '''[chance_to_hit]''', '''value''' is 0 by default&lt;br /&gt;
* '''[petrifies]''': turns the target to stone&lt;br /&gt;
* '''[plague]''': when used to kill an enemy, a friendly unit takes its place&lt;br /&gt;
* '''[poison]''': poisons the target&lt;br /&gt;
* '''[slow]''': slows the target&lt;br /&gt;
* '''[swarm]''': number of strikes decreases as the unit loses hitpoints&lt;br /&gt;
Any other tag is valid, but will result in a special that does nothing but report it is there.&lt;br /&gt;
&lt;br /&gt;
=== Common keys and tags for every weapon special ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|?}} All keys inside any weapon special that expects a numeric value will also accept formulas using [[Wesnoth Formula Language]]. In order to use a formula in these keys, you must enclose it in parentheses.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the (translatable) name of the special. If omitted, the special will be hidden from the player.&lt;br /&gt;
* '''name_inactive''': the (translatable) name of the special when inactive. Defaults to ''name'' if not specified; if the special is supposed to be not displayed when inactive, you must explicitly set ''name_inactive'' to an empty string (nothing after the equals sign).&lt;br /&gt;
* '''description''': the (translatable) description of the special.&lt;br /&gt;
* '''description_inactive''': the (translatable) description of the special when inactive. Defaults to ''description'' if not specified.&lt;br /&gt;
* '''special_note''' {{DevFeature1.15|14}} Translatable string, which will be displayed in the unit’s help. See also [[UnitTypeWML#Special_Notes]].&lt;br /&gt;
* '''id''': this ability will not be cumulative with other specials using this id.&lt;br /&gt;
* '''unique_id''': {{DevFeature1.19|18}} A unique identifier for this weapon special, used for the registry under [[UnitsWML#.5Bweapon_specials.5D|[units][weapon_specials]]]. If not defined, falls back to '''id'''. Used to add this weapon special via '''[unit_type][attack]specials_list''', or via [[EffectWML]].&lt;br /&gt;
* '''active_on''': one of '''defense''' or '''offense'''; if left out, the special is active on both.&lt;br /&gt;
* '''apply_to''': one of '''self''','''opponent''','''attacker''','''defender''','''both''' (default: ''self''). Determines who the effects of this special are applied to.&lt;br /&gt;
* '''[filter_adjacent]''': if an adjacent unit does not match this filter, the special will not be active and no-one will receive its effects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]]. In fact, it's really a shorthand for a [filter_adjacent] nested within [filter_self], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). The variables $this_unit and {{DevFeature1.13|2}} $other_unit both work as you'd expect. Multiple [filter_adjacent] can be provided, all of which must pass for the ability to activate. {{DevFeature1.19|18}} '''filter_adjacent''' is deprecated and will likely be removed in version 1.21, since a version already exists in the [[StandardUnitFilter]] and ''count'' is no longer required.&lt;br /&gt;
* '''[filter_adjacent_location]''': like [filter_adjacent], but filters on locations instead of units. This is a shorthand for [filter_self][filter_location][filter_adjacent_location]. {{DevFeature1.19|18}} '''filter_adjacent_location''' is deprecated and will likely be removed in version 1.21, since a version already exists in the [[StandardUnitFilter]].&lt;br /&gt;
* {{anchor|filter_self|'''[filter_self]'''}}: the special will only be active if the owner matches this [[StandardUnitFilter]] (SUF).&lt;br /&gt;
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.&lt;br /&gt;
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the opponent.&lt;br /&gt;
* {{anchor|filter_opponent|'''[filter_opponent]'''}}: the special will only be active if the opponent matches this SUF.&lt;br /&gt;
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.&lt;br /&gt;
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the unit that owns the weapon.&lt;br /&gt;
* {{anchor|filter_attacker|'''[filter_attacker]'''}}: the special will only be active if the attacker matches this SUF.&lt;br /&gt;
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.&lt;br /&gt;
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the defender.&lt;br /&gt;
* {{anchor|filter_defender|'''[filter_defender]'''}} the special will only be active if the defender matches this SUF.&lt;br /&gt;
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.&lt;br /&gt;
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the attacker.&lt;br /&gt;
* '''overwrite_specials''': if equal to 'one_side', then only this unit's specials are evaluated. If equal to 'both_sides', then both this unit's specials and any of the opponent's weapon specials that affect this unit are evaluated. If a special with this attribute is active, it will take precedence over any other specials of the same type that do not have this attribute. Don't applied to boolean weapon special like [poison] ,[slow], [firststrike] or [petrifies].&lt;br /&gt;
* '''[overwrite]''': {{DevFeature1.17|22}} Allows more flexibility in determining which specials should take priority over other specials of the same type.&lt;br /&gt;
** '''priority''': A numeric value to use when determining which special should be used if multiple specials of the same type have the '''overwrite_specials''' attribute. Default is 0.&lt;br /&gt;
** '''[experimental_filter_specials]''': [[StandardAbilityFilter]] Further attributes to filter specials by to determine if it should take priority over other specials. Accepts the same attributes as [experimental_filter_ability], {{DevFeature1.19|5}} [experimental_filter_specials] deprecated, use [filter_specials] instead.&lt;br /&gt;
* '''[event]''': [[EventWML]]. {{DevFeature1.19|4}} An [event] to be included into any scenario where a unit with this weapon special appears in. Note that such events get included when a unit with this weapon special first appears in the scenario, not automatically when the scenario begins (meaning that ''name=prestart'' events, for example, would usually never trigger). See [[WML_Abilities|WML Abilities]]. Shortcut of [unit_type][event].&lt;br /&gt;
* {{DevFeature1.15|3}} When used inside '''[abilities]''' tag, relevant ability keys can also be used (see [[#Extra_tags_and_keys_used_by_weapon_specials_as_abilities|above]]).&lt;br /&gt;
&lt;br /&gt;
=== Common keys and tags for specials with a value ===&lt;br /&gt;
&lt;br /&gt;
The '''[damage]''', '''[attacks]''', and '''[chance_to_hit]''' specials take values that specify how those specials modify their respective base values. The '''[drains]''' special takes a value specifying the percentage of damage drained (default 50) and '''[heal_on_hit]''' takes the amount to heal (default 0; negative values will harm the attacker, but not kill). &lt;br /&gt;
&lt;br /&gt;
* '''value''': the value to be used. Available inside translatable strings as '''$value'''.&lt;br /&gt;
* '''add''': the number to add to the base value. Note the interaction with '''sub''' in [[#Common_calculations]]. Available inside translatable strings as '''$add'''.&lt;br /&gt;
* '''sub''': the number to subtract from the base value. Available inside translatable strings as '''$sub'''.&lt;br /&gt;
* '''multiply''': this multiplies the base value. Available inside translatable strings as '''$multiply'''.&lt;br /&gt;
* '''divide''': this divides the base value. Available inside translatable strings as '''$divide'''.&lt;br /&gt;
* '''max_value''': {{DevFeature1.19|2}}  maximum special value. Default: no limit. Available inside translatable strings as '''$max_value'''.&lt;br /&gt;
* '''min_value''': {{DevFeature1.19|2}}  minimum special value. Default: no limit. Available inside translatable strings as '''$min_value'''.&lt;br /&gt;
* '''priority''': {{DevFeature1.19|19}}  This attribute allows a higher-priority special to use as its base the value returned by a lower-priority special of the same type. Default: 0.&lt;br /&gt;
* '''cumulative''': if set to 'yes', this special will be cumulative with the base value.&lt;br /&gt;
* '''backstab''': if set to 'yes', this special will only apply to the attacker, and only when there is an enemy on the target's opposite side (i.e. when the standard backstab special applies). {{DevFeature1.13|2}} This is now deprecated. The same functionality can be achieved with a [filter_adjacent] in [filter_opponent]; see the implementation of the default backstab special for details.&lt;br /&gt;
* '''[filter_base_value]''': filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', '''less_than''', '''greater_than''', '''less_than_equal_to''', '''greater_than_equal_to'''.&lt;br /&gt;
&lt;br /&gt;
==== Common calculations ====&lt;br /&gt;
&lt;br /&gt;
Several abilities and weapon specials take the keys '''add''', '''sub''', '''multiply''' and '''divide'''.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}} '''add''' and '''sub''' work independently.&lt;br /&gt;
&lt;br /&gt;
Prior to 1.19.4:&lt;br /&gt;
&lt;br /&gt;
* If '''add''' and '''sub''' are used in the same ability, the '''add''' is ignored&lt;br /&gt;
* If '''add''' and '''sub''' are used in separate abilities with the same id, or with the default id that's used when no id is specified, then the order in which the abilities are encountered controls the calculation, which may change depending on units' positions on the map.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[damage_type]'' special ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|23}}&lt;br /&gt;
&lt;br /&gt;
* '''replacement_type''': replaces the attack type with the specified type when [damage_type] is active.&lt;br /&gt;
* '''alternative_type''': add a second type of attack to the existing type, it is always the one of the two which will do the most damage to the opponent which will be used.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In 1.18, alternative_type may be stronger than expected, as the damage calculations sometimes ignore [resistance] abilities. This is a known bug, which occurs deterministically and will be left unfixed in 1.18.x to prevent Out Of Sync errors.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' If a [damage_type] special includes a [filter_weapon]type=, that filter is tested against the base type of the weapon, ignoring all [damage_type] specials.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[berserk]'' special ===&lt;br /&gt;
&lt;br /&gt;
* '''value''': the maximum number of combat rounds (default 1).&lt;br /&gt;
* '''cumulative''': if set to 'yes', this special will be cumulative with other active berserk specials (on the current combatant, not with an opponent's berserk).&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[plague]'' special ===&lt;br /&gt;
&lt;br /&gt;
* '''type''': the unit type to be spawned on kill. When not specified, the default is the unit type of the unit doing the plaguing. This value can be used via the PO variable '''$type''' inside translatable string keys, such as '''description'''.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[swarm]'' special ===&lt;br /&gt;
&lt;br /&gt;
* '''swarm_attacks_max''': the maximum number of attacks for the swarm. Defaults to the base number of attacks modified by any applicable [attacks] specials. If this is specified, then the base number of attacks is ignored.&lt;br /&gt;
* '''swarm_attacks_min''': the minimum number of attacks for the swarm. Defaults to zero. This can be set higher than swarm_attacks_max to cause a unit to gain attacks as health decreases.&lt;br /&gt;
The ratio of the unit's current to maximum hit points will be used to scale the number of attacks between these two values.&lt;br /&gt;
&lt;br /&gt;
Prior to version 1.11, a [swarm] special will cause [attacks] specials to be ignored. In 1.11 and later, [attacks] specials are applied before [swarm].&lt;br /&gt;
&lt;br /&gt;
=== Macros for common weapon specials ===&lt;br /&gt;
&lt;br /&gt;
[https://www.wesnoth.org/macro-reference.html#file:weapon_specials.cfg macro reference]&lt;br /&gt;
* WEAPON_SPECIAL_BACKSTAB&lt;br /&gt;
* WEAPON_SPECIAL_BERSERK&lt;br /&gt;
* WEAPON_SPECIAL_CHARGE&lt;br /&gt;
* WEAPON_SPECIAL_DRAIN&lt;br /&gt;
* WEAPON_SPECIAL_FIRSTSTRIKE&lt;br /&gt;
* WEAPON_SPECIAL_MAGICAL&lt;br /&gt;
* WEAPON_SPECIAL_MARKSMAN&lt;br /&gt;
* WEAPON_SPECIAL_PLAGUE&lt;br /&gt;
* WEAPON_SPECIAL_PLAGUE_TYPE TYPE&lt;br /&gt;
* WEAPON_SPECIAL_POISON&lt;br /&gt;
* WEAPON_SPECIAL_SLOW&lt;br /&gt;
* WEAPON_SPECIAL_STONE&lt;br /&gt;
* WEAPON_SPECIAL_SWARM&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[UnitTypeWML]]&lt;br /&gt;
* [[SingleUnitWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=FilterWML&amp;diff=74797</id>
		<title>FilterWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=FilterWML&amp;diff=74797"/>
		<updated>2026-02-05T00:32:02Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Filtering Abilities */ New section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
== Filtering in WML ==&lt;br /&gt;
&lt;br /&gt;
A ''filter'' is a special WML block.&lt;br /&gt;
Filters are used to describe a set of units, hexes, weapons or something else.&lt;br /&gt;
Filters are defined as matching something if all the keys in the filter match that thing.&lt;br /&gt;
For example, if a unit filter contains two keys,&lt;br /&gt;
a unit must match both of the keys in order to match the filter.&lt;br /&gt;
&lt;br /&gt;
A StandardUnit(Location, Side, ...)Filter is the place where the set of such keys and tags can appear. A StandardFilter sometimes needs an according surrounding tag but often doesn't. It should be mentioned at the place in the wiki where it's said that you can use at a certain code position a StandardFilter whether you need a surrounding tag or not.&lt;br /&gt;
&lt;br /&gt;
== Filtering Units ==&lt;br /&gt;
&lt;br /&gt;
Filters are often used in action tags (see [[EventWML]]).&lt;br /&gt;
In this case the phrase &amp;quot;standard unit filter&amp;quot; is used in place of the set of standard keys.&lt;br /&gt;
Sometimes a filter is used to find the first unit that matches the filter;&lt;br /&gt;
for example, the '''[recall]''' tag recalls that unit.&lt;br /&gt;
&lt;br /&gt;
Standard unit filters are also used in the tags '''[filter]''' and '''[filter_second]'''.&lt;br /&gt;
These are subtags of '''[event]''' which describe when the event should trigger.&lt;br /&gt;
Most event names (see [[EventWML]]) have units related to them called &amp;quot;primary unit&amp;quot; and &amp;quot;secondary unit&amp;quot;.&lt;br /&gt;
In order for an event to be triggered, ''primary unit'' must match the filter contained in '''[filter]''',&lt;br /&gt;
and ''secondary unit'' must match the filter contained in '''[filter_second]'''.&lt;br /&gt;
&lt;br /&gt;
See [[StandardUnitFilter]] for details.&lt;br /&gt;
&lt;br /&gt;
== Filtering Locations ==&lt;br /&gt;
&lt;br /&gt;
As you have seen, standard unit filter can contain a location filter.&lt;br /&gt;
Several actions, such as '''[terrain]''', also use location filters.&lt;br /&gt;
Location filters are represented on this site by the phrase &amp;quot;standard location filter&amp;quot;.&lt;br /&gt;
A common use for location filters is to check the terrain of a space.&lt;br /&gt;
&lt;br /&gt;
See [[StandardLocationFilter]] for details.&lt;br /&gt;
&lt;br /&gt;
== Filtering Sides ==&lt;br /&gt;
Sometimes, it's needed to get a list of sides which satisfy certain criteria. For this, a side filter can be used.&lt;br /&gt;
Side filters are represented on this site by the phrase &amp;quot;standard side filter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
See [[StandardSideFilter]] for details.&lt;br /&gt;
&lt;br /&gt;
== Filtering Abilities ==&lt;br /&gt;
Occasionally, you need to filter for matching unit abilities or weapon specials. For this, an ability filter can be used.&lt;br /&gt;
Ability filters are represented on this site by the phrase &amp;quot;standard ability filter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
See [[StandardAbilityFilter]] for details.&lt;br /&gt;
&lt;br /&gt;
== Filtering Weapons ==&lt;br /&gt;
&lt;br /&gt;
Sometimes weapons/attacks are filtered on in WML.  See also [[EventWML]], [[EffectWML]], [[AnimationWML]].&lt;br /&gt;
&lt;br /&gt;
These keys are used as filter input for attack filters.&lt;br /&gt;
&lt;br /&gt;
* '''range''': a range to filter&lt;br /&gt;
** '''melee''': only melee weapons pass &lt;br /&gt;
** '''ranged''': only ranged weapons pass &lt;br /&gt;
* '''name''': filter on the attack's name. See &amp;lt;code&amp;gt;data/units/&amp;lt;/code&amp;gt; to find the name of a particular unit's attack.&lt;br /&gt;
* '''type''': filter on the attack's type. Values are 'blade', 'pierce', 'impact', 'fire', 'cold', and 'arcane' or customised type. {{DevFeature1.17|23}} [damage_type] can change the type of damage inflicted, and this change can be detected in the filter except when it is applied from a [damage_type] which affects the filtered attack, in this case only the type before any modification by a any [damage_type] will be detectable.&lt;br /&gt;
* '''damage''': filter on damage value. Can be a specific number or a list of ranges like 'damage=0-5,7-99'&lt;br /&gt;
* '''special_id''': {{DevFeature1.15|2}} Filter on a weapon special by id, for example, &amp;lt;code&amp;gt;magical&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;[chance_to_hit] id=magical&amp;lt;/code&amp;gt;. True if the unit has the special, whether or not it's currently active.&lt;br /&gt;
* '''special_type''': {{DevFeature1.15|2}} Filter on a weapon special by tag name for example, &amp;lt;code&amp;gt;chance_to_hit&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;[chance_to_hit] id=magical&amp;lt;/code&amp;gt;. True if the unit has the special, whether or not it's currently active. For values see [[AbilitiesWML]].&lt;br /&gt;
* '''special_id_active''': {{DevFeature1.15|2}} Like '''special_id''', but true if the special is active at the current location. Does not work in 1.16. {{DevFeature1.17|17}} Works again.&lt;br /&gt;
* '''special_type_active''': {{DevFeature1.15|2}} Like '''special_type''', but true if the special is active at the current location.&lt;br /&gt;
* '''special''': filter on the attack's special power, matches both id and tag name. {{DevFeature1.15|2}} Deprecated, see '''special_id''' and '''special_type''' instead.&lt;br /&gt;
* '''special_active''': {{DevFeature1.13|8}} Like '''special''', but true if the special is active at the current location. {{DevFeature1.15|2}} Deprecated, see '''special_id''' and '''special_type''' instead.&lt;br /&gt;
* '''[filter_special]''':   {{DevFeature1.19|6}}  Filter on a weapon special by using[[StandardAbilityFilter]]&lt;br /&gt;
** '''active''': if active=yes, true if the special is active at the current location. If active=no, true whether or not it's currently active, in this case, one special encoded in [attack] can be checked.&lt;br /&gt;
* '''number''': {{DevFeature1.13|5}} filter on number of strikes&lt;br /&gt;
* '''parry''': {{DevFeature1.13|5}} filter on parry value&lt;br /&gt;
* '''accuracy''': {{DevFeature1.13|5}} filter on accuracy value&lt;br /&gt;
* '''movement_used''': {{DevFeature1.13|5}} filter on attack's movement cost&lt;br /&gt;
* '''attacks_used''': {{DevFeature1.17|13}} filter on attack's attack cost&lt;br /&gt;
* '''min_range''': {{DevFeature1.19|4}} filter on attack's range (distance)&lt;br /&gt;
* '''max_range''': {{DevFeature1.19|4}} filter on attack's range (distance)&lt;br /&gt;
* '''formula''': {{DevFeature1.13|5}} filter using [[Wesnoth Formula Language]]. The context object for the formula is a '''weapon object''', which supports the following keys: '''name''', '''description''', '''type''', '''icon''', '''range''', '''damage''', '''number''', '''attack_weight''', '''defense_weight''', '''accuracy''', '''parry''', '''movement_used''', '''specials'''. The '''specials''' key is a list of all the special IDs the unit possesses. Do not surround the formula in &amp;lt;code&amp;gt;$(...)&amp;lt;/code&amp;gt;, since that will erase the &amp;lt;tt&amp;gt;self&amp;lt;/tt&amp;gt; variable. Keys supported after specific version: {{DevFeature1.17|13}} '''attacks_used'''. {{DevFeature1.19|4}} '''min_range''', '''max_range'''.&lt;br /&gt;
&lt;br /&gt;
'''[and]''', '''[or]''', and '''[not]''' subfilters are also supported.&lt;br /&gt;
&lt;br /&gt;
== Filtering Vision ==&lt;br /&gt;
&lt;br /&gt;
The '''[filter_vision]''' tag allows you to filter units or locations based on whether or not the hex is obscured by fog or shroud from the point-of-view of a viewing side, and (in the case of units) whether or not the unit is hidden (via the {{tag|AbilitiesWML|hides}} ability).&lt;br /&gt;
&lt;br /&gt;
* '''visible''':&lt;br /&gt;
** '''yes''' (default): matches when the location is not obscured by fog or shroud for the ''side'' and, when in a SUF, the unit is not hiding.&lt;br /&gt;
** '''no''': matches when the location is obscured by fog or shroud for the ''side'' or, when in a SUF, the unit is hiding.&lt;br /&gt;
* '''respect_fog''': yes or no, default yes. In a location filter (only), setting this to &amp;quot;no&amp;quot; will cause the test to ignore fog; it becomes a test for shrouded or not shrouded. &lt;br /&gt;
** When multiple viewing sides are listed, all of the sides must pass the visibility check in order for the [filter_vision] filter to return a successful match.&lt;br /&gt;
** When no viewing sides are listed, all enemy sides must pass the visibility check.&lt;br /&gt;
*'''[[StandardSideFilter]]''' tags and keys; all matching sides must be able to see the unit/location. If an empty filter, all sides (instead of only all enemy sides) match. If there is *at least one* matching side which can see the unit / location (accounting for fog / hiding / shroud) then the filter matches, and otherwise it fails to match.&lt;br /&gt;
&lt;br /&gt;
'''Example:''' This event will fire when the enemy (side 2) moves to a location within the player's (side 1's) field of vision:&lt;br /&gt;
 [event]&lt;br /&gt;
     name=moveto&lt;br /&gt;
     first_time_only=yes&lt;br /&gt;
     [filter]&lt;br /&gt;
         side=2&lt;br /&gt;
         [filter_vision]&lt;br /&gt;
             side=1 &lt;br /&gt;
         [/filter_vision]&lt;br /&gt;
     [/filter]&lt;br /&gt;
     [message]&lt;br /&gt;
         speaker=unit&lt;br /&gt;
         message=&amp;quot;I am your enemy. I know that you can see me here.&amp;quot;&lt;br /&gt;
     [/message]&lt;br /&gt;
 [/event]&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In a location filter, this tag is only useful when the viewing side is under a fog or shroud. You ''can'' set a shroud over an AI side. This will allow you to use the vision filter from the point-of-view of an AI side. The fog/shroud does not currently affect AI movement patterns, but the AI algorithm may become constrained by fog/shroud in the future.&lt;br /&gt;
&lt;br /&gt;
== Filtering on WML data ==&lt;br /&gt;
&lt;br /&gt;
Some places allow you to filter directly on WML data. WML filters are more free-form than other filters, allowing arbitrary WML data that is to be matched. Anything between '''&amp;lt;&amp;gt;''' needs to be replaced by the actual data to be filtered for. The following conventions are possible:&lt;br /&gt;
&lt;br /&gt;
* ''&amp;lt;key&amp;gt;'''='''&amp;lt;value&amp;gt;'': Means that the key '''key''' must be present with the specified '''value'''.&lt;br /&gt;
* '''glob_on_'''''&amp;lt;key&amp;gt;'''''='''''&amp;lt;glob&amp;gt;'': {{DevFeature1.15|0}} Means that the key '''key''' must be present with a value that matches the specified glob. In a glob, the '''*''' character matches any sequence of characters, while the '''?''' character matches any single character. In addition to the obvious, this is useful for matching the absence of a key - just place '''glob_on_'''''&amp;lt;key&amp;gt;'''''=*''' in a '''[not]''' tag.&lt;br /&gt;
* '''['''''&amp;lt;some_tag&amp;gt;''''']''': In a WML filter, all tags contain further WML filter data as children. The presence of a tag in the filter means that the WML must have at least one tag '''some_tag''' present, and at least one of the '''some_tag''' tags must match the WML filter contained in '''[some_tag]'''.&lt;br /&gt;
* '''[not]''': The WML filter contained in '''[not]''' ''must not'' match the WML.&lt;br /&gt;
* '''[and]''': {{DevFeature1.15|0}} In addition to the main filter, the filter contained in '''[and]''' must also match the WML. In most cases this tag is not necessary (the two filters can simply be merged), but in some unusual cases (particularly when globs are involved) it might be needed to get the desired result.&lt;br /&gt;
* '''[or]''': {{DevFeature1.15|0}} Adds another filter that is allowed to match in place of the main filter. Note that when combining several WML filters with '''[or]''' tags, the first filter must not be wrapped in '''[or]''' tags - doing so would mean that the first filter is actually an empty filter, which matches everything, meaning the other '''[or]''' tags are irrelevant.&lt;br /&gt;
&lt;br /&gt;
== Tutorial ==&lt;br /&gt;
* [[FilterWML/Examples_-_How_to_use_Filter|How To Use Filter (with examples)]]&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[AnimationWML#Animation_Filtering|Animation filtering]]&lt;br /&gt;
* [[UnitTypeWML]]&lt;br /&gt;
* [[EventWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
* [[FilterWML/Examples - How to use Filter]]&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Modifying_AI_Components&amp;diff=74795</id>
		<title>Modifying AI Components</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Modifying_AI_Components&amp;diff=74795"/>
		<updated>2026-02-01T07:36:45Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* [modify_ai] Tag Syntax */ Be clearer about the basic format of the new configuration tag.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Methods for Modifying the AI Mid Scenario ==&lt;br /&gt;
&lt;br /&gt;
The AI and its parameters are usually set up at the beginning of a scenario and often left unchanged for the entire scenario.  See [[AiWML]] and [[Creating Custom AIs]] for instructions on how to do this, or the complete list of AI resources at [[Wesnoth AI]].&lt;br /&gt;
&lt;br /&gt;
Sometimes it is, however, desirable to modify parts or all of the AI mid-scenario.  Wesnoth provides different tools to accomplish this:&lt;br /&gt;
* Standard aspects can be modified mid scenario using the [modify_side] tag&lt;br /&gt;
* Composite aspects, goals and all other AI components can be modified mid scenario using the [modify_ai] tag.&lt;br /&gt;
** A large number of helper macros are available to facilitate these tasks.&lt;br /&gt;
* Micro AIs can be modified mid scenario using the [micro_ai] tag&lt;br /&gt;
** The [micro_ai] tag is always used in an event.  There is no difference between using it at the beginning of the scenario, that is, in a ''prestart'' or ''start'' event, or in any other event.  We therefore refer to the [[Micro AIs]] page for this.&lt;br /&gt;
&lt;br /&gt;
== Using [modify_side] to Change Aspects Mid Scenario ==&lt;br /&gt;
&lt;br /&gt;
The [modify_side] tag can contain an [ai] tag for modifying aspects while a game is in progress.  This works, however, &amp;lt;u&amp;gt;only&amp;lt;/u&amp;gt; for [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|standard aspects]].  An example is&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_side]&lt;br /&gt;
    side=2&lt;br /&gt;
    [ai]&lt;br /&gt;
        aggression=0.765&lt;br /&gt;
    [/ai]&lt;br /&gt;
[/modify_side]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|Composite aspects]] and all other [[Wesnoth_AI_Framework#Types_of_AI_Components|AI components]] cannot be modified in this way.  Use the [modify_ai] tag described below for these tasks.&lt;br /&gt;
&lt;br /&gt;
Note that modifying an aspect in this fashion does not replace the [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|facet]] used to define the aspect in the AI configuration.  It simply adds another facet that then takes precedence over the already existing ones.  In most situations, this does not make a difference, but there might be some cases (for example when facets are only defined for certain times of day or turns), when it might be necessary to replace the existing facet rather than adding a new one.  This can also be done using the [modify_ai] tag as described below.&lt;br /&gt;
&lt;br /&gt;
Note that it is, in principle, also possible to define the aspect using this syntax&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_side]&lt;br /&gt;
    side=2&lt;br /&gt;
    [ai]&lt;br /&gt;
        [aspect]&lt;br /&gt;
            id=aggression&lt;br /&gt;
            [facet]&lt;br /&gt;
                value=0.765&lt;br /&gt;
            [/facet]&lt;br /&gt;
        [/aspect]&lt;br /&gt;
   [/ai]&lt;br /&gt;
[/modify_side]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
However, as this &amp;lt;u&amp;gt;only&amp;lt;/u&amp;gt; works for standard aspects which can also be set with the simpler syntax shown above, there is really no point in doing so.&lt;br /&gt;
&lt;br /&gt;
== The [modify_ai] Tag ==&lt;br /&gt;
&lt;br /&gt;
The [modify_ai] tag is a tool for modifying [[Wesnoth_AI_Framework#Stages|stages]], [[Wesnoth_AI_Framework#The_Candidate_Actions_of_the_main_loop_Stage|candidate actions]], [[Wesnoth_AI_Framework#Aspects_and_Goals|aspects and goals]] of the active AI on the fly at any time during a scenario.  Since all this functionality is packed into a single tag, its syntax is a bit more complex than that of other tags.  To facilitate this, Wesnoth also provides a large variety of [[#Modifying_AI_Components_Helper_Macros|helper macros]], but even for using those one still needs to understand the general syntax of the [modify_ai] tag.&lt;br /&gt;
&lt;br /&gt;
Note that the [modify_ai] tag can be used both in [event] tags and in [side][ai], [era][ai] or [modification][ai] tags, meaning it can also be used to change the AI configuration at game setup time.&lt;br /&gt;
&lt;br /&gt;
=== [modify_ai] Tag Syntax ===&lt;br /&gt;
&lt;br /&gt;
The [modify_ai] tag takes the following keys:&lt;br /&gt;
&lt;br /&gt;
* '''side''': The side of the AI to be modified if used in an event.  This key is not needed if used in [side][ai].  In fact, if given there, it is simply ignored.&lt;br /&gt;
** More generally, a [[StandardSideFilter]] can be used.&lt;br /&gt;
* '''action''': (string) The action to take concerning the component.  The following values are allowed:&lt;br /&gt;
** 'add': Add a component.&lt;br /&gt;
** 'change': Change an existing component.&lt;br /&gt;
** 'delete': Delete an existing component.&lt;br /&gt;
** 'try_delete': Delete a component if it exists.  This does not produce a warning if [modify_ai] fails to change the AI.&lt;br /&gt;
* '''path''': (string) Defines the component of the AI to be modified.  See below.&lt;br /&gt;
* '''New configuration''' for the component (only when adding or changing): This depends on the type of component and is shown in the examples below. It must always be a tag whose name matches the final component of the '''path'''.&lt;br /&gt;
&lt;br /&gt;
====Possible values for [modify_ai]path ====&lt;br /&gt;
&lt;br /&gt;
Depending on the AI component one wants to modify, the '''path''' key can take on different values. The general form of a path is a series of elements separated by dots; each element consists of a component type followed by an ID in square brackets. In many cases, the path consists of only a single level (goals or stages) or two levels (aspect/facet and stage/CA), but {{DevFeature1.13|5}} three or even four levels is occasionally possible with aspects.&lt;br /&gt;
&lt;br /&gt;
The possible toplevel elements in a path are:&lt;br /&gt;
&lt;br /&gt;
* '''aspect'''[''aspect_id'']: Select the aspect with the specified name. The ''aspect_id'' is the name of a known aspect, for example '''aggression'''.&lt;br /&gt;
* '''goal'''[''goal_id'']: Select the goal with the specified name.&lt;br /&gt;
* '''stage'''[''stage_id'']: Select the state with the specified name. Usually, the ''stage_id'' will be '''main_loop''', though in unusual setups there could be other stages with different IDs.&lt;br /&gt;
&lt;br /&gt;
Other possible elements in a path are:&lt;br /&gt;
&lt;br /&gt;
* '''facet'''[''facet_id'']: May only appear under an '''aspect''', or nested in another '''facet'''. Selects a specific facet in a composite aspect.&lt;br /&gt;
* '''recruit'''[''recruit_id'']: May only appear under '''aspect[recruitment_instructions]''', usually nested within a '''facet'''. Selects a single recruitment instruction defined by a '''recruit''', '''pattern''', or '''total''' tag.&lt;br /&gt;
* '''limit'''[''recruit_id'']: May only appear under '''aspect[recruitment_instructions]''', usually nested within a '''facet'''. Selects a single recruitment limit defined by a '''limit''' tag.&lt;br /&gt;
* '''candidate_action'''[''ca_id'']: May only appear under a '''stage'''. See [[RCA_AI#Available_Candidate_Actions|here]] for the ids of the default CAs.&lt;br /&gt;
&lt;br /&gt;
The ''goal_id'', ''stage_id'', ''facet_id'', and ''recruit_id'' can take on any of the following values:&lt;br /&gt;
* A string: Identify the component by the id used when defining it (the '''id''' key)&lt;br /&gt;
* An integer, starting at 0: Select a component by its index, in the order in which they were defined&lt;br /&gt;
* '''*''': Select all components of this type&lt;br /&gt;
* Blank: Used when adding new components, where the ID will be specified in the tag and should not be duplicated in the path.&lt;br /&gt;
&lt;br /&gt;
Some examples:&lt;br /&gt;
&lt;br /&gt;
* Select facet 'quark' of the aggression (composite) aspect: &amp;lt;code&amp;gt;aspect[aggression].facet[quark]&amp;lt;/code&amp;gt;&lt;br /&gt;
* {{DevFeature1.13|5}} Select recruit job 'bobby' of the recruitment_instructions aspect defined as a standard aspect: &amp;lt;code&amp;gt;aspect[recruitment_instructions].recruit[bobby]&amp;lt;/code&amp;gt;&lt;br /&gt;
* {{DevFeature1.13|5}} Select recruit limit 'limit_wc' of the recruitment_instructions aspect defined as a standard aspect: &amp;lt;code&amp;gt;aspect[recruitment_instructions].limit[limit_wc]&amp;lt;/code&amp;gt;&lt;br /&gt;
* {{DevFeature1.13|5}} Select the default facet of the (composite) village_value aspect: &amp;lt;code&amp;gt;aspect[village_value].facet[default_facet]&amp;lt;/code&amp;gt;&lt;br /&gt;
* Select goal 'lighthouse': &amp;lt;code&amp;gt;goal[lighthouse]&amp;lt;/code&amp;gt;&lt;br /&gt;
* Select the 'main_loop' stage: &amp;lt;code&amp;gt;stage[main_loop]&amp;lt;/code&amp;gt;&lt;br /&gt;
* Select candidate action 'healer_support' of the 'main_loop' stage: &amp;lt;code&amp;gt;stage[main_loop].candidate_action[healer_support]&amp;lt;/code&amp;gt;&lt;br /&gt;
* Select an unspecified facet in the composite 'aggression' aspect: &amp;lt;code&amp;gt;aspect[aggression].facet[]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If all this seemed a bit theoretical, don't worry.  Below, we provide many examples for how to do this in practice.&lt;br /&gt;
&lt;br /&gt;
== Modifying AI Components Helper Macros ==&lt;br /&gt;
&lt;br /&gt;
A large number of helper macros are available to simplify the WML needed for modifying AI components.  These macros are defined in file 'data/core/macros/ai.cfg', see the [http://www.wesnoth.org/macro-reference.xhtml#file:ai.cfg list] of available macros or the [https://github.com/wesnoth/wesnoth/blob/master/data/core/macros/ai.cfg full definitions].&lt;br /&gt;
&lt;br /&gt;
'''Notes on the macros:'''&lt;br /&gt;
&lt;br /&gt;
* We do not describe the individual macros here.  There are way too many of them and, quite frankly, most of them are not really needed as they barely simplify the syntax compared to the full [modify_ai] tag.  Instead, a variety of examples are given in the following sections.  If in doubt how to use a macro, or if you want to see all available macros, check out their definitions at the link above.&lt;br /&gt;
* There are several macros with ''SIMPLE_ASPECT'' in the name.  Formally, there is no such things as a ''simple'' aspect, only ''standard'' and ''composite'' aspects.  This is just a convention used by the macros for standard aspects which consist of a single scalar value.  Thus, all simple aspects (such as ''aggression'') are standard aspects, but not all standard aspects (such as ''avoid'') are simple aspects.&lt;br /&gt;
* There are several macros with ''ALWAYS_ASPECT'' in the name.  These are macros for aspects which apply at all times of day and at all turns.  However, the 'always' used as macro argument is actually the facet id, not the values of either the ''time_of_day'' or ''turns'' keys.  This is done so that the facet ids are standardized should removal of these aspects be desired later.&lt;br /&gt;
&lt;br /&gt;
== Modifying AI Component Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Modifying Standard Aspects ===&lt;br /&gt;
&lt;br /&gt;
As was shown above, standard aspects, and &amp;lt;u&amp;gt;only&amp;lt;/u&amp;gt; standard aspects, can be modified using [modify_side].  A simple example is&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_side]&lt;br /&gt;
    side=1&lt;br /&gt;
    [ai]&lt;br /&gt;
        aggression=0.765&lt;br /&gt;
    [/ai]&lt;br /&gt;
[/modify_side]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is the simplest syntax for modifying standard aspects (without using macros).  However, as we explain [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|here]], internally &amp;lt;u&amp;gt;all&amp;lt;/u&amp;gt; aspects are set up as composite aspects.  Thus, [modify_ai] and composite aspect syntax can also be used for simple aspects and we use this example to demonstrate this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=aspect[aggression].facet[]&lt;br /&gt;
    [facet]&lt;br /&gt;
        value=0.765&lt;br /&gt;
    [/facet]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Finally, using one of the helper macros results in this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_ADD_SIMPLE_ASPECT 1 aggression 0.765}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Removing this setting of the aggression aspect again is done as:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=delete  # or try_delete&lt;br /&gt;
    path=aspect[aggression].facet[0]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Assuming we know that it is the first non-default facet of the ''aggression'' aspect that needs to be removed.  If, instead, we want to remove all custom definitions of aggression, we use&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=delete  # or try_delete&lt;br /&gt;
    path=aspect[aggression].facet[*]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using macros, this is done with&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_ASPECT 1 aggression 0}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_ASPECT 1 aggression &amp;quot;*&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If we don't know the number of the facet and do not want to remove all of them, we need to assign an id to the facet defining the aspect (the simple syntax of the very first example cannot be used in that case) and use that id for selective removal.  For example, the definition could look like this&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=aspect[aggression].facet[]&lt;br /&gt;
    [facet]&lt;br /&gt;
        id=my_custom_aggression&lt;br /&gt;
        value=0.765&lt;br /&gt;
    [/facet]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and removal like this&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=delete  # or try_delete&lt;br /&gt;
    path=aspect[aggression].facet[my_custom_aggression]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The macro versions of these are&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_ADD_ASPECT 1 aggression (        &lt;br /&gt;
    [facet]&lt;br /&gt;
        id=my_custom_aggression&lt;br /&gt;
        value=0.765&lt;br /&gt;
    [/facet]&lt;br /&gt;
)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and &lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_ASPECT 1 aggression my_custom_aggression}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we stress that a ''standard'' aspect does not need to be restricted to a single, scalar value.  For example, ''avoid'' is a standard aspect and can be defined using both types of syntax, such as&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_side]&lt;br /&gt;
    side=1&lt;br /&gt;
    [ai]&lt;br /&gt;
        [avoid]&lt;br /&gt;
            x,y=20,16&lt;br /&gt;
            radius=6&lt;br /&gt;
        [/avoid]&lt;br /&gt;
    [/ai]&lt;br /&gt;
[/modify_side]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=aspect[avoid].facet[]&lt;br /&gt;
    [facet]&lt;br /&gt;
        [value]&lt;br /&gt;
            x,y=20,16&lt;br /&gt;
            radius=6&lt;br /&gt;
        [/value]&lt;br /&gt;
    [/facet]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Finale note: Any aspect listed at [[AiWML]] which is not specifically pointed out to be a composite aspect (and there are very few of those), is a standard aspect.&lt;br /&gt;
&lt;br /&gt;
=== Modifying Composite Aspects ===&lt;br /&gt;
&lt;br /&gt;
A small number of the aspects listed at [[AiWML]] are available in ''composite'' aspect syntax only.  However, there is really nothing new about modifying them compared to what is shown above for ''standard'' aspects.  The only difference (as far as modifying the aspects is concerned) is that we &amp;lt;u&amp;gt;have to&amp;lt;/u&amp;gt; use composite aspect syntax, standard aspect syntax does not work.  Thus, we only show one example of the [[AiWML#Filtering_Combat_with_the_attacks_Aspect|''attacks'' aspect]] here.&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=2&lt;br /&gt;
    action=add&lt;br /&gt;
    path=aspect[attacks].facet[]&lt;br /&gt;
    [facet]&lt;br /&gt;
        invalidate_on_gamestate_change=yes&lt;br /&gt;
        [filter_own]&lt;br /&gt;
            type=Elvish Sorceress,Elvish Enchantress,Elvish Sylph&lt;br /&gt;
        [/filter_own]&lt;br /&gt;
        [filter_enemy]&lt;br /&gt;
            race=undead&lt;br /&gt;
        [/filter_enemy]&lt;br /&gt;
    [/facet]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== A Few More Notes on Modifying Aspects === &lt;br /&gt;
&lt;br /&gt;
* The aspect itself and its [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|[default]]] facet cannot be deleted, only the custom facets. {{DevFeature1.13|5}} However, they can be changed, replacing them with a new definition. (The id attribute must match when changing an aspect.) This could change a standard aspect to a composite aspect or vice versa.&lt;br /&gt;
* For standard aspects, it is generally not necessary to delete custom facets.  One can simply overwrite the current value with a new one.  The only times when one might have to remove a standard aspect is when it is defined for specific times of day or turns, or when it is defined so many times that it might bloat the AI configuration (and therefore the savefile).&lt;br /&gt;
* We can also use &amp;lt;code&amp;gt;action=change&amp;lt;/code&amp;gt; to delete an existing facet and overwrite it with a new definition.  If &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; is used as ''facet_id'', this deletes all existing facets of this aspect and replaces them with a single facet with the new definition.&lt;br /&gt;
* Adding a facet with the same ''id'' as an existing facet overwrites the previous occurrence, making this equivalent to changing that facet.&lt;br /&gt;
* If in doubt about the exact syntax of a given aspect, one can always open the gamestate inspector (by typing &amp;lt;code&amp;gt;:inspect&amp;lt;/code&amp;gt; in-game in debug mode) and check out the [default] tag of the respective aspect under 'ai config full' for a given side (team).  Note though that it might be necessary to play through at least one partial turn of that side, as the AI config of the side is not necessarily fully initialized until that happens.&lt;br /&gt;
&lt;br /&gt;
=== Modifying Goals ===&lt;br /&gt;
&lt;br /&gt;
Goals can be added and removed using a syntax that is very similar to that for composite aspects&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=goal[]&lt;br /&gt;
    [goal]&lt;br /&gt;
        id=my_custom_goal&lt;br /&gt;
        [criteria]&lt;br /&gt;
            side=3&lt;br /&gt;
        [/criteria]&lt;br /&gt;
        value=5&lt;br /&gt;
    [/goal]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=delete&lt;br /&gt;
    path=goal[my_custom_goal]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that we assigned a custom id to the goal here, that was then used for removal.  We could also use the method described above for aspects, using the number of the goal or &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The macro versions of these examples are&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_ADD_GOAL 1 (&lt;br /&gt;
    [goal]&lt;br /&gt;
        id=my_custom_goal&lt;br /&gt;
        [criteria]&lt;br /&gt;
            side=3&lt;br /&gt;
        [/criteria]&lt;br /&gt;
        value=5&lt;br /&gt;
    [/goal]&lt;br /&gt;
)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_GOAL 1 my_custom_goal}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Modifying Candidate Action of the ''main_loop'' Stage ===&lt;br /&gt;
&lt;br /&gt;
The syntax for modifying candidate actions is entirely equivalent to that for aspects and goals shown above. If one wants to, for example, set up an AI that does not fight, this can be done by removing the ''combat'' CA.  {{DevFeature1.15|3}} There are now additional CAs which also perform attacks. Check out [[RCA_AI#The_Candidate_Actions_.28CAs.29_of_the_main_loop_Stage_in_the_RCA_AI|the candidate actions of the default AI]] to see which CAs need to be remove in order to produce an AI that truly does not attack.&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=2&lt;br /&gt;
    action=delete&lt;br /&gt;
    path=stage[main_loop].candidate_action[combat]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_CANDIDATE_ACTION 2 main_loop combat}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Adding a [[Creating_Custom_AIs#Creating_Custom_Candidate_Actions|custom Lua candidate action]] is done as follows&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=stage[main_loop].candidate_action[]&lt;br /&gt;
    [candidate_action]&lt;br /&gt;
        engine=lua&lt;br /&gt;
        name=return_guardian_bob&lt;br /&gt;
        id=return_guardian_bob&lt;br /&gt;
        max_score=100010&lt;br /&gt;
        location=&amp;quot;~add-ons/my_addon/lua/return_guardian.lua&amp;quot;&lt;br /&gt;
        eval_parms=&amp;quot;id = 'Bob', return_x = 10, return_y = 15&amp;quot;&lt;br /&gt;
        exec_parms=&amp;quot;id = 'Bob', return_x = 10, return_y = 15&amp;quot;&lt;br /&gt;
    [/candidate_action]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We'll omit the macro version here as it is almost identical to previous examples.&lt;br /&gt;
&lt;br /&gt;
=== Modifying Stages ===&lt;br /&gt;
&lt;br /&gt;
Working with a single stage, the [[Wesnoth_AI_Framework#Stages|''main_loop'' stage]], should be sufficient for essentially all Wesnoth AI projects these days.  It should therefore rarely ever be necessary to add or remove stages any more.  It can, however, be done in the same way as for the other AI components.  The macro definitions linked to above can be used as syntax reference if you ever need to do so.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''See also:''' [[Wesnoth AI]]&lt;br /&gt;
[[Category:AI]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Modifying_AI_Components&amp;diff=74794</id>
		<title>Modifying AI Components</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Modifying_AI_Components&amp;diff=74794"/>
		<updated>2026-02-01T07:31:47Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Possible values for [modify_ai]path */ Try to be more clear about what's possible&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Methods for Modifying the AI Mid Scenario ==&lt;br /&gt;
&lt;br /&gt;
The AI and its parameters are usually set up at the beginning of a scenario and often left unchanged for the entire scenario.  See [[AiWML]] and [[Creating Custom AIs]] for instructions on how to do this, or the complete list of AI resources at [[Wesnoth AI]].&lt;br /&gt;
&lt;br /&gt;
Sometimes it is, however, desirable to modify parts or all of the AI mid-scenario.  Wesnoth provides different tools to accomplish this:&lt;br /&gt;
* Standard aspects can be modified mid scenario using the [modify_side] tag&lt;br /&gt;
* Composite aspects, goals and all other AI components can be modified mid scenario using the [modify_ai] tag.&lt;br /&gt;
** A large number of helper macros are available to facilitate these tasks.&lt;br /&gt;
* Micro AIs can be modified mid scenario using the [micro_ai] tag&lt;br /&gt;
** The [micro_ai] tag is always used in an event.  There is no difference between using it at the beginning of the scenario, that is, in a ''prestart'' or ''start'' event, or in any other event.  We therefore refer to the [[Micro AIs]] page for this.&lt;br /&gt;
&lt;br /&gt;
== Using [modify_side] to Change Aspects Mid Scenario ==&lt;br /&gt;
&lt;br /&gt;
The [modify_side] tag can contain an [ai] tag for modifying aspects while a game is in progress.  This works, however, &amp;lt;u&amp;gt;only&amp;lt;/u&amp;gt; for [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|standard aspects]].  An example is&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_side]&lt;br /&gt;
    side=2&lt;br /&gt;
    [ai]&lt;br /&gt;
        aggression=0.765&lt;br /&gt;
    [/ai]&lt;br /&gt;
[/modify_side]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|Composite aspects]] and all other [[Wesnoth_AI_Framework#Types_of_AI_Components|AI components]] cannot be modified in this way.  Use the [modify_ai] tag described below for these tasks.&lt;br /&gt;
&lt;br /&gt;
Note that modifying an aspect in this fashion does not replace the [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|facet]] used to define the aspect in the AI configuration.  It simply adds another facet that then takes precedence over the already existing ones.  In most situations, this does not make a difference, but there might be some cases (for example when facets are only defined for certain times of day or turns), when it might be necessary to replace the existing facet rather than adding a new one.  This can also be done using the [modify_ai] tag as described below.&lt;br /&gt;
&lt;br /&gt;
Note that it is, in principle, also possible to define the aspect using this syntax&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_side]&lt;br /&gt;
    side=2&lt;br /&gt;
    [ai]&lt;br /&gt;
        [aspect]&lt;br /&gt;
            id=aggression&lt;br /&gt;
            [facet]&lt;br /&gt;
                value=0.765&lt;br /&gt;
            [/facet]&lt;br /&gt;
        [/aspect]&lt;br /&gt;
   [/ai]&lt;br /&gt;
[/modify_side]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
However, as this &amp;lt;u&amp;gt;only&amp;lt;/u&amp;gt; works for standard aspects which can also be set with the simpler syntax shown above, there is really no point in doing so.&lt;br /&gt;
&lt;br /&gt;
== The [modify_ai] Tag ==&lt;br /&gt;
&lt;br /&gt;
The [modify_ai] tag is a tool for modifying [[Wesnoth_AI_Framework#Stages|stages]], [[Wesnoth_AI_Framework#The_Candidate_Actions_of_the_main_loop_Stage|candidate actions]], [[Wesnoth_AI_Framework#Aspects_and_Goals|aspects and goals]] of the active AI on the fly at any time during a scenario.  Since all this functionality is packed into a single tag, its syntax is a bit more complex than that of other tags.  To facilitate this, Wesnoth also provides a large variety of [[#Modifying_AI_Components_Helper_Macros|helper macros]], but even for using those one still needs to understand the general syntax of the [modify_ai] tag.&lt;br /&gt;
&lt;br /&gt;
Note that the [modify_ai] tag can be used both in [event] tags and in [side][ai], [era][ai] or [modification][ai] tags, meaning it can also be used to change the AI configuration at game setup time.&lt;br /&gt;
&lt;br /&gt;
=== [modify_ai] Tag Syntax ===&lt;br /&gt;
&lt;br /&gt;
The [modify_ai] tag takes the following keys:&lt;br /&gt;
&lt;br /&gt;
* '''side''': The side of the AI to be modified if used in an event.  This key is not needed if used in [side][ai].  In fact, if given there, it is simply ignored.&lt;br /&gt;
** More generally, a [[StandardSideFilter]] can be used.&lt;br /&gt;
* '''action''': (string) The action to take concerning the component.  The following values are allowed:&lt;br /&gt;
** 'add': Add a component.&lt;br /&gt;
** 'change': Change an existing component.&lt;br /&gt;
** 'delete': Delete an existing component.&lt;br /&gt;
** 'try_delete': Delete a component if it exists.  This does not produce a warning if [modify_ai] fails to change the AI.&lt;br /&gt;
* '''path''': (string) Defines the component of the AI to be modified.  See below.&lt;br /&gt;
* '''New configuration''' for the component: This depends on the type of component and is shown in the examples below.&lt;br /&gt;
&lt;br /&gt;
====Possible values for [modify_ai]path ====&lt;br /&gt;
&lt;br /&gt;
Depending on the AI component one wants to modify, the '''path''' key can take on different values. The general form of a path is a series of elements separated by dots; each element consists of a component type followed by an ID in square brackets. In many cases, the path consists of only a single level (goals or stages) or two levels (aspect/facet and stage/CA), but {{DevFeature1.13|5}} three or even four levels is occasionally possible with aspects.&lt;br /&gt;
&lt;br /&gt;
The possible toplevel elements in a path are:&lt;br /&gt;
&lt;br /&gt;
* '''aspect'''[''aspect_id'']: Select the aspect with the specified name. The ''aspect_id'' is the name of a known aspect, for example '''aggression'''.&lt;br /&gt;
* '''goal'''[''goal_id'']: Select the goal with the specified name.&lt;br /&gt;
* '''stage'''[''stage_id'']: Select the state with the specified name. Usually, the ''stage_id'' will be '''main_loop''', though in unusual setups there could be other stages with different IDs.&lt;br /&gt;
&lt;br /&gt;
Other possible elements in a path are:&lt;br /&gt;
&lt;br /&gt;
* '''facet'''[''facet_id'']: May only appear under an '''aspect''', or nested in another '''facet'''. Selects a specific facet in a composite aspect.&lt;br /&gt;
* '''recruit'''[''recruit_id'']: May only appear under '''aspect[recruitment_instructions]''', usually nested within a '''facet'''. Selects a single recruitment instruction defined by a '''recruit''', '''pattern''', or '''total''' tag.&lt;br /&gt;
* '''limit'''[''recruit_id'']: May only appear under '''aspect[recruitment_instructions]''', usually nested within a '''facet'''. Selects a single recruitment limit defined by a '''limit''' tag.&lt;br /&gt;
* '''candidate_action'''[''ca_id'']: May only appear under a '''stage'''. See [[RCA_AI#Available_Candidate_Actions|here]] for the ids of the default CAs.&lt;br /&gt;
&lt;br /&gt;
The ''goal_id'', ''stage_id'', ''facet_id'', and ''recruit_id'' can take on any of the following values:&lt;br /&gt;
* A string: Identify the component by the id used when defining it (the '''id''' key)&lt;br /&gt;
* An integer, starting at 0: Select a component by its index, in the order in which they were defined&lt;br /&gt;
* '''*''': Select all components of this type&lt;br /&gt;
* Blank: Used when adding new components, where the ID will be specified in the tag and should not be duplicated in the path.&lt;br /&gt;
&lt;br /&gt;
Some examples:&lt;br /&gt;
&lt;br /&gt;
* Select facet 'quark' of the aggression (composite) aspect: &amp;lt;code&amp;gt;aspect[aggression].facet[quark]&amp;lt;/code&amp;gt;&lt;br /&gt;
* {{DevFeature1.13|5}} Select recruit job 'bobby' of the recruitment_instructions aspect defined as a standard aspect: &amp;lt;code&amp;gt;aspect[recruitment_instructions].recruit[bobby]&amp;lt;/code&amp;gt;&lt;br /&gt;
* {{DevFeature1.13|5}} Select recruit limit 'limit_wc' of the recruitment_instructions aspect defined as a standard aspect: &amp;lt;code&amp;gt;aspect[recruitment_instructions].limit[limit_wc]&amp;lt;/code&amp;gt;&lt;br /&gt;
* {{DevFeature1.13|5}} Select the default facet of the (composite) village_value aspect: &amp;lt;code&amp;gt;aspect[village_value].facet[default_facet]&amp;lt;/code&amp;gt;&lt;br /&gt;
* Select goal 'lighthouse': &amp;lt;code&amp;gt;goal[lighthouse]&amp;lt;/code&amp;gt;&lt;br /&gt;
* Select the 'main_loop' stage: &amp;lt;code&amp;gt;stage[main_loop]&amp;lt;/code&amp;gt;&lt;br /&gt;
* Select candidate action 'healer_support' of the 'main_loop' stage: &amp;lt;code&amp;gt;stage[main_loop].candidate_action[healer_support]&amp;lt;/code&amp;gt;&lt;br /&gt;
* Select an unspecified facet in the composite 'aggression' aspect: &amp;lt;code&amp;gt;aspect[aggression].facet[]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If all this seemed a bit theoretical, don't worry.  Below, we provide many examples for how to do this in practice.&lt;br /&gt;
&lt;br /&gt;
== Modifying AI Components Helper Macros ==&lt;br /&gt;
&lt;br /&gt;
A large number of helper macros are available to simplify the WML needed for modifying AI components.  These macros are defined in file 'data/core/macros/ai.cfg', see the [http://www.wesnoth.org/macro-reference.xhtml#file:ai.cfg list] of available macros or the [https://github.com/wesnoth/wesnoth/blob/master/data/core/macros/ai.cfg full definitions].&lt;br /&gt;
&lt;br /&gt;
'''Notes on the macros:'''&lt;br /&gt;
&lt;br /&gt;
* We do not describe the individual macros here.  There are way too many of them and, quite frankly, most of them are not really needed as they barely simplify the syntax compared to the full [modify_ai] tag.  Instead, a variety of examples are given in the following sections.  If in doubt how to use a macro, or if you want to see all available macros, check out their definitions at the link above.&lt;br /&gt;
* There are several macros with ''SIMPLE_ASPECT'' in the name.  Formally, there is no such things as a ''simple'' aspect, only ''standard'' and ''composite'' aspects.  This is just a convention used by the macros for standard aspects which consist of a single scalar value.  Thus, all simple aspects (such as ''aggression'') are standard aspects, but not all standard aspects (such as ''avoid'') are simple aspects.&lt;br /&gt;
* There are several macros with ''ALWAYS_ASPECT'' in the name.  These are macros for aspects which apply at all times of day and at all turns.  However, the 'always' used as macro argument is actually the facet id, not the values of either the ''time_of_day'' or ''turns'' keys.  This is done so that the facet ids are standardized should removal of these aspects be desired later.&lt;br /&gt;
&lt;br /&gt;
== Modifying AI Component Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Modifying Standard Aspects ===&lt;br /&gt;
&lt;br /&gt;
As was shown above, standard aspects, and &amp;lt;u&amp;gt;only&amp;lt;/u&amp;gt; standard aspects, can be modified using [modify_side].  A simple example is&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_side]&lt;br /&gt;
    side=1&lt;br /&gt;
    [ai]&lt;br /&gt;
        aggression=0.765&lt;br /&gt;
    [/ai]&lt;br /&gt;
[/modify_side]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is the simplest syntax for modifying standard aspects (without using macros).  However, as we explain [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|here]], internally &amp;lt;u&amp;gt;all&amp;lt;/u&amp;gt; aspects are set up as composite aspects.  Thus, [modify_ai] and composite aspect syntax can also be used for simple aspects and we use this example to demonstrate this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=aspect[aggression].facet[]&lt;br /&gt;
    [facet]&lt;br /&gt;
        value=0.765&lt;br /&gt;
    [/facet]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Finally, using one of the helper macros results in this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_ADD_SIMPLE_ASPECT 1 aggression 0.765}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Removing this setting of the aggression aspect again is done as:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=delete  # or try_delete&lt;br /&gt;
    path=aspect[aggression].facet[0]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Assuming we know that it is the first non-default facet of the ''aggression'' aspect that needs to be removed.  If, instead, we want to remove all custom definitions of aggression, we use&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=delete  # or try_delete&lt;br /&gt;
    path=aspect[aggression].facet[*]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using macros, this is done with&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_ASPECT 1 aggression 0}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_ASPECT 1 aggression &amp;quot;*&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If we don't know the number of the facet and do not want to remove all of them, we need to assign an id to the facet defining the aspect (the simple syntax of the very first example cannot be used in that case) and use that id for selective removal.  For example, the definition could look like this&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=aspect[aggression].facet[]&lt;br /&gt;
    [facet]&lt;br /&gt;
        id=my_custom_aggression&lt;br /&gt;
        value=0.765&lt;br /&gt;
    [/facet]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and removal like this&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=delete  # or try_delete&lt;br /&gt;
    path=aspect[aggression].facet[my_custom_aggression]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The macro versions of these are&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_ADD_ASPECT 1 aggression (        &lt;br /&gt;
    [facet]&lt;br /&gt;
        id=my_custom_aggression&lt;br /&gt;
        value=0.765&lt;br /&gt;
    [/facet]&lt;br /&gt;
)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and &lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_ASPECT 1 aggression my_custom_aggression}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we stress that a ''standard'' aspect does not need to be restricted to a single, scalar value.  For example, ''avoid'' is a standard aspect and can be defined using both types of syntax, such as&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_side]&lt;br /&gt;
    side=1&lt;br /&gt;
    [ai]&lt;br /&gt;
        [avoid]&lt;br /&gt;
            x,y=20,16&lt;br /&gt;
            radius=6&lt;br /&gt;
        [/avoid]&lt;br /&gt;
    [/ai]&lt;br /&gt;
[/modify_side]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=aspect[avoid].facet[]&lt;br /&gt;
    [facet]&lt;br /&gt;
        [value]&lt;br /&gt;
            x,y=20,16&lt;br /&gt;
            radius=6&lt;br /&gt;
        [/value]&lt;br /&gt;
    [/facet]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Finale note: Any aspect listed at [[AiWML]] which is not specifically pointed out to be a composite aspect (and there are very few of those), is a standard aspect.&lt;br /&gt;
&lt;br /&gt;
=== Modifying Composite Aspects ===&lt;br /&gt;
&lt;br /&gt;
A small number of the aspects listed at [[AiWML]] are available in ''composite'' aspect syntax only.  However, there is really nothing new about modifying them compared to what is shown above for ''standard'' aspects.  The only difference (as far as modifying the aspects is concerned) is that we &amp;lt;u&amp;gt;have to&amp;lt;/u&amp;gt; use composite aspect syntax, standard aspect syntax does not work.  Thus, we only show one example of the [[AiWML#Filtering_Combat_with_the_attacks_Aspect|''attacks'' aspect]] here.&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=2&lt;br /&gt;
    action=add&lt;br /&gt;
    path=aspect[attacks].facet[]&lt;br /&gt;
    [facet]&lt;br /&gt;
        invalidate_on_gamestate_change=yes&lt;br /&gt;
        [filter_own]&lt;br /&gt;
            type=Elvish Sorceress,Elvish Enchantress,Elvish Sylph&lt;br /&gt;
        [/filter_own]&lt;br /&gt;
        [filter_enemy]&lt;br /&gt;
            race=undead&lt;br /&gt;
        [/filter_enemy]&lt;br /&gt;
    [/facet]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== A Few More Notes on Modifying Aspects === &lt;br /&gt;
&lt;br /&gt;
* The aspect itself and its [[Wesnoth_AI_Framework#The_.5Bai.5D_Tag_.E2.80.94_Aspects|[default]]] facet cannot be deleted, only the custom facets. {{DevFeature1.13|5}} However, they can be changed, replacing them with a new definition. (The id attribute must match when changing an aspect.) This could change a standard aspect to a composite aspect or vice versa.&lt;br /&gt;
* For standard aspects, it is generally not necessary to delete custom facets.  One can simply overwrite the current value with a new one.  The only times when one might have to remove a standard aspect is when it is defined for specific times of day or turns, or when it is defined so many times that it might bloat the AI configuration (and therefore the savefile).&lt;br /&gt;
* We can also use &amp;lt;code&amp;gt;action=change&amp;lt;/code&amp;gt; to delete an existing facet and overwrite it with a new definition.  If &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; is used as ''facet_id'', this deletes all existing facets of this aspect and replaces them with a single facet with the new definition.&lt;br /&gt;
* Adding a facet with the same ''id'' as an existing facet overwrites the previous occurrence, making this equivalent to changing that facet.&lt;br /&gt;
* If in doubt about the exact syntax of a given aspect, one can always open the gamestate inspector (by typing &amp;lt;code&amp;gt;:inspect&amp;lt;/code&amp;gt; in-game in debug mode) and check out the [default] tag of the respective aspect under 'ai config full' for a given side (team).  Note though that it might be necessary to play through at least one partial turn of that side, as the AI config of the side is not necessarily fully initialized until that happens.&lt;br /&gt;
&lt;br /&gt;
=== Modifying Goals ===&lt;br /&gt;
&lt;br /&gt;
Goals can be added and removed using a syntax that is very similar to that for composite aspects&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=goal[]&lt;br /&gt;
    [goal]&lt;br /&gt;
        id=my_custom_goal&lt;br /&gt;
        [criteria]&lt;br /&gt;
            side=3&lt;br /&gt;
        [/criteria]&lt;br /&gt;
        value=5&lt;br /&gt;
    [/goal]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=delete&lt;br /&gt;
    path=goal[my_custom_goal]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that we assigned a custom id to the goal here, that was then used for removal.  We could also use the method described above for aspects, using the number of the goal or &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The macro versions of these examples are&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_ADD_GOAL 1 (&lt;br /&gt;
    [goal]&lt;br /&gt;
        id=my_custom_goal&lt;br /&gt;
        [criteria]&lt;br /&gt;
            side=3&lt;br /&gt;
        [/criteria]&lt;br /&gt;
        value=5&lt;br /&gt;
    [/goal]&lt;br /&gt;
)}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_GOAL 1 my_custom_goal}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Modifying Candidate Action of the ''main_loop'' Stage ===&lt;br /&gt;
&lt;br /&gt;
The syntax for modifying candidate actions is entirely equivalent to that for aspects and goals shown above. If one wants to, for example, set up an AI that does not fight, this can be done by removing the ''combat'' CA.  {{DevFeature1.15|3}} There are now additional CAs which also perform attacks. Check out [[RCA_AI#The_Candidate_Actions_.28CAs.29_of_the_main_loop_Stage_in_the_RCA_AI|the candidate actions of the default AI]] to see which CAs need to be remove in order to produce an AI that truly does not attack.&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=2&lt;br /&gt;
    action=delete&lt;br /&gt;
    path=stage[main_loop].candidate_action[combat]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
{MODIFY_AI_DELETE_CANDIDATE_ACTION 2 main_loop combat}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Adding a [[Creating_Custom_AIs#Creating_Custom_Candidate_Actions|custom Lua candidate action]] is done as follows&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[modify_ai]&lt;br /&gt;
    side=1&lt;br /&gt;
    action=add&lt;br /&gt;
    path=stage[main_loop].candidate_action[]&lt;br /&gt;
    [candidate_action]&lt;br /&gt;
        engine=lua&lt;br /&gt;
        name=return_guardian_bob&lt;br /&gt;
        id=return_guardian_bob&lt;br /&gt;
        max_score=100010&lt;br /&gt;
        location=&amp;quot;~add-ons/my_addon/lua/return_guardian.lua&amp;quot;&lt;br /&gt;
        eval_parms=&amp;quot;id = 'Bob', return_x = 10, return_y = 15&amp;quot;&lt;br /&gt;
        exec_parms=&amp;quot;id = 'Bob', return_x = 10, return_y = 15&amp;quot;&lt;br /&gt;
    [/candidate_action]&lt;br /&gt;
[/modify_ai]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We'll omit the macro version here as it is almost identical to previous examples.&lt;br /&gt;
&lt;br /&gt;
=== Modifying Stages ===&lt;br /&gt;
&lt;br /&gt;
Working with a single stage, the [[Wesnoth_AI_Framework#Stages|''main_loop'' stage]], should be sufficient for essentially all Wesnoth AI projects these days.  It should therefore rarely ever be necessary to add or remove stages any more.  It can, however, be done in the same way as for the other AI components.  The macro definitions linked to above can be used as syntax reference if you ever need to do so.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''See also:''' [[Wesnoth AI]]&lt;br /&gt;
[[Category:AI]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Roadmap&amp;diff=74775</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Roadmap&amp;diff=74775"/>
		<updated>2026-01-25T18:10:10Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Redirected page to 1.19 Roadmap&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[1.19 Roadmap]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Wesnoth_Formula_Language&amp;diff=74774</id>
		<title>Wesnoth Formula Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Wesnoth_Formula_Language&amp;diff=74774"/>
		<updated>2026-01-25T06:59:30Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Action Functions */ Add missing header&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;tright&amp;quot;&amp;gt; __TOC__ &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Wesnoth Formula Language is a functional language used to evaluate expressions within the game engine. It allows performing calculations that would not otherwise be possible using only WML. For example, to have an event trigger when a unit has less than half its hitpoints, you could write the following as the event's filter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[filter]&lt;br /&gt;
    formula = &amp;quot;(hitpoints &amp;lt; max_hitpoints / 2)&amp;quot;&lt;br /&gt;
[/filter]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''formula''' key is a part of [[StandardUnitFilter]] that accepts a condition written as WFL. The part inside the quotes is the WFL formula. This example will evaluate to true if the unit's '''hitpoints''' are less than half its '''max_hitpoints'''.&lt;br /&gt;
&lt;br /&gt;
== Data Types and Operators ==&lt;br /&gt;
&lt;br /&gt;
Wesnoth Formula Language has seven basic data types – [[#Numbers|integers]], [[#Numbers|real numbers]] (usually called &amp;quot;decimals&amp;quot;), [[#Strings|strings]], [[#Lists|lists]], [[#Maps|maps]], [[#Objects|objects]], and [[#Other Types and Operators|null]].&lt;br /&gt;
&lt;br /&gt;
=== Numbers ===&lt;br /&gt;
&lt;br /&gt;
The most common use of WFL is for simple calculations involving numbers. For this, the standard arithmetic operators (&amp;lt;code&amp;gt;+ - * / %&amp;lt;/code&amp;gt;) work as you would expect, performing addition, subtraction, multiplication, division, and remainder. {{DevFeature1.13|5}} The remainder operator even works on decimal numbers, producing the integer remainder of the division.&lt;br /&gt;
&lt;br /&gt;
The only caveat to watch out for is that &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; rounds down when used on integers. For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;5 / 2&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;. To avoid this, make sure at least one of the numbers includes a decimal point (or use [[#as_decimal|as_decimal]] if variables are involved) - &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;5.0 / 2&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;2.5&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note that WFL supports only three decimal places of precision for decimal numbers; beyond that it will still be rounded down. (So &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;1.0 / 16&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;0.062&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;0.0625&amp;lt;/code&amp;gt;.) The &amp;lt;code&amp;gt;^&amp;lt;/code&amp;gt; operator performs exponentiation (raising to a power) - for example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;2 ^ 3&amp;lt;/syntaxhighlight&amp;gt; evaluates to &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use the standard comparison operators (&amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;=&amp;lt;/code&amp;gt;) on numbers. This is often useful in unit filters - for example, a formula of &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;hitpoints &amp;lt; max_hitpoints / 2&amp;lt;/syntaxhighlight&amp;gt; will match only if the unit is at less than half health. Comparison operators return 1 for true and 0 for false; there is no boolean type. Comparing values of different types will always return 0, with one exception – comparing an integer and decimal number will work as expected.&lt;br /&gt;
&lt;br /&gt;
One final numeric operator exists - the dice roll. The syntax &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;3d12&amp;lt;/syntaxhighlight&amp;gt; will roll three 12-sided dice and return the sum of the results. Note however that this is not multiplayer-safe, so using it can and will produce OOS errors. {{DevFeature1.13|5}} The dice operator is now synced and should be safe for use in multiplayer contexts.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' {{DevFeature1.13|5}} Some numeric operations will return null instead of a number. This usually involves the exponentiation operator - for example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;(-2) ^ 0.5&amp;lt;/syntaxhighlight&amp;gt; attempts to take the square root of -2, which doesn't exist, so it returns null to indicate this. Dividing by zero also returns null, as well as certain [[#Numeric Functions|math functions]] in appropriate circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
WFL also supports strings, which must be enclosed in single quotes (&amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;'like this'&amp;lt;/syntaxhighlight&amp;gt;). The comparison operators (&amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;=&amp;lt;/code&amp;gt;) also work on strings, performing lexicographical comparison (ie, alphabetical order). The comparison is case sensitive.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
Strings can be concatenated with the concatenation operator &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt;. They also support interpolations enclosed in square brackets, the contents of which can be any valid formula. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Some text: [a + b]' where a = 12, b = 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
results in the string &amp;lt;code&amp;gt;Some text: 22&amp;lt;/code&amp;gt;. (The &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; operator is explained [[#Variables|below]].)&lt;br /&gt;
&lt;br /&gt;
If you need to include a literal square bracket in a string, write &amp;lt;code&amp;gt;[(]&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;[)]&amp;lt;/code&amp;gt;. For a literal single quote, you can write &amp;lt;code&amp;gt;[']&amp;lt;/code&amp;gt;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'[(]It[']s bracketed![)]'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
results in the string &amp;lt;code&amp;gt;[It's bracketed!]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can index the characters or words of a string with the following syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Hello World'.char[4]&lt;br /&gt;
'Hello World'.word[1]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These return &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;World&amp;lt;/code&amp;gt;, respectively. A third option is also available, &amp;lt;code&amp;gt;item&amp;lt;/code&amp;gt;, which splits the string on commas but allows parentheses to prevent a portion of the string from being split up. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'First Item,Second Item,Third Item'.item[1]&lt;br /&gt;
'a,b,(c,d,e),f,g'.item[2]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These return &amp;lt;code&amp;gt;Second Item&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;(c,d,e)&amp;lt;/code&amp;gt;, respectively. When not providing index, list is returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Hello World'.char = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']&lt;br /&gt;
'Hello World'.word = ['Hello', 'World']&lt;br /&gt;
'a,b,(c,d,e),f,g'.item = ['a', 'b', '(c,d,e)', 'f', 'g']&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lists ===&lt;br /&gt;
&lt;br /&gt;
A list is a sequence of values represented as square brackets, [], surrounding a comma-separated list. For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[ 1, 5, 'abc' ]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The comparison operators work on lists, performing lexicographical comparison. A specific list index can be obtained with the indexing operator, like this: &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;my_list[index]&amp;lt;/syntaxhighlight&amp;gt;. The first element of a list is numbered 0.&lt;br /&gt;
&lt;br /&gt;
There are four ''vector operators'' (&amp;lt;code&amp;gt;.+ .- .* ./&amp;lt;/code&amp;gt;) that perform entrywise operations on lists. For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;[1,2,3] .+ [12,2,8]&amp;lt;/syntaxhighlight&amp;gt; produces &amp;lt;code&amp;gt;[13,4,11]&amp;lt;/code&amp;gt;. Both lists must be of the same length to use these operators, and of course, they must contain only numbers.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
A negative list index now counts from the end of the list - &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt; refers to the last element. You can check if an element exists in a list using the &amp;lt;code&amp;gt;in&amp;lt;/code&amp;gt; operator. Lists can also be joined with the concatenation operator &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt;, and sliced using the range operator &amp;lt;code&amp;gt;~&amp;lt;/code&amp;gt;. In fact, the range operator produces a list of consecutive numbers, and in fact any list of numbers can be used to index a list - the result is to take the elements at the requested indices, in order. Some examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[1, 7, 'abc', 2.5, 'foobar', 127][1~3]&lt;br /&gt;
(10~20)[[0,-1]]&lt;br /&gt;
[1, 7, 'abc', 2.5, 'foobar', 127][[2,4]]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These result in the following lists:&lt;br /&gt;
&lt;br /&gt;
 [7, 'abc', 2.5]&lt;br /&gt;
 [10,20]&lt;br /&gt;
 ['abc', 'foobar']&lt;br /&gt;
&lt;br /&gt;
=== Maps ===&lt;br /&gt;
&lt;br /&gt;
A map is a sequence of key-value pairs. For example: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[12 -&amp;gt; 'Hello', [1,2] -&amp;gt; 9, 'abc' -&amp;gt; 1.5]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The comparison operators work on maps. A specific element of a map can be obtained with the indexing operation. In the above example, the following conditions are all true (assuming the map is in a variable called &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self[12] = 'Hello'&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self[[1,2]] = 9&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self['abc'] = 1.5&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
You can now use the &amp;lt;code&amp;gt;in&amp;lt;/code&amp;gt; operator to test if a key exists in the map. You can also access string keys using the dot operator &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; as long as they are valid identifiers. (Valid identifiers contain letters and underscores only; no digits are permitted.)&lt;br /&gt;
&lt;br /&gt;
Note that the selection indexing that lists use is ''not'' valid for maps - a list can be used as a key, after all.&lt;br /&gt;
&lt;br /&gt;
Though it's rarely needed, it's possible to define an empty map with &amp;lt;code&amp;gt;[ -&amp;gt; ]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Objects ===&lt;br /&gt;
&lt;br /&gt;
An object is a container containing additional variables (see [[#Variables|below]] for further explanation of variables) which are not in the global scope. The ''dot operator'' can be used to evaluate a formula in the object's scope. For example, suppose ''u'' is a unit object referring to your leader, who is an Elvish Ranger who has taken 12 damage (thus has 30 hit points). Then &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u.hitpoints&amp;lt;/syntaxhighlight&amp;gt; will evaluate to the number 30. For a more advanced example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u . (hitpoints &amp;lt; max_hitpoints - 10)&amp;lt;/syntaxhighlight&amp;gt; will evaluate to true if the unit has taken more than 10 damage, which in this example, it has. (This could also be written &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u.hitpoints &amp;lt; u.max_hitpoints - 10&amp;lt;/syntaxhighlight&amp;gt; if you prefer; this enters the scope twice, instead of once, but the result is identical.)&lt;br /&gt;
&lt;br /&gt;
Objects generally cannot be created directly by the code - they are created for you by the game when formulas are called in certain contexts. However, there are two types of object that ''can'' be created by your code. The first is the location object, which has variables ''x'' and ''y''; it can be created by the [[#loc|&amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;]] function. The second is the map pair object, which is returned (or used internally) by several of the built-in functions and has variables ''key'' and ''value''.&lt;br /&gt;
&lt;br /&gt;
==== Documentation of some common objects ====&lt;br /&gt;
&lt;br /&gt;
There are a number of common objects that are given as the context object for formulas throughout the engine. Not all of these will be available in all formulas, but many of them are available in more than one formula. To learn what objects are available in a given location, see the WML documentation of that location.&lt;br /&gt;
&lt;br /&gt;
* [[StandardUnitFilter#Wesnoth_Formula_Language|unit objects]]&lt;br /&gt;
* [[FilterWML#Filtering_Weapons|weapon objects]]&lt;br /&gt;
* [[StandardLocationFilter#Wesnoth_Formula_Language|terrain objects]]&lt;br /&gt;
* [[StandardSideFilter#Wesnoth_Formula_Language|side objects]]&lt;br /&gt;
* [[ImagePathFunctions#CHAN:_General function|pixel objects]]&lt;br /&gt;
* [[ConditionalActionsWML#.5Bvariable.5D|WML objects]]&lt;br /&gt;
* [[EventWML#filter_formula|game state objects]]&lt;br /&gt;
&lt;br /&gt;
=== Other Types and Operators ===&lt;br /&gt;
&lt;br /&gt;
There is one other basic type in WFL - the null type, which is used to mean &amp;quot;no value&amp;quot;. It will be returned if you attempt to perform an invalid operation, such as dividing a string. It is also returned by the built-in &amp;lt;code&amp;gt;null()&amp;lt;/code&amp;gt; function, which allows you to test if a value is null by writing &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;value = null()&amp;lt;/syntaxhighlight&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The logical operators &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; can be used to connect conditional expressions, and the unary operator &amp;lt;code&amp;gt;not&amp;lt;/code&amp;gt; negates them. Note that &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; is inclusive - &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;A or B&amp;lt;/syntaxhighlight&amp;gt; is false only if both ''A'' and ''B'' are false. These operators consider &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or null to be false, while all other values count as true. The [[#if|&amp;lt;code&amp;gt;if()&amp;lt;/code&amp;gt;]] function also follows the same rules to determine whether a value is true or false.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Programmers familiar with other languages may occasionally be surprised by the fact that &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; do not short-circuit (which would mean that they will never evaluate their second argument if they can know their result solely from the first argument). This should not be a problem in general formula usage, since functions do not have side-effects, but it could make a difference when using the debug functions.&lt;br /&gt;
&lt;br /&gt;
=== Operator Precedence ===&lt;br /&gt;
&lt;br /&gt;
The precedence of various operators is, more or less, what you'd expect - you can write something like &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a + b * 2 &amp;lt;= 5 and n - m / 4 &amp;gt; 7&amp;lt;/syntaxhighlight&amp;gt; and the engine will do what you expect - first multiplication and division, then addition and subtraction, then comparison, and finally logical conjunction. The only thing to watch out for is when chaining exponentiation - all operators are left associative, so &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a ^ b ^ c&amp;lt;/syntaxhighlight&amp;gt; will be evaluated as &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;(a ^ b) ^ c&amp;lt;/syntaxhighlight&amp;gt; instead of &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a ^ (b ^ c)&amp;lt;/syntaxhighlight&amp;gt; like you would expect. {{DevFeature1.13|5}} This has been fixed - exponentiation is now right-associative.&lt;br /&gt;
&lt;br /&gt;
The full precedence list is as follows, from lowest to highest; operators on the same line have equal precedence.&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;not&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clauses&lt;br /&gt;
# &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt;&lt;br /&gt;
# Comparison operators &amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;= in&amp;lt;/code&amp;gt;&lt;br /&gt;
# Range-generating operator &amp;lt;code&amp;gt;~&amp;lt;/code&amp;gt;&lt;br /&gt;
# Additive operators &amp;lt;code&amp;gt;+ - ..&amp;lt;/code&amp;gt;&lt;br /&gt;
# Multiplicative operators &amp;lt;code&amp;gt;* /&amp;lt;/code&amp;gt;&lt;br /&gt;
# Modulus &amp;lt;code&amp;gt;%&amp;lt;/code&amp;gt;&lt;br /&gt;
# Exponentiation &amp;lt;code&amp;gt;^&amp;lt;/code&amp;gt;&lt;br /&gt;
# Dice operator &amp;lt;code&amp;gt;d&amp;lt;/code&amp;gt;&lt;br /&gt;
# Dot operator &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
WFL is a ''functional'' language, so of course it has functions. There is a large library of [[#Core Functions|built-in functions]], and you can also [[#Defining Functions|define your own]].&lt;br /&gt;
&lt;br /&gt;
Calling a function is simple, and works exactly how you would expect if you've worked with functions in a mathematical context: &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;clamp(value, 0, 21)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Being a functional language, WFL does not have conditional or looping statements. Instead, these are provided by functions. For a simple conditional, you can use the &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; function, as in the following example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wfl&amp;gt;&lt;br /&gt;
if(hitpoints &amp;gt; 37,&lt;br /&gt;
    max_hitpoints / 2,&lt;br /&gt;
    hitpoints - 3&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Similarly, looping is done via functions. There are several built-in higher-order functions that can be used to iterate over lists and maps, such as &amp;lt;tt&amp;gt;filter&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;choose&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;map&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;reduce&amp;lt;/tt&amp;gt;. See the corresponding function definitions for more information.&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
Formulas may have a variety of variables, depending on the context in which they are evaluated. A string substitution formula like &amp;lt;code&amp;gt;$(3 + 5)&amp;lt;/code&amp;gt; has no variables, but a [[StandardUnitFilter|unit filter]] formula has variables such as &amp;lt;code&amp;gt;hitpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max_hitpoints&amp;lt;/code&amp;gt; which contain various properties of the unit being tested (the same unit which is also referred to in variable substitution as &amp;lt;code&amp;gt;$this_unit&amp;lt;/code&amp;gt;). The special variable &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; typically refers to the &amp;quot;global context&amp;quot; - in the case of a unit filter formula, the unit itself. This means for example that &amp;lt;code&amp;gt;self.hitpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;hitpoints&amp;lt;/code&amp;gt; are equivalent when used in a unit filter formula. In a string substitution formula (the &amp;lt;code&amp;gt;$(formula)&amp;lt;/code&amp;gt; syntax), &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; is null. Because of this, you should prefer not to use the substitution syntax in places where formulas are specifically supported.&lt;br /&gt;
&lt;br /&gt;
A formula may declare additional variables using a &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clause. This assigns a meaning to any unknown variables in the preceding formula. The general syntax is:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;formula&amp;gt; where &amp;lt;variable&amp;gt; = &amp;lt;value&amp;gt; [, &amp;lt;variable&amp;gt; = value ...]&lt;br /&gt;
&lt;br /&gt;
This functions similarly to an operator, so if desired, you could have multiple where clauses in a single formula. Note that all variables in WFL are read-only - they are variables because they may have different values depending on the context in which the formula is evaluated, but for a given context, they are constant. A variable that has not been assigned a value is considered to have a value of null. Variables are lazily-evaluated - if a where clause declares a variable that is never used, the expression assigned to it will never be evaluated. (This only really matters if it contains a call to a debug function.)&lt;br /&gt;
&lt;br /&gt;
Variable names can contain letters and underscores only. In particular, they cannot contain digits. Also, names are case-sensitive, so ''y'' and ''Y'' refer to two different variables. The following names are reserved and cannot be used for the name of a variable or function:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;d&amp;lt;/tt&amp;gt; - dice operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;or&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; - containment operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;def&amp;lt;/tt&amp;gt; - defines a function&lt;br /&gt;
* &amp;lt;tt&amp;gt;and&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;fai&amp;lt;/tt&amp;gt; - deprecated synonym of &amp;lt;tt&amp;gt;wfl&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;wfl&amp;lt;/tt&amp;gt; - declares filename&lt;br /&gt;
* &amp;lt;tt&amp;gt;where&amp;lt;/tt&amp;gt; - declares variables&lt;br /&gt;
* &amp;lt;tt&amp;gt;faiend&amp;lt;/tt&amp;gt; - deprecated synonym of &amp;lt;tt&amp;gt;wflend&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;wflend&amp;lt;/tt&amp;gt; - closes file scope&lt;br /&gt;
* &amp;lt;tt&amp;gt;functions&amp;lt;/tt&amp;gt; - lists all defined functions&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
Sometimes with particularly complicated formulas, it may be useful to document what's going on inline. Of course, you can use WML comments to do this, but in some cases it may be useful to put some comments in the middle of the formula. This is easily done - simply enclose them in &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; characters, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
#This is a Wesnoth Formula Language comment.#&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the final &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; - unlike WML, WFL requires this to indicate where the comment ends.&lt;br /&gt;
&lt;br /&gt;
== Defining Functions ==&lt;br /&gt;
&lt;br /&gt;
There are several predefined functions in the Wesnoth Formula Language, and if these are not enough, it is possible to define your own functions. The special variable &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;functions&amp;lt;/syntaxhighlight&amp;gt; always evaluates to a list of all known function names. This is mainly useful only as a debugging tool, though.&lt;br /&gt;
&lt;br /&gt;
To define a function, you use the &amp;lt;code&amp;gt;def&amp;lt;/code&amp;gt; keyword. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def sgn(x) if(x &amp;lt; 0, -1, x &amp;gt; 0, 1, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This defines a function called &amp;lt;code&amp;gt;sgn&amp;lt;/code&amp;gt; which returns the sign of the input number. The semicolon marks the end of the function. It's optional if there's nothing else following the function, but in practice this will very rarely be the case.&lt;br /&gt;
&lt;br /&gt;
Function names have the same limitation as variable names – they can contain only letters and underscores, and cannot contain digits.&lt;br /&gt;
&lt;br /&gt;
You can select one of the function's arguments to be the &amp;quot;default&amp;quot; argument. If an object is passed to the default argument, then any attributes of that object are directly accessible in the global scope. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def is_badly_wounded(u*) hitpoints &amp;lt; max_hitpoints / 2;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function takes a unit and returns 1 if it is at less than half hitpoints. The &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; indicates the default argument, without which it would instead have to be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def is_badly_wounded(u) u.hitpoints &amp;lt; u.max_hitpoints / 2;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It's important to remember that the function body has access to no variables other than its parameters. For example, the following function would not work (in a unit filter context) even though the unit variable is defined:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def endangers_me(u) distance_between(u.loc, unit.loc) &amp;lt; u.moves;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is because the body of the function can't see the unit variable. To make this work, you would need to pass in unit as an additional parameter.&lt;br /&gt;
&lt;br /&gt;
'''Note: Prior to 1.14, function definitions only work in AI code and GUI2 code.'''&lt;br /&gt;
&lt;br /&gt;
== Where to Use Formulas ==&lt;br /&gt;
&lt;br /&gt;
Formulas can only be used in specific attributes in WML. The documentation of a WML tag will note which keys can have a formula placed in them. Some common examples include [[FilterWML|filters]], [[GUIToolkit|GUI2 dialogs]], and [[AbilitiesWML|unit abilities]]. Another example is the [[VariablesWML#Variable_Substitution|&amp;lt;code&amp;gt;$(formula)&amp;lt;/code&amp;gt; substitution]] syntax, which allows the use of formulas wherever variables are parsed.&lt;br /&gt;
&lt;br /&gt;
When using a formula in WML (other than in a substitution, which is usually part of a longer already-quoted passage), it is highly recommended to place double quotes around the formula, to avoid ambiguity between the WML and WFL parsers. The double angle quotes are also acceptable for this purpose. If you don't quote your formulas, there are two issues you could run into:&lt;br /&gt;
&lt;br /&gt;
# WML uses the &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; operator to represent concatenation of strings, as well as line continuation. Because of this, an unquoted &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; will be ''removed'', likely causing the WFL formula to fail to compile.&lt;br /&gt;
# Unquoted WML text has the whitespace collapsed. If using WFL strings where whitespace is significant, this can result in surprises. For example, the formula &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;length('One    Two    Three')&amp;lt;/syntaxhighlight&amp;gt; would return 13 instead of the expected 19 if double quotes are not placed around the formula.&lt;br /&gt;
&lt;br /&gt;
Some attributes in WML ''require'' a formula, which means that anything placed in the attribute will always be considered to be a formula. In this case, the formula doesn't need to be enclosed in parentheses – just the double quotes will suffice. However, there are also attributes that take an ''optional'' formula. These are most common in GUI2, but are also found in other places. In such attributes, the formula ''must'' be enclosed in parentheses. Failure to do so will result in it being parsed as just a straight value. As a general guideline, if the attribute key contains the word &amp;quot;formula&amp;quot;, it is usually required to be a formula, whereas attributes with optional formulas do ''not'' contain the word &amp;quot;formula&amp;quot; in the key.&lt;br /&gt;
&lt;br /&gt;
'''Note''': Do ''not'' use a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; to introduce a formula. The &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; is not part of WFL syntax. It introduces a ''substitution'', a concept which is covered in more detail at [[VariablesWML#Variable Substitution]]. Although WFL can be used ''inside'' a substitution, a substitution itself is not WFL, and you should ''never'' use a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; in WFL. However, in practice, substitutions and WFL are often used together – as substitution is processed first, you may see WFL formulas that appear to contain a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; inside them. This is ''not'' part of the WFL – it is more like a macro substitution to be carried out before the formula runs. So, of course, it will only work in places that support ''both'' WFL and substitution.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
On occasion, you may find yourself working with formulas complex enough to split them out into a separate file. The formula engine normally assumes that it is executing inline code and reports errors accordingly, but you can tell it to enter a file scope using the special &amp;lt;code&amp;gt;wfl&amp;lt;/code&amp;gt; keyword. The convention is to frame your code, so that any file looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
wfl 'filename.wfl'&lt;br /&gt;
&lt;br /&gt;
# Put whatever code you need here, possibly including function definitions. #&lt;br /&gt;
&lt;br /&gt;
wflend&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The matching &amp;lt;code&amp;gt;wflend&amp;lt;/code&amp;gt; is required.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This functionality was available prior to 1.13.5 using keywords &amp;lt;code&amp;gt;fai&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;faiend&amp;lt;/code&amp;gt;. {{DevFeature1.19|14}} As of 1.19.14, support for the &amp;lt;code&amp;gt;fai&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;faiend&amp;lt;/code&amp;gt; keywords has been removed.&lt;br /&gt;
&lt;br /&gt;
These directives have no effect on the formula code itself. They only change how error messages are reported if something goes wrong. Files using these directives are usually included using the WML preprocessor, though they could also be loaded in Lua with [[LuaAPI/filesystem#filesystem.read_file|filesystem.read_file]].&lt;br /&gt;
&lt;br /&gt;
== Core Functions ==&lt;br /&gt;
&lt;br /&gt;
Many of the core functions exhibit two features that (as of 1.13.4) cannot be used in user-defined functions. The first is the ability to accept a varying number of arguments - some core functions accept any number of arguments, while others have a few optional arguments. The second is that arguments are lazily-evaluated, and in some cases some arguments will not be evaluated at all, while others may be evaluated multiple times with different variable values. The description of each function will explain how and when its arguments are evaluated.&lt;br /&gt;
&lt;br /&gt;
Most of the core functions can be used from any formula. However, there are some that are only available in formulas that have access to the game state. The following formulas have access to the game state and can use those functions:&lt;br /&gt;
&lt;br /&gt;
* Formulas used in [[FilterWML]]&lt;br /&gt;
* Formulas used in [[AbilitiesWML]]&lt;br /&gt;
* &amp;lt;tt&amp;gt;filter_formula&amp;lt;/tt&amp;gt; in [[EventWML#filter_formula|EventWML]]&lt;br /&gt;
* Formulas evaluated from the formula console (accessed by pressing F)&lt;br /&gt;
&lt;br /&gt;
The following formulas do not have access to the game state and cannot use those functions:&lt;br /&gt;
&lt;br /&gt;
* Formulas used in [[GUI2]]&lt;br /&gt;
* [[SyntaxWML#formula_substitution|Substitution]] formulas using &amp;lt;tt&amp;gt;$(...)&amp;lt;/tt&amp;gt;&lt;br /&gt;
* [[ImagePathFunctions#CHAN: General function|IPF]] formulas used in &amp;lt;tt&amp;gt;~CHAN()&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;~ALPHA()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Formulas compiled from [[LuaAPI/wesnoth#wesnoth.compile_formula|Lua]]&lt;br /&gt;
&lt;br /&gt;
=== Conditional Functions ===&lt;br /&gt;
&lt;br /&gt;
There are two functions which return one of their input values based on some condition - the &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; function, and the &amp;lt;code&amp;gt;switch&amp;lt;/code&amp;gt; function. Both evaluate only as many parameters as is needed to determine which value to return. In particular, parameters that are neither returned nor part of the condition will never be evaluated.&lt;br /&gt;
&lt;br /&gt;
==== if ====&lt;br /&gt;
&lt;br /&gt;
* if(''condition'', ''if true'' [, ''condition 2'', ''if true 2'', ...] [, ''otherwise''])&lt;br /&gt;
&lt;br /&gt;
This function first evaluates the ''condition'', which is a formula. If it evaluates to true, then the function evaluates and returns the ''if true'' parameter; otherwise, it tries the next condition (if any) with the same result. If none of the conditions evaluate to true, then it returns the ''otherwise'' parameter if present, or &amp;lt;code&amp;gt;null()&amp;lt;/code&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
For instance, an event that is triggered by Wolf Riders on the first turn, and Orcish Grunts thereafter might have a unit filter formula that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
if(turn_number = 1, type = 'Wolf Rider', type = 'Orcish Grunt))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== switch ====&lt;br /&gt;
&lt;br /&gt;
* switch(''formula'', ''value 1'', ''outcome 1'' [, ... , ''value N'', ''outcome N''] [, ''default outcome''])&lt;br /&gt;
&lt;br /&gt;
The switch function first evaluates the input ''formula'', and then checks if it is equal to any of the specified ''values''. If matching value is found, the ''outcome'' assigned to it is returned; if not, then function returns either ''default outcome'' (if specified) or null.&lt;br /&gt;
&lt;br /&gt;
=== Numeric Functions ===&lt;br /&gt;
&lt;br /&gt;
Several basic math functions are available. These generally work equally on integer and decimal values.&lt;br /&gt;
&lt;br /&gt;
==== abs ====&lt;br /&gt;
&lt;br /&gt;
* abs(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the absolute value of an input number; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
abs( -5 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return 5.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== acos ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* acos(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arccosine of the input number, in degrees.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== asin ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* asin(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arcsine of the input number, in degrees.&lt;br /&gt;
&lt;br /&gt;
==== atan ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* atan(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arctangent of the input number, in degrees.&lt;br /&gt;
==== as_decimal ====&lt;br /&gt;
&lt;br /&gt;
* as_decimal(''number'')&lt;br /&gt;
&lt;br /&gt;
Ensures that the number is a decimal rather than an integer; useful if you're dividing two unknown values and want to ensure that the result is a decimal.&lt;br /&gt;
&lt;br /&gt;
==== cbrt ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* cbrt(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the cube root of the input number. This is better than using the exponentiation operator, because it will give the correct result for negative numbers.&lt;br /&gt;
&lt;br /&gt;
==== ceil ====&lt;br /&gt;
&lt;br /&gt;
* ceil(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the ceiling of the specified number, ie rounding it up to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== clamp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|0}}&lt;br /&gt;
&lt;br /&gt;
* clamp(''number'', ''min'', ''max'')&lt;br /&gt;
&lt;br /&gt;
Combines min and max into a single call. If ''number'' is less than ''min'', returns ''min''; if it's greater than ''max'', returns ''max''. Otherwise, returns ''number''.&lt;br /&gt;
&lt;br /&gt;
==== cos ====&lt;br /&gt;
&lt;br /&gt;
* cos(''angle'')&lt;br /&gt;
&lt;br /&gt;
Returns the cosine of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== exp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* exp(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the exponential of the input number, which is the constant ''e'' raised to the specified power.&lt;br /&gt;
&lt;br /&gt;
==== floor ====&lt;br /&gt;
&lt;br /&gt;
* floor(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the floor of the specified number, ie rounding it down to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== frac ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* frac(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the fractional part of the specified number.&lt;br /&gt;
&lt;br /&gt;
==== hypot ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* hypot(''x'', ''y'')&lt;br /&gt;
&lt;br /&gt;
Returns the hypoteneuse length of a triangle with sides ''x'' and ''y''.&lt;br /&gt;
&lt;br /&gt;
==== lerp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|0}}&lt;br /&gt;
&lt;br /&gt;
* lerp(''min'', ''max'', ''fraction'')&lt;br /&gt;
&lt;br /&gt;
Returns a linear interpolation between ''min'' and ''max'' according to the specified ''fraction''.&lt;br /&gt;
&lt;br /&gt;
==== lerp_index ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* lerp_index(''list'', ''ratio'')&lt;br /&gt;
&lt;br /&gt;
Returns the element of the list that is closest to being at the specified ratio of the list's length.&lt;br /&gt;
&lt;br /&gt;
'''Example''': &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;lerp_index([1, 12, 32, 10], 0.26])&amp;lt;/syntaxhighlight&amp;gt; returns 12.&lt;br /&gt;
&lt;br /&gt;
==== log ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* log(''number'', [, ''base''])&lt;br /&gt;
&lt;br /&gt;
Returns the logarithm of the input number. If ''base'' is omitted, it returns the natural logarithm; otherwise, the logarithm to the specified base.&lt;br /&gt;
&lt;br /&gt;
==== max ====&lt;br /&gt;
&lt;br /&gt;
* max(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
Returns the largest number from the list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
max([2, 8, -10, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== min ====&lt;br /&gt;
&lt;br /&gt;
* min(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
Returns the smallest number from the list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
min( [ 3, 7, -2, 6] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return &amp;lt;code&amp;gt;-2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== pi ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* pi()&lt;br /&gt;
&lt;br /&gt;
Returns pi.&lt;br /&gt;
&lt;br /&gt;
==== root ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* root(''number'', ''base'')&lt;br /&gt;
&lt;br /&gt;
Returns the root of the input number, to the specified base. This is better than using the exponentiation operator, because it will give the correct result for negative numbers and odd bases (for example, the fifth root of -32, which is -2).&lt;br /&gt;
&lt;br /&gt;
==== round ====&lt;br /&gt;
&lt;br /&gt;
* round(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the specified number rounded to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== sgn ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* sgn(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the sign of the number, ie -1 if it is negative, 1 if it is positive, and 0 if it is zero.&lt;br /&gt;
&lt;br /&gt;
==== sin ====&lt;br /&gt;
&lt;br /&gt;
* sin(''angle'')&lt;br /&gt;
&lt;br /&gt;
Returns the sine of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== sqrt ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* sqrt(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the square root of the input number.&lt;br /&gt;
&lt;br /&gt;
==== sum ====&lt;br /&gt;
&lt;br /&gt;
* sum(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates to the sum of the numbers in the ''list of numbers''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sum([ 2, 5, 8])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt;, and:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sum(map(my_units, max_hitpoints - hitpoints))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
finds the total damage your units have taken.&lt;br /&gt;
&lt;br /&gt;
==== tan ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* tan(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the tangent of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== trunc ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* trunc(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the truncation of the specified number, ie rounding it towards zero. This is different from floor when applied to negative numbers - floor(-7.5) gives -8, but trunc(-7.5) gives -7.&lt;br /&gt;
&lt;br /&gt;
==== wave ====&lt;br /&gt;
&lt;br /&gt;
* wave(''number'')&lt;br /&gt;
&lt;br /&gt;
Given a numeric value V, this returns:&lt;br /&gt;
&lt;br /&gt;
  sin(2*pi*V)&lt;br /&gt;
&lt;br /&gt;
=== String Functions ===&lt;br /&gt;
&lt;br /&gt;
There are a few useful functions for manipulating strings.&lt;br /&gt;
&lt;br /&gt;
==== concatenate ====&lt;br /&gt;
&lt;br /&gt;
* concatenate(''value1''[, ''value2'', ...])&lt;br /&gt;
&lt;br /&gt;
Converts each of its arguments to a string, and concatenates the result together into a single string.&lt;br /&gt;
&lt;br /&gt;
==== contains_string ====&lt;br /&gt;
&lt;br /&gt;
* contains_string(''string'', ''search_string'')&lt;br /&gt;
&lt;br /&gt;
Returns 1 if ''search_string'' can be found within ''string'' (as a substring), 0 otherwise. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
contains_string( 'Testing', 'ing' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== length ====&lt;br /&gt;
&lt;br /&gt;
* length(''string'')&lt;br /&gt;
&lt;br /&gt;
Returns the length of the input string.&lt;br /&gt;
&lt;br /&gt;
==== ends_with ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* ends_with(''string'', ''suffix'')&lt;br /&gt;
&lt;br /&gt;
Determines whether the ''string'' ends with the specified ''suffix''.&lt;br /&gt;
&lt;br /&gt;
==== find_string ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* find_string(''string'', ''search_string'')&lt;br /&gt;
&lt;br /&gt;
Returns the index at which ''search_string'' starts within ''string'' (as a substring), or -1 if it is not found. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
find_string( 'Testing', 'ing' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== replace ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* replace(''string'', ''offset'', [''size'',] ''replacement'')&lt;br /&gt;
&lt;br /&gt;
Returns a new string obtained by replacing a portion of the input ''string'' with the contents of the ''replacement'' string. The ''offset'' and ''size'' work the same as for &amp;lt;code&amp;gt;substring&amp;lt;/code&amp;gt;. Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', 4, 5, 'dumb')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -9, 4, 'sleeping')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -9, 'brook!')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -6, -4, 'yellow')&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return the following strings:&lt;br /&gt;
&lt;br /&gt;
 'The dumb brown fox jumps over the lazy dog!'&lt;br /&gt;
 'The quick brown fox jumps over the sleeping dog!'&lt;br /&gt;
 'The quick brown fox jumps over the brook!'&lt;br /&gt;
 'The quick brown fox jumps over the yellow dog!'&lt;br /&gt;
&lt;br /&gt;
==== replace_all ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* replace_all(''string'', ''match'', ''replacement'')&lt;br /&gt;
&lt;br /&gt;
Returns a copy of ''string'' with all occurrences of ''match'' replaced by ''replacement''.&lt;br /&gt;
&lt;br /&gt;
==== starts_with ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* starts_with(''string'', ''prefix'')&lt;br /&gt;
&lt;br /&gt;
Determines whether the ''string'' begins with the specified ''prefix''.&lt;br /&gt;
&lt;br /&gt;
==== substring ====&lt;br /&gt;
&lt;br /&gt;
* substring(''string'', ''offset''[, ''size''])&lt;br /&gt;
&lt;br /&gt;
Extracts a substring from the given input string. The ''offset'' specifies the first character to extract; the first character is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;, and negative values count from the end, so the last character is &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;. If specified, the ''size'' indicates the total number of characters to extract; it cannot be negative. If omitted, all characters from the ''offset'' to the end of the string are returned. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', 4, 5)&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -9, 4)&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -9)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return &amp;lt;code&amp;gt;'quick'&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'lazy'&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;'lazy dog!'&amp;lt;/code&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The ''size'' can now be negative. This means to count backwards from the given ''offset'' (but always including the given offset, so a ''size'' of -1 gives the same result as 1). For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -6, -4)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'lazy'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== List and Map Functions ===&lt;br /&gt;
&lt;br /&gt;
This section contains functions that directly manipulate a map or list.&lt;br /&gt;
&lt;br /&gt;
==== head ====&lt;br /&gt;
&lt;br /&gt;
* head(''list'' [, ''count''])&lt;br /&gt;
&lt;br /&gt;
Returns the first item from the ''list''; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
head([5, 7, 9])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
head( [ 'Orc', 'Human' ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'Orc'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} If a second argument is given, it returns a list containing the first ''count'' elements from the ''list''. Note that &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;head(L)&amp;lt;/syntaxhighlight&amp;gt; is different from &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;head(L,1)&amp;lt;/syntaxhighlight&amp;gt; - the former returns the first element, while the latter returns a list containing only the first element.&lt;br /&gt;
&lt;br /&gt;
==== index_of ====&lt;br /&gt;
&lt;br /&gt;
* index_of(''value'', ''list'')&lt;br /&gt;
&lt;br /&gt;
This function will return the first index where ''value'' can be found in the input ''list''. It will return -1 if the value is not found in the ''list'.&lt;br /&gt;
&lt;br /&gt;
==== keys ====&lt;br /&gt;
&lt;br /&gt;
* keys(''map'')&lt;br /&gt;
&lt;br /&gt;
Extracts the key values from an input ''map'' and returns them as a list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
keys(['Elvish Fighter' -&amp;gt; 50, 'Elvish Archer' -&amp;gt; 60])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns&lt;br /&gt;
&lt;br /&gt;
 ['Elvish Fighter', 'Elvish Archer']&lt;br /&gt;
&lt;br /&gt;
==== size ====&lt;br /&gt;
&lt;br /&gt;
* size(''list'')&lt;br /&gt;
&lt;br /&gt;
This function returns the number of elements in the ''list''.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;size([5, 7, 9])&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; and &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;size(['Archer', 'Fighter'])&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== sort ====&lt;br /&gt;
&lt;br /&gt;
* sort(''list'', ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates to a result list sorted according to the comparison ''formula'' for each item &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and its successor &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;. For instance, sorting units according to hitpoints would be done by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sort(my_units, a.hitpoints &amp;gt; b.hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To sort them in the reverse order, simply use &amp;lt;code&amp;gt;&amp;amp;lt;&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== tail ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* tail(''list'' [, ''count''])&lt;br /&gt;
&lt;br /&gt;
Returns the last item from the ''list''; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tail([5, 7, 9])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;9&amp;lt;/code&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tail( [ 'Orc', 'Human' ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'Human'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a second argument is given, it returns a list containing the last ''count'' elements from the ''list''. Note that &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;tail(L)&amp;lt;/syntaxhighlight&amp;gt; is different from &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;tail(L,1)&amp;lt;/syntaxhighlight&amp;gt; - the former returns the last element, while the latter returns a list containing only the last element.&lt;br /&gt;
&lt;br /&gt;
==== tolist ====&lt;br /&gt;
&lt;br /&gt;
* tolist(''map'')&lt;br /&gt;
&lt;br /&gt;
This function takes a map and return a list of key-value pair objects. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tolist(['Elf' -&amp;gt; 10, 'Dwarf' -&amp;gt; 20])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
&lt;br /&gt;
 [{key-&amp;gt;'Elf',value-&amp;gt;10}, {key-&amp;gt;'Dwarf',value-&amp;gt;20}]&lt;br /&gt;
&lt;br /&gt;
==== tomap ====&lt;br /&gt;
&lt;br /&gt;
* tomap(''list A'' [, ''list B''])&lt;br /&gt;
&lt;br /&gt;
This function takes one or two ''lists'' as input and returns a map. If only one list is specified, then the function will evaluate this list, count how many similar elements are found within the list, and return a map with keys being these elements, and values being a number representing how many of them the list contains. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tomap(['elf', 'dwarf', 'elf', 'elf', 'human', 'human'])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
&lt;br /&gt;
 ['elf' -&amp;gt; 3, 'dwarf' -&amp;gt; 1, 'human' -&amp;gt; 2]&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} However, if all the elements are key-value pairs such as those created by ''pair'' or ''tolist'', then this function will invert the effect of ''tolist'' and return the original map which would have produced the input list as output when passed to ''tolist''. If only some elements are key-value pairs, those elements will be directly converted into key-value pairs in the resulting map, while other values will be treated as described above.&lt;br /&gt;
&lt;br /&gt;
If two lists are specified, then the elements of the first one will be used as a keys, and the elements of the second one as a values, when creating an output map. Note that these input lists must be of the same length. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tomap(['elf', 'dwarf' ], [10, 20])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in:&lt;br /&gt;
&lt;br /&gt;
 ['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20]&lt;br /&gt;
&lt;br /&gt;
==== values ====&lt;br /&gt;
&lt;br /&gt;
* values(''map'')&lt;br /&gt;
&lt;br /&gt;
Extracts the values assigned to keys from an input ''map'' and returns them as a list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
values(['Elvish Fighter' -&amp;gt; 50, 'Elvish Archer' -&amp;gt; 60])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns&lt;br /&gt;
&lt;br /&gt;
 [50, 60]&lt;br /&gt;
&lt;br /&gt;
=== List-processing Functions ===&lt;br /&gt;
&lt;br /&gt;
This section covers functions that operate on maps or lists by applying one or more formulas in succession to each element. Most return another map or list, &amp;lt;code&amp;gt;reduce&amp;lt;/code&amp;gt; instead combines all the elements into a single result.&lt;br /&gt;
&lt;br /&gt;
==== choose ====&lt;br /&gt;
&lt;br /&gt;
* choose(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates ''formula'' for each item in the ''input'' (which can be a list or a map). It will return the first item to which ''formula'' gave the highest value. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
choose(my_units, level)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gives back the unit with the highest level.&lt;br /&gt;
&lt;br /&gt;
The implicit input when evaluating a mapping/filtering function's ''formula'' component will be that specific item under evaluation (in this example one of &amp;quot;my_units&amp;quot;), and it can be explicitly referenced as &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; when necessary. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
When evaluating a map, we can reference each key by &amp;lt;code&amp;gt;key&amp;lt;/code&amp;gt; and each value by &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;. In this case, the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable is this key-value pair. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
choose(['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20 ], value)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return a key-value pair &lt;br /&gt;
&lt;br /&gt;
 {key-&amp;gt;'dwarf', value-&amp;gt;20}&lt;br /&gt;
&lt;br /&gt;
The curly braces are used in output to indicate that this is an object, not a map. It is not valid WFL syntax.&lt;br /&gt;
&lt;br /&gt;
==== filter ====&lt;br /&gt;
&lt;br /&gt;
* filter(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on each item in the ''input'' (which can be a list or a map). It will evaluate to a list or map which only contains items that the ''formula'' was true for. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
filter(my_units, hitpoints &amp;lt; max_hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return all of your units which have less than maximum hitpoints. For instance this could be used if looking for candidates for healing.&lt;br /&gt;
&lt;br /&gt;
==== find ====&lt;br /&gt;
 &lt;br /&gt;
* find(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run &amp;lt;formula&amp;gt; on each item in the &amp;lt;input&amp;gt; (which can be a list or a map) and will return the first item for which &amp;lt;formula&amp;gt; was true. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
find(units, type = 'Elvish Archer' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return the first unit of type 'Elvish Archer'.&lt;br /&gt;
&lt;br /&gt;
==== map ====&lt;br /&gt;
&lt;br /&gt;
* map(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on each item in the ''input'' (which can be a list or a map), and evaluate to a new list or map or a map, which contains the same number of items as in ''input'', with the formulas run on each item. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable. When run on a map, the resulting map has the same keys as the input map, but with the values updated to the results of the ''formula''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map([10,20], self*self)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map([10,20], 'value', value*value)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will both result in [100, 400]. The formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(my_units, hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will give a list back with the number of hitpoints each unit has. This is more useful in conjunction with other functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20 ], value*2)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will produce ['elf' -&amp;gt; 20, 'dwarf' -&amp;gt; 40]. Note that in case of a map data type, the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; function can only modify the value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(tomap([3,5,8,8]), value+key*100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will produce &amp;lt;code&amp;gt;[3 -&amp;gt; 301, 5 -&amp;gt; 502, 8 -&amp;gt; 801]&amp;lt;/code&amp;gt;. This can be used to take a list and make a map containing pairs &amp;lt;code&amp;gt;[element_from_that_list -&amp;gt; f(element_from_that_list,number_of_repetitions_of_that_element_in_that_list)]&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; is an arbitrary function.&lt;br /&gt;
&lt;br /&gt;
==== reduce ====&lt;br /&gt;
&lt;br /&gt;
* reduce(''list'', [''identity'', ] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on the first and second members of the ''list'', then on the result and the third member and so on until the list is depleted. The final result is then returned. The two variables used in the ''formula'' are always 'a' and 'b'.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;reduce([1,2,3,4], a+b)&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; and &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;reduce([9,4,8,2], 10*a+b)&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;9482&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The new ''identity'' argument specifies the starting value (which is null or 0 by default). If ''list'' is empty, then ''identity'' is returned. Otherwise, the list will be considered as if ''identity'' were an extra first element. For example, to calculate the product of a list of numbers, you might do something like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
reduce(your_list, 1, a * b)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will return 1 if the list is empty, as expected - the product of no numbers is 1. If the list is not empty, adding 1 to the list will have no effect, since it is the multiplicative identity.&lt;br /&gt;
&lt;br /&gt;
==== take_while ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* take_while(''list'', ''formula'')&lt;br /&gt;
&lt;br /&gt;
Evaluates the ''formula'' for each element of the ''list'' until it finds one for which it evaluates to false, then returns a list of all elements up to but not including that element. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
take_while([1,5,3,6,3,7,9,5,6,4,12,2,53,2,1], self &amp;lt; 10)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns the list &amp;lt;code&amp;gt;[1,5,3,6,3,7,9,5,6,4]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== zip ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* zip(''list1'', ... , ''listN'')&lt;br /&gt;
* zip(''list of lists'')&lt;br /&gt;
&lt;br /&gt;
Takes a list of lists and generates a new list of lists such that list ''n'' contains element ''n'' of each of the original lists, in order. If the lists are not all of the same length, it treats them as if they were padded on the end with null values so that they are all the length of the longest list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
zip([1,2,3],[4,5,6])&lt;br /&gt;
zip([1,4],[2,5],[3,6])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return &amp;lt;code&amp;gt;[[1,4],[2,5],[3,6]]&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;[[1,2,3],[4,5,6]]&amp;lt;/code&amp;gt;, respectively.&lt;br /&gt;
&lt;br /&gt;
=== Location Functions ===&lt;br /&gt;
&lt;br /&gt;
Functions for working with locations on a hex map.&lt;br /&gt;
&lt;br /&gt;
==== adjacent_locs ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* adjacent_locs(''center'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of all locations adjacent to the specified location. When called from a formula with access to the game state, it automatically excludes locations that don't exist on the map. Otherwise, it operates as if on an infinite map. This means you should generally not expect the returned list to contain exactly 6 elements.&lt;br /&gt;
&lt;br /&gt;
==== are_adjacent ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* are_adjacent(''loc1'', ''loc2'')&lt;br /&gt;
&lt;br /&gt;
Check if two locations are adjacent. Returns 1 (true) or 0 (false).&lt;br /&gt;
&lt;br /&gt;
==== direction_from ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* direction_from(''start'', ''direction'', [''distance''])&lt;br /&gt;
&lt;br /&gt;
Returns the hex reached by travelling in the specified direction from a starting hex for a certain distance (default 1 hex).&lt;br /&gt;
&lt;br /&gt;
==== distance_between ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* distance_between(''start'', ''end'')&lt;br /&gt;
&lt;br /&gt;
Returns the distance between the locations ''start'' and ''end'', which must be location objects such as those created by &amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This function was already available in FormulaAI prior to 1.13.5; however, from 1.13.5 onward it is available to all formulas.&lt;br /&gt;
&lt;br /&gt;
==== loc ====&lt;br /&gt;
&lt;br /&gt;
* loc(''x'', ''y'')&lt;br /&gt;
&lt;br /&gt;
Creates and returns a location object with the specified coordinates. If assigned to a variable ''pos'' (eg with a &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clause), the individual coordinates can be accessed as &amp;lt;code&amp;gt;pos.x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;pos.y&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== locations_in_radius ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* locations_in_radius(''center'', ''radius'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of all locations within a given radius of the specified center hex.&lt;br /&gt;
Only locations on the map will be returned.&lt;br /&gt;
&lt;br /&gt;
==== nearest_loc ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* nearest_loc(''origin'', ''locations'')&lt;br /&gt;
&lt;br /&gt;
Returns the location in the given list closest to ''origin''. All arguments must be location objects such as those created by &amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This function was already available in FormulaAI prior to 1.19.14; however, from 1.19.14 onward it is available to all formulas.&lt;br /&gt;
&lt;br /&gt;
==== relative_dir ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* relative_dir(''loc1'', ''loc2'')&lt;br /&gt;
&lt;br /&gt;
Returns the direction you need to travel to progress from one location to another. The returned location is one of the six possible directions on the Wesnoth hex map, or an empty string if both locations are the same.&lt;br /&gt;
&lt;br /&gt;
==== rotate_loc_around ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}} but returns wrong result until {{DevFeature1.19|2}}&lt;br /&gt;
&lt;br /&gt;
* rotate_loc_around(''center'', ''loc'', ''angle'')&lt;br /&gt;
&lt;br /&gt;
Rotates a location around a given center to produce a new location. The angle is an integer between -6 and 6, which can be understood as a multiple of 60 degrees.&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous Functions ===&lt;br /&gt;
&lt;br /&gt;
Some functions really don't fit into any category. They are all listed here.&lt;br /&gt;
&lt;br /&gt;
==== null ====&lt;br /&gt;
&lt;br /&gt;
* null([''arguments''])&lt;br /&gt;
&lt;br /&gt;
Evaluates each of its arguments (if any) in order, then returns null. Since formulas generally do not have side-effects, there is usually little point in specifying any arguments, but it could be thought of as a way to &amp;quot;comment out&amp;quot; a section of the formula while ensuring it remains syntactically valid.&lt;br /&gt;
&lt;br /&gt;
==== pair ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* pair(''key'', ''value'')&lt;br /&gt;
&lt;br /&gt;
Creates a key-value pair object, the same as those created by the ''tolist'' function.&lt;br /&gt;
&lt;br /&gt;
==== reverse ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* reverse(''string or list'')&lt;br /&gt;
&lt;br /&gt;
Returns the input string or list backwards.&lt;br /&gt;
&lt;br /&gt;
==== type ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* type(''anything'')&lt;br /&gt;
&lt;br /&gt;
Returns the type of its input as a string. Possible results are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;'integer'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'decimal'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'string'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'list'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'map'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'null'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'object'&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== get_palette ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* get_palette(''name'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of colours that make up the named palette. Palettes are defined by a '''[color_palette]''' tag, usually in the [[GameConfigWML#Color_Palettes|game config]]. The palettes defined in core Wesnoth are '''magenta''', '''flag_green''', and '''ellipse_red'''. In addition to defined palettes, several hard-coded palettes are available by name. They are '''red_green_scale''', '''red_green_scale_text''', '''blue_white_scale''', and '''blue_white_scale_text'''. These are also defined in the game config, but not with a '''[color_palette]''' tag.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Functions ===&lt;br /&gt;
&lt;br /&gt;
There are also a few functions that can be useful for debugging formulas, for example by displaying intermediate results to the screen. Note that this breaks the general rule that functions do not have side-effects.&lt;br /&gt;
&lt;br /&gt;
==== debug ====&lt;br /&gt;
&lt;br /&gt;
* debug([''formula''])&lt;br /&gt;
&lt;br /&gt;
Starts a GUI formula debugger when evaluating a formula. It takes a formula, evaluates it and returns the result unchanged. '''Note:''' this does not appear to work in 1.13.3.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The formula allows you to step through the formula one operation at a time, viewing the current stack and execution trace. As of 1.13.5, you need to enable [[CommandMode|debug mode]] to use the debugger; otherwise, it will simply be skipped.&lt;br /&gt;
&lt;br /&gt;
==== debug_print ====&lt;br /&gt;
&lt;br /&gt;
'''you need to enable formula log (--log-info='scripting/formula') to see the result of this call'''&lt;br /&gt;
&lt;br /&gt;
* debug_print([''explanation'' ,] ''formula'' )&lt;br /&gt;
&lt;br /&gt;
This function can be used for debugging a formula. It takes a ''formula'', writes its result to the console, and returns it unchanged. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_print([1, 2, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in printing to the console&lt;br /&gt;
&lt;br /&gt;
 [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
and returning the same.&lt;br /&gt;
&lt;br /&gt;
We can specify an optional parameter ''explanation'' that helps to distinguish between multiple ''debug_print'' calls in the same formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_print('My array: ', [1, 2, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will write in the console:&lt;br /&gt;
&lt;br /&gt;
 My array: [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
and return&lt;br /&gt;
&lt;br /&gt;
 [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
==== debug_profile ====&lt;br /&gt;
&lt;br /&gt;
* debug_profile(''formula'' [, ''explanation''])&lt;br /&gt;
&lt;br /&gt;
Evaluates the formula 1000 times and prints (as with debug_print) a number indicating the average time required to evaluate the formula. Mainly intended for internal testing, but could occasionally be useful for people working with complicated formulas. The optional ''explanation'' argument is used in the same way as in debug_print.&lt;br /&gt;
&lt;br /&gt;
==== debug_float ====&lt;br /&gt;
&lt;br /&gt;
* debug_float(''location'', [''explanation'',] ''formula'' )&lt;br /&gt;
&lt;br /&gt;
This function can be used for debugging a formula. It takes a formula, floats a label containing the result on the hex specified (in the same way damage is displayed) and returns it unchanged. Note that the ''location'' here is an object type; it can be created with the &amp;lt;code&amp;gt;[[#loc|loc()]]&amp;lt;/code&amp;gt; function. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_float(me.loc, me.id)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will make a label containing the id of the unit ''me'' float over the unit.&lt;br /&gt;
&lt;br /&gt;
Return value is also the unit id.&lt;br /&gt;
&lt;br /&gt;
We can specify an optional parameter ''explanation'' that helps to distinguish between multiple ''debug_float'' calls in the same formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_float( me.loc, 'id: ', me.id )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will float the following label&lt;br /&gt;
&lt;br /&gt;
 id: unit_id&lt;br /&gt;
&lt;br /&gt;
and return the unit id.&lt;br /&gt;
&lt;br /&gt;
==== dir ====&lt;br /&gt;
&lt;br /&gt;
* dir(''object'')&lt;br /&gt;
&lt;br /&gt;
This function return a list of all attributes in ''object''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
dir(my_leader)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in the following output:&lt;br /&gt;
&lt;br /&gt;
 [ 'x', 'y', 'loc', 'id', 'type', 'name', 'leader', 'undead', 'traits', 'attacks', 'abilities', 'hitpoints',&lt;br /&gt;
 'max_hitpoints', 'experience', 'max_experience', 'level', 'total_movement', 'movement_left', 'attacks_left',&lt;br /&gt;
 'side', 'states', 'cost', 'usage', 'vars']&lt;br /&gt;
&lt;br /&gt;
This command is useful in the formula command line, to get information about the attributes of different types of data.&lt;br /&gt;
&lt;br /&gt;
=== Game State Functions ===&lt;br /&gt;
&lt;br /&gt;
These are functions that access the game state. Therefore, they are not available in all formulas, as described above.&lt;br /&gt;
&lt;br /&gt;
==== base_tod_bonus ====&lt;br /&gt;
&lt;br /&gt;
* base_tod_bonus([''loc'', [''turn'']])&lt;br /&gt;
&lt;br /&gt;
Evaluates the base time-of-day bonus, excluding the effect of illumination from abilities or terrain. If no turn is specified, the current turn is used. If no location is specified, the bonus is calculated for the global schedule without taking any time areas into account, but if a location is specified, it will account for any time areas that might affect that location.&lt;br /&gt;
&lt;br /&gt;
==== chance_to_hit ====&lt;br /&gt;
&lt;br /&gt;
* chance_to_hit(''unit'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the base chance for the unit to be hit if it moved to the given location or terrain. This is essentially the inverse of its defense. It is returned as an integer between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
==== defense_on ====&lt;br /&gt;
&lt;br /&gt;
* defense_on(''unit'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the defense that the unit would have if it moved to the given location or terrain. It is returned as an integer between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
==== enemy_of ====&lt;br /&gt;
&lt;br /&gt;
* enemy_of(''self'', ''other'')&lt;br /&gt;
&lt;br /&gt;
Determines whether two units are enemies. Returns 1 (true) or 0 (false).&lt;br /&gt;
&lt;br /&gt;
==== get_unit_type ====&lt;br /&gt;
&lt;br /&gt;
* get_unit_type(''id'')&lt;br /&gt;
&lt;br /&gt;
Returns an object describing the specified unit type, or null if no such unit type exists. A unit type object has many of the same keys as a unit, excluding those that are expected to change over time such as &amp;lt;tt&amp;gt;hitpoints&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== jamming_cost ====&lt;br /&gt;
&lt;br /&gt;
* jamming_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the jamming cost for the unit to block vision on the given location terrain.&lt;br /&gt;
&lt;br /&gt;
==== is_fogged ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* is_shrouded(''loc'', ''side_number''])&lt;br /&gt;
&lt;br /&gt;
Returns whether the given location is currently fogged from the point of view of the given side.&lt;br /&gt;
&lt;br /&gt;
==== is_shrouded ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* is_shrouded(''loc'', ''side_number''])&lt;br /&gt;
&lt;br /&gt;
Returns whether the given location is currently shrouded from the point of view of the given side.&lt;br /&gt;
&lt;br /&gt;
==== movement_cost ====&lt;br /&gt;
&lt;br /&gt;
* movement_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the movement cost for the unit to enter the given location or terrain.&lt;br /&gt;
&lt;br /&gt;
==== resistance_on ====&lt;br /&gt;
&lt;br /&gt;
* resistance_on(''unit'', ''location'', ''type'', [''attacker''])&lt;br /&gt;
&lt;br /&gt;
Calculates the unit's resistance to the given damage type when standing on the specified location. If specified, the ''attacker'' parameter should be 1 to indicate that the unit is the attacker, or 0 to indicate that it is the defender, as this status can affect resistances. By default, it is assumed to be the defender.&lt;br /&gt;
&lt;br /&gt;
This is returned not as the raw resistance set in WML, but the actual resistance that the player sees, so it ranges between -100 and 100.&lt;br /&gt;
&lt;br /&gt;
==== tod_bonus ====&lt;br /&gt;
&lt;br /&gt;
* tod_bonus([''loc'', [''turn'']])&lt;br /&gt;
&lt;br /&gt;
Evaluates the final time-of-day bonus, accounting for the effect of illumination from abilities or terrain. If no turn is specified, the current turn is used. If no location is specified, the bonus is calculated for the global schedule without taking any time areas into account, but if a location is specified, it will account for any time areas that might affect that location.&lt;br /&gt;
&lt;br /&gt;
==== unit_at ====&lt;br /&gt;
&lt;br /&gt;
* unit_at(''location'')&lt;br /&gt;
&lt;br /&gt;
Returns the unit on the given location, or null if there is no unit there.&lt;br /&gt;
&lt;br /&gt;
==== unit_tod_modifier ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* unit_tod_modifier(''unit'', [''loc''])&lt;br /&gt;
&lt;br /&gt;
Returns the current combat damage modifier for the given unit for the current time of day, taking into account any abilities whose effects it is currently under (illuminates, for example). If no location is specified, the unit's current location will be used.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Prior to 1.19.4, this function was available as the FormulaAI function ''timeofday_modifier''.&lt;br /&gt;
&lt;br /&gt;
==== vision_cost ====&lt;br /&gt;
&lt;br /&gt;
* vision_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the vision cost for the unit to see through the given location or terrain.&lt;br /&gt;
&lt;br /&gt;
=== Action Functions ===&lt;br /&gt;
&lt;br /&gt;
These are special functions that represent an action to be executed. They don't actually execute the action, merely describe it – the action will be executed only after the formula has been fully evaluated.&lt;br /&gt;
&lt;br /&gt;
Action functions can currently only be used in GUI2, in the '''actions''' key. This key must always evaluate to either an action or a list of actions.&lt;br /&gt;
&lt;br /&gt;
==== set_var ====&lt;br /&gt;
&lt;br /&gt;
* set_var(''name'', ''value'')&lt;br /&gt;
&lt;br /&gt;
Sets a variable in the current '''self''' context to the specified value.&lt;br /&gt;
&lt;br /&gt;
The result of this function is an object that has '''name''' and '''value''' keys with the passed-in values.&lt;br /&gt;
&lt;br /&gt;
==== safe_call ====&lt;br /&gt;
&lt;br /&gt;
* safe_call(''main'', ''backup'')&lt;br /&gt;
&lt;br /&gt;
Tries to execute the ''main'' action first. If that fails, the ''backup'' action is executed instead.&lt;br /&gt;
&lt;br /&gt;
The ''backup'' formula can access a special '''error''' object, which in turn contains two values:&lt;br /&gt;
&lt;br /&gt;
* '''status''': A status code representing the type of error. Currently, the only possible status is 5001, which means the current context is immutable.&lt;br /&gt;
* '''object''': The action that failed to execute – in other words, the result of evaluating the ''main'' formula.&lt;br /&gt;
&lt;br /&gt;
The result of this function is an object that has a '''main''' key that contains the result of evaluating the main formula.&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Wesnoth_Formula_Language&amp;diff=74773</id>
		<title>Wesnoth Formula Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Wesnoth_Formula_Language&amp;diff=74773"/>
		<updated>2026-01-25T06:58:44Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Document the two action functions.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;tright&amp;quot;&amp;gt; __TOC__ &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Wesnoth Formula Language is a functional language used to evaluate expressions within the game engine. It allows performing calculations that would not otherwise be possible using only WML. For example, to have an event trigger when a unit has less than half its hitpoints, you could write the following as the event's filter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[filter]&lt;br /&gt;
    formula = &amp;quot;(hitpoints &amp;lt; max_hitpoints / 2)&amp;quot;&lt;br /&gt;
[/filter]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''formula''' key is a part of [[StandardUnitFilter]] that accepts a condition written as WFL. The part inside the quotes is the WFL formula. This example will evaluate to true if the unit's '''hitpoints''' are less than half its '''max_hitpoints'''.&lt;br /&gt;
&lt;br /&gt;
== Data Types and Operators ==&lt;br /&gt;
&lt;br /&gt;
Wesnoth Formula Language has seven basic data types – [[#Numbers|integers]], [[#Numbers|real numbers]] (usually called &amp;quot;decimals&amp;quot;), [[#Strings|strings]], [[#Lists|lists]], [[#Maps|maps]], [[#Objects|objects]], and [[#Other Types and Operators|null]].&lt;br /&gt;
&lt;br /&gt;
=== Numbers ===&lt;br /&gt;
&lt;br /&gt;
The most common use of WFL is for simple calculations involving numbers. For this, the standard arithmetic operators (&amp;lt;code&amp;gt;+ - * / %&amp;lt;/code&amp;gt;) work as you would expect, performing addition, subtraction, multiplication, division, and remainder. {{DevFeature1.13|5}} The remainder operator even works on decimal numbers, producing the integer remainder of the division.&lt;br /&gt;
&lt;br /&gt;
The only caveat to watch out for is that &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; rounds down when used on integers. For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;5 / 2&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;. To avoid this, make sure at least one of the numbers includes a decimal point (or use [[#as_decimal|as_decimal]] if variables are involved) - &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;5.0 / 2&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;2.5&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note that WFL supports only three decimal places of precision for decimal numbers; beyond that it will still be rounded down. (So &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;1.0 / 16&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;0.062&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;0.0625&amp;lt;/code&amp;gt;.) The &amp;lt;code&amp;gt;^&amp;lt;/code&amp;gt; operator performs exponentiation (raising to a power) - for example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;2 ^ 3&amp;lt;/syntaxhighlight&amp;gt; evaluates to &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use the standard comparison operators (&amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;=&amp;lt;/code&amp;gt;) on numbers. This is often useful in unit filters - for example, a formula of &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;hitpoints &amp;lt; max_hitpoints / 2&amp;lt;/syntaxhighlight&amp;gt; will match only if the unit is at less than half health. Comparison operators return 1 for true and 0 for false; there is no boolean type. Comparing values of different types will always return 0, with one exception – comparing an integer and decimal number will work as expected.&lt;br /&gt;
&lt;br /&gt;
One final numeric operator exists - the dice roll. The syntax &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;3d12&amp;lt;/syntaxhighlight&amp;gt; will roll three 12-sided dice and return the sum of the results. Note however that this is not multiplayer-safe, so using it can and will produce OOS errors. {{DevFeature1.13|5}} The dice operator is now synced and should be safe for use in multiplayer contexts.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' {{DevFeature1.13|5}} Some numeric operations will return null instead of a number. This usually involves the exponentiation operator - for example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;(-2) ^ 0.5&amp;lt;/syntaxhighlight&amp;gt; attempts to take the square root of -2, which doesn't exist, so it returns null to indicate this. Dividing by zero also returns null, as well as certain [[#Numeric Functions|math functions]] in appropriate circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
WFL also supports strings, which must be enclosed in single quotes (&amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;'like this'&amp;lt;/syntaxhighlight&amp;gt;). The comparison operators (&amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;=&amp;lt;/code&amp;gt;) also work on strings, performing lexicographical comparison (ie, alphabetical order). The comparison is case sensitive.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
Strings can be concatenated with the concatenation operator &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt;. They also support interpolations enclosed in square brackets, the contents of which can be any valid formula. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Some text: [a + b]' where a = 12, b = 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
results in the string &amp;lt;code&amp;gt;Some text: 22&amp;lt;/code&amp;gt;. (The &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; operator is explained [[#Variables|below]].)&lt;br /&gt;
&lt;br /&gt;
If you need to include a literal square bracket in a string, write &amp;lt;code&amp;gt;[(]&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;[)]&amp;lt;/code&amp;gt;. For a literal single quote, you can write &amp;lt;code&amp;gt;[']&amp;lt;/code&amp;gt;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'[(]It[']s bracketed![)]'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
results in the string &amp;lt;code&amp;gt;[It's bracketed!]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can index the characters or words of a string with the following syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Hello World'.char[4]&lt;br /&gt;
'Hello World'.word[1]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These return &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;World&amp;lt;/code&amp;gt;, respectively. A third option is also available, &amp;lt;code&amp;gt;item&amp;lt;/code&amp;gt;, which splits the string on commas but allows parentheses to prevent a portion of the string from being split up. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'First Item,Second Item,Third Item'.item[1]&lt;br /&gt;
'a,b,(c,d,e),f,g'.item[2]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These return &amp;lt;code&amp;gt;Second Item&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;(c,d,e)&amp;lt;/code&amp;gt;, respectively. When not providing index, list is returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Hello World'.char = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']&lt;br /&gt;
'Hello World'.word = ['Hello', 'World']&lt;br /&gt;
'a,b,(c,d,e),f,g'.item = ['a', 'b', '(c,d,e)', 'f', 'g']&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lists ===&lt;br /&gt;
&lt;br /&gt;
A list is a sequence of values represented as square brackets, [], surrounding a comma-separated list. For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[ 1, 5, 'abc' ]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The comparison operators work on lists, performing lexicographical comparison. A specific list index can be obtained with the indexing operator, like this: &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;my_list[index]&amp;lt;/syntaxhighlight&amp;gt;. The first element of a list is numbered 0.&lt;br /&gt;
&lt;br /&gt;
There are four ''vector operators'' (&amp;lt;code&amp;gt;.+ .- .* ./&amp;lt;/code&amp;gt;) that perform entrywise operations on lists. For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;[1,2,3] .+ [12,2,8]&amp;lt;/syntaxhighlight&amp;gt; produces &amp;lt;code&amp;gt;[13,4,11]&amp;lt;/code&amp;gt;. Both lists must be of the same length to use these operators, and of course, they must contain only numbers.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
A negative list index now counts from the end of the list - &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt; refers to the last element. You can check if an element exists in a list using the &amp;lt;code&amp;gt;in&amp;lt;/code&amp;gt; operator. Lists can also be joined with the concatenation operator &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt;, and sliced using the range operator &amp;lt;code&amp;gt;~&amp;lt;/code&amp;gt;. In fact, the range operator produces a list of consecutive numbers, and in fact any list of numbers can be used to index a list - the result is to take the elements at the requested indices, in order. Some examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[1, 7, 'abc', 2.5, 'foobar', 127][1~3]&lt;br /&gt;
(10~20)[[0,-1]]&lt;br /&gt;
[1, 7, 'abc', 2.5, 'foobar', 127][[2,4]]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These result in the following lists:&lt;br /&gt;
&lt;br /&gt;
 [7, 'abc', 2.5]&lt;br /&gt;
 [10,20]&lt;br /&gt;
 ['abc', 'foobar']&lt;br /&gt;
&lt;br /&gt;
=== Maps ===&lt;br /&gt;
&lt;br /&gt;
A map is a sequence of key-value pairs. For example: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[12 -&amp;gt; 'Hello', [1,2] -&amp;gt; 9, 'abc' -&amp;gt; 1.5]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The comparison operators work on maps. A specific element of a map can be obtained with the indexing operation. In the above example, the following conditions are all true (assuming the map is in a variable called &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self[12] = 'Hello'&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self[[1,2]] = 9&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self['abc'] = 1.5&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
You can now use the &amp;lt;code&amp;gt;in&amp;lt;/code&amp;gt; operator to test if a key exists in the map. You can also access string keys using the dot operator &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; as long as they are valid identifiers. (Valid identifiers contain letters and underscores only; no digits are permitted.)&lt;br /&gt;
&lt;br /&gt;
Note that the selection indexing that lists use is ''not'' valid for maps - a list can be used as a key, after all.&lt;br /&gt;
&lt;br /&gt;
Though it's rarely needed, it's possible to define an empty map with &amp;lt;code&amp;gt;[ -&amp;gt; ]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Objects ===&lt;br /&gt;
&lt;br /&gt;
An object is a container containing additional variables (see [[#Variables|below]] for further explanation of variables) which are not in the global scope. The ''dot operator'' can be used to evaluate a formula in the object's scope. For example, suppose ''u'' is a unit object referring to your leader, who is an Elvish Ranger who has taken 12 damage (thus has 30 hit points). Then &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u.hitpoints&amp;lt;/syntaxhighlight&amp;gt; will evaluate to the number 30. For a more advanced example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u . (hitpoints &amp;lt; max_hitpoints - 10)&amp;lt;/syntaxhighlight&amp;gt; will evaluate to true if the unit has taken more than 10 damage, which in this example, it has. (This could also be written &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u.hitpoints &amp;lt; u.max_hitpoints - 10&amp;lt;/syntaxhighlight&amp;gt; if you prefer; this enters the scope twice, instead of once, but the result is identical.)&lt;br /&gt;
&lt;br /&gt;
Objects generally cannot be created directly by the code - they are created for you by the game when formulas are called in certain contexts. However, there are two types of object that ''can'' be created by your code. The first is the location object, which has variables ''x'' and ''y''; it can be created by the [[#loc|&amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;]] function. The second is the map pair object, which is returned (or used internally) by several of the built-in functions and has variables ''key'' and ''value''.&lt;br /&gt;
&lt;br /&gt;
==== Documentation of some common objects ====&lt;br /&gt;
&lt;br /&gt;
There are a number of common objects that are given as the context object for formulas throughout the engine. Not all of these will be available in all formulas, but many of them are available in more than one formula. To learn what objects are available in a given location, see the WML documentation of that location.&lt;br /&gt;
&lt;br /&gt;
* [[StandardUnitFilter#Wesnoth_Formula_Language|unit objects]]&lt;br /&gt;
* [[FilterWML#Filtering_Weapons|weapon objects]]&lt;br /&gt;
* [[StandardLocationFilter#Wesnoth_Formula_Language|terrain objects]]&lt;br /&gt;
* [[StandardSideFilter#Wesnoth_Formula_Language|side objects]]&lt;br /&gt;
* [[ImagePathFunctions#CHAN:_General function|pixel objects]]&lt;br /&gt;
* [[ConditionalActionsWML#.5Bvariable.5D|WML objects]]&lt;br /&gt;
* [[EventWML#filter_formula|game state objects]]&lt;br /&gt;
&lt;br /&gt;
=== Other Types and Operators ===&lt;br /&gt;
&lt;br /&gt;
There is one other basic type in WFL - the null type, which is used to mean &amp;quot;no value&amp;quot;. It will be returned if you attempt to perform an invalid operation, such as dividing a string. It is also returned by the built-in &amp;lt;code&amp;gt;null()&amp;lt;/code&amp;gt; function, which allows you to test if a value is null by writing &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;value = null()&amp;lt;/syntaxhighlight&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The logical operators &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; can be used to connect conditional expressions, and the unary operator &amp;lt;code&amp;gt;not&amp;lt;/code&amp;gt; negates them. Note that &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; is inclusive - &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;A or B&amp;lt;/syntaxhighlight&amp;gt; is false only if both ''A'' and ''B'' are false. These operators consider &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or null to be false, while all other values count as true. The [[#if|&amp;lt;code&amp;gt;if()&amp;lt;/code&amp;gt;]] function also follows the same rules to determine whether a value is true or false.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Programmers familiar with other languages may occasionally be surprised by the fact that &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; do not short-circuit (which would mean that they will never evaluate their second argument if they can know their result solely from the first argument). This should not be a problem in general formula usage, since functions do not have side-effects, but it could make a difference when using the debug functions.&lt;br /&gt;
&lt;br /&gt;
=== Operator Precedence ===&lt;br /&gt;
&lt;br /&gt;
The precedence of various operators is, more or less, what you'd expect - you can write something like &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a + b * 2 &amp;lt;= 5 and n - m / 4 &amp;gt; 7&amp;lt;/syntaxhighlight&amp;gt; and the engine will do what you expect - first multiplication and division, then addition and subtraction, then comparison, and finally logical conjunction. The only thing to watch out for is when chaining exponentiation - all operators are left associative, so &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a ^ b ^ c&amp;lt;/syntaxhighlight&amp;gt; will be evaluated as &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;(a ^ b) ^ c&amp;lt;/syntaxhighlight&amp;gt; instead of &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a ^ (b ^ c)&amp;lt;/syntaxhighlight&amp;gt; like you would expect. {{DevFeature1.13|5}} This has been fixed - exponentiation is now right-associative.&lt;br /&gt;
&lt;br /&gt;
The full precedence list is as follows, from lowest to highest; operators on the same line have equal precedence.&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;not&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clauses&lt;br /&gt;
# &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt;&lt;br /&gt;
# Comparison operators &amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;= in&amp;lt;/code&amp;gt;&lt;br /&gt;
# Range-generating operator &amp;lt;code&amp;gt;~&amp;lt;/code&amp;gt;&lt;br /&gt;
# Additive operators &amp;lt;code&amp;gt;+ - ..&amp;lt;/code&amp;gt;&lt;br /&gt;
# Multiplicative operators &amp;lt;code&amp;gt;* /&amp;lt;/code&amp;gt;&lt;br /&gt;
# Modulus &amp;lt;code&amp;gt;%&amp;lt;/code&amp;gt;&lt;br /&gt;
# Exponentiation &amp;lt;code&amp;gt;^&amp;lt;/code&amp;gt;&lt;br /&gt;
# Dice operator &amp;lt;code&amp;gt;d&amp;lt;/code&amp;gt;&lt;br /&gt;
# Dot operator &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
WFL is a ''functional'' language, so of course it has functions. There is a large library of [[#Core Functions|built-in functions]], and you can also [[#Defining Functions|define your own]].&lt;br /&gt;
&lt;br /&gt;
Calling a function is simple, and works exactly how you would expect if you've worked with functions in a mathematical context: &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;clamp(value, 0, 21)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Being a functional language, WFL does not have conditional or looping statements. Instead, these are provided by functions. For a simple conditional, you can use the &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; function, as in the following example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wfl&amp;gt;&lt;br /&gt;
if(hitpoints &amp;gt; 37,&lt;br /&gt;
    max_hitpoints / 2,&lt;br /&gt;
    hitpoints - 3&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Similarly, looping is done via functions. There are several built-in higher-order functions that can be used to iterate over lists and maps, such as &amp;lt;tt&amp;gt;filter&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;choose&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;map&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;reduce&amp;lt;/tt&amp;gt;. See the corresponding function definitions for more information.&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
Formulas may have a variety of variables, depending on the context in which they are evaluated. A string substitution formula like &amp;lt;code&amp;gt;$(3 + 5)&amp;lt;/code&amp;gt; has no variables, but a [[StandardUnitFilter|unit filter]] formula has variables such as &amp;lt;code&amp;gt;hitpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max_hitpoints&amp;lt;/code&amp;gt; which contain various properties of the unit being tested (the same unit which is also referred to in variable substitution as &amp;lt;code&amp;gt;$this_unit&amp;lt;/code&amp;gt;). The special variable &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; typically refers to the &amp;quot;global context&amp;quot; - in the case of a unit filter formula, the unit itself. This means for example that &amp;lt;code&amp;gt;self.hitpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;hitpoints&amp;lt;/code&amp;gt; are equivalent when used in a unit filter formula. In a string substitution formula (the &amp;lt;code&amp;gt;$(formula)&amp;lt;/code&amp;gt; syntax), &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; is null. Because of this, you should prefer not to use the substitution syntax in places where formulas are specifically supported.&lt;br /&gt;
&lt;br /&gt;
A formula may declare additional variables using a &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clause. This assigns a meaning to any unknown variables in the preceding formula. The general syntax is:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;formula&amp;gt; where &amp;lt;variable&amp;gt; = &amp;lt;value&amp;gt; [, &amp;lt;variable&amp;gt; = value ...]&lt;br /&gt;
&lt;br /&gt;
This functions similarly to an operator, so if desired, you could have multiple where clauses in a single formula. Note that all variables in WFL are read-only - they are variables because they may have different values depending on the context in which the formula is evaluated, but for a given context, they are constant. A variable that has not been assigned a value is considered to have a value of null. Variables are lazily-evaluated - if a where clause declares a variable that is never used, the expression assigned to it will never be evaluated. (This only really matters if it contains a call to a debug function.)&lt;br /&gt;
&lt;br /&gt;
Variable names can contain letters and underscores only. In particular, they cannot contain digits. Also, names are case-sensitive, so ''y'' and ''Y'' refer to two different variables. The following names are reserved and cannot be used for the name of a variable or function:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;d&amp;lt;/tt&amp;gt; - dice operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;or&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; - containment operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;def&amp;lt;/tt&amp;gt; - defines a function&lt;br /&gt;
* &amp;lt;tt&amp;gt;and&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;fai&amp;lt;/tt&amp;gt; - deprecated synonym of &amp;lt;tt&amp;gt;wfl&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;wfl&amp;lt;/tt&amp;gt; - declares filename&lt;br /&gt;
* &amp;lt;tt&amp;gt;where&amp;lt;/tt&amp;gt; - declares variables&lt;br /&gt;
* &amp;lt;tt&amp;gt;faiend&amp;lt;/tt&amp;gt; - deprecated synonym of &amp;lt;tt&amp;gt;wflend&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;wflend&amp;lt;/tt&amp;gt; - closes file scope&lt;br /&gt;
* &amp;lt;tt&amp;gt;functions&amp;lt;/tt&amp;gt; - lists all defined functions&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
Sometimes with particularly complicated formulas, it may be useful to document what's going on inline. Of course, you can use WML comments to do this, but in some cases it may be useful to put some comments in the middle of the formula. This is easily done - simply enclose them in &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; characters, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
#This is a Wesnoth Formula Language comment.#&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the final &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; - unlike WML, WFL requires this to indicate where the comment ends.&lt;br /&gt;
&lt;br /&gt;
== Defining Functions ==&lt;br /&gt;
&lt;br /&gt;
There are several predefined functions in the Wesnoth Formula Language, and if these are not enough, it is possible to define your own functions. The special variable &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;functions&amp;lt;/syntaxhighlight&amp;gt; always evaluates to a list of all known function names. This is mainly useful only as a debugging tool, though.&lt;br /&gt;
&lt;br /&gt;
To define a function, you use the &amp;lt;code&amp;gt;def&amp;lt;/code&amp;gt; keyword. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def sgn(x) if(x &amp;lt; 0, -1, x &amp;gt; 0, 1, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This defines a function called &amp;lt;code&amp;gt;sgn&amp;lt;/code&amp;gt; which returns the sign of the input number. The semicolon marks the end of the function. It's optional if there's nothing else following the function, but in practice this will very rarely be the case.&lt;br /&gt;
&lt;br /&gt;
Function names have the same limitation as variable names – they can contain only letters and underscores, and cannot contain digits.&lt;br /&gt;
&lt;br /&gt;
You can select one of the function's arguments to be the &amp;quot;default&amp;quot; argument. If an object is passed to the default argument, then any attributes of that object are directly accessible in the global scope. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def is_badly_wounded(u*) hitpoints &amp;lt; max_hitpoints / 2;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function takes a unit and returns 1 if it is at less than half hitpoints. The &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; indicates the default argument, without which it would instead have to be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def is_badly_wounded(u) u.hitpoints &amp;lt; u.max_hitpoints / 2;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It's important to remember that the function body has access to no variables other than its parameters. For example, the following function would not work (in a unit filter context) even though the unit variable is defined:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def endangers_me(u) distance_between(u.loc, unit.loc) &amp;lt; u.moves;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is because the body of the function can't see the unit variable. To make this work, you would need to pass in unit as an additional parameter.&lt;br /&gt;
&lt;br /&gt;
'''Note: Prior to 1.14, function definitions only work in AI code and GUI2 code.'''&lt;br /&gt;
&lt;br /&gt;
== Where to Use Formulas ==&lt;br /&gt;
&lt;br /&gt;
Formulas can only be used in specific attributes in WML. The documentation of a WML tag will note which keys can have a formula placed in them. Some common examples include [[FilterWML|filters]], [[GUIToolkit|GUI2 dialogs]], and [[AbilitiesWML|unit abilities]]. Another example is the [[VariablesWML#Variable_Substitution|&amp;lt;code&amp;gt;$(formula)&amp;lt;/code&amp;gt; substitution]] syntax, which allows the use of formulas wherever variables are parsed.&lt;br /&gt;
&lt;br /&gt;
When using a formula in WML (other than in a substitution, which is usually part of a longer already-quoted passage), it is highly recommended to place double quotes around the formula, to avoid ambiguity between the WML and WFL parsers. The double angle quotes are also acceptable for this purpose. If you don't quote your formulas, there are two issues you could run into:&lt;br /&gt;
&lt;br /&gt;
# WML uses the &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; operator to represent concatenation of strings, as well as line continuation. Because of this, an unquoted &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; will be ''removed'', likely causing the WFL formula to fail to compile.&lt;br /&gt;
# Unquoted WML text has the whitespace collapsed. If using WFL strings where whitespace is significant, this can result in surprises. For example, the formula &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;length('One    Two    Three')&amp;lt;/syntaxhighlight&amp;gt; would return 13 instead of the expected 19 if double quotes are not placed around the formula.&lt;br /&gt;
&lt;br /&gt;
Some attributes in WML ''require'' a formula, which means that anything placed in the attribute will always be considered to be a formula. In this case, the formula doesn't need to be enclosed in parentheses – just the double quotes will suffice. However, there are also attributes that take an ''optional'' formula. These are most common in GUI2, but are also found in other places. In such attributes, the formula ''must'' be enclosed in parentheses. Failure to do so will result in it being parsed as just a straight value. As a general guideline, if the attribute key contains the word &amp;quot;formula&amp;quot;, it is usually required to be a formula, whereas attributes with optional formulas do ''not'' contain the word &amp;quot;formula&amp;quot; in the key.&lt;br /&gt;
&lt;br /&gt;
'''Note''': Do ''not'' use a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; to introduce a formula. The &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; is not part of WFL syntax. It introduces a ''substitution'', a concept which is covered in more detail at [[VariablesWML#Variable Substitution]]. Although WFL can be used ''inside'' a substitution, a substitution itself is not WFL, and you should ''never'' use a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; in WFL. However, in practice, substitutions and WFL are often used together – as substitution is processed first, you may see WFL formulas that appear to contain a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; inside them. This is ''not'' part of the WFL – it is more like a macro substitution to be carried out before the formula runs. So, of course, it will only work in places that support ''both'' WFL and substitution.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
On occasion, you may find yourself working with formulas complex enough to split them out into a separate file. The formula engine normally assumes that it is executing inline code and reports errors accordingly, but you can tell it to enter a file scope using the special &amp;lt;code&amp;gt;wfl&amp;lt;/code&amp;gt; keyword. The convention is to frame your code, so that any file looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
wfl 'filename.wfl'&lt;br /&gt;
&lt;br /&gt;
# Put whatever code you need here, possibly including function definitions. #&lt;br /&gt;
&lt;br /&gt;
wflend&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The matching &amp;lt;code&amp;gt;wflend&amp;lt;/code&amp;gt; is required.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This functionality was available prior to 1.13.5 using keywords &amp;lt;code&amp;gt;fai&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;faiend&amp;lt;/code&amp;gt;. {{DevFeature1.19|14}} As of 1.19.14, support for the &amp;lt;code&amp;gt;fai&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;faiend&amp;lt;/code&amp;gt; keywords has been removed.&lt;br /&gt;
&lt;br /&gt;
These directives have no effect on the formula code itself. They only change how error messages are reported if something goes wrong. Files using these directives are usually included using the WML preprocessor, though they could also be loaded in Lua with [[LuaAPI/filesystem#filesystem.read_file|filesystem.read_file]].&lt;br /&gt;
&lt;br /&gt;
== Core Functions ==&lt;br /&gt;
&lt;br /&gt;
Many of the core functions exhibit two features that (as of 1.13.4) cannot be used in user-defined functions. The first is the ability to accept a varying number of arguments - some core functions accept any number of arguments, while others have a few optional arguments. The second is that arguments are lazily-evaluated, and in some cases some arguments will not be evaluated at all, while others may be evaluated multiple times with different variable values. The description of each function will explain how and when its arguments are evaluated.&lt;br /&gt;
&lt;br /&gt;
Most of the core functions can be used from any formula. However, there are some that are only available in formulas that have access to the game state. The following formulas have access to the game state and can use those functions:&lt;br /&gt;
&lt;br /&gt;
* Formulas used in [[FilterWML]]&lt;br /&gt;
* Formulas used in [[AbilitiesWML]]&lt;br /&gt;
* &amp;lt;tt&amp;gt;filter_formula&amp;lt;/tt&amp;gt; in [[EventWML#filter_formula|EventWML]]&lt;br /&gt;
* Formulas evaluated from the formula console (accessed by pressing F)&lt;br /&gt;
&lt;br /&gt;
The following formulas do not have access to the game state and cannot use those functions:&lt;br /&gt;
&lt;br /&gt;
* Formulas used in [[GUI2]]&lt;br /&gt;
* [[SyntaxWML#formula_substitution|Substitution]] formulas using &amp;lt;tt&amp;gt;$(...)&amp;lt;/tt&amp;gt;&lt;br /&gt;
* [[ImagePathFunctions#CHAN: General function|IPF]] formulas used in &amp;lt;tt&amp;gt;~CHAN()&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;~ALPHA()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Formulas compiled from [[LuaAPI/wesnoth#wesnoth.compile_formula|Lua]]&lt;br /&gt;
&lt;br /&gt;
=== Conditional Functions ===&lt;br /&gt;
&lt;br /&gt;
There are two functions which return one of their input values based on some condition - the &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; function, and the &amp;lt;code&amp;gt;switch&amp;lt;/code&amp;gt; function. Both evaluate only as many parameters as is needed to determine which value to return. In particular, parameters that are neither returned nor part of the condition will never be evaluated.&lt;br /&gt;
&lt;br /&gt;
==== if ====&lt;br /&gt;
&lt;br /&gt;
* if(''condition'', ''if true'' [, ''condition 2'', ''if true 2'', ...] [, ''otherwise''])&lt;br /&gt;
&lt;br /&gt;
This function first evaluates the ''condition'', which is a formula. If it evaluates to true, then the function evaluates and returns the ''if true'' parameter; otherwise, it tries the next condition (if any) with the same result. If none of the conditions evaluate to true, then it returns the ''otherwise'' parameter if present, or &amp;lt;code&amp;gt;null()&amp;lt;/code&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
For instance, an event that is triggered by Wolf Riders on the first turn, and Orcish Grunts thereafter might have a unit filter formula that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
if(turn_number = 1, type = 'Wolf Rider', type = 'Orcish Grunt))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== switch ====&lt;br /&gt;
&lt;br /&gt;
* switch(''formula'', ''value 1'', ''outcome 1'' [, ... , ''value N'', ''outcome N''] [, ''default outcome''])&lt;br /&gt;
&lt;br /&gt;
The switch function first evaluates the input ''formula'', and then checks if it is equal to any of the specified ''values''. If matching value is found, the ''outcome'' assigned to it is returned; if not, then function returns either ''default outcome'' (if specified) or null.&lt;br /&gt;
&lt;br /&gt;
=== Numeric Functions ===&lt;br /&gt;
&lt;br /&gt;
Several basic math functions are available. These generally work equally on integer and decimal values.&lt;br /&gt;
&lt;br /&gt;
==== abs ====&lt;br /&gt;
&lt;br /&gt;
* abs(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the absolute value of an input number; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
abs( -5 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return 5.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== acos ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* acos(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arccosine of the input number, in degrees.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== asin ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* asin(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arcsine of the input number, in degrees.&lt;br /&gt;
&lt;br /&gt;
==== atan ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* atan(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arctangent of the input number, in degrees.&lt;br /&gt;
==== as_decimal ====&lt;br /&gt;
&lt;br /&gt;
* as_decimal(''number'')&lt;br /&gt;
&lt;br /&gt;
Ensures that the number is a decimal rather than an integer; useful if you're dividing two unknown values and want to ensure that the result is a decimal.&lt;br /&gt;
&lt;br /&gt;
==== cbrt ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* cbrt(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the cube root of the input number. This is better than using the exponentiation operator, because it will give the correct result for negative numbers.&lt;br /&gt;
&lt;br /&gt;
==== ceil ====&lt;br /&gt;
&lt;br /&gt;
* ceil(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the ceiling of the specified number, ie rounding it up to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== clamp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|0}}&lt;br /&gt;
&lt;br /&gt;
* clamp(''number'', ''min'', ''max'')&lt;br /&gt;
&lt;br /&gt;
Combines min and max into a single call. If ''number'' is less than ''min'', returns ''min''; if it's greater than ''max'', returns ''max''. Otherwise, returns ''number''.&lt;br /&gt;
&lt;br /&gt;
==== cos ====&lt;br /&gt;
&lt;br /&gt;
* cos(''angle'')&lt;br /&gt;
&lt;br /&gt;
Returns the cosine of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== exp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* exp(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the exponential of the input number, which is the constant ''e'' raised to the specified power.&lt;br /&gt;
&lt;br /&gt;
==== floor ====&lt;br /&gt;
&lt;br /&gt;
* floor(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the floor of the specified number, ie rounding it down to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== frac ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* frac(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the fractional part of the specified number.&lt;br /&gt;
&lt;br /&gt;
==== hypot ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* hypot(''x'', ''y'')&lt;br /&gt;
&lt;br /&gt;
Returns the hypoteneuse length of a triangle with sides ''x'' and ''y''.&lt;br /&gt;
&lt;br /&gt;
==== lerp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|0}}&lt;br /&gt;
&lt;br /&gt;
* lerp(''min'', ''max'', ''fraction'')&lt;br /&gt;
&lt;br /&gt;
Returns a linear interpolation between ''min'' and ''max'' according to the specified ''fraction''.&lt;br /&gt;
&lt;br /&gt;
==== lerp_index ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* lerp_index(''list'', ''ratio'')&lt;br /&gt;
&lt;br /&gt;
Returns the element of the list that is closest to being at the specified ratio of the list's length.&lt;br /&gt;
&lt;br /&gt;
'''Example''': &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;lerp_index([1, 12, 32, 10], 0.26])&amp;lt;/syntaxhighlight&amp;gt; returns 12.&lt;br /&gt;
&lt;br /&gt;
==== log ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* log(''number'', [, ''base''])&lt;br /&gt;
&lt;br /&gt;
Returns the logarithm of the input number. If ''base'' is omitted, it returns the natural logarithm; otherwise, the logarithm to the specified base.&lt;br /&gt;
&lt;br /&gt;
==== max ====&lt;br /&gt;
&lt;br /&gt;
* max(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
Returns the largest number from the list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
max([2, 8, -10, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== min ====&lt;br /&gt;
&lt;br /&gt;
* min(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
Returns the smallest number from the list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
min( [ 3, 7, -2, 6] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return &amp;lt;code&amp;gt;-2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== pi ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* pi()&lt;br /&gt;
&lt;br /&gt;
Returns pi.&lt;br /&gt;
&lt;br /&gt;
==== root ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* root(''number'', ''base'')&lt;br /&gt;
&lt;br /&gt;
Returns the root of the input number, to the specified base. This is better than using the exponentiation operator, because it will give the correct result for negative numbers and odd bases (for example, the fifth root of -32, which is -2).&lt;br /&gt;
&lt;br /&gt;
==== round ====&lt;br /&gt;
&lt;br /&gt;
* round(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the specified number rounded to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== sgn ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* sgn(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the sign of the number, ie -1 if it is negative, 1 if it is positive, and 0 if it is zero.&lt;br /&gt;
&lt;br /&gt;
==== sin ====&lt;br /&gt;
&lt;br /&gt;
* sin(''angle'')&lt;br /&gt;
&lt;br /&gt;
Returns the sine of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== sqrt ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* sqrt(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the square root of the input number.&lt;br /&gt;
&lt;br /&gt;
==== sum ====&lt;br /&gt;
&lt;br /&gt;
* sum(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates to the sum of the numbers in the ''list of numbers''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sum([ 2, 5, 8])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt;, and:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sum(map(my_units, max_hitpoints - hitpoints))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
finds the total damage your units have taken.&lt;br /&gt;
&lt;br /&gt;
==== tan ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* tan(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the tangent of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== trunc ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* trunc(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the truncation of the specified number, ie rounding it towards zero. This is different from floor when applied to negative numbers - floor(-7.5) gives -8, but trunc(-7.5) gives -7.&lt;br /&gt;
&lt;br /&gt;
==== wave ====&lt;br /&gt;
&lt;br /&gt;
* wave(''number'')&lt;br /&gt;
&lt;br /&gt;
Given a numeric value V, this returns:&lt;br /&gt;
&lt;br /&gt;
  sin(2*pi*V)&lt;br /&gt;
&lt;br /&gt;
=== String Functions ===&lt;br /&gt;
&lt;br /&gt;
There are a few useful functions for manipulating strings.&lt;br /&gt;
&lt;br /&gt;
==== concatenate ====&lt;br /&gt;
&lt;br /&gt;
* concatenate(''value1''[, ''value2'', ...])&lt;br /&gt;
&lt;br /&gt;
Converts each of its arguments to a string, and concatenates the result together into a single string.&lt;br /&gt;
&lt;br /&gt;
==== contains_string ====&lt;br /&gt;
&lt;br /&gt;
* contains_string(''string'', ''search_string'')&lt;br /&gt;
&lt;br /&gt;
Returns 1 if ''search_string'' can be found within ''string'' (as a substring), 0 otherwise. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
contains_string( 'Testing', 'ing' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== length ====&lt;br /&gt;
&lt;br /&gt;
* length(''string'')&lt;br /&gt;
&lt;br /&gt;
Returns the length of the input string.&lt;br /&gt;
&lt;br /&gt;
==== ends_with ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* ends_with(''string'', ''suffix'')&lt;br /&gt;
&lt;br /&gt;
Determines whether the ''string'' ends with the specified ''suffix''.&lt;br /&gt;
&lt;br /&gt;
==== find_string ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* find_string(''string'', ''search_string'')&lt;br /&gt;
&lt;br /&gt;
Returns the index at which ''search_string'' starts within ''string'' (as a substring), or -1 if it is not found. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
find_string( 'Testing', 'ing' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== replace ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* replace(''string'', ''offset'', [''size'',] ''replacement'')&lt;br /&gt;
&lt;br /&gt;
Returns a new string obtained by replacing a portion of the input ''string'' with the contents of the ''replacement'' string. The ''offset'' and ''size'' work the same as for &amp;lt;code&amp;gt;substring&amp;lt;/code&amp;gt;. Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', 4, 5, 'dumb')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -9, 4, 'sleeping')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -9, 'brook!')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -6, -4, 'yellow')&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return the following strings:&lt;br /&gt;
&lt;br /&gt;
 'The dumb brown fox jumps over the lazy dog!'&lt;br /&gt;
 'The quick brown fox jumps over the sleeping dog!'&lt;br /&gt;
 'The quick brown fox jumps over the brook!'&lt;br /&gt;
 'The quick brown fox jumps over the yellow dog!'&lt;br /&gt;
&lt;br /&gt;
==== replace_all ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* replace_all(''string'', ''match'', ''replacement'')&lt;br /&gt;
&lt;br /&gt;
Returns a copy of ''string'' with all occurrences of ''match'' replaced by ''replacement''.&lt;br /&gt;
&lt;br /&gt;
==== starts_with ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* starts_with(''string'', ''prefix'')&lt;br /&gt;
&lt;br /&gt;
Determines whether the ''string'' begins with the specified ''prefix''.&lt;br /&gt;
&lt;br /&gt;
==== substring ====&lt;br /&gt;
&lt;br /&gt;
* substring(''string'', ''offset''[, ''size''])&lt;br /&gt;
&lt;br /&gt;
Extracts a substring from the given input string. The ''offset'' specifies the first character to extract; the first character is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;, and negative values count from the end, so the last character is &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;. If specified, the ''size'' indicates the total number of characters to extract; it cannot be negative. If omitted, all characters from the ''offset'' to the end of the string are returned. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', 4, 5)&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -9, 4)&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -9)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return &amp;lt;code&amp;gt;'quick'&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'lazy'&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;'lazy dog!'&amp;lt;/code&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The ''size'' can now be negative. This means to count backwards from the given ''offset'' (but always including the given offset, so a ''size'' of -1 gives the same result as 1). For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -6, -4)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'lazy'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== List and Map Functions ===&lt;br /&gt;
&lt;br /&gt;
This section contains functions that directly manipulate a map or list.&lt;br /&gt;
&lt;br /&gt;
==== head ====&lt;br /&gt;
&lt;br /&gt;
* head(''list'' [, ''count''])&lt;br /&gt;
&lt;br /&gt;
Returns the first item from the ''list''; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
head([5, 7, 9])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
head( [ 'Orc', 'Human' ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'Orc'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} If a second argument is given, it returns a list containing the first ''count'' elements from the ''list''. Note that &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;head(L)&amp;lt;/syntaxhighlight&amp;gt; is different from &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;head(L,1)&amp;lt;/syntaxhighlight&amp;gt; - the former returns the first element, while the latter returns a list containing only the first element.&lt;br /&gt;
&lt;br /&gt;
==== index_of ====&lt;br /&gt;
&lt;br /&gt;
* index_of(''value'', ''list'')&lt;br /&gt;
&lt;br /&gt;
This function will return the first index where ''value'' can be found in the input ''list''. It will return -1 if the value is not found in the ''list'.&lt;br /&gt;
&lt;br /&gt;
==== keys ====&lt;br /&gt;
&lt;br /&gt;
* keys(''map'')&lt;br /&gt;
&lt;br /&gt;
Extracts the key values from an input ''map'' and returns them as a list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
keys(['Elvish Fighter' -&amp;gt; 50, 'Elvish Archer' -&amp;gt; 60])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns&lt;br /&gt;
&lt;br /&gt;
 ['Elvish Fighter', 'Elvish Archer']&lt;br /&gt;
&lt;br /&gt;
==== size ====&lt;br /&gt;
&lt;br /&gt;
* size(''list'')&lt;br /&gt;
&lt;br /&gt;
This function returns the number of elements in the ''list''.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;size([5, 7, 9])&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; and &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;size(['Archer', 'Fighter'])&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== sort ====&lt;br /&gt;
&lt;br /&gt;
* sort(''list'', ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates to a result list sorted according to the comparison ''formula'' for each item &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and its successor &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;. For instance, sorting units according to hitpoints would be done by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sort(my_units, a.hitpoints &amp;gt; b.hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To sort them in the reverse order, simply use &amp;lt;code&amp;gt;&amp;amp;lt;&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== tail ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* tail(''list'' [, ''count''])&lt;br /&gt;
&lt;br /&gt;
Returns the last item from the ''list''; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tail([5, 7, 9])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;9&amp;lt;/code&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tail( [ 'Orc', 'Human' ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'Human'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a second argument is given, it returns a list containing the last ''count'' elements from the ''list''. Note that &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;tail(L)&amp;lt;/syntaxhighlight&amp;gt; is different from &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;tail(L,1)&amp;lt;/syntaxhighlight&amp;gt; - the former returns the last element, while the latter returns a list containing only the last element.&lt;br /&gt;
&lt;br /&gt;
==== tolist ====&lt;br /&gt;
&lt;br /&gt;
* tolist(''map'')&lt;br /&gt;
&lt;br /&gt;
This function takes a map and return a list of key-value pair objects. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tolist(['Elf' -&amp;gt; 10, 'Dwarf' -&amp;gt; 20])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
&lt;br /&gt;
 [{key-&amp;gt;'Elf',value-&amp;gt;10}, {key-&amp;gt;'Dwarf',value-&amp;gt;20}]&lt;br /&gt;
&lt;br /&gt;
==== tomap ====&lt;br /&gt;
&lt;br /&gt;
* tomap(''list A'' [, ''list B''])&lt;br /&gt;
&lt;br /&gt;
This function takes one or two ''lists'' as input and returns a map. If only one list is specified, then the function will evaluate this list, count how many similar elements are found within the list, and return a map with keys being these elements, and values being a number representing how many of them the list contains. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tomap(['elf', 'dwarf', 'elf', 'elf', 'human', 'human'])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
&lt;br /&gt;
 ['elf' -&amp;gt; 3, 'dwarf' -&amp;gt; 1, 'human' -&amp;gt; 2]&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} However, if all the elements are key-value pairs such as those created by ''pair'' or ''tolist'', then this function will invert the effect of ''tolist'' and return the original map which would have produced the input list as output when passed to ''tolist''. If only some elements are key-value pairs, those elements will be directly converted into key-value pairs in the resulting map, while other values will be treated as described above.&lt;br /&gt;
&lt;br /&gt;
If two lists are specified, then the elements of the first one will be used as a keys, and the elements of the second one as a values, when creating an output map. Note that these input lists must be of the same length. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tomap(['elf', 'dwarf' ], [10, 20])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in:&lt;br /&gt;
&lt;br /&gt;
 ['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20]&lt;br /&gt;
&lt;br /&gt;
==== values ====&lt;br /&gt;
&lt;br /&gt;
* values(''map'')&lt;br /&gt;
&lt;br /&gt;
Extracts the values assigned to keys from an input ''map'' and returns them as a list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
values(['Elvish Fighter' -&amp;gt; 50, 'Elvish Archer' -&amp;gt; 60])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns&lt;br /&gt;
&lt;br /&gt;
 [50, 60]&lt;br /&gt;
&lt;br /&gt;
=== List-processing Functions ===&lt;br /&gt;
&lt;br /&gt;
This section covers functions that operate on maps or lists by applying one or more formulas in succession to each element. Most return another map or list, &amp;lt;code&amp;gt;reduce&amp;lt;/code&amp;gt; instead combines all the elements into a single result.&lt;br /&gt;
&lt;br /&gt;
==== choose ====&lt;br /&gt;
&lt;br /&gt;
* choose(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates ''formula'' for each item in the ''input'' (which can be a list or a map). It will return the first item to which ''formula'' gave the highest value. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
choose(my_units, level)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gives back the unit with the highest level.&lt;br /&gt;
&lt;br /&gt;
The implicit input when evaluating a mapping/filtering function's ''formula'' component will be that specific item under evaluation (in this example one of &amp;quot;my_units&amp;quot;), and it can be explicitly referenced as &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; when necessary. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
When evaluating a map, we can reference each key by &amp;lt;code&amp;gt;key&amp;lt;/code&amp;gt; and each value by &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;. In this case, the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable is this key-value pair. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
choose(['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20 ], value)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return a key-value pair &lt;br /&gt;
&lt;br /&gt;
 {key-&amp;gt;'dwarf', value-&amp;gt;20}&lt;br /&gt;
&lt;br /&gt;
The curly braces are used in output to indicate that this is an object, not a map. It is not valid WFL syntax.&lt;br /&gt;
&lt;br /&gt;
==== filter ====&lt;br /&gt;
&lt;br /&gt;
* filter(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on each item in the ''input'' (which can be a list or a map). It will evaluate to a list or map which only contains items that the ''formula'' was true for. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
filter(my_units, hitpoints &amp;lt; max_hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return all of your units which have less than maximum hitpoints. For instance this could be used if looking for candidates for healing.&lt;br /&gt;
&lt;br /&gt;
==== find ====&lt;br /&gt;
 &lt;br /&gt;
* find(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run &amp;lt;formula&amp;gt; on each item in the &amp;lt;input&amp;gt; (which can be a list or a map) and will return the first item for which &amp;lt;formula&amp;gt; was true. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
find(units, type = 'Elvish Archer' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return the first unit of type 'Elvish Archer'.&lt;br /&gt;
&lt;br /&gt;
==== map ====&lt;br /&gt;
&lt;br /&gt;
* map(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on each item in the ''input'' (which can be a list or a map), and evaluate to a new list or map or a map, which contains the same number of items as in ''input'', with the formulas run on each item. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable. When run on a map, the resulting map has the same keys as the input map, but with the values updated to the results of the ''formula''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map([10,20], self*self)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map([10,20], 'value', value*value)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will both result in [100, 400]. The formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(my_units, hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will give a list back with the number of hitpoints each unit has. This is more useful in conjunction with other functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20 ], value*2)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will produce ['elf' -&amp;gt; 20, 'dwarf' -&amp;gt; 40]. Note that in case of a map data type, the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; function can only modify the value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(tomap([3,5,8,8]), value+key*100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will produce &amp;lt;code&amp;gt;[3 -&amp;gt; 301, 5 -&amp;gt; 502, 8 -&amp;gt; 801]&amp;lt;/code&amp;gt;. This can be used to take a list and make a map containing pairs &amp;lt;code&amp;gt;[element_from_that_list -&amp;gt; f(element_from_that_list,number_of_repetitions_of_that_element_in_that_list)]&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; is an arbitrary function.&lt;br /&gt;
&lt;br /&gt;
==== reduce ====&lt;br /&gt;
&lt;br /&gt;
* reduce(''list'', [''identity'', ] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on the first and second members of the ''list'', then on the result and the third member and so on until the list is depleted. The final result is then returned. The two variables used in the ''formula'' are always 'a' and 'b'.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;reduce([1,2,3,4], a+b)&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; and &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;reduce([9,4,8,2], 10*a+b)&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;9482&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The new ''identity'' argument specifies the starting value (which is null or 0 by default). If ''list'' is empty, then ''identity'' is returned. Otherwise, the list will be considered as if ''identity'' were an extra first element. For example, to calculate the product of a list of numbers, you might do something like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
reduce(your_list, 1, a * b)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will return 1 if the list is empty, as expected - the product of no numbers is 1. If the list is not empty, adding 1 to the list will have no effect, since it is the multiplicative identity.&lt;br /&gt;
&lt;br /&gt;
==== take_while ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* take_while(''list'', ''formula'')&lt;br /&gt;
&lt;br /&gt;
Evaluates the ''formula'' for each element of the ''list'' until it finds one for which it evaluates to false, then returns a list of all elements up to but not including that element. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
take_while([1,5,3,6,3,7,9,5,6,4,12,2,53,2,1], self &amp;lt; 10)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns the list &amp;lt;code&amp;gt;[1,5,3,6,3,7,9,5,6,4]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== zip ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* zip(''list1'', ... , ''listN'')&lt;br /&gt;
* zip(''list of lists'')&lt;br /&gt;
&lt;br /&gt;
Takes a list of lists and generates a new list of lists such that list ''n'' contains element ''n'' of each of the original lists, in order. If the lists are not all of the same length, it treats them as if they were padded on the end with null values so that they are all the length of the longest list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
zip([1,2,3],[4,5,6])&lt;br /&gt;
zip([1,4],[2,5],[3,6])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return &amp;lt;code&amp;gt;[[1,4],[2,5],[3,6]]&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;[[1,2,3],[4,5,6]]&amp;lt;/code&amp;gt;, respectively.&lt;br /&gt;
&lt;br /&gt;
=== Location Functions ===&lt;br /&gt;
&lt;br /&gt;
Functions for working with locations on a hex map.&lt;br /&gt;
&lt;br /&gt;
==== adjacent_locs ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* adjacent_locs(''center'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of all locations adjacent to the specified location. When called from a formula with access to the game state, it automatically excludes locations that don't exist on the map. Otherwise, it operates as if on an infinite map. This means you should generally not expect the returned list to contain exactly 6 elements.&lt;br /&gt;
&lt;br /&gt;
==== are_adjacent ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* are_adjacent(''loc1'', ''loc2'')&lt;br /&gt;
&lt;br /&gt;
Check if two locations are adjacent. Returns 1 (true) or 0 (false).&lt;br /&gt;
&lt;br /&gt;
==== direction_from ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* direction_from(''start'', ''direction'', [''distance''])&lt;br /&gt;
&lt;br /&gt;
Returns the hex reached by travelling in the specified direction from a starting hex for a certain distance (default 1 hex).&lt;br /&gt;
&lt;br /&gt;
==== distance_between ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* distance_between(''start'', ''end'')&lt;br /&gt;
&lt;br /&gt;
Returns the distance between the locations ''start'' and ''end'', which must be location objects such as those created by &amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This function was already available in FormulaAI prior to 1.13.5; however, from 1.13.5 onward it is available to all formulas.&lt;br /&gt;
&lt;br /&gt;
==== loc ====&lt;br /&gt;
&lt;br /&gt;
* loc(''x'', ''y'')&lt;br /&gt;
&lt;br /&gt;
Creates and returns a location object with the specified coordinates. If assigned to a variable ''pos'' (eg with a &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clause), the individual coordinates can be accessed as &amp;lt;code&amp;gt;pos.x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;pos.y&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== locations_in_radius ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* locations_in_radius(''center'', ''radius'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of all locations within a given radius of the specified center hex.&lt;br /&gt;
Only locations on the map will be returned.&lt;br /&gt;
&lt;br /&gt;
==== nearest_loc ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* nearest_loc(''origin'', ''locations'')&lt;br /&gt;
&lt;br /&gt;
Returns the location in the given list closest to ''origin''. All arguments must be location objects such as those created by &amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This function was already available in FormulaAI prior to 1.19.14; however, from 1.19.14 onward it is available to all formulas.&lt;br /&gt;
&lt;br /&gt;
==== relative_dir ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* relative_dir(''loc1'', ''loc2'')&lt;br /&gt;
&lt;br /&gt;
Returns the direction you need to travel to progress from one location to another. The returned location is one of the six possible directions on the Wesnoth hex map, or an empty string if both locations are the same.&lt;br /&gt;
&lt;br /&gt;
==== rotate_loc_around ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}} but returns wrong result until {{DevFeature1.19|2}}&lt;br /&gt;
&lt;br /&gt;
* rotate_loc_around(''center'', ''loc'', ''angle'')&lt;br /&gt;
&lt;br /&gt;
Rotates a location around a given center to produce a new location. The angle is an integer between -6 and 6, which can be understood as a multiple of 60 degrees.&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous Functions ===&lt;br /&gt;
&lt;br /&gt;
Some functions really don't fit into any category. They are all listed here.&lt;br /&gt;
&lt;br /&gt;
==== null ====&lt;br /&gt;
&lt;br /&gt;
* null([''arguments''])&lt;br /&gt;
&lt;br /&gt;
Evaluates each of its arguments (if any) in order, then returns null. Since formulas generally do not have side-effects, there is usually little point in specifying any arguments, but it could be thought of as a way to &amp;quot;comment out&amp;quot; a section of the formula while ensuring it remains syntactically valid.&lt;br /&gt;
&lt;br /&gt;
==== pair ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* pair(''key'', ''value'')&lt;br /&gt;
&lt;br /&gt;
Creates a key-value pair object, the same as those created by the ''tolist'' function.&lt;br /&gt;
&lt;br /&gt;
==== reverse ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* reverse(''string or list'')&lt;br /&gt;
&lt;br /&gt;
Returns the input string or list backwards.&lt;br /&gt;
&lt;br /&gt;
==== type ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* type(''anything'')&lt;br /&gt;
&lt;br /&gt;
Returns the type of its input as a string. Possible results are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;'integer'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'decimal'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'string'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'list'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'map'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'null'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'object'&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== get_palette ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* get_palette(''name'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of colours that make up the named palette. Palettes are defined by a '''[color_palette]''' tag, usually in the [[GameConfigWML#Color_Palettes|game config]]. The palettes defined in core Wesnoth are '''magenta''', '''flag_green''', and '''ellipse_red'''. In addition to defined palettes, several hard-coded palettes are available by name. They are '''red_green_scale''', '''red_green_scale_text''', '''blue_white_scale''', and '''blue_white_scale_text'''. These are also defined in the game config, but not with a '''[color_palette]''' tag.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Functions ===&lt;br /&gt;
&lt;br /&gt;
There are also a few functions that can be useful for debugging formulas, for example by displaying intermediate results to the screen. Note that this breaks the general rule that functions do not have side-effects.&lt;br /&gt;
&lt;br /&gt;
==== debug ====&lt;br /&gt;
&lt;br /&gt;
* debug([''formula''])&lt;br /&gt;
&lt;br /&gt;
Starts a GUI formula debugger when evaluating a formula. It takes a formula, evaluates it and returns the result unchanged. '''Note:''' this does not appear to work in 1.13.3.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The formula allows you to step through the formula one operation at a time, viewing the current stack and execution trace. As of 1.13.5, you need to enable [[CommandMode|debug mode]] to use the debugger; otherwise, it will simply be skipped.&lt;br /&gt;
&lt;br /&gt;
==== debug_print ====&lt;br /&gt;
&lt;br /&gt;
'''you need to enable formula log (--log-info='scripting/formula') to see the result of this call'''&lt;br /&gt;
&lt;br /&gt;
* debug_print([''explanation'' ,] ''formula'' )&lt;br /&gt;
&lt;br /&gt;
This function can be used for debugging a formula. It takes a ''formula'', writes its result to the console, and returns it unchanged. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_print([1, 2, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in printing to the console&lt;br /&gt;
&lt;br /&gt;
 [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
and returning the same.&lt;br /&gt;
&lt;br /&gt;
We can specify an optional parameter ''explanation'' that helps to distinguish between multiple ''debug_print'' calls in the same formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_print('My array: ', [1, 2, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will write in the console:&lt;br /&gt;
&lt;br /&gt;
 My array: [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
and return&lt;br /&gt;
&lt;br /&gt;
 [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
==== debug_profile ====&lt;br /&gt;
&lt;br /&gt;
* debug_profile(''formula'' [, ''explanation''])&lt;br /&gt;
&lt;br /&gt;
Evaluates the formula 1000 times and prints (as with debug_print) a number indicating the average time required to evaluate the formula. Mainly intended for internal testing, but could occasionally be useful for people working with complicated formulas. The optional ''explanation'' argument is used in the same way as in debug_print.&lt;br /&gt;
&lt;br /&gt;
==== debug_float ====&lt;br /&gt;
&lt;br /&gt;
* debug_float(''location'', [''explanation'',] ''formula'' )&lt;br /&gt;
&lt;br /&gt;
This function can be used for debugging a formula. It takes a formula, floats a label containing the result on the hex specified (in the same way damage is displayed) and returns it unchanged. Note that the ''location'' here is an object type; it can be created with the &amp;lt;code&amp;gt;[[#loc|loc()]]&amp;lt;/code&amp;gt; function. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_float(me.loc, me.id)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will make a label containing the id of the unit ''me'' float over the unit.&lt;br /&gt;
&lt;br /&gt;
Return value is also the unit id.&lt;br /&gt;
&lt;br /&gt;
We can specify an optional parameter ''explanation'' that helps to distinguish between multiple ''debug_float'' calls in the same formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_float( me.loc, 'id: ', me.id )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will float the following label&lt;br /&gt;
&lt;br /&gt;
 id: unit_id&lt;br /&gt;
&lt;br /&gt;
and return the unit id.&lt;br /&gt;
&lt;br /&gt;
==== dir ====&lt;br /&gt;
&lt;br /&gt;
* dir(''object'')&lt;br /&gt;
&lt;br /&gt;
This function return a list of all attributes in ''object''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
dir(my_leader)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in the following output:&lt;br /&gt;
&lt;br /&gt;
 [ 'x', 'y', 'loc', 'id', 'type', 'name', 'leader', 'undead', 'traits', 'attacks', 'abilities', 'hitpoints',&lt;br /&gt;
 'max_hitpoints', 'experience', 'max_experience', 'level', 'total_movement', 'movement_left', 'attacks_left',&lt;br /&gt;
 'side', 'states', 'cost', 'usage', 'vars']&lt;br /&gt;
&lt;br /&gt;
This command is useful in the formula command line, to get information about the attributes of different types of data.&lt;br /&gt;
&lt;br /&gt;
=== Game State Functions ===&lt;br /&gt;
&lt;br /&gt;
These are functions that access the game state. Therefore, they are not available in all formulas, as described above.&lt;br /&gt;
&lt;br /&gt;
==== base_tod_bonus ====&lt;br /&gt;
&lt;br /&gt;
* base_tod_bonus([''loc'', [''turn'']])&lt;br /&gt;
&lt;br /&gt;
Evaluates the base time-of-day bonus, excluding the effect of illumination from abilities or terrain. If no turn is specified, the current turn is used. If no location is specified, the bonus is calculated for the global schedule without taking any time areas into account, but if a location is specified, it will account for any time areas that might affect that location.&lt;br /&gt;
&lt;br /&gt;
==== chance_to_hit ====&lt;br /&gt;
&lt;br /&gt;
* chance_to_hit(''unit'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the base chance for the unit to be hit if it moved to the given location or terrain. This is essentially the inverse of its defense. It is returned as an integer between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
==== defense_on ====&lt;br /&gt;
&lt;br /&gt;
* defense_on(''unit'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the defense that the unit would have if it moved to the given location or terrain. It is returned as an integer between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
==== enemy_of ====&lt;br /&gt;
&lt;br /&gt;
* enemy_of(''self'', ''other'')&lt;br /&gt;
&lt;br /&gt;
Determines whether two units are enemies. Returns 1 (true) or 0 (false).&lt;br /&gt;
&lt;br /&gt;
==== get_unit_type ====&lt;br /&gt;
&lt;br /&gt;
* get_unit_type(''id'')&lt;br /&gt;
&lt;br /&gt;
Returns an object describing the specified unit type, or null if no such unit type exists. A unit type object has many of the same keys as a unit, excluding those that are expected to change over time such as &amp;lt;tt&amp;gt;hitpoints&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== jamming_cost ====&lt;br /&gt;
&lt;br /&gt;
* jamming_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the jamming cost for the unit to block vision on the given location terrain.&lt;br /&gt;
&lt;br /&gt;
==== is_fogged ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* is_shrouded(''loc'', ''side_number''])&lt;br /&gt;
&lt;br /&gt;
Returns whether the given location is currently fogged from the point of view of the given side.&lt;br /&gt;
&lt;br /&gt;
==== is_shrouded ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* is_shrouded(''loc'', ''side_number''])&lt;br /&gt;
&lt;br /&gt;
Returns whether the given location is currently shrouded from the point of view of the given side.&lt;br /&gt;
&lt;br /&gt;
==== movement_cost ====&lt;br /&gt;
&lt;br /&gt;
* movement_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the movement cost for the unit to enter the given location or terrain.&lt;br /&gt;
&lt;br /&gt;
==== resistance_on ====&lt;br /&gt;
&lt;br /&gt;
* resistance_on(''unit'', ''location'', ''type'', [''attacker''])&lt;br /&gt;
&lt;br /&gt;
Calculates the unit's resistance to the given damage type when standing on the specified location. If specified, the ''attacker'' parameter should be 1 to indicate that the unit is the attacker, or 0 to indicate that it is the defender, as this status can affect resistances. By default, it is assumed to be the defender.&lt;br /&gt;
&lt;br /&gt;
This is returned not as the raw resistance set in WML, but the actual resistance that the player sees, so it ranges between -100 and 100.&lt;br /&gt;
&lt;br /&gt;
==== tod_bonus ====&lt;br /&gt;
&lt;br /&gt;
* tod_bonus([''loc'', [''turn'']])&lt;br /&gt;
&lt;br /&gt;
Evaluates the final time-of-day bonus, accounting for the effect of illumination from abilities or terrain. If no turn is specified, the current turn is used. If no location is specified, the bonus is calculated for the global schedule without taking any time areas into account, but if a location is specified, it will account for any time areas that might affect that location.&lt;br /&gt;
&lt;br /&gt;
==== unit_at ====&lt;br /&gt;
&lt;br /&gt;
* unit_at(''location'')&lt;br /&gt;
&lt;br /&gt;
Returns the unit on the given location, or null if there is no unit there.&lt;br /&gt;
&lt;br /&gt;
==== unit_tod_modifier ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* unit_tod_modifier(''unit'', [''loc''])&lt;br /&gt;
&lt;br /&gt;
Returns the current combat damage modifier for the given unit for the current time of day, taking into account any abilities whose effects it is currently under (illuminates, for example). If no location is specified, the unit's current location will be used.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Prior to 1.19.4, this function was available as the FormulaAI function ''timeofday_modifier''.&lt;br /&gt;
&lt;br /&gt;
==== vision_cost ====&lt;br /&gt;
&lt;br /&gt;
* vision_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the vision cost for the unit to see through the given location or terrain.&lt;br /&gt;
&lt;br /&gt;
=== Action Functions ===&lt;br /&gt;
&lt;br /&gt;
These are special functions that represent an action to be executed. They don't actually execute the action, merely describe it – the action will be executed only after the formula has been fully evaluated.&lt;br /&gt;
&lt;br /&gt;
Action functions can currently only be used in GUI2, in the '''actions''' key. This key must always evaluate to either an action or a list of actions.&lt;br /&gt;
&lt;br /&gt;
==== set_var ====&lt;br /&gt;
&lt;br /&gt;
* set_var(''name'', ''value'')&lt;br /&gt;
&lt;br /&gt;
Sets a variable in the current '''self''' context to the specified value.&lt;br /&gt;
&lt;br /&gt;
The result of this function is an object that has '''name''' and '''value''' keys with the passed-in values.&lt;br /&gt;
&lt;br /&gt;
* safe_call(''main'', ''backup'')&lt;br /&gt;
&lt;br /&gt;
Tries to execute the ''main'' action first. If that fails, the ''backup'' action is executed instead.&lt;br /&gt;
&lt;br /&gt;
The ''backup'' formula can access a special '''error''' object, which in turn contains two values:&lt;br /&gt;
&lt;br /&gt;
* '''status''': A status code representing the type of error. Currently, the only possible status is 5001, which means the current context is immutable.&lt;br /&gt;
* '''object''': The action that failed to execute – in other words, the result of evaluating the ''main'' formula.&lt;br /&gt;
&lt;br /&gt;
The result of this function is an object that has a '''main''' key that contains the result of evaluating the main formula.&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Wesnoth_Formula_Language&amp;diff=74714</id>
		<title>Wesnoth Formula Language</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Wesnoth_Formula_Language&amp;diff=74714"/>
		<updated>2026-01-07T19:48:56Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Maps */ Document empty map literal&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;tright&amp;quot;&amp;gt; __TOC__ &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Wesnoth Formula Language is a functional language used to evaluate expressions within the game engine. It allows performing calculations that would not otherwise be possible using only WML. For example, to have an event trigger when a unit has less than half its hitpoints, you could write the following as the event's filter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[filter]&lt;br /&gt;
    formula = &amp;quot;(hitpoints &amp;lt; max_hitpoints / 2)&amp;quot;&lt;br /&gt;
[/filter]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''formula''' key is a part of [[StandardUnitFilter]] that accepts a condition written as WFL. The part inside the quotes is the WFL formula. This example will evaluate to true if the unit's '''hitpoints''' are less than half its '''max_hitpoints'''.&lt;br /&gt;
&lt;br /&gt;
== Data Types and Operators ==&lt;br /&gt;
&lt;br /&gt;
Wesnoth Formula Language has seven basic data types – [[#Numbers|integers]], [[#Numbers|real numbers]] (usually called &amp;quot;decimals&amp;quot;), [[#Strings|strings]], [[#Lists|lists]], [[#Maps|maps]], [[#Objects|objects]], and [[#Other Types and Operators|null]].&lt;br /&gt;
&lt;br /&gt;
=== Numbers ===&lt;br /&gt;
&lt;br /&gt;
The most common use of WFL is for simple calculations involving numbers. For this, the standard arithmetic operators (&amp;lt;code&amp;gt;+ - * / %&amp;lt;/code&amp;gt;) work as you would expect, performing addition, subtraction, multiplication, division, and remainder. {{DevFeature1.13|5}} The remainder operator even works on decimal numbers, producing the integer remainder of the division.&lt;br /&gt;
&lt;br /&gt;
The only caveat to watch out for is that &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; rounds down when used on integers. For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;5 / 2&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;. To avoid this, make sure at least one of the numbers includes a decimal point (or use [[#as_decimal|as_decimal]] if variables are involved) - &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;5.0 / 2&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;2.5&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note that WFL supports only three decimal places of precision for decimal numbers; beyond that it will still be rounded down. (So &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;1.0 / 16&amp;lt;/syntaxhighlight&amp;gt; will evaluate to &amp;lt;code&amp;gt;0.062&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;0.0625&amp;lt;/code&amp;gt;.) The &amp;lt;code&amp;gt;^&amp;lt;/code&amp;gt; operator performs exponentiation (raising to a power) - for example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;2 ^ 3&amp;lt;/syntaxhighlight&amp;gt; evaluates to &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use the standard comparison operators (&amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;=&amp;lt;/code&amp;gt;) on numbers. This is often useful in unit filters - for example, a formula of &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;hitpoints &amp;lt; max_hitpoints / 2&amp;lt;/syntaxhighlight&amp;gt; will match only if the unit is at less than half health. Comparison operators return 1 for true and 0 for false; there is no boolean type. Comparing values of different types will always return 0, with one exception – comparing an integer and decimal number will work as expected.&lt;br /&gt;
&lt;br /&gt;
One final numeric operator exists - the dice roll. The syntax &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;3d12&amp;lt;/syntaxhighlight&amp;gt; will roll three 12-sided dice and return the sum of the results. Note however that this is not multiplayer-safe, so using it can and will produce OOS errors. {{DevFeature1.13|5}} The dice operator is now synced and should be safe for use in multiplayer contexts.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' {{DevFeature1.13|5}} Some numeric operations will return null instead of a number. This usually involves the exponentiation operator - for example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;(-2) ^ 0.5&amp;lt;/syntaxhighlight&amp;gt; attempts to take the square root of -2, which doesn't exist, so it returns null to indicate this. Dividing by zero also returns null, as well as certain [[#Numeric Functions|math functions]] in appropriate circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
WFL also supports strings, which must be enclosed in single quotes (&amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;'like this'&amp;lt;/syntaxhighlight&amp;gt;). The comparison operators (&amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;=&amp;lt;/code&amp;gt;) also work on strings, performing lexicographical comparison (ie, alphabetical order). The comparison is case sensitive.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
Strings can be concatenated with the concatenation operator &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt;. They also support interpolations enclosed in square brackets, the contents of which can be any valid formula. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Some text: [a + b]' where a = 12, b = 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
results in the string &amp;lt;code&amp;gt;Some text: 22&amp;lt;/code&amp;gt;. (The &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; operator is explained [[#Variables|below]].)&lt;br /&gt;
&lt;br /&gt;
If you need to include a literal square bracket in a string, write &amp;lt;code&amp;gt;[(]&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;[)]&amp;lt;/code&amp;gt;. For a literal single quote, you can write &amp;lt;code&amp;gt;[']&amp;lt;/code&amp;gt;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'[(]It[']s bracketed![)]'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
results in the string &amp;lt;code&amp;gt;[It's bracketed!]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You can index the characters or words of a string with the following syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Hello World'.char[4]&lt;br /&gt;
'Hello World'.word[1]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These return &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;World&amp;lt;/code&amp;gt;, respectively. A third option is also available, &amp;lt;code&amp;gt;item&amp;lt;/code&amp;gt;, which splits the string on commas but allows parentheses to prevent a portion of the string from being split up. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'First Item,Second Item,Third Item'.item[1]&lt;br /&gt;
'a,b,(c,d,e),f,g'.item[2]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These return &amp;lt;code&amp;gt;Second Item&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;(c,d,e)&amp;lt;/code&amp;gt;, respectively. When not providing index, list is returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
'Hello World'.char = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']&lt;br /&gt;
'Hello World'.word = ['Hello', 'World']&lt;br /&gt;
'a,b,(c,d,e),f,g'.item = ['a', 'b', '(c,d,e)', 'f', 'g']&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lists ===&lt;br /&gt;
&lt;br /&gt;
A list is a sequence of values represented as square brackets, [], surrounding a comma-separated list. For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[ 1, 5, 'abc' ]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The comparison operators work on lists, performing lexicographical comparison. A specific list index can be obtained with the indexing operator, like this: &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;my_list[index]&amp;lt;/syntaxhighlight&amp;gt;. The first element of a list is numbered 0.&lt;br /&gt;
&lt;br /&gt;
There are four ''vector operators'' (&amp;lt;code&amp;gt;.+ .- .* ./&amp;lt;/code&amp;gt;) that perform entrywise operations on lists. For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;[1,2,3] .+ [12,2,8]&amp;lt;/syntaxhighlight&amp;gt; produces &amp;lt;code&amp;gt;[13,4,11]&amp;lt;/code&amp;gt;. Both lists must be of the same length to use these operators, and of course, they must contain only numbers.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
A negative list index now counts from the end of the list - &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt; refers to the last element. You can check if an element exists in a list using the &amp;lt;code&amp;gt;in&amp;lt;/code&amp;gt; operator. Lists can also be joined with the concatenation operator &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt;, and sliced using the range operator &amp;lt;code&amp;gt;~&amp;lt;/code&amp;gt;. In fact, the range operator produces a list of consecutive numbers, and in fact any list of numbers can be used to index a list - the result is to take the elements at the requested indices, in order. Some examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[1, 7, 'abc', 2.5, 'foobar', 127][1~3]&lt;br /&gt;
(10~20)[[0,-1]]&lt;br /&gt;
[1, 7, 'abc', 2.5, 'foobar', 127][[2,4]]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These result in the following lists:&lt;br /&gt;
&lt;br /&gt;
 [7, 'abc', 2.5]&lt;br /&gt;
 [10,20]&lt;br /&gt;
 ['abc', 'foobar']&lt;br /&gt;
&lt;br /&gt;
=== Maps ===&lt;br /&gt;
&lt;br /&gt;
A map is a sequence of key-value pairs. For example: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
[12 -&amp;gt; 'Hello', [1,2] -&amp;gt; 9, 'abc' -&amp;gt; 1.5]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The comparison operators work on maps. A specific element of a map can be obtained with the indexing operation. In the above example, the following conditions are all true (assuming the map is in a variable called &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self[12] = 'Hello'&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self[[1,2]] = 9&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;self['abc'] = 1.5&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
You can now use the &amp;lt;code&amp;gt;in&amp;lt;/code&amp;gt; operator to test if a key exists in the map. You can also access string keys using the dot operator &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; as long as they are valid identifiers. (Valid identifiers contain letters and underscores only; no digits are permitted.)&lt;br /&gt;
&lt;br /&gt;
Note that the selection indexing that lists use is ''not'' valid for maps - a list can be used as a key, after all.&lt;br /&gt;
&lt;br /&gt;
Though it's rarely needed, it's possible to define an empty map with &amp;lt;code&amp;gt;[ -&amp;gt; ]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Objects ===&lt;br /&gt;
&lt;br /&gt;
An object is a container containing additional variables (see [[#Variables|below]] for further explanation of variables) which are not in the global scope. The ''dot operator'' can be used to evaluate a formula in the object's scope. For example, suppose ''u'' is a unit object referring to your leader, who is an Elvish Ranger who has taken 12 damage (thus has 30 hit points). Then &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u.hitpoints&amp;lt;/syntaxhighlight&amp;gt; will evaluate to the number 30. For a more advanced example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u . (hitpoints &amp;lt; max_hitpoints - 10)&amp;lt;/syntaxhighlight&amp;gt; will evaluate to true if the unit has taken more than 10 damage, which in this example, it has. (This could also be written &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;u.hitpoints &amp;lt; u.max_hitpoints - 10&amp;lt;/syntaxhighlight&amp;gt; if you prefer; this enters the scope twice, instead of once, but the result is identical.)&lt;br /&gt;
&lt;br /&gt;
Objects generally cannot be created directly by the code - they are created for you by the game when formulas are called in certain contexts. However, there are two types of object that ''can'' be created by your code. The first is the location object, which has variables ''x'' and ''y''; it can be created by the [[#loc|&amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;]] function. The second is the map pair object, which is returned (or used internally) by several of the built-in functions and has variables ''key'' and ''value''.&lt;br /&gt;
&lt;br /&gt;
==== Documentation of some common objects ====&lt;br /&gt;
&lt;br /&gt;
There are a number of common objects that are given as the context object for formulas throughout the engine. Not all of these will be available in all formulas, but many of them are available in more than one formula. To learn what objects are available in a given location, see the WML documentation of that location.&lt;br /&gt;
&lt;br /&gt;
* [[StandardUnitFilter#Wesnoth_Formula_Language|unit objects]]&lt;br /&gt;
* [[FilterWML#Filtering_Weapons|weapon objects]]&lt;br /&gt;
* [[StandardLocationFilter#Wesnoth_Formula_Language|terrain objects]]&lt;br /&gt;
* [[StandardSideFilter#Wesnoth_Formula_Language|side objects]]&lt;br /&gt;
* [[ImagePathFunctions#CHAN:_General function|pixel objects]]&lt;br /&gt;
* [[ConditionalActionsWML#.5Bvariable.5D|WML objects]]&lt;br /&gt;
* [[EventWML#filter_formula|game state objects]]&lt;br /&gt;
&lt;br /&gt;
=== Other Types and Operators ===&lt;br /&gt;
&lt;br /&gt;
There is one other basic type in WFL - the null type, which is used to mean &amp;quot;no value&amp;quot;. It will be returned if you attempt to perform an invalid operation, such as dividing a string. It is also returned by the built-in &amp;lt;code&amp;gt;null()&amp;lt;/code&amp;gt; function, which allows you to test if a value is null by writing &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;value = null()&amp;lt;/syntaxhighlight&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The logical operators &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; can be used to connect conditional expressions, and the unary operator &amp;lt;code&amp;gt;not&amp;lt;/code&amp;gt; negates them. Note that &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; is inclusive - &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;A or B&amp;lt;/syntaxhighlight&amp;gt; is false only if both ''A'' and ''B'' are false. These operators consider &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or null to be false, while all other values count as true. The [[#if|&amp;lt;code&amp;gt;if()&amp;lt;/code&amp;gt;]] function also follows the same rules to determine whether a value is true or false.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Programmers familiar with other languages may occasionally be surprised by the fact that &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt; do not short-circuit (which would mean that they will never evaluate their second argument if they can know their result solely from the first argument). This should not be a problem in general formula usage, since functions do not have side-effects, but it could make a difference when using the debug functions.&lt;br /&gt;
&lt;br /&gt;
=== Operator Precedence ===&lt;br /&gt;
&lt;br /&gt;
The precedence of various operators is, more or less, what you'd expect - you can write something like &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a + b * 2 &amp;lt;= 5 and n - m / 4 &amp;gt; 7&amp;lt;/syntaxhighlight&amp;gt; and the engine will do what you expect - first multiplication and division, then addition and subtraction, then comparison, and finally logical conjunction. The only thing to watch out for is when chaining exponentiation - all operators are left associative, so &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a ^ b ^ c&amp;lt;/syntaxhighlight&amp;gt; will be evaluated as &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;(a ^ b) ^ c&amp;lt;/syntaxhighlight&amp;gt; instead of &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;a ^ (b ^ c)&amp;lt;/syntaxhighlight&amp;gt; like you would expect. {{DevFeature1.13|5}} This has been fixed - exponentiation is now right-associative.&lt;br /&gt;
&lt;br /&gt;
The full precedence list is as follows, from lowest to highest; operators on the same line have equal precedence.&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;not&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clauses&lt;br /&gt;
# &amp;lt;code&amp;gt;or&amp;lt;/code&amp;gt;&lt;br /&gt;
# &amp;lt;code&amp;gt;and&amp;lt;/code&amp;gt;&lt;br /&gt;
# Comparison operators &amp;lt;code&amp;gt;= != &amp;lt; &amp;lt;= &amp;gt; &amp;gt;= in&amp;lt;/code&amp;gt;&lt;br /&gt;
# Range-generating operator &amp;lt;code&amp;gt;~&amp;lt;/code&amp;gt;&lt;br /&gt;
# Additive operators &amp;lt;code&amp;gt;+ - ..&amp;lt;/code&amp;gt;&lt;br /&gt;
# Multiplicative operators &amp;lt;code&amp;gt;* /&amp;lt;/code&amp;gt;&lt;br /&gt;
# Modulus &amp;lt;code&amp;gt;%&amp;lt;/code&amp;gt;&lt;br /&gt;
# Exponentiation &amp;lt;code&amp;gt;^&amp;lt;/code&amp;gt;&lt;br /&gt;
# Dice operator &amp;lt;code&amp;gt;d&amp;lt;/code&amp;gt;&lt;br /&gt;
# Dot operator &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
WFL is a ''functional'' language, so of course it has functions. There is a large library of [[#Core Functions|built-in functions]], and you can also [[#Defining Functions|define your own]].&lt;br /&gt;
&lt;br /&gt;
Calling a function is simple, and works exactly how you would expect if you've worked with functions in a mathematical context: &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;clamp(value, 0, 21)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Being a functional language, WFL does not have conditional or looping statements. Instead, these are provided by functions. For a simple conditional, you can use the &amp;lt;tt&amp;gt;if&amp;lt;/tt&amp;gt; function, as in the following example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wfl&amp;gt;&lt;br /&gt;
if(hitpoints &amp;gt; 37,&lt;br /&gt;
    max_hitpoints / 2,&lt;br /&gt;
    hitpoints - 3&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Similarly, looping is done via functions. There are several built-in higher-order functions that can be used to iterate over lists and maps, such as &amp;lt;tt&amp;gt;filter&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;choose&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;map&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;reduce&amp;lt;/tt&amp;gt;. See the corresponding function definitions for more information.&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
Formulas may have a variety of variables, depending on the context in which they are evaluated. A string substitution formula like &amp;lt;code&amp;gt;$(3 + 5)&amp;lt;/code&amp;gt; has no variables, but a [[StandardUnitFilter|unit filter]] formula has variables such as &amp;lt;code&amp;gt;hitpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max_hitpoints&amp;lt;/code&amp;gt; which contain various properties of the unit being tested (the same unit which is also referred to in variable substitution as &amp;lt;code&amp;gt;$this_unit&amp;lt;/code&amp;gt;). The special variable &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; typically refers to the &amp;quot;global context&amp;quot; - in the case of a unit filter formula, the unit itself. This means for example that &amp;lt;code&amp;gt;self.hitpoints&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;hitpoints&amp;lt;/code&amp;gt; are equivalent when used in a unit filter formula. In a string substitution formula (the &amp;lt;code&amp;gt;$(formula)&amp;lt;/code&amp;gt; syntax), &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; is null. Because of this, you should prefer not to use the substitution syntax in places where formulas are specifically supported.&lt;br /&gt;
&lt;br /&gt;
A formula may declare additional variables using a &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clause. This assigns a meaning to any unknown variables in the preceding formula. The general syntax is:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;formula&amp;gt; where &amp;lt;variable&amp;gt; = &amp;lt;value&amp;gt; [, &amp;lt;variable&amp;gt; = value ...]&lt;br /&gt;
&lt;br /&gt;
This functions similarly to an operator, so if desired, you could have multiple where clauses in a single formula. Note that all variables in WFL are read-only - they are variables because they may have different values depending on the context in which the formula is evaluated, but for a given context, they are constant. A variable that has not been assigned a value is considered to have a value of null. Variables are lazily-evaluated - if a where clause declares a variable that is never used, the expression assigned to it will never be evaluated. (This only really matters if it contains a call to a debug function.)&lt;br /&gt;
&lt;br /&gt;
Variable names can contain letters and underscores only. In particular, they cannot contain digits. Also, names are case-sensitive, so ''y'' and ''Y'' refer to two different variables. The following names are reserved and cannot be used for the name of a variable or function:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;d&amp;lt;/tt&amp;gt; - dice operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;or&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; - containment operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;def&amp;lt;/tt&amp;gt; - defines a function&lt;br /&gt;
* &amp;lt;tt&amp;gt;and&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;not&amp;lt;/tt&amp;gt; - logical operator&lt;br /&gt;
* &amp;lt;tt&amp;gt;fai&amp;lt;/tt&amp;gt; - deprecated synonym of &amp;lt;tt&amp;gt;wfl&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;wfl&amp;lt;/tt&amp;gt; - declares filename&lt;br /&gt;
* &amp;lt;tt&amp;gt;where&amp;lt;/tt&amp;gt; - declares variables&lt;br /&gt;
* &amp;lt;tt&amp;gt;faiend&amp;lt;/tt&amp;gt; - deprecated synonym of &amp;lt;tt&amp;gt;wflend&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;wflend&amp;lt;/tt&amp;gt; - closes file scope&lt;br /&gt;
* &amp;lt;tt&amp;gt;functions&amp;lt;/tt&amp;gt; - lists all defined functions&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
Sometimes with particularly complicated formulas, it may be useful to document what's going on inline. Of course, you can use WML comments to do this, but in some cases it may be useful to put some comments in the middle of the formula. This is easily done - simply enclose them in &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; characters, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
#This is a Wesnoth Formula Language comment.#&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the final &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; - unlike WML, WFL requires this to indicate where the comment ends.&lt;br /&gt;
&lt;br /&gt;
== Defining Functions ==&lt;br /&gt;
&lt;br /&gt;
There are several predefined functions in the Wesnoth Formula Language, and if these are not enough, it is possible to define your own functions. The special variable &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;functions&amp;lt;/syntaxhighlight&amp;gt; always evaluates to a list of all known function names. This is mainly useful only as a debugging tool, though.&lt;br /&gt;
&lt;br /&gt;
To define a function, you use the &amp;lt;code&amp;gt;def&amp;lt;/code&amp;gt; keyword. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def sgn(x) if(x &amp;lt; 0, -1, x &amp;gt; 0, 1, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This defines a function called &amp;lt;code&amp;gt;sgn&amp;lt;/code&amp;gt; which returns the sign of the input number. The semicolon marks the end of the function. It's optional if there's nothing else following the function, but in practice this will very rarely be the case.&lt;br /&gt;
&lt;br /&gt;
Function names have the same limitation as variable names – they can contain only letters and underscores, and cannot contain digits.&lt;br /&gt;
&lt;br /&gt;
You can select one of the function's arguments to be the &amp;quot;default&amp;quot; argument. If an object is passed to the default argument, then any attributes of that object are directly accessible in the global scope. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def is_badly_wounded(u*) hitpoints &amp;lt; max_hitpoints / 2;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function takes a unit and returns 1 if it is at less than half hitpoints. The &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt; indicates the default argument, without which it would instead have to be defined like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def is_badly_wounded(u) u.hitpoints &amp;lt; u.max_hitpoints / 2;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It's important to remember that the function body has access to no variables other than its parameters. For example, the following function would not work (in a unit filter context) even though the unit variable is defined:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
def endangers_me(u) distance_between(u.loc, unit.loc) &amp;lt; u.moves;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is because the body of the function can't see the unit variable. To make this work, you would need to pass in unit as an additional parameter.&lt;br /&gt;
&lt;br /&gt;
'''Note: Prior to 1.14, function definitions only work in AI code and GUI2 code.'''&lt;br /&gt;
&lt;br /&gt;
== Where to Use Formulas ==&lt;br /&gt;
&lt;br /&gt;
Formulas can only be used in specific attributes in WML. The documentation of a WML tag will note which keys can have a formula placed in them. Some common examples include [[FilterWML|filters]], [[GUIToolkit|GUI2 dialogs]], and [[AbilitiesWML|unit abilities]]. Another example is the [[VariablesWML#Variable_Substitution|&amp;lt;code&amp;gt;$(formula)&amp;lt;/code&amp;gt; substitution]] syntax, which allows the use of formulas wherever variables are parsed.&lt;br /&gt;
&lt;br /&gt;
When using a formula in WML (other than in a substitution, which is usually part of a longer already-quoted passage), it is highly recommended to place double quotes around the formula, to avoid ambiguity between the WML and WFL parsers. The double angle quotes are also acceptable for this purpose. If you don't quote your formulas, there are two issues you could run into:&lt;br /&gt;
&lt;br /&gt;
# WML uses the &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; operator to represent concatenation of strings, as well as line continuation. Because of this, an unquoted &amp;lt;code&amp;gt;+&amp;lt;/code&amp;gt; will be ''removed'', likely causing the WFL formula to fail to compile.&lt;br /&gt;
# Unquoted WML text has the whitespace collapsed. If using WFL strings where whitespace is significant, this can result in surprises. For example, the formula &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;length('One    Two    Three')&amp;lt;/syntaxhighlight&amp;gt; would return 13 instead of the expected 19 if double quotes are not placed around the formula.&lt;br /&gt;
&lt;br /&gt;
Some attributes in WML ''require'' a formula, which means that anything placed in the attribute will always be considered to be a formula. In this case, the formula doesn't need to be enclosed in parentheses – just the double quotes will suffice. However, there are also attributes that take an ''optional'' formula. These are most common in GUI2, but are also found in other places. In such attributes, the formula ''must'' be enclosed in parentheses. Failure to do so will result in it being parsed as just a straight value. As a general guideline, if the attribute key contains the word &amp;quot;formula&amp;quot;, it is usually required to be a formula, whereas attributes with optional formulas do ''not'' contain the word &amp;quot;formula&amp;quot; in the key.&lt;br /&gt;
&lt;br /&gt;
'''Note''': Do ''not'' use a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; to introduce a formula. The &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; is not part of WFL syntax. It introduces a ''substitution'', a concept which is covered in more detail at [[VariablesWML#Variable Substitution]]. Although WFL can be used ''inside'' a substitution, a substitution itself is not WFL, and you should ''never'' use a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; in WFL. However, in practice, substitutions and WFL are often used together – as substitution is processed first, you may see WFL formulas that appear to contain a &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; inside them. This is ''not'' part of the WFL – it is more like a macro substitution to be carried out before the formula runs. So, of course, it will only work in places that support ''both'' WFL and substitution.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
On occasion, you may find yourself working with formulas complex enough to split them out into a separate file. The formula engine normally assumes that it is executing inline code and reports errors accordingly, but you can tell it to enter a file scope using the special &amp;lt;code&amp;gt;wfl&amp;lt;/code&amp;gt; keyword. The convention is to frame your code, so that any file looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
wfl 'filename.wfl'&lt;br /&gt;
&lt;br /&gt;
# Put whatever code you need here, possibly including function definitions. #&lt;br /&gt;
&lt;br /&gt;
wflend&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The matching &amp;lt;code&amp;gt;wflend&amp;lt;/code&amp;gt; is required.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This functionality was available prior to 1.13.5 using keywords &amp;lt;code&amp;gt;fai&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;faiend&amp;lt;/code&amp;gt;. {{DevFeature1.19|14}} As of 1.19.14, support for the &amp;lt;code&amp;gt;fai&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;faiend&amp;lt;/code&amp;gt; keywords has been removed.&lt;br /&gt;
&lt;br /&gt;
These directives have no effect on the formula code itself. They only change how error messages are reported if something goes wrong. Files using these directives are usually included using the WML preprocessor, though they could also be loaded in Lua with [[LuaAPI/filesystem#filesystem.read_file|filesystem.read_file]].&lt;br /&gt;
&lt;br /&gt;
== Core Functions ==&lt;br /&gt;
&lt;br /&gt;
Many of the core functions exhibit two features that (as of 1.13.4) cannot be used in user-defined functions. The first is the ability to accept a varying number of arguments - some core functions accept any number of arguments, while others have a few optional arguments. The second is that arguments are lazily-evaluated, and in some cases some arguments will not be evaluated at all, while others may be evaluated multiple times with different variable values. The description of each function will explain how and when its arguments are evaluated.&lt;br /&gt;
&lt;br /&gt;
Most of the core functions can be used from any formula. However, there are some that are only available in formulas that have access to the game state. The following formulas have access to the game state and can use those functions:&lt;br /&gt;
&lt;br /&gt;
* Formulas used in [[FilterWML]]&lt;br /&gt;
* Formulas used in [[AbilitiesWML]]&lt;br /&gt;
* &amp;lt;tt&amp;gt;filter_formula&amp;lt;/tt&amp;gt; in [[EventWML#filter_formula|EventWML]]&lt;br /&gt;
* Formulas evaluated from the formula console (accessed by pressing F)&lt;br /&gt;
&lt;br /&gt;
The following formulas do not have access to the game state and cannot use those functions:&lt;br /&gt;
&lt;br /&gt;
* Formulas used in [[GUI2]]&lt;br /&gt;
* [[SyntaxWML#formula_substitution|Substitution]] formulas using &amp;lt;tt&amp;gt;$(...)&amp;lt;/tt&amp;gt;&lt;br /&gt;
* [[ImagePathFunctions#CHAN: General function|IPF]] formulas used in &amp;lt;tt&amp;gt;~CHAN()&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;~ALPHA()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Formulas compiled from [[LuaAPI/wesnoth#wesnoth.compile_formula|Lua]]&lt;br /&gt;
&lt;br /&gt;
=== Conditional Functions ===&lt;br /&gt;
&lt;br /&gt;
There are two functions which return one of their input values based on some condition - the &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; function, and the &amp;lt;code&amp;gt;switch&amp;lt;/code&amp;gt; function. Both evaluate only as many parameters as is needed to determine which value to return. In particular, parameters that are neither returned nor part of the condition will never be evaluated.&lt;br /&gt;
&lt;br /&gt;
==== if ====&lt;br /&gt;
&lt;br /&gt;
* if(''condition'', ''if true'' [, ''condition 2'', ''if true 2'', ...] [, ''otherwise''])&lt;br /&gt;
&lt;br /&gt;
This function first evaluates the ''condition'', which is a formula. If it evaluates to true, then the function evaluates and returns the ''if true'' parameter; otherwise, it tries the next condition (if any) with the same result. If none of the conditions evaluate to true, then it returns the ''otherwise'' parameter if present, or &amp;lt;code&amp;gt;null()&amp;lt;/code&amp;gt; otherwise.&lt;br /&gt;
&lt;br /&gt;
For instance, an event that is triggered by Wolf Riders on the first turn, and Orcish Grunts thereafter might have a unit filter formula that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
if(turn_number = 1, type = 'Wolf Rider', type = 'Orcish Grunt))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== switch ====&lt;br /&gt;
&lt;br /&gt;
* switch(''formula'', ''value 1'', ''outcome 1'' [, ... , ''value N'', ''outcome N''] [, ''default outcome''])&lt;br /&gt;
&lt;br /&gt;
The switch function first evaluates the input ''formula'', and then checks if it is equal to any of the specified ''values''. If matching value is found, the ''outcome'' assigned to it is returned; if not, then function returns either ''default outcome'' (if specified) or null.&lt;br /&gt;
&lt;br /&gt;
=== Numeric Functions ===&lt;br /&gt;
&lt;br /&gt;
Several basic math functions are available. These generally work equally on integer and decimal values.&lt;br /&gt;
&lt;br /&gt;
==== abs ====&lt;br /&gt;
&lt;br /&gt;
* abs(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the absolute value of an input number; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
abs( -5 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return 5.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== acos ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* acos(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arccosine of the input number, in degrees.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== asin ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* asin(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arcsine of the input number, in degrees.&lt;br /&gt;
&lt;br /&gt;
==== atan ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* atan(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the arctangent of the input number, in degrees.&lt;br /&gt;
==== as_decimal ====&lt;br /&gt;
&lt;br /&gt;
* as_decimal(''number'')&lt;br /&gt;
&lt;br /&gt;
Ensures that the number is a decimal rather than an integer; useful if you're dividing two unknown values and want to ensure that the result is a decimal.&lt;br /&gt;
&lt;br /&gt;
==== cbrt ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* cbrt(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the cube root of the input number. This is better than using the exponentiation operator, because it will give the correct result for negative numbers.&lt;br /&gt;
&lt;br /&gt;
==== ceil ====&lt;br /&gt;
&lt;br /&gt;
* ceil(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the ceiling of the specified number, ie rounding it up to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== clamp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|0}}&lt;br /&gt;
&lt;br /&gt;
* clamp(''number'', ''min'', ''max'')&lt;br /&gt;
&lt;br /&gt;
Combines min and max into a single call. If ''number'' is less than ''min'', returns ''min''; if it's greater than ''max'', returns ''max''. Otherwise, returns ''number''.&lt;br /&gt;
&lt;br /&gt;
==== cos ====&lt;br /&gt;
&lt;br /&gt;
* cos(''angle'')&lt;br /&gt;
&lt;br /&gt;
Returns the cosine of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== exp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* exp(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the exponential of the input number, which is the constant ''e'' raised to the specified power.&lt;br /&gt;
&lt;br /&gt;
==== floor ====&lt;br /&gt;
&lt;br /&gt;
* floor(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the floor of the specified number, ie rounding it down to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== frac ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* frac(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the fractional part of the specified number.&lt;br /&gt;
&lt;br /&gt;
==== hypot ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* hypot(''x'', ''y'')&lt;br /&gt;
&lt;br /&gt;
Returns the hypoteneuse length of a triangle with sides ''x'' and ''y''.&lt;br /&gt;
&lt;br /&gt;
==== lerp ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|0}}&lt;br /&gt;
&lt;br /&gt;
* lerp(''min'', ''max'', ''fraction'')&lt;br /&gt;
&lt;br /&gt;
Returns a linear interpolation between ''min'' and ''max'' according to the specified ''fraction''.&lt;br /&gt;
&lt;br /&gt;
==== lerp_index ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* lerp_index(''list'', ''ratio'')&lt;br /&gt;
&lt;br /&gt;
Returns the element of the list that is closest to being at the specified ratio of the list's length.&lt;br /&gt;
&lt;br /&gt;
'''Example''': &amp;lt;syntaxhighlight lang=wfl inline&amp;gt;lerp_index([1, 12, 32, 10], 0.26])&amp;lt;/syntaxhighlight&amp;gt; returns 12.&lt;br /&gt;
&lt;br /&gt;
==== log ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* log(''number'', [, ''base''])&lt;br /&gt;
&lt;br /&gt;
Returns the logarithm of the input number. If ''base'' is omitted, it returns the natural logarithm; otherwise, the logarithm to the specified base.&lt;br /&gt;
&lt;br /&gt;
==== max ====&lt;br /&gt;
&lt;br /&gt;
* max(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
Returns the largest number from the list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
max([2, 8, -10, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return &amp;lt;code&amp;gt;8&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== min ====&lt;br /&gt;
&lt;br /&gt;
* min(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
Returns the smallest number from the list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
min( [ 3, 7, -2, 6] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return &amp;lt;code&amp;gt;-2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} This now works on decimals as well as integers.&lt;br /&gt;
&lt;br /&gt;
==== pi ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* pi()&lt;br /&gt;
&lt;br /&gt;
Returns pi.&lt;br /&gt;
&lt;br /&gt;
==== root ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* root(''number'', ''base'')&lt;br /&gt;
&lt;br /&gt;
Returns the root of the input number, to the specified base. This is better than using the exponentiation operator, because it will give the correct result for negative numbers and odd bases (for example, the fifth root of -32, which is -2).&lt;br /&gt;
&lt;br /&gt;
==== round ====&lt;br /&gt;
&lt;br /&gt;
* round(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the specified number rounded to the nearest integer.&lt;br /&gt;
&lt;br /&gt;
==== sgn ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* sgn(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the sign of the number, ie -1 if it is negative, 1 if it is positive, and 0 if it is zero.&lt;br /&gt;
&lt;br /&gt;
==== sin ====&lt;br /&gt;
&lt;br /&gt;
* sin(''angle'')&lt;br /&gt;
&lt;br /&gt;
Returns the sine of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== sqrt ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* sqrt(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the square root of the input number.&lt;br /&gt;
&lt;br /&gt;
==== sum ====&lt;br /&gt;
&lt;br /&gt;
* sum(''list of numbers'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates to the sum of the numbers in the ''list of numbers''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sum([ 2, 5, 8])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;15&amp;lt;/code&amp;gt;, and:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sum(map(my_units, max_hitpoints - hitpoints))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
finds the total damage your units have taken.&lt;br /&gt;
&lt;br /&gt;
==== tan ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* tan(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the tangent of the given angle, which is specified in degrees.&lt;br /&gt;
&lt;br /&gt;
==== trunc ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* trunc(''number'')&lt;br /&gt;
&lt;br /&gt;
Returns the truncation of the specified number, ie rounding it towards zero. This is different from floor when applied to negative numbers - floor(-7.5) gives -8, but trunc(-7.5) gives -7.&lt;br /&gt;
&lt;br /&gt;
==== wave ====&lt;br /&gt;
&lt;br /&gt;
* wave(''number'')&lt;br /&gt;
&lt;br /&gt;
Given a numeric value V, this returns:&lt;br /&gt;
&lt;br /&gt;
  sin(2*pi*V)&lt;br /&gt;
&lt;br /&gt;
=== String Functions ===&lt;br /&gt;
&lt;br /&gt;
There are a few useful functions for manipulating strings.&lt;br /&gt;
&lt;br /&gt;
==== concatenate ====&lt;br /&gt;
&lt;br /&gt;
* concatenate(''value1''[, ''value2'', ...])&lt;br /&gt;
&lt;br /&gt;
Converts each of its arguments to a string, and concatenates the result together into a single string.&lt;br /&gt;
&lt;br /&gt;
==== contains_string ====&lt;br /&gt;
&lt;br /&gt;
* contains_string(''string'', ''search_string'')&lt;br /&gt;
&lt;br /&gt;
Returns 1 if ''search_string'' can be found within ''string'' (as a substring), 0 otherwise. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
contains_string( 'Testing', 'ing' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== length ====&lt;br /&gt;
&lt;br /&gt;
* length(''string'')&lt;br /&gt;
&lt;br /&gt;
Returns the length of the input string.&lt;br /&gt;
&lt;br /&gt;
==== ends_with ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* ends_with(''string'', ''suffix'')&lt;br /&gt;
&lt;br /&gt;
Determines whether the ''string'' ends with the specified ''suffix''.&lt;br /&gt;
&lt;br /&gt;
==== find_string ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* find_string(''string'', ''search_string'')&lt;br /&gt;
&lt;br /&gt;
Returns the index at which ''search_string'' starts within ''string'' (as a substring), or -1 if it is not found. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
find_string( 'Testing', 'ing' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== replace ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* replace(''string'', ''offset'', [''size'',] ''replacement'')&lt;br /&gt;
&lt;br /&gt;
Returns a new string obtained by replacing a portion of the input ''string'' with the contents of the ''replacement'' string. The ''offset'' and ''size'' work the same as for &amp;lt;code&amp;gt;substring&amp;lt;/code&amp;gt;. Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', 4, 5, 'dumb')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -9, 4, 'sleeping')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -9, 'brook!')&lt;br /&gt;
replace('The quick brown fox jumps over the lazy dog!', -6, -4, 'yellow')&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return the following strings:&lt;br /&gt;
&lt;br /&gt;
 'The dumb brown fox jumps over the lazy dog!'&lt;br /&gt;
 'The quick brown fox jumps over the sleeping dog!'&lt;br /&gt;
 'The quick brown fox jumps over the brook!'&lt;br /&gt;
 'The quick brown fox jumps over the yellow dog!'&lt;br /&gt;
&lt;br /&gt;
==== replace_all ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* replace_all(''string'', ''match'', ''replacement'')&lt;br /&gt;
&lt;br /&gt;
Returns a copy of ''string'' with all occurrences of ''match'' replaced by ''replacement''.&lt;br /&gt;
&lt;br /&gt;
==== starts_with ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* starts_with(''string'', ''prefix'')&lt;br /&gt;
&lt;br /&gt;
Determines whether the ''string'' begins with the specified ''prefix''.&lt;br /&gt;
&lt;br /&gt;
==== substring ====&lt;br /&gt;
&lt;br /&gt;
* substring(''string'', ''offset''[, ''size''])&lt;br /&gt;
&lt;br /&gt;
Extracts a substring from the given input string. The ''offset'' specifies the first character to extract; the first character is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;, and negative values count from the end, so the last character is &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;. If specified, the ''size'' indicates the total number of characters to extract; it cannot be negative. If omitted, all characters from the ''offset'' to the end of the string are returned. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', 4, 5)&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -9, 4)&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -9)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return &amp;lt;code&amp;gt;'quick'&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'lazy'&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;'lazy dog!'&amp;lt;/code&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The ''size'' can now be negative. This means to count backwards from the given ''offset'' (but always including the given offset, so a ''size'' of -1 gives the same result as 1). For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
substring('The quick brown fox jumps over the lazy dog!', -6, -4)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'lazy'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== List and Map Functions ===&lt;br /&gt;
&lt;br /&gt;
This section contains functions that directly manipulate a map or list.&lt;br /&gt;
&lt;br /&gt;
==== head ====&lt;br /&gt;
&lt;br /&gt;
* head(''list'' [, ''count''])&lt;br /&gt;
&lt;br /&gt;
Returns the first item from the ''list''; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
head([5, 7, 9])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
head( [ 'Orc', 'Human' ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'Orc'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} If a second argument is given, it returns a list containing the first ''count'' elements from the ''list''. Note that &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;head(L)&amp;lt;/syntaxhighlight&amp;gt; is different from &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;head(L,1)&amp;lt;/syntaxhighlight&amp;gt; - the former returns the first element, while the latter returns a list containing only the first element.&lt;br /&gt;
&lt;br /&gt;
==== index_of ====&lt;br /&gt;
&lt;br /&gt;
* index_of(''value'', ''list'')&lt;br /&gt;
&lt;br /&gt;
This function will return the first index where ''value'' can be found in the input ''list''. It will return -1 if the value is not found in the ''list'.&lt;br /&gt;
&lt;br /&gt;
==== keys ====&lt;br /&gt;
&lt;br /&gt;
* keys(''map'')&lt;br /&gt;
&lt;br /&gt;
Extracts the key values from an input ''map'' and returns them as a list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
keys(['Elvish Fighter' -&amp;gt; 50, 'Elvish Archer' -&amp;gt; 60])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns&lt;br /&gt;
&lt;br /&gt;
 ['Elvish Fighter', 'Elvish Archer']&lt;br /&gt;
&lt;br /&gt;
==== size ====&lt;br /&gt;
&lt;br /&gt;
* size(''list'')&lt;br /&gt;
&lt;br /&gt;
This function returns the number of elements in the ''list''.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;size([5, 7, 9])&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; and &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;size(['Archer', 'Fighter'])&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== sort ====&lt;br /&gt;
&lt;br /&gt;
* sort(''list'', ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates to a result list sorted according to the comparison ''formula'' for each item &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and its successor &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;. For instance, sorting units according to hitpoints would be done by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
sort(my_units, a.hitpoints &amp;gt; b.hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To sort them in the reverse order, simply use &amp;lt;code&amp;gt;&amp;amp;lt;&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== tail ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* tail(''list'' [, ''count''])&lt;br /&gt;
&lt;br /&gt;
Returns the last item from the ''list''; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tail([5, 7, 9])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;9&amp;lt;/code&amp;gt;, and&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tail( [ 'Orc', 'Human' ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns &amp;lt;code&amp;gt;'Human'&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a second argument is given, it returns a list containing the last ''count'' elements from the ''list''. Note that &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;tail(L)&amp;lt;/syntaxhighlight&amp;gt; is different from &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;tail(L,1)&amp;lt;/syntaxhighlight&amp;gt; - the former returns the last element, while the latter returns a list containing only the last element.&lt;br /&gt;
&lt;br /&gt;
==== tolist ====&lt;br /&gt;
&lt;br /&gt;
* tolist(''map'')&lt;br /&gt;
&lt;br /&gt;
This function takes a map and return a list of key-value pair objects. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tolist(['Elf' -&amp;gt; 10, 'Dwarf' -&amp;gt; 20])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
&lt;br /&gt;
 [{key-&amp;gt;'Elf',value-&amp;gt;10}, {key-&amp;gt;'Dwarf',value-&amp;gt;20}]&lt;br /&gt;
&lt;br /&gt;
==== tomap ====&lt;br /&gt;
&lt;br /&gt;
* tomap(''list A'' [, ''list B''])&lt;br /&gt;
&lt;br /&gt;
This function takes one or two ''lists'' as input and returns a map. If only one list is specified, then the function will evaluate this list, count how many similar elements are found within the list, and return a map with keys being these elements, and values being a number representing how many of them the list contains. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tomap(['elf', 'dwarf', 'elf', 'elf', 'human', 'human'])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
&lt;br /&gt;
 ['elf' -&amp;gt; 3, 'dwarf' -&amp;gt; 1, 'human' -&amp;gt; 2]&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} However, if all the elements are key-value pairs such as those created by ''pair'' or ''tolist'', then this function will invert the effect of ''tolist'' and return the original map which would have produced the input list as output when passed to ''tolist''. If only some elements are key-value pairs, those elements will be directly converted into key-value pairs in the resulting map, while other values will be treated as described above.&lt;br /&gt;
&lt;br /&gt;
If two lists are specified, then the elements of the first one will be used as a keys, and the elements of the second one as a values, when creating an output map. Note that these input lists must be of the same length. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
tomap(['elf', 'dwarf' ], [10, 20])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in:&lt;br /&gt;
&lt;br /&gt;
 ['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20]&lt;br /&gt;
&lt;br /&gt;
==== values ====&lt;br /&gt;
&lt;br /&gt;
* values(''map'')&lt;br /&gt;
&lt;br /&gt;
Extracts the values assigned to keys from an input ''map'' and returns them as a list. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
values(['Elvish Fighter' -&amp;gt; 50, 'Elvish Archer' -&amp;gt; 60])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns&lt;br /&gt;
&lt;br /&gt;
 [50, 60]&lt;br /&gt;
&lt;br /&gt;
=== List-processing Functions ===&lt;br /&gt;
&lt;br /&gt;
This section covers functions that operate on maps or lists by applying one or more formulas in succession to each element. Most return another map or list, &amp;lt;code&amp;gt;reduce&amp;lt;/code&amp;gt; instead combines all the elements into a single result.&lt;br /&gt;
&lt;br /&gt;
==== choose ====&lt;br /&gt;
&lt;br /&gt;
* choose(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function evaluates ''formula'' for each item in the ''input'' (which can be a list or a map). It will return the first item to which ''formula'' gave the highest value. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
choose(my_units, level)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
gives back the unit with the highest level.&lt;br /&gt;
&lt;br /&gt;
The implicit input when evaluating a mapping/filtering function's ''formula'' component will be that specific item under evaluation (in this example one of &amp;quot;my_units&amp;quot;), and it can be explicitly referenced as &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; when necessary. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
When evaluating a map, we can reference each key by &amp;lt;code&amp;gt;key&amp;lt;/code&amp;gt; and each value by &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;. In this case, the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable is this key-value pair. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
choose(['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20 ], value)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return a key-value pair &lt;br /&gt;
&lt;br /&gt;
 {key-&amp;gt;'dwarf', value-&amp;gt;20}&lt;br /&gt;
&lt;br /&gt;
The curly braces are used in output to indicate that this is an object, not a map. It is not valid WFL syntax.&lt;br /&gt;
&lt;br /&gt;
==== filter ====&lt;br /&gt;
&lt;br /&gt;
* filter(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on each item in the ''input'' (which can be a list or a map). It will evaluate to a list or map which only contains items that the ''formula'' was true for. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
filter(my_units, hitpoints &amp;lt; max_hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return all of your units which have less than maximum hitpoints. For instance this could be used if looking for candidates for healing.&lt;br /&gt;
&lt;br /&gt;
==== find ====&lt;br /&gt;
 &lt;br /&gt;
* find(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run &amp;lt;formula&amp;gt; on each item in the &amp;lt;input&amp;gt; (which can be a list or a map) and will return the first item for which &amp;lt;formula&amp;gt; was true. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
find(units, type = 'Elvish Archer' )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will return the first unit of type 'Elvish Archer'.&lt;br /&gt;
&lt;br /&gt;
==== map ====&lt;br /&gt;
&lt;br /&gt;
* map(''input'', [''self_name'',] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on each item in the ''input'' (which can be a list or a map), and evaluate to a new list or map or a map, which contains the same number of items as in ''input'', with the formulas run on each item. The optional &amp;lt;self_name&amp;gt; parameter can be used to give a different name to the &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; variable. When run on a map, the resulting map has the same keys as the input map, but with the values updated to the results of the ''formula''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map([10,20], self*self)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map([10,20], 'value', value*value)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will both result in [100, 400]. The formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(my_units, hitpoints)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will give a list back with the number of hitpoints each unit has. This is more useful in conjunction with other functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(['elf' -&amp;gt; 10, 'dwarf' -&amp;gt; 20 ], value*2)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will produce ['elf' -&amp;gt; 20, 'dwarf' -&amp;gt; 40]. Note that in case of a map data type, the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; function can only modify the value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
map(tomap([3,5,8,8]), value+key*100)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above will produce &amp;lt;code&amp;gt;[3 -&amp;gt; 301, 5 -&amp;gt; 502, 8 -&amp;gt; 801]&amp;lt;/code&amp;gt;. This can be used to take a list and make a map containing pairs &amp;lt;code&amp;gt;[element_from_that_list -&amp;gt; f(element_from_that_list,number_of_repetitions_of_that_element_in_that_list)]&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; is an arbitrary function.&lt;br /&gt;
&lt;br /&gt;
==== reduce ====&lt;br /&gt;
&lt;br /&gt;
* reduce(''list'', [''identity'', ] ''formula'')&lt;br /&gt;
&lt;br /&gt;
This function will run the ''formula'' on the first and second members of the ''list'', then on the result and the third member and so on until the list is depleted. The final result is then returned. The two variables used in the ''formula'' are always 'a' and 'b'.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;reduce([1,2,3,4], a+b)&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; and &amp;lt;syntaxhighlight lang='wfl' inline&amp;gt;reduce([9,4,8,2], 10*a+b)&amp;lt;/syntaxhighlight&amp;gt; returns &amp;lt;code&amp;gt;9482&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The new ''identity'' argument specifies the starting value (which is null or 0 by default). If ''list'' is empty, then ''identity'' is returned. Otherwise, the list will be considered as if ''identity'' were an extra first element. For example, to calculate the product of a list of numbers, you might do something like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
reduce(your_list, 1, a * b)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will return 1 if the list is empty, as expected - the product of no numbers is 1. If the list is not empty, adding 1 to the list will have no effect, since it is the multiplicative identity.&lt;br /&gt;
&lt;br /&gt;
==== take_while ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* take_while(''list'', ''formula'')&lt;br /&gt;
&lt;br /&gt;
Evaluates the ''formula'' for each element of the ''list'' until it finds one for which it evaluates to false, then returns a list of all elements up to but not including that element. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
take_while([1,5,3,6,3,7,9,5,6,4,12,2,53,2,1], self &amp;lt; 10)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
returns the list &amp;lt;code&amp;gt;[1,5,3,6,3,7,9,5,6,4]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== zip ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* zip(''list1'', ... , ''listN'')&lt;br /&gt;
* zip(''list of lists'')&lt;br /&gt;
&lt;br /&gt;
Takes a list of lists and generates a new list of lists such that list ''n'' contains element ''n'' of each of the original lists, in order. If the lists are not all of the same length, it treats them as if they were padded on the end with null values so that they are all the length of the longest list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
zip([1,2,3],[4,5,6])&lt;br /&gt;
zip([1,4],[2,5],[3,6])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
return &amp;lt;code&amp;gt;[[1,4],[2,5],[3,6]]&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;[[1,2,3],[4,5,6]]&amp;lt;/code&amp;gt;, respectively.&lt;br /&gt;
&lt;br /&gt;
=== Location Functions ===&lt;br /&gt;
&lt;br /&gt;
Functions for working with locations on a hex map.&lt;br /&gt;
&lt;br /&gt;
==== adjacent_locs ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* adjacent_locs(''center'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of all locations adjacent to the specified location. When called from a formula with access to the game state, it automatically excludes locations that don't exist on the map. Otherwise, it operates as if on an infinite map. This means you should generally not expect the returned list to contain exactly 6 elements.&lt;br /&gt;
&lt;br /&gt;
==== are_adjacent ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* are_adjacent(''loc1'', ''loc2'')&lt;br /&gt;
&lt;br /&gt;
Check if two locations are adjacent. Returns 1 (true) or 0 (false).&lt;br /&gt;
&lt;br /&gt;
==== direction_from ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* direction_from(''start'', ''direction'', [''distance''])&lt;br /&gt;
&lt;br /&gt;
Returns the hex reached by travelling in the specified direction from a starting hex for a certain distance (default 1 hex).&lt;br /&gt;
&lt;br /&gt;
==== distance_between ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* distance_between(''start'', ''end'')&lt;br /&gt;
&lt;br /&gt;
Returns the distance between the locations ''start'' and ''end'', which must be location objects such as those created by &amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This function was already available in FormulaAI prior to 1.13.5; however, from 1.13.5 onward it is available to all formulas.&lt;br /&gt;
&lt;br /&gt;
==== loc ====&lt;br /&gt;
&lt;br /&gt;
* loc(''x'', ''y'')&lt;br /&gt;
&lt;br /&gt;
Creates and returns a location object with the specified coordinates. If assigned to a variable ''pos'' (eg with a &amp;lt;code&amp;gt;where&amp;lt;/code&amp;gt; clause), the individual coordinates can be accessed as &amp;lt;code&amp;gt;pos.x&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;pos.y&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== locations_in_radius ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* locations_in_radius(''center'', ''radius'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of all locations within a given radius of the specified center hex.&lt;br /&gt;
Only locations on the map will be returned.&lt;br /&gt;
&lt;br /&gt;
==== nearest_loc ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* nearest_loc(''origin'', ''locations'')&lt;br /&gt;
&lt;br /&gt;
Returns the location in the given list closest to ''origin''. All arguments must be location objects such as those created by &amp;lt;code&amp;gt;loc()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This function was already available in FormulaAI prior to 1.19.14; however, from 1.19.14 onward it is available to all formulas.&lt;br /&gt;
&lt;br /&gt;
==== relative_dir ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
* relative_dir(''loc1'', ''loc2'')&lt;br /&gt;
&lt;br /&gt;
Returns the direction you need to travel to progress from one location to another. The returned location is one of the six possible directions on the Wesnoth hex map, or an empty string if both locations are the same.&lt;br /&gt;
&lt;br /&gt;
==== rotate_loc_around ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}} but returns wrong result until {{DevFeature1.19|2}}&lt;br /&gt;
&lt;br /&gt;
* rotate_loc_around(''center'', ''loc'', ''angle'')&lt;br /&gt;
&lt;br /&gt;
Rotates a location around a given center to produce a new location. The angle is an integer between -6 and 6, which can be understood as a multiple of 60 degrees.&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous Functions ===&lt;br /&gt;
&lt;br /&gt;
Some functions really don't fit into any category. They are all listed here.&lt;br /&gt;
&lt;br /&gt;
==== null ====&lt;br /&gt;
&lt;br /&gt;
* null([''arguments''])&lt;br /&gt;
&lt;br /&gt;
Evaluates each of its arguments (if any) in order, then returns null. Since formulas generally do not have side-effects, there is usually little point in specifying any arguments, but it could be thought of as a way to &amp;quot;comment out&amp;quot; a section of the formula while ensuring it remains syntactically valid.&lt;br /&gt;
&lt;br /&gt;
==== pair ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* pair(''key'', ''value'')&lt;br /&gt;
&lt;br /&gt;
Creates a key-value pair object, the same as those created by the ''tolist'' function.&lt;br /&gt;
&lt;br /&gt;
==== reverse ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* reverse(''string or list'')&lt;br /&gt;
&lt;br /&gt;
Returns the input string or list backwards.&lt;br /&gt;
&lt;br /&gt;
==== type ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
* type(''anything'')&lt;br /&gt;
&lt;br /&gt;
Returns the type of its input as a string. Possible results are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;'integer'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'decimal'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'string'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'list'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'map'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'null'&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;'object'&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== get_palette ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}}&lt;br /&gt;
&lt;br /&gt;
* get_palette(''name'')&lt;br /&gt;
&lt;br /&gt;
Returns a list of colours that make up the named palette. Palettes are defined by a '''[color_palette]''' tag, usually in the [[GameConfigWML#Color_Palettes|game config]]. The palettes defined in core Wesnoth are '''magenta''', '''flag_green''', and '''ellipse_red'''. In addition to defined palettes, several hard-coded palettes are available by name. They are '''red_green_scale''', '''red_green_scale_text''', '''blue_white_scale''', and '''blue_white_scale_text'''. These are also defined in the game config, but not with a '''[color_palette]''' tag.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Functions ===&lt;br /&gt;
&lt;br /&gt;
There are also a few functions that can be useful for debugging formulas, for example by displaying intermediate results to the screen. Note that this breaks the general rule that functions do not have side-effects.&lt;br /&gt;
&lt;br /&gt;
==== debug ====&lt;br /&gt;
&lt;br /&gt;
* debug([''formula''])&lt;br /&gt;
&lt;br /&gt;
Starts a GUI formula debugger when evaluating a formula. It takes a formula, evaluates it and returns the result unchanged. '''Note:''' this does not appear to work in 1.13.3.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|5}} The formula allows you to step through the formula one operation at a time, viewing the current stack and execution trace. As of 1.13.5, you need to enable [[CommandMode|debug mode]] to use the debugger; otherwise, it will simply be skipped.&lt;br /&gt;
&lt;br /&gt;
==== debug_print ====&lt;br /&gt;
&lt;br /&gt;
'''you need to enable formula log (--log-info='scripting/formula') to see the result of this call'''&lt;br /&gt;
&lt;br /&gt;
* debug_print([''explanation'' ,] ''formula'' )&lt;br /&gt;
&lt;br /&gt;
This function can be used for debugging a formula. It takes a ''formula'', writes its result to the console, and returns it unchanged. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_print([1, 2, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in printing to the console&lt;br /&gt;
&lt;br /&gt;
 [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
and returning the same.&lt;br /&gt;
&lt;br /&gt;
We can specify an optional parameter ''explanation'' that helps to distinguish between multiple ''debug_print'' calls in the same formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_print('My array: ', [1, 2, 3])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will write in the console:&lt;br /&gt;
&lt;br /&gt;
 My array: [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
and return&lt;br /&gt;
&lt;br /&gt;
 [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
==== debug_profile ====&lt;br /&gt;
&lt;br /&gt;
* debug_profile(''formula'' [, ''explanation''])&lt;br /&gt;
&lt;br /&gt;
Evaluates the formula 1000 times and prints (as with debug_print) a number indicating the average time required to evaluate the formula. Mainly intended for internal testing, but could occasionally be useful for people working with complicated formulas. The optional ''explanation'' argument is used in the same way as in debug_print.&lt;br /&gt;
&lt;br /&gt;
==== debug_float ====&lt;br /&gt;
&lt;br /&gt;
* debug_float(''location'', [''explanation'',] ''formula'' )&lt;br /&gt;
&lt;br /&gt;
This function can be used for debugging a formula. It takes a formula, floats a label containing the result on the hex specified (in the same way damage is displayed) and returns it unchanged. Note that the ''location'' here is an object type; it can be created with the &amp;lt;code&amp;gt;[[#loc|loc()]]&amp;lt;/code&amp;gt; function. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_float(me.loc, me.id)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will make a label containing the id of the unit ''me'' float over the unit.&lt;br /&gt;
&lt;br /&gt;
Return value is also the unit id.&lt;br /&gt;
&lt;br /&gt;
We can specify an optional parameter ''explanation'' that helps to distinguish between multiple ''debug_float'' calls in the same formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
debug_float( me.loc, 'id: ', me.id )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will float the following label&lt;br /&gt;
&lt;br /&gt;
 id: unit_id&lt;br /&gt;
&lt;br /&gt;
and return the unit id.&lt;br /&gt;
&lt;br /&gt;
==== dir ====&lt;br /&gt;
&lt;br /&gt;
* dir(''object'')&lt;br /&gt;
&lt;br /&gt;
This function return a list of all attributes in ''object''. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wfl'&amp;gt;&lt;br /&gt;
dir(my_leader)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will result in the following output:&lt;br /&gt;
&lt;br /&gt;
 [ 'x', 'y', 'loc', 'id', 'type', 'name', 'leader', 'undead', 'traits', 'attacks', 'abilities', 'hitpoints',&lt;br /&gt;
 'max_hitpoints', 'experience', 'max_experience', 'level', 'total_movement', 'movement_left', 'attacks_left',&lt;br /&gt;
 'side', 'states', 'cost', 'usage', 'vars']&lt;br /&gt;
&lt;br /&gt;
This command is useful in the formula command line, to get information about the attributes of different types of data.&lt;br /&gt;
&lt;br /&gt;
=== Game State Functions ===&lt;br /&gt;
&lt;br /&gt;
These are functions that access the game state. Therefore, they are not available in all formulas, as described above.&lt;br /&gt;
&lt;br /&gt;
==== base_tod_bonus ====&lt;br /&gt;
&lt;br /&gt;
* base_tod_bonus([''loc'', [''turn'']])&lt;br /&gt;
&lt;br /&gt;
Evaluates the base time-of-day bonus, excluding the effect of illumination from abilities or terrain. If no turn is specified, the current turn is used. If no location is specified, the bonus is calculated for the global schedule without taking any time areas into account, but if a location is specified, it will account for any time areas that might affect that location.&lt;br /&gt;
&lt;br /&gt;
==== chance_to_hit ====&lt;br /&gt;
&lt;br /&gt;
* chance_to_hit(''unit'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the base chance for the unit to be hit if it moved to the given location or terrain. This is essentially the inverse of its defense. It is returned as an integer between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
==== defense_on ====&lt;br /&gt;
&lt;br /&gt;
* defense_on(''unit'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the defense that the unit would have if it moved to the given location or terrain. It is returned as an integer between 0 and 100.&lt;br /&gt;
&lt;br /&gt;
==== enemy_of ====&lt;br /&gt;
&lt;br /&gt;
* enemy_of(''self'', ''other'')&lt;br /&gt;
&lt;br /&gt;
Determines whether two units are enemies. Returns 1 (true) or 0 (false).&lt;br /&gt;
&lt;br /&gt;
==== get_unit_type ====&lt;br /&gt;
&lt;br /&gt;
* get_unit_type(''id'')&lt;br /&gt;
&lt;br /&gt;
Returns an object describing the specified unit type, or null if no such unit type exists. A unit type object has many of the same keys as a unit, excluding those that are expected to change over time such as &amp;lt;tt&amp;gt;hitpoints&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== jamming_cost ====&lt;br /&gt;
&lt;br /&gt;
* jamming_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the jamming cost for the unit to block vision on the given location terrain.&lt;br /&gt;
&lt;br /&gt;
==== is_fogged ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* is_shrouded(''loc'', ''side_number''])&lt;br /&gt;
&lt;br /&gt;
Returns whether the given location is currently fogged from the point of view of the given side.&lt;br /&gt;
&lt;br /&gt;
==== is_shrouded ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* is_shrouded(''loc'', ''side_number''])&lt;br /&gt;
&lt;br /&gt;
Returns whether the given location is currently shrouded from the point of view of the given side.&lt;br /&gt;
&lt;br /&gt;
==== movement_cost ====&lt;br /&gt;
&lt;br /&gt;
* movement_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the movement cost for the unit to enter the given location or terrain.&lt;br /&gt;
&lt;br /&gt;
==== resistance_on ====&lt;br /&gt;
&lt;br /&gt;
* resistance_on(''unit'', ''location'', ''type'', [''attacker''])&lt;br /&gt;
&lt;br /&gt;
Calculates the unit's resistance to the given damage type when standing on the specified location. If specified, the ''attacker'' parameter should be 1 to indicate that the unit is the attacker, or 0 to indicate that it is the defender, as this status can affect resistances. By default, it is assumed to be the defender.&lt;br /&gt;
&lt;br /&gt;
This is returned not as the raw resistance set in WML, but the actual resistance that the player sees, so it ranges between -100 and 100.&lt;br /&gt;
&lt;br /&gt;
==== tod_bonus ====&lt;br /&gt;
&lt;br /&gt;
* tod_bonus([''loc'', [''turn'']])&lt;br /&gt;
&lt;br /&gt;
Evaluates the final time-of-day bonus, accounting for the effect of illumination from abilities or terrain. If no turn is specified, the current turn is used. If no location is specified, the bonus is calculated for the global schedule without taking any time areas into account, but if a location is specified, it will account for any time areas that might affect that location.&lt;br /&gt;
&lt;br /&gt;
==== unit_at ====&lt;br /&gt;
&lt;br /&gt;
* unit_at(''location'')&lt;br /&gt;
&lt;br /&gt;
Returns the unit on the given location, or null if there is no unit there.&lt;br /&gt;
&lt;br /&gt;
==== unit_tod_modifier ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|14}}&lt;br /&gt;
&lt;br /&gt;
* unit_tod_modifier(''unit'', [''loc''])&lt;br /&gt;
&lt;br /&gt;
Returns the current combat damage modifier for the given unit for the current time of day, taking into account any abilities whose effects it is currently under (illuminates, for example). If no location is specified, the unit's current location will be used.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Prior to 1.19.4, this function was available as the FormulaAI function ''timeofday_modifier''.&lt;br /&gt;
&lt;br /&gt;
==== vision_cost ====&lt;br /&gt;
&lt;br /&gt;
* vision_cost(''unit or unit type'', ''location or terrain'')&lt;br /&gt;
&lt;br /&gt;
Calculates the vision cost for the unit to see through the given location or terrain.&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=InternalActionsWML&amp;diff=74648</id>
		<title>InternalActionsWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=InternalActionsWML&amp;diff=74648"/>
		<updated>2025-11-26T19:37:36Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* [set_variables] */ Document how an explicit index changes the behaviour of replace and merge modes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
&lt;br /&gt;
Part of [[ActionWML]], Internal actions are actions that WML uses internally that do not directly affect game play (or, at least, are not readily apparent to the player). For example, storing a variable is an internal action.&lt;br /&gt;
&lt;br /&gt;
== Variable Actions ==&lt;br /&gt;
&lt;br /&gt;
These actions are focused, in one way or another, on [[VariablesWML|variables]]. Creating them, modifying them, capturing game data to them, you name it, these actions are all about the variables.&lt;br /&gt;
&lt;br /&gt;
=== [set_variable] ===&lt;br /&gt;
&lt;br /&gt;
The '''[set_variable]''' tag is used to create and manipulate [[VariablesWML|WML variables­­­]]. The [https://www.wesnoth.org/macro-reference.html#VARIABLE VARIABLE] macro is a quick syntactic shortcut for simple variable creation and the [https://www.wesnoth.org/macro-reference.html#VARIABLE_OP VARIABLE_OP] macro is a quick syntactic shortcut for performing simple mathematical operations on variables.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the name of the variable to manipulate&lt;br /&gt;
&lt;br /&gt;
* '''value''': set the variable to the given value (can be numeric or string). Use literal for no substitution. (see [[VariablesWML]])&lt;br /&gt;
&lt;br /&gt;
* '''literal''': set the variable to the given value (can be numeric or string). This does not interpret any dollar signs.&lt;br /&gt;
&lt;br /&gt;
* '''to_variable''': set the variable to the value of the given variable, e.g. 'to_variable=temp' would be equivalent to 'value=$temp'.&lt;br /&gt;
&lt;br /&gt;
* '''add''': add the given amount to the variable.&lt;br /&gt;
&lt;br /&gt;
* '''sub''': subtract the given amount from the variable.&lt;br /&gt;
&lt;br /&gt;
* '''multiply''': multiply the variable by the given number. The result is a float.&amp;lt;br /&amp;gt;To negate a number, multiply by -1. If you negate 0, the result is a floating-point negative zero -0. To display -0 as 0, use a second tag with add=0; it will flip -0 to 0 but not affect other numbers.&lt;br /&gt;
&lt;br /&gt;
* '''divide''': divide the variable by the given number. The result is a float. Wesnoth 1.9 and later no longer uses integer division. Use a second tag with round=floor if you relied on this.&lt;br /&gt;
&lt;br /&gt;
* '''modulo''': returns the remainder of a division.&lt;br /&gt;
&lt;br /&gt;
* '''abs''': Returns the absolute value of the variable.&lt;br /&gt;
&lt;br /&gt;
* '''root''': Use '''root=square''' to calculate the square root. {{DevFeature1.15|0}} Also supports '''root=cube''' and arbitrary integer roots.&lt;br /&gt;
&lt;br /&gt;
* '''power''': Raise the variable to some power.&lt;br /&gt;
&lt;br /&gt;
* '''rand''': the variable will be randomly set.&amp;lt;br&amp;gt;You may provide a comma separated list of possibilities, e.g. 'rand=Bob,Bill,Bella'.&amp;lt;br&amp;gt;You may provide a range of numbers (integers), e.g. 'rand=3..5'.&amp;lt;br&amp;gt;You may combine these, e.g. 'rand=100,1..9', in which case there would be 1/10th chance of getting 100, just like for each of 1 to 9. If a number or item is repeated, it is sampled more frequently as appropriate. See [[MultiplayerContent]] for more info on the MP case.&amp;lt;br&amp;gt;Using rand= will automatically result in the current action being non undoable. Ignoring possible [allow_undo].&lt;br /&gt;
&lt;br /&gt;
* '''time=stamp''': Retrieves a timestamp in milliseconds since wesnoth was started, can be used as timing aid. Don't try to use this as random value in MP since it will cause an OOS.&lt;br /&gt;
&lt;br /&gt;
* '''string_length''': Retrieves the length in characters of the string passed as this attribute's value; such string is parsed and variable substitution applied automatically (see [[VariablesWML]] for details).&lt;br /&gt;
&lt;br /&gt;
* {{anchor|join|'''[join]'''}} joins an array of strings to create a textual list&lt;br /&gt;
** '''variable''': name of the array&lt;br /&gt;
** '''key''': the key of each array element(array[$i].foo) in which the strings are stored&lt;br /&gt;
** '''separator''': separator to connect the elements&lt;br /&gt;
** '''remove_empty''': whether to ignore empty elements&lt;br /&gt;
&lt;br /&gt;
* '''ipart''': Assigns the integer part (the part to the left of the decimal point) of the referenced variable.&lt;br /&gt;
&lt;br /&gt;
* '''fpart''': Assigns the decimal part (the part to the right of the decimal point) of the referenced variable.&lt;br /&gt;
&lt;br /&gt;
* '''round''': Rounds the variable to the specified number of digits of precision. Negative precision works as expected (rounding 19517 to -2 = 19500). Special values:&lt;br /&gt;
**'''round=ceil''': Rounds upward to the nearest integer.&lt;br /&gt;
**'''round=floor''': Rounds down to the nearest integer.&lt;br /&gt;
**'''round=trunc''': {{DevFeature1.15|0}} Rounds towards zero; this is the same operation as '''ipart''', but operating on the value already contained in the variable rather than the value assigned to the key.&lt;br /&gt;
&lt;br /&gt;
* '''min''', '''max''': {{DevFeature1.15|9}} Specify a comma-separated list of numbers; either the smallest or largest number in the list will be assigned to the variable.&lt;br /&gt;
&lt;br /&gt;
* '''reverse=yes''': {{DevFeature1.15|9}} Reverses the string value of the variable. For example, &amp;quot;delfador&amp;quot; becomes &amp;quot;rodafled&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* '''formula''': Calculate the new value of the variable from a [[Wesnoth_Formula_Language|WFL]] formula operating on the old value. This is similar to using the '''$(...)''' syntax but avoids the possibility of WFL syntax errors if a referenced variable is empty.&lt;br /&gt;
&lt;br /&gt;
=== [set_variables] ===&lt;br /&gt;
&lt;br /&gt;
Manipulates a WML array or container&lt;br /&gt;
&lt;br /&gt;
* '''name''': the name of the array or container to manipulate&lt;br /&gt;
&lt;br /&gt;
* '''mode''': one of the following values:&lt;br /&gt;
** ''replace'': will clear the variable '''name''' and replace it with given data. This is the default value. If given an explicit index, such as name=my_array[1], only that single element of the array is replaced, and the new data is inserted into that slot, potentially pushing other elements up. If ''not'' given an explicit index, the entire array is replaced.&lt;br /&gt;
** ''append'': will append given data to the current array. An explicit index is ignored if given.&lt;br /&gt;
** ''merge'': will merge in the given data into '''name'''. Attributes in '''[value]''' will overwrite any existing already in '''name'''. Tags in '''[value]''' modify the corresponding tag of the original value of '''name''', so for example the first '''[attack]''' tag in '''[value]''' would modify the first '''[attack]''' tag of '''name''' rather than appending a new '''[attack]''' tag. If given an explicit index, all the '''[value]''' and '''[literal]''' tags will be merged together into a single tag (as if with mode=append), and this resulting container will then be merged into the container at the specified element. A few special syntaxes are supported:&lt;br /&gt;
*** ''__remove=yes'': When used in a subtag, causes the corresponding subtag in '''name''' to be deleted rather than merged. Deletion happens after any other subtags have been merged.&lt;br /&gt;
*** ''add_to_xxx'': Adds its integer value to the integer value of '''xxx''' in '''name''', and sets '''xxx''' in '''name''' to the result. {{DevFeature1.13|8}} Now adds as real numbers rather than integers.&lt;br /&gt;
*** ''concat_to_xxx'': {{DevFeature1.13|8}} Similar to '''add_to_xxx''', but does string concatenation instead of numerical addition.&lt;br /&gt;
** ''insert'': will insert the given data at the index specified in the '''name''' attribute, such as name=my_array[1]. The default index is zero, which will insert to the front of the array. Otherwise, it is inserted so as to become the element at the specified index, meaning that the element previously at that index and all later elements are pushed up by one. '''Note:''' if an invalid index is used, empty containers will be created before the insertion is performed. In other words, do not attempt to insert at an index greater than (or equal to) the array's current length. This limitation may be removed in future versions.&lt;br /&gt;
&lt;br /&gt;
* '''to_variable''': set the array or container to the value of the given variable&lt;br /&gt;
&lt;br /&gt;
* {{anchor|set_variables-value|'''[value]'''}}: the WML inside the [value] tags will be stored in data, variables will be interpolated directly, use $| in order to escape the $ sign, you can store arrays of WML by supplying multiple [value] tags. ([[#Using_.5Bset_variables.5D_to_Create_Arrays_of_WML|See Example]])&lt;br /&gt;
&lt;br /&gt;
* {{anchor|set_variables-literal|'''[literal]'''}}: same as '''[value]''', but variables will not be substituted, '''[literal]''' and '''[value]''' can not be used in the same [set_variables] tag, i.e. you can not create arrays by piling a mix of '''[value]''' and '''[literal]''' tags&lt;br /&gt;
&lt;br /&gt;
*{{anchor|set_variables-split|'''[split]'''}}: splits a textual list into an array which will then be set to data&lt;br /&gt;
** '''list''': textual list to split&lt;br /&gt;
** '''key''': the key of each array element(array[$i].foo) in which the strings are stored; defaults to ''value'' if omitted.&lt;br /&gt;
** '''separator''': separator to separate the elements; if omitted, each character of the string will become an element in the result array.&lt;br /&gt;
** '''remove_empty''': whether to ignore empty elements; ignored if '''separator''' is omitted&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|4}} You can now mix '''[value]''', '''[literal]''', and '''[split]''' in the same '''[set_variables]''' tag. They will be processed in order of appearance. Multiple instances of [split] are also supported now.&lt;br /&gt;
&lt;br /&gt;
=== Capturing Game Data ===&lt;br /&gt;
&lt;br /&gt;
These actions capture different bits of game data and store them to variables so they can be examined and/or manipulated.&lt;br /&gt;
&lt;br /&gt;
==== [store_gold] ====&lt;br /&gt;
&lt;br /&gt;
Stores a side's gold into a variable.&lt;br /&gt;
&lt;br /&gt;
* '''[[StandardSideFilter]]''': The first matching side's gold will be stored in the variable &amp;quot;variable&amp;quot;.&lt;br /&gt;
* '''variable''': (default='gold') the name of the variable to store the gold in&lt;br /&gt;
&lt;br /&gt;
==== [store_locations] ====&lt;br /&gt;
&lt;br /&gt;
Stores a series of locations that pass certain criteria into an array. Each member of the array has members 'x' and 'y' (the position) and 'terrain' (the terrain type) and 'owner_side' (villages only). The array will include any unreachable border hexes, if applicable.&lt;br /&gt;
&lt;br /&gt;
* [[StandardLocationFilter]]: a location or location range which specifies the locations to store. By default, all locations on the map are stored.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable (array) into which to store the locations. Defaults to '''location'''.&lt;br /&gt;
&lt;br /&gt;
* '''mode''': {{DevFeature1.13|0}} defaults to ''always_clear'', which clears the variable, whether or not a match is found. If mode is set to ''replace'', the variable will not be cleared, and locations which match the filter will overwrite existing elements at the start of the array, leaving any additional elements intact if the original array contained more elements than there are locations matching the filter. If mode is set to ''append'', the variable will not be cleared, and locations which match the filter will be added to the array after the existing elements.&lt;br /&gt;
&lt;br /&gt;
==== [store_reachable_locations] ====&lt;br /&gt;
&lt;br /&gt;
Stores locations reachable by the given units. Can store either the movement, attack or vision ranges.&lt;br /&gt;
&lt;br /&gt;
* '''[filter]''': a [[StandardUnitFilter]]. The locations reachable by any of the matching units will be stored.&lt;br /&gt;
* '''[filter_location]''': (optional) a [[StandardLocationFilter]]. Only locations which also match this filter will be stored.&lt;br /&gt;
* '''range''': possible values ''movement'' (default), ''attack'', ''vision''. If ''movement'', stores the locations within the movement range of the unit, taking Zone of Control into account. If ''attack'', stores the attack range (movement range + 1 hex). See note below for ''vision''.&lt;br /&gt;
* '''moves''':  possible values ''current'' (default), ''max''. For ''movement'' and ''attack'', specifies whether to use the current or maximum movement points when calculating the range. Ignored for ''vision''.&lt;br /&gt;
* '''viewing_side''': If left unset then fog and shroud are ignored, hidden ambushers are not ignored, and the real reach of the units is stored. If set to a non-zero number, then the area stored for each unit matching the SUF is based on the information visible to that unit's side; it doesn't matter which non-zero number is given. Ignored completely for ''vision''.&lt;br /&gt;
* '''variable''': the name of the variable (array) into which to store the locations.&lt;br /&gt;
&lt;br /&gt;
In 1.14 and before, the ''vision'' range is calculated as max movement range ignoring ZoC + 1 hex.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|12}} ''vision'' uses the same calculations as the fog and shroud, and handles:&lt;br /&gt;
* units with vision costs different to movement costs&lt;br /&gt;
* units whose vision points aren't the same as their max movement points&lt;br /&gt;
* jamming by enemy units&lt;br /&gt;
&lt;br /&gt;
==== [store_map_dimensions] ====&lt;br /&gt;
&lt;br /&gt;
Stores the map dimensions in a variable.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable where the values will be saved into. If it is skipped, a variable 'map_size' is used, and its contents overridden, if they existed already. The result is a container variable, with members ''width'' and ''height''.&lt;br /&gt;
&lt;br /&gt;
==== [store_side] ====&lt;br /&gt;
&lt;br /&gt;
Stores information about a certain side in a variable.&lt;br /&gt;
&lt;br /&gt;
'''Keys:'''&lt;br /&gt;
* '''[[StandardSideFilter]]''': All matching sides are stored. (An array is created if several sides match - access it with side[2].team_name and so on.)&lt;br /&gt;
* '''variable''': the name of the variable to store the information in (default: &amp;quot;side&amp;quot;)&lt;br /&gt;
* '''mode''':{{DevFeature1.13|0}} defaults to ''always_clear'', which clears the variable, whether or not a match is found. If mode is set to ''replace'', the variable will not be cleared, and sides which match the filter will overwrite existing elements at the start of the array, leaving any additional elements intact if the original array contained more elements than there are sides matching the filter. If mode is set to ''append'', the variable will not be cleared, and sides which match the filter will be added to the array after the existing elements.&lt;br /&gt;
'''Result'''&lt;br /&gt;
&lt;br /&gt;
Variable will contain following members:&lt;br /&gt;
* '''color''': Team color used for ellipses, sprites, and flags. Will be one of the id's found in data/core/team-colors.cfg or a custom color defined by [[GameConfigWML#Color_Palettes|[color_range]]].&lt;br /&gt;
* '''controller''': Indicates type of player that control this side. ''Note: In networked multiplayer, the controller attribute may not be the same on all clients. Be very careful or you have OOS errors.''&lt;br /&gt;
** '''human''': Human player&lt;br /&gt;
** '''ai''': If players assigns &amp;quot;Computer Player&amp;quot; to &amp;quot;Player/Type&amp;quot; in game lobby&lt;br /&gt;
** '''null''': If players assigns &amp;quot;Empty&amp;quot; to &amp;quot;Player/Type&amp;quot; in game lobby&lt;br /&gt;
* '''fog''': Indicates whether this side is affected by fog of war.&lt;br /&gt;
* '''gold''': The amount of gold the side has.&lt;br /&gt;
* '''hidden''': (boolean) If 'yes', side is not shown in status table.&lt;br /&gt;
* '''income''': Income for this side (base income + all village income. AKA gross income. Note that this is different from the [side] income key).&lt;br /&gt;
* '''name''': Name of player.&lt;br /&gt;
* '''recruit''': A comma-separated list of unit types that can be recruited by this side.&lt;br /&gt;
* '''shroud''': Whether this side is affected by shroud.&lt;br /&gt;
* '''side''': The $side_number of the side belonging to this container&lt;br /&gt;
* '''side_name''': Translated string representing the side's description.&lt;br /&gt;
* '''team_name''': String representing the team's description. Sides with the same team_name are allied.&lt;br /&gt;
* '''user_team_name''': Translated string representing the team's description.&lt;br /&gt;
* '''village_gold''': The amount of gold given to this side per village it controls per turn.&lt;br /&gt;
* '''scroll_to_leader''': (boolean) Whether the game view scrolls to the side leader at the start of their turn.&lt;br /&gt;
* '''flag''': Flag animation for villages owned by this side (see [[SideWML|[side]]]). Unless previously specified in [side] or changed with WML (see [[DirectActionsWML#.5Bmodify_side.5D|[modify_side]]]), this value may be empty for the default flag animation.&lt;br /&gt;
* '''flag_icon''': Flag icon for the status bar for this side (see [[SideWML|[side]]]). Unless previously specified in [side] or changed with WML (see [[DirectActionsWML#.5Bmodify_side.5D|[modify_side]]]), this value may be empty for the default flag icon.&lt;br /&gt;
* '''village_support''': The number of unit levels this side is able to support (does not pay upkeep on) per village it controls.&lt;br /&gt;
* '''defeat_condition''': {{DevFeature1.13|7}} When the side will be considered defeated. See description at [[SideWML]], [[ScenarioWML#Scenario_End_Conditions]]&lt;br /&gt;
* '''faction''': {{DevFeature1.13|7}} id of the selected faction, string (multiplayer-only)&lt;br /&gt;
* '''faction_name''': {{DevFeature1.13|7}} Name of the selected faction, string (multiplayer-only)&lt;br /&gt;
* '''num_units''' {{DevFeature1.13|7}}: The number of units the side currently has on the map.&lt;br /&gt;
* '''num_villages''' {{DevFeature1.13|7}}: The number of villages the side currently controls.&lt;br /&gt;
* '''total_upkeep''' {{DevFeature1.13|7}}: The number of unit levels the side is currently supporting.&lt;br /&gt;
* '''expenses''' {{DevFeature1.13|7}}: The amount of gold the side is currently spending to support units.&lt;br /&gt;
* '''net_income''' {{DevFeature1.13|7}}: The income the side gains per turn after expenses.&lt;br /&gt;
* '''base_income''' {{DevFeature1.13|8}}: The income the side gains per turn (same as [side] income key)&lt;br /&gt;
&lt;br /&gt;
* {{DevFeature1.13|7}} All other keys and tags of the side that are contained in [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]] .__cfg&lt;br /&gt;
&lt;br /&gt;
==== [store_starting_location] ====&lt;br /&gt;
&lt;br /&gt;
Stores the starting location of a side's leader in a variable. The variable is a composite type which will have members 'x', 'y', 'terrain' and 'owner_side' (villages only)&lt;br /&gt;
&lt;br /&gt;
* [[StandardSideFilter]]: The starting locations of all matching sides will be stored. If multiple sides are matched, a WML array will be created.&lt;br /&gt;
* '''variable''': (default='location'): the name of the variable to store the location in&lt;br /&gt;
* '''mode''':{{DevFeature1.13|0}} defaults to ''always_clear'', which clears the variable, whether or not a match is found. If mode is set to ''replace'', the variable will not be cleared, and the starting locations of the sides which match the filter will overwrite existing elements at the start of the array, leaving any additional elements intact if the original array contained more elements than there are locations matching the filter. If mode is set to ''append'', the variable will not be cleared, and the starting locations of the matching sides will be added to the array after the existing elements.&lt;br /&gt;
&lt;br /&gt;
==== [store_time_of_day] ====&lt;br /&gt;
&lt;br /&gt;
Stores time of day information from the current scenario into a WML variable container.&lt;br /&gt;
&lt;br /&gt;
* '''x, y''': Location to store the time for. [[DirectActionsWML#.5Btime_area.5D|Time areas]] matter; illumination does not. If this is omitted, the global (location-independent) time is stored.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': (default='time_of_day') name of the container on which to store the information. The container will be filled with the same attributes found on [[TimeWML]].&lt;br /&gt;
&lt;br /&gt;
* '''turn''': (defaults to the current turn number) changes the turn number for which time of day information should be retrieved.&lt;br /&gt;
&lt;br /&gt;
==== [store_turns] ====&lt;br /&gt;
&lt;br /&gt;
Stores the turn limit (the maximum number of turns). If there is no limit, this stores ''-1''.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': (default='turns') the name of the variable in which to store the turn limit.&lt;br /&gt;
&lt;br /&gt;
==== [store_unit] ====&lt;br /&gt;
&lt;br /&gt;
Stores details about units into a [[VariablesWML#Container|container]] variable. When a unit is stored, all keys and tags in the unit definition may be manipulated, including some others, with [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]]. A sample '''list of these tags and keys''' can be found at [[InternalActionsWMLUnitTags]].&lt;br /&gt;
&lt;br /&gt;
If you have a doubt about what keys are valid or what the valid value range is for each key, code a [store_unit] event, save the game, and examine what keys are in the file (or just examine the '''[unit]''' tag(s) in any save file). One can also use the [[CommandMode|:inspect]] command or the [[InterfaceActionsWML#.5Binspect.5D|[inspect]]] tag to open a game-state inspector dialog, which can be used to view unit properties.&lt;br /&gt;
&lt;br /&gt;
Common usage is to manipulate a unit by using '''[store_unit]''' to store it into a variable, followed by manipulation of the variable, and then [[DirectActionsWML#.5Bunstore_unit.5D|[unstore_unit]]] to re-create the unit with the modified variables.&lt;br /&gt;
&lt;br /&gt;
''Note: stored units also exist on the field, and modifying the stored variable will not automatically change the stats of the units. You need to use [unstore_unit]. See also [[DirectActionsWML#.5Bunstore_unit.5D|[unstore_unit]]] and [[ConditionalActionsWML#.5Bforeach.5D|[foreach]]].&lt;br /&gt;
&lt;br /&gt;
* '''[filter]''' with a [[StandardUnitFilter]] as argument. All units matching this filter will be stored. If there are multiple units, they will be stored into an array of variables. The units will be stored in order of their internal ''underlying_id'' attribute, which is usually in creation order (but you normally should not depend on the order).&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable into which to store the unit(s)&lt;br /&gt;
&lt;br /&gt;
* '''mode''': defaults to ''always_clear'', which clears the variable, whether or not a match is found. If mode is set to ''replace'', the variable will not be cleared, and units which match the filter will overwrite existing elements at the start of the array, leaving any additional elements intact if the original array contained more elements than there are units matching the filter. If mode is set to ''append'', the variable will not be cleared, and units which match the filter will be added to the array after the existing elements.&lt;br /&gt;
&lt;br /&gt;
* '''kill''': if 'yes' the units that are stored will be removed from play. This is useful for instance to remove access to a player's recall list, with the intent to restore the recall list later.&lt;br /&gt;
&lt;br /&gt;
==== [store_unit_defense] ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|7}} Fixed, was broken in 1.15.3&lt;br /&gt;
&lt;br /&gt;
Stores in a variable the defense of a unit on a particular terrain. If terrain or location is not specified, the terrain on which the unit currently stands is used. (Note: it is a WML defense, so the higher it is, the weaker unit's defense is. A footpad on castle has 70% defense, so this function stores the value 30.)&lt;br /&gt;
&lt;br /&gt;
* StandardUnitFilter&lt;br /&gt;
* '''loc_x''', '''loc_y''': x and y of a valid map location. The terrain on this location will be used for the defense calculation.&lt;br /&gt;
* '''terrain''': The terrain code for which unit defense should be calculated. If '''terrain''' is specified, '''loc_x''' and '''loc_y''' are ignored.&lt;br /&gt;
* '''variable''': the name of the variable into which to store the defense. default: &amp;quot;terrain_defense&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== [store_unit_defense_on] ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|7}} Similar to [store_unit_defense], but stores the same number that would be shown in the UI. For example, a footpad on castle has 70% defense, so this stores the value 70.&lt;br /&gt;
&lt;br /&gt;
Takes the same attributes as [store_unit_defense], and defaults to storing the value in &amp;quot;terrain_defense&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== [store_unit_type] ====&lt;br /&gt;
&lt;br /&gt;
Stores a unit type definition into a variable.&lt;br /&gt;
&lt;br /&gt;
* '''type''': (required) the defined ID of the unit type, for example &amp;quot;Goblin Knight&amp;quot;. Do not use a translation mark or it will not work correctly for different languages. A comma-separated list of IDs may also be used to store an array of unit types.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable into which to store the unit type information (default &amp;quot;unit_type&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* '''mode''':{{DevFeature1.13|0}} defaults to ''always_clear'', which clears the variable. If mode is set to ''replace'', the variable will not be cleared, and the unit type will overwrite the existing element at the start of the array, leaving any additional elements intact if the original array contained more elements. If mode is set to ''append'', the variable will not be cleared, and the unit type will be added to the array after the existing elements.&lt;br /&gt;
&lt;br /&gt;
==== [store_unit_type_ids] ====&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable into which to store a comma-separated list of all unit type IDs including all from all loaded addons&lt;br /&gt;
&lt;br /&gt;
==== [store_villages] ====&lt;br /&gt;
&lt;br /&gt;
Stores a series of locations of villages that pass certain criteria into an array. Each member of the result array will have members 'x' and 'y' (the position) and 'terrain' (the terrain type) and 'owner_side'.&lt;br /&gt;
&lt;br /&gt;
Note: This differs from using [store_locations] only in that the hexes considered for match are restricted to those with villages (those whose terrain type has its 'gives_income' flag set to true), in the same way that use of either the 'owner_side' key or the '[filter_owner]' will. In fact, if either of these are present, [store_villages] and [store_locations] will behave identically.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable (array) into which to store the locations (default: &amp;quot;location&amp;quot;)&lt;br /&gt;
* '''[[StandardLocationFilter]]''' tags and keys as arguments&lt;br /&gt;
&lt;br /&gt;
==== [store_items] ====&lt;br /&gt;
&lt;br /&gt;
Stores current items in the scenario into an array. Each entry has at least members x and y and can have all of the other keys listed in the documentation of [[InterfaceActionsWML#.5Bitem.5D|[item]]] (depending on what was set during creating the item).&lt;br /&gt;
&lt;br /&gt;
*'''variable''': name of the wml variable array to use (default &amp;quot;items&amp;quot;)&lt;br /&gt;
*'''[[StandardLocationFilter]]''' keys as arguments: only items on locations matching this [[StandardLocationFilter]] will be stored&lt;br /&gt;
*'''item_name''': {{DevFeature1.15|0}} if given, only items created with a matching '''[item]name=''' will be stored. As of 1.15.0, this does not support comma-separated lists.&lt;br /&gt;
&lt;br /&gt;
==== [store_relative_direction] ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|0}}&lt;br /&gt;
&lt;br /&gt;
Gets the relative direction from one hex to another. This is an interface to the function wesnoth uses to decide how a unit will face while it is moving / attacking / defending.&lt;br /&gt;
&lt;br /&gt;
* '''[source]''' x and y must describe a map location&lt;br /&gt;
* '''[destination]''' similar&lt;br /&gt;
* '''variable''' name of the variable to store string result in (one of 'n', 'nw', 'ne', 's', 'sw', 'se')&lt;br /&gt;
* '''mode''' optional. 0 is the default setting corresponding to default wesnoth implementation used in animations. 1 is an alternate &amp;quot;radially symmetric&amp;quot; mode. The default mode breaks ties in the direction of south, since this makes more units face the player directly on screen. The radially symmetric mode breaks ties in the direction of counter-clockwise, and might be more appropriate in some cases.&lt;br /&gt;
&lt;br /&gt;
==== [find_path] ====&lt;br /&gt;
&lt;br /&gt;
A WML interface to the pathfinder. Calculates the path between a unit and a location and returns the result in a WML variable, that contains also an array for every step of the path (including the starting hex).&lt;br /&gt;
&lt;br /&gt;
*'''[traveler]''': [[StandardUnitFilter]], only the first matching unit will be used for calculation&lt;br /&gt;
*'''[destination]''': [[StandardLocationFilter]]&lt;br /&gt;
*'''variable''': the variable name where the result will be stored, if no value is supplied 'path' will be used as default name. Each step will be stored in a [step] array inside that variable.&lt;br /&gt;
*'''allow_multiple_turns''': default no, if yes also moves that require more than one turn will be calculated.&lt;br /&gt;
*'''check_visibility''': default no, if yes the path will not be computed if some hexes are not visible due to shroud.&lt;br /&gt;
*'''check_teleport''': default yes; if no, teleport won't be taken in account while computing path.&lt;br /&gt;
*'''check_zoc''': default yes; if no, unit ZOCs won't be considered while calculating the path.&lt;br /&gt;
*'''nearest_by''': {{DevFeature1.15|2}} possible values &amp;quot;movement_cost&amp;quot; (default), &amp;quot;steps&amp;quot;, &amp;quot;hexes&amp;quot;; if the [destination] SLF matches multiple hexes, the one that would need the least movement points to reach may not be the one that's closest as measured by '''hexes''', or closest as measured by steps, from the starting point. This option chooses which measurement to prefer.&lt;br /&gt;
&lt;br /&gt;
More detail about multiple destinations and the return structure is on [[FindPathExplanation]] (moved out of this page because it has an image in it).&lt;br /&gt;
&lt;br /&gt;
This is the structure of the variable returned by [find_path]:&lt;br /&gt;
 [path]&lt;br /&gt;
 	hexes = non-zero if a path was successfully found.&lt;br /&gt;
 		if the path is calculated to an impassable hex, or the move requires multiple turns&lt;br /&gt;
 		and allow_multiple_turns is no, its value will be 0.&lt;br /&gt;
 	from_x, from_y = location of the unit&lt;br /&gt;
 	to_x, to_y = destination&lt;br /&gt;
 	movement_cost = total movement cost required by unit to reach that hex&lt;br /&gt;
 	required_turns = total turns required by unit to reach that hex&lt;br /&gt;
 	[step]&lt;br /&gt;
 		x, y = location of the step&lt;br /&gt;
 		terrain = terrain of the step&lt;br /&gt;
 		movement_cost = movement cost required by unit to reach that hex&lt;br /&gt;
 		required_turns = turns required by unit to reach that hex&lt;br /&gt;
 	[/step]&lt;br /&gt;
 [/path]&lt;br /&gt;
&lt;br /&gt;
==== [unit_worth] ====&lt;br /&gt;
Takes only an inline [[StandardUnitFilter]] (only the first matching unit will be used for the calculation) and outputs the following variables: &lt;br /&gt;
*'''cost''': the current unit cost&lt;br /&gt;
*'''next_cost''': the cost of the most expensive advancement&lt;br /&gt;
*'''health''': the health of the unit in percentage&lt;br /&gt;
*'''experience''': current experience in percentage&lt;br /&gt;
*'''unit_worth''': how much the unit is worth&lt;br /&gt;
&lt;br /&gt;
Mainly used for internal AI checks, but one could in theory just do anything with it.&lt;br /&gt;
&lt;br /&gt;
 [event]&lt;br /&gt;
     name=moveto&lt;br /&gt;
     [unit_worth]&lt;br /&gt;
        x,y=$x1,$y1&lt;br /&gt;
     [/unit_worth]&lt;br /&gt;
     [message]&lt;br /&gt;
         id=$unit.id&lt;br /&gt;
         message=_&amp;quot;I cost $cost gold, with $health|% of my hitpoints and $experience|% on the way to cost $next_cost|.&lt;br /&gt;
 I am estimated to be worth $unit_worth&amp;quot;&lt;br /&gt;
     [/message]&lt;br /&gt;
     [clear_variable]&lt;br /&gt;
         name=cost,next_cost,health,experience,unit_worth&lt;br /&gt;
     [/clear_variable]&lt;br /&gt;
 [/event]&lt;br /&gt;
&lt;br /&gt;
=== [clear_variable] ===&lt;br /&gt;
&lt;br /&gt;
This will delete the given variable. This tag can delete a scalar or an entire array; it can also delete one container at an array index. The macro [https://www.wesnoth.org/macro-reference.html#CLEAR_VARIABLE CLEAR_VARIABLE] is a shortcut for this tag.&lt;br /&gt;
&lt;br /&gt;
This action is good to use to clean up the set of variables; for example, a well-behaved scenario will delete any variables that should not be kept for the next scenario before the end of the scenario. One can also clear tags and variables of stored units; for example, one can remove [trait]s and [object]s.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the name of the variable to clear. This can also be a comma-separated list of multiple variable names.&lt;br /&gt;
** If a name ends with an array index, then it deletes that one container, and shifts the indexes of all subsequent containers. For example, &amp;lt;code&amp;gt;{CLEAR_VARIABLE my_awesome_array[2]}&amp;lt;/code&amp;gt; deletes &amp;lt;code&amp;gt;my_awesome_array[2]&amp;lt;/code&amp;gt;, but then moves &amp;lt;code&amp;gt;my_awesome_array[3]&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;my_awesome_array[2]&amp;lt;/code&amp;gt;, moves &amp;lt;code&amp;gt;my_awesome_array[4]&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;my_awesome_array[3]&amp;lt;/code&amp;gt;, and so on until the end of the array.&lt;br /&gt;
** Note that &amp;lt;code&amp;gt;{CLEAR_VARIABLE my_awesome_array}&amp;lt;/code&amp;gt; deletes the entire array, but &amp;lt;code&amp;gt;{CLEAR_VARIABLE my_awesome_array[0]}&amp;lt;/code&amp;gt; deletes only the first container.&lt;br /&gt;
&lt;br /&gt;
=== [sync_variable] ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|0}}&lt;br /&gt;
&lt;br /&gt;
Sets one or multiple variables to the same value as on all clients and also on replays, it uses the value from the currently active side.&lt;br /&gt;
* '''name''' the name of the variable to synchonize this can be a comma seperated list.&lt;br /&gt;
&lt;br /&gt;
== Other Internal Actions ==&lt;br /&gt;
&lt;br /&gt;
Believe it or not, there are some internal actions that are not focused primarily on variables. They are all grouped here.&lt;br /&gt;
&lt;br /&gt;
=== [fire_event] ===&lt;br /&gt;
&lt;br /&gt;
Trigger a WML event (used often for [[EventWML#Custom_events|custom events]])&lt;br /&gt;
&lt;br /&gt;
* '''name''': the name of event to trigger&lt;br /&gt;
** ''(Optional)'' {{DevFeature1.13|6}}&lt;br /&gt;
&lt;br /&gt;
* '''id''': ''(Optional)'' the id of a single event to trigger {{DevFeature1.13|6}}&lt;br /&gt;
&lt;br /&gt;
* '''[primary_unit]''': ''(Optional)'' Primary unit for the event. Will never match on a recall list unit. The first unit matching the filter will be chosen.&lt;br /&gt;
**[[StandardUnitFilter]] as argument. Do not use a [filter] tag.&lt;br /&gt;
&lt;br /&gt;
* '''[secondary_unit]''': ''(Optional)'' Same as '''[primary_unit]''' except for the secondary unit.&lt;br /&gt;
**[[StandardUnitFilter]] as argument. Do not use a [filter] tag.&lt;br /&gt;
&lt;br /&gt;
* '''[primary_attack]''': Information passed to the primary attack filter and $weapon variable on the new event.&lt;br /&gt;
&lt;br /&gt;
* '''[secondary_attack]''': Information passed to the second attack filter and $second_weapon variable on the new event.&lt;br /&gt;
&lt;br /&gt;
* {{DevFeature1.17|6}} '''[data]''': Additional arbitrary data to pass to the event. In addition to passing custom data, this can be used to set the '''damage_inflicted''' in an attack event or the '''owner_side''' in a village capture event. Values can be used by Lua. {{DevFeature1.19|9}} Values can be accessed as $data.&lt;br /&gt;
&lt;br /&gt;
=== [remove_event] ===&lt;br /&gt;
{{DevFeature1.13|0}} Removes the event with the specified id.&lt;br /&gt;
&lt;br /&gt;
* '''id''': the id of the event to remove. May be a comma separated list.&lt;br /&gt;
&lt;br /&gt;
'''Note''': Only events whose IDs are explicitly specified will be removed. For example, this will ''not'' automatically remove events nested within the events with those IDs.&lt;br /&gt;
&lt;br /&gt;
=== [role] ===&lt;br /&gt;
&lt;br /&gt;
Tries to find a unit to assign a role to.&amp;lt;br&amp;gt;This is useful if you want to choose a non-major character to say some things during the game. Once a role is assigned, you can use '''role=''' in a unit filter to identify the unit with that role (See [[FilterWML]]).&amp;lt;br&amp;gt;However, there is no guarantee that roles will ever be assigned. You can use '''[have_unit]''' (see [[ConditionalActionsWML#Condition_Tags|Condition Tags]]) to see whether a role was assigned. This tag uses a [[StandardUnitFilter]] (without [filter]) with the modification to order the search by type, mark only the first unit found with the role, and the role attribute is not used in the search. If for some reason you want to search for units that have or don't have existing roles, you can use one or more [not] filters. The will check recall lists in addition to units on the map. In normal use, you will probably want to include a ''side'' attribute to force the unit to be on a particular side.&lt;br /&gt;
&lt;br /&gt;
* '''role''': the value to store as the unit's role. This role is not used in the [[StandardUnitFilter]] when doing the search for the unit to assign this role to.&lt;br /&gt;
&lt;br /&gt;
* '''type''': a comma-separated list of possible types the unit can be. If any types are given, then units will be searched by type in the order listed. If no type is given, then no particular order with respect to type is guaranteed.&lt;br /&gt;
&lt;br /&gt;
* '''reassign''': {{DevFeature1.13|6}} Can be either yes or no, defaults to yes. If set to '''no''' then first search for a unit that already has this role, and if found use that unit.&lt;br /&gt;
&lt;br /&gt;
* '''search_recall_list''': {{DevFeature1.13|5}} whether to consider units on the recall list when assigning the role. Can be either yes or no, defaults to yes. {{DevFeature1.13|6}} If set to 'only', then units on the map are not considered when assigning the role - only units on the recall list can receive it. If '''reassign''' is '''no''', this setting also affects the search for a unit that already has the role.&lt;br /&gt;
&lt;br /&gt;
* '''[else]''' {{DevFeature1.13|5}} ActionWML to execute if the game is unable to find a unit to assign the role to. For example, this could be used to create a new unit satisfying the role.&lt;br /&gt;
&lt;br /&gt;
* {{anchor|auto_recall|'''[auto_recall]'''}}: {{DevFeature1.13|6}} If present, and the role is assigned to a unit on the recall list, then that unit is recalled. Supports all unique keys of [[DirectActionsWML#.5Brecall.5D|&amp;amp;#x5b;recall&amp;amp;#x5d;]], but no [[StandardUnitFilter]].&lt;br /&gt;
&lt;br /&gt;
* [[StandardUnitFilter]], do not use a [filter] sub-tag. SUF's role= and type= keys are not used: if you want to use them, use a nested SUF wrapped inside a [and] tag.&lt;br /&gt;
&lt;br /&gt;
=== [random_placement] ===&lt;br /&gt;
{{DevFeature1.13|2}}&lt;br /&gt;
&lt;br /&gt;
Selects randomly a given number of locations from a given set of locations and exectutes the given code for each of those locations.&lt;br /&gt;
&lt;br /&gt;
* '''[filter_location]''': a [[StandardLocationFilter]].&lt;br /&gt;
* '''[command]''': contains ActionWml that is executed for each of the locations.&lt;br /&gt;
* '''num_items''': the number of locations that should be selected. There are several ways of specifying this:&lt;br /&gt;
** An integer, giving the exact number of locations to use. (Variable substitution is supported too.)&lt;br /&gt;
** {{DevFeature1.15|0}} A percentage, meaning that fraction of the total available spaces.&lt;br /&gt;
** {{DevFeature1.15|0}} A [[Wesnoth_Formula_Language|WFL]] formula. It has access to one variable, ''size'', which is the total number of available spaces. In order to identify it as a WFL formula, the entire expression must be enclosed in parentheses. (Do not use a '''$''', as that will cause it to see ''size'' as zero.)&lt;br /&gt;
** A Lua expression. As with a WFL expression, it can access the ''size'' variable. {{DevFeature1.15|0}} This is now deprecated.&lt;br /&gt;
* '''variable''': The name of the variable that contains the current location during the execution of [command]. This is a container with the attributes x, y, n and terrain.&lt;br /&gt;
* '''min_distance''': The minimum distance of 2 chosen locations, a value less than 0 means that the same locations can be chosen more than one time.&lt;br /&gt;
* '''allow_less''': If yes, the tag will not show an error in case there were less than num_items locations available.&lt;br /&gt;
&lt;br /&gt;
=== Flow control actions ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|2}}&lt;br /&gt;
&lt;br /&gt;
There are three actions that alter the flow of execution. They are '''[break]''', '''[continue]''', and '''[return]'''. All of them take no arguments.&lt;br /&gt;
&lt;br /&gt;
* '''[break]''': The nearest enclosing loop immediately stops executing, and control continues with the next action after the end of that loop. If there is no enclosing loop, this is equivalent to '''[return]'''.&lt;br /&gt;
* '''[continue]''': The nearest enclosing loop immediately stops executing, and control continues at the beginning of that loop, with any iteration variables updated for the next iteration. If there is no enclosing loop, this is an error.&lt;br /&gt;
* '''[return]''': Control immediately returns to the Wesnoth engine. This completely exits the current event, including any nested events, such that the [message] will not be displayed in the below example. No further WML actions are executed in this context. Any separate, subsequent events will be run as usual.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
   name=moveto&lt;br /&gt;
   [fire_event]&lt;br /&gt;
      name=return_please&lt;br /&gt;
   [/fire_event]&lt;br /&gt;
   [message]&lt;br /&gt;
     message=&amp;quot;Made it back&amp;quot;&lt;br /&gt;
   [/message]&lt;br /&gt;
[/event]&lt;br /&gt;
[event]&lt;br /&gt;
   name=return_please&lt;br /&gt;
   [return][/return]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== [unsynced] ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|2}}&lt;br /&gt;
&lt;br /&gt;
Runs the contained actionwml in a unsynced context, that means actions performed inside [unsynced] are not synced over the network. for example &lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
   name=moveto&lt;br /&gt;
   {VARIABLE_OP message rand &amp;quot;Hi,Hello,How are you?&amp;quot;}&lt;br /&gt;
   [message]&lt;br /&gt;
      message = $message&lt;br /&gt;
   [/message]&lt;br /&gt;
   {CLEAR_VARIABLE message}&lt;br /&gt;
   [allow_undo]&lt;br /&gt;
   [/allow_undo]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
will print the same message to all clients, but also disallow undoing (regardless of [allow_undo]) for that moveto becasue it requests a synced random seed form the server. However this code&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
   name=moveto&lt;br /&gt;
   [unsynced]&lt;br /&gt;
      {VARIABLE_OP message rand &amp;quot;Hi,Hello,How are you?&amp;quot;}&lt;br /&gt;
      [message]&lt;br /&gt;
         message = $message&lt;br /&gt;
      [/message]&lt;br /&gt;
      {CLEAR_VARIABLE message}&lt;br /&gt;
   [/unsynced]&lt;br /&gt;
   [allow_undo]&lt;br /&gt;
   [/allow_undo]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
will not prevent undoing, but might print a different message for each client in a multiplayer game (or during a sp replay), so `[unsynced]` should not be used for actions that actually change the gamestate otherwise you'll get OOS&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Using [set_variables] to Create Arrays of WML ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[set_variables]&lt;br /&gt;
    name=arr&lt;br /&gt;
    mode=replace&lt;br /&gt;
    [value]&lt;br /&gt;
        foo=bar&lt;br /&gt;
    [/value]&lt;br /&gt;
    [value]&lt;br /&gt;
       foo=more&lt;br /&gt;
    [/value]&lt;br /&gt;
[/set_variables]&lt;br /&gt;
{DEBUG_MSG $arr[0].foo}&lt;br /&gt;
{DEBUG_MSG $arr[1].foo}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will produce two output messages, first one saying '''bar''' and next one saying '''more'''.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[VariablesWML]]&lt;br /&gt;
* [[ActionWML]]&lt;br /&gt;
** [[ConditionalWML]]&lt;br /&gt;
** [[DirectActionsWML]]&lt;br /&gt;
** [[InterfaceActionsWML]]&lt;br /&gt;
* [[EventWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;br /&gt;
[[Category: ActionsWML]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=EffectWML&amp;diff=74598</id>
		<title>EffectWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=EffectWML&amp;diff=74598"/>
		<updated>2025-11-05T01:25:15Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
&lt;br /&gt;
== [effect] ==&lt;br /&gt;
&lt;br /&gt;
The tag [effect] is used to describe one modification to a unit. Any number of [effect] tags can be used to describe a complete modification.&lt;br /&gt;
&lt;br /&gt;
Modifications are permanent changes to a unit; however using an [[DirectActionsWML#.5Bobject.5D|[object]]] with a limited ''duration'' to apply an [effect] will cause the unit to be rebuilt without the effect's effects when the duration expires. &lt;br /&gt;
&lt;br /&gt;
The following keys and subtags are always recognized:&lt;br /&gt;
* '''[filter]''': only apply this effect if the affected unit matches. See [[StandardUnitFilter]] for details.&lt;br /&gt;
* '''times''': describes how many times the effect is applied. The default is to apply the effect once. Other possible value : &amp;quot;per level&amp;quot; which means that the effect is applied level times, where level is the unit level. {{DevFeature1.13|5}} Integers are now supported for ''times''.&lt;br /&gt;
* '''apply_to''': describes what the effect actually affects. New effect types can be added with [[LuaAPI/wesnoth#wesnoth.effects]]. Some examples can be seen in [https://github.com/wesnoth/wesnoth/blob/master/data/campaigns/World_Conquest/lua/game_mechanics/effects.lua World Conquest].&lt;br /&gt;
&lt;br /&gt;
[effect] uses different keys depending on the value of '''apply_to'''.  '''apply_to''' can take the following values:&lt;br /&gt;
* {{anchor|apply_to-new_attack|'''new_attack'''}}: will use all other keys and tags as the description of an attack that will be added to the unit. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]].&lt;br /&gt;
* {{anchor|apply_to-remove_attacks|'''remove_attacks'''}}: remove the matching attacks. All tags from the attack filter construct will be used to match the attack; see [[FilterWML#Filtering Weapons|FilterWML]]. Do not use a [filter] tag otherwise it will not work properly.&lt;br /&gt;
* {{anchor|apply_to-attack|'''attack'''}}: find an attack and modify it.  All tags from the attack filter construct will be used to match the attack; see [[FilterWML#Filtering Weapons|FilterWML]].  After that, the following keys and tags can be used to modify the attack.  Note: do not use a [filter] tag.  Just put the keys you want to filter on inside the [effect] tag.&lt;br /&gt;
** '''set_name''': change the attack's name (ie identifier).&lt;br /&gt;
** '''set_description''': change the attack's description (ie displayed name). &lt;br /&gt;
** '''set_type''': change the attack type. The standard values are '''blade''', '''pierce''', '''impact''', '''fire''', '''cold''', and '''arcane'''.&lt;br /&gt;
** '''set_range''': change the attack range. The standard values are '''ranged''' and '''melee'''.&lt;br /&gt;
** '''set_icon''': change the attack's icon.&lt;br /&gt;
** {{anchor|set_specials|'''[set_specials]'''}}: change the attack's specials. The specials to add are given exactly as in the [[AbilitiesWML#The_.5Bspecials.5D_tag|[specials]]] tag.&lt;br /&gt;
*** '''mode''': if '''append''', adds the given specials to the attack. If '''replace''', replaces the existing specials with the given ones. Default '''replace'''.&lt;br /&gt;
**** {{DevFeature1.15|3}} A deprecation warning is triggered unless the '''mode''' attribute is set, although the effect will still be '''replace'''. This is to allow the default to change in the 1.17.x series.&lt;br /&gt;
** '''remove_specials''': remove the listed specials. The value of this key is the comma-separated list of the id of the specials to remove. This key is always evaluated before a [set_specials] tags in the same [effect]&lt;br /&gt;
** '''[remove_specials]''': {{DevFeature1.19|6}} remove the listed specials. Use [[StandardAbilityFilter]], special removed if matches. This tag is always evaluated before a [set_specials] tags in the same [effect]&lt;br /&gt;
** '''increase_damage''': increases the attack's damage.  This can be positive or negative, so you can use it to decrease damage as well.  If it ends in a percent(''''%''''), the change in damage will be a percentage ratio of the attack's original damage.&lt;br /&gt;
** '''increase_attacks''': increases the number of attack strikes. Like '''increase_damage''', it can be positive or negative, or a percentage.&lt;br /&gt;
** '''increase_accuracy''': increases the attack accuracy; can be positive or negative, or a percentage&lt;br /&gt;
** '''increase_parry''': increases the attack parry bonus; can be positive or negative, or a percentage&lt;br /&gt;
** '''increase_movement_used''': {{DevFeature1.13|2}} increases the movement points used by the attack; can be positive or negative, or a percentage&lt;br /&gt;
** '''increase_attacks_used''': {{DevFeature1.17|13}} increases the attack points used by the attack; can be positive or negative, or a percentage&lt;br /&gt;
** '''set_damage''' {{DevFeature1.13|2}} like increase_damage, but sets the damage to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_attacks''' {{DevFeature1.13|2}} like increase_attacks, but sets the attacks to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_accuracy''' {{DevFeature1.13|2}} like increase_accuracy, but sets the accuracy to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_parry''' {{DevFeature1.13|2}} like increase_parry, but sets the parry to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_movement_used''' {{DevFeature1.13|2}} like increase_movement_used, but sets the movement used to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_attacks_used''' {{DevFeature1.17|13}} like increase_attacks_used, but sets the attacks used to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''attack_weight''': change the attack's attack_weight. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]] for explanations about attack_weight.&lt;br /&gt;
** '''defense_weight''': change the attack's defense_weight. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]] for explanations about defense_weight.&lt;br /&gt;
** '''set_min_range''' {{DevFeature1.19|4}} modify required distance between units in order to allow using attack&lt;br /&gt;
** '''set_max_range''' {{DevFeature1.19|4}} modify required distance between units in order to allow using attack&lt;br /&gt;
** '''increase_min_range''' {{DevFeature1.19|4}} modify required distance between units in order to allow using attack&lt;br /&gt;
** '''increase_max_range''' {{DevFeature1.19|4}} modify required distance between units in order to allow using attack&lt;br /&gt;
* {{anchor|apply_to-max_attacks|'''max_attacks'''}}: {{DevFeature1.13|2}} change the unit's maximum attacks per turn&lt;br /&gt;
** '''increase''': how much to increase by; can be positive or negative, or a percentage&lt;br /&gt;
* {{anchor|apply_to-hitpoints|'''hitpoints'''}}: modifies the unit's HP and/or max HP.&lt;br /&gt;
** '''increase''': the amount to increase the unit's HP.&lt;br /&gt;
** '''set''': the new amount of the unit's HP.&lt;br /&gt;
** '''heal_full''': if present  and not set to &amp;quot;no&amp;quot; the unit will be put back to full HP.&lt;br /&gt;
** '''increase_total''': will increase the total HP of the unit.  Can be specified either as a negative or a positive value.  It can also be specified as a percentage of the current total; i.e. &amp;quot;-50%&amp;quot; will cut max HP in half.&lt;br /&gt;
** '''set_total''': will set the unit's max HP to the specified value.&lt;br /&gt;
** '''violate_maximum''': if the unit ends up with more than its max HP after these modifications, and this key is present (set to any non-null value, ex. '''yes'''), the unit's HP won't be lowered to its max HP.&lt;br /&gt;
* {{anchor|apply_to-movement|'''movement'''}}: modifies the unit's movement points.&lt;br /&gt;
** '''increase''': maximum movement is increased by this amount. It can be positive, negative, or specified as a percentage.&lt;br /&gt;
** '''set''': maximum movement is set to a specific value.&lt;br /&gt;
** '''apply_to_vision''': {{DevFeature1.15|13}} if set to '''yes''' (which is the default), then the vision points will change by the same amount. See [[#Movement_and_Vision|Movement and Vision]].&lt;br /&gt;
* {{anchor|apply_to-vision|'''vision'''}}: {{DevFeature1.13|2}} modifies the unit's vision points. Note: this has side effects described in [[#Movement_and_Vision|Movement and Vision]].&lt;br /&gt;
** '''increase''': maximum vision is increased by this amount. It can be positive, negative, or specified as a percentage.&lt;br /&gt;
** '''set''': maximum vision is set to a specific value. &lt;br /&gt;
* {{anchor|apply_to-jamming|'''jamming'''}}: {{DevFeature1.13|2}} modifies the unit's jamming points.&lt;br /&gt;
** '''increase''': maximum jamming is increased by this amount. It can be positive, negative, or specified as a percentage.&lt;br /&gt;
** '''set''': maximum jamming is set to a specific value.&lt;br /&gt;
* {{anchor|apply_to-experience|'''experience'''}}: affects the unit's current XP.&lt;br /&gt;
** '''increase''': current XP is increased by this amount. It can be positive, negative, or specified as a percentage.&lt;br /&gt;
** '''set''': current XP is set to a specific value.&lt;br /&gt;
* {{anchor|apply_to-max_experience|'''max_experience'''}}: affects the amount of XP the unit needs for the next level.&lt;br /&gt;
** '''increase''': how to change the xp; again it can be negative, positive or a percentage.&lt;br /&gt;
** '''set''': current max XP is set to a specific value.&lt;br /&gt;
* {{anchor|apply_to-loyal|'''loyal'''}}: no keys associated. The affected unit will be loyal i.e have an upkeep of 0.&lt;br /&gt;
* {{anchor|apply_to-fearless|'''fearless'''}}: Add/Remove fearless attribute.&lt;br /&gt;
** '''set''': new value for fearless (boolean). Defaults to '''yes'''.&lt;br /&gt;
* {{anchor|apply_to-healthy|'''healthy'''}}: Add/Remove healthy attribute.&lt;br /&gt;
** '''set''': new value for healthy (boolean). Defaults to '''yes'''.&lt;br /&gt;
* {{anchor|apply_to_movement_costs|'''movement_costs'''}}: speed through specific terrain is modified&lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed). Defaults to '''no'''.&lt;br /&gt;
** '''[movement_costs]''': a subtag that describes the new movement costs just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-vision_costs|'''vision_costs'''}}: vision through specific terrain is modified&lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed). Defaults to '''no'''.&lt;br /&gt;
** '''[vision_costs]''': a subtag that describes the new vision costs just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-jamming_costs|'''jamming_costs'''}}: jamming through specific terrain is modified&lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed). Defaults to '''no'''.&lt;br /&gt;
** '''[jamming_costs]''': a subtag that describes the new jamming costs just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-defense|'''defense'''}}: Sets the unit's chance to be hit in specific terrain (100 - the unit's defense as shown in-game). &lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values. In most cases, adding a positive number makes the unit easier to hit, while adding a negative number makes the unit harder to hit. The new value is added to the absolute value of the old, and the sign of the old value is preserved. Defaults to '''no'''.&lt;br /&gt;
** '''[defense]''': a subtag that describes the new defense just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-resistance|'''resistance'''}}: Sets percent damage taken from combat (100 - the unit's resistance as shown in-game)&lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values. Adding a positive number makes the unit take more damage, while adding a negative number makes the unit take less damage. Defaults to '''no'''.&lt;br /&gt;
** '''[resistance]''': a subtag that describes the new resistance just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-variation|'''variation'''}}: switches the unit into one of its variations. Similar to the '''type''' effect below, this might not behave properly outside of [advancement].&lt;br /&gt;
** '''name''': the id of the variation to invoke. &lt;br /&gt;
* {{anchor|apply_to-type|'''type'''}}: transforms the unit into a new unit_type. This does not work in [trait]; in ActionWML it's recommended to use [transform_unit] instead of an [object] with this effect. This effect cannot be undone with [remove_object].&lt;br /&gt;
** '''name''': the id of the unit_type to invoke.&lt;br /&gt;
* {{anchor|apply_to-status|'''status'''}}: modifies the status affecting the unit.&lt;br /&gt;
** '''add''': a list of status modifications to add. Beware, these may be reapplied later, such as when the unit is recalled or levels up; if in an event, you can use [[InternalActionsWML|[store_unit]]] and [[DirectActionsWML|[unstore_unit]]], modifying unit.status.name directly, to avoid this, or if you are creating the unit, you can just add it to the unit's [status] tag in the [unit] tag.  These are listed in [status], [[SingleUnitWML]].&lt;br /&gt;
** '''remove''': a list of status modifications to remove.&lt;br /&gt;
* {{anchor|apply_to-zoc|'''zoc'''}}: toggle the zone of control.&lt;br /&gt;
** '''value''': new value for zoc (boolean).&lt;br /&gt;
* {{anchor|apply_to-profile|'''profile'''}}: customize the profile of the unit. See [[UnitTypeWML]].&lt;br /&gt;
** '''portrait''': new image to display when the unit speaks.&lt;br /&gt;
** '''small_portrait''': new image to display in unit reports.&lt;br /&gt;
** '''description''': sets the text to display when hovering over the unit's type in the righthand pane.&lt;br /&gt;
** '''[special_note]''': {{DevFeature1.15|2}} Adds or removes a special note in the unit's description.&lt;br /&gt;
*** '''remove''': A boolean value specifying whether to add or remove a note. Defaults to '''no'''.&lt;br /&gt;
*** '''note''' (translatable): The text of the note you want to add or remove. If removing a note, this must be an exact match, character-for-character, for the note you want to remove, and must also be in the same textdomain.&lt;br /&gt;
*** Since the tag name is the same, notes can also be added using the standard special note macros, eg '''{NOTE_HEALS}'''.&lt;br /&gt;
*** To remove a note, you can simply suffix '''{NOTE_REMOVE}''' to the regular note macro, eg '''{NOTE_HEALS}{NOTE_REMOVE}'''.&lt;br /&gt;
* {{anchor|apply_to-new_ability|'''new_ability'''}}: Adds one or more abilities to a unit.&lt;br /&gt;
** '''abilities''': {{DevFeature1.19|17}} A comma-separated list of ability [[AbilitiesWML#Common_keys_and_tags_for_every_ability|'''unique_id''']]s. If defined in the registry [[UnitsWML#.5Babilities.5D|[units][abilities]]], these will be added to this effect as if their full definition was included in '''[abilities]'''. Example: ''abilities=heals_8,regenerates''.&lt;br /&gt;
** '''[abilities]''': A subtag that contains the ability definitions.&lt;br /&gt;
* '''remove_ability''': Removes one or more abilities from a unit. Abilities are not reference counted. Adding twice and removing once still means the ability is gone.&lt;br /&gt;
** '''[abilities]''': A subtag that contains the ability definitions. Strictly speaking, all that is needed is the id= inside some tag. {{DevFeature1.17|17}} This is now deprecated, use [experimental_filter_ability] instead.&lt;br /&gt;
** {{DevFeature1.17|17}} '''[experimental_filter_ability]''': [[StandardAbilityFilter]] to match the abilities to remove.&lt;br /&gt;
* {{anchor|apply_to-new_animation|'''new_animation'''}}: contain animations that will be added to the unit, it can contain multiple animation blocks, and a single &amp;quot;id=&amp;quot; line. That Id should be unique for each effect block and is used by the engine to reuse WML parsing, making the loading faster. See [[AnimationWML]] for further reference.&lt;br /&gt;
* {{anchor|apply_to-image_mod|'''image_mod'''}}: modify the image path function ([[ImagePathFunctions]]) of all the unit's frames. Due to a bug, the effect is permanent even inside [object]duration=turn&lt;br /&gt;
** '''replace''': replaces the image path function(s) to be used, e.g. &amp;quot;RC(magenta&amp;gt;red)&amp;quot;&lt;br /&gt;
** '''add''': adds an image path function without removing any existing ones.&lt;br /&gt;
** If needed, you can also define new [[GameConfigWML#Color_Palettes|color palettes]] here.&lt;br /&gt;
* {{anchor|apply_to-ellipse|'''ellipse'''}}: Change the image used for the unit's ellipse.&lt;br /&gt;
** '''ellipse''' : the new image base path to use. Defaults to '''misc/ellipse'''. Can be set to '''none''' to disable the ellipse. An ellipse consist of a top and bottom part so by default in the simplest case the game will look for image files misc/ellipse-top.png and misc/ellipse-bottom.png. This can get further modified based on if the unit is a leader (can_recruit), does the unit emit a zone of control (ZoC) and/or is the unit selected. For a unit that is a leader, emits no ZoC and is currently selected the used files would then be misc/ellipse-leader-nozoc-selected-top.png and misc/ellipse-leader-nozoc-selected-bottom.png.&lt;br /&gt;
* {{anchor|apply_to-halp|'''halo'''}}: Change the image used for the unit's halo.&lt;br /&gt;
** '''halo''': the new image to use.&lt;br /&gt;
* {{anchor|apply_to-overlay|'''overlay'''}}: Change the unit's overlays.&lt;br /&gt;
**'''add''': the specified overlay will be added to the unit's overlays. It can be a comma separated list with multiple overlays. ''Note: overlays added in this way cannot be removed by [remove_unit_overlay] until the effect's duration is over.''&lt;br /&gt;
**'''replace''': all the unit's overlays will be removed and replaced with the specified one. Again, it can be a comma separated list. ''Note: overlays replaced in this way cannot be modified by [unit_overlay] or [remove_unit_overlay] until the effect's duration is over.''&lt;br /&gt;
**'''remove''': {{DevFeature1.15|0}} the specified overlay will be removed from the unit's overlays. It can be a comma separated list with multiple overlays.&lt;br /&gt;
** {{DevFeature1.15|0}} [unit_overlay] and [remove_unit_overlay] are now equivalent to adding a permanent object with this effect, after checking if the unit already has / already doesn't have the overlay (effects with temporary durations will cause false positives / false negatives in this check).&lt;br /&gt;
* {{anchor|apply_to-recall_cost|'''recall_cost'''}}: {{DevFeature1.13|2}} change a unit's recall cost&lt;br /&gt;
** '''set''': set recall cost to a specific value, or a percentage of original value&lt;br /&gt;
** '''increase''': alter recall cost relative to original value; can be positive or negative, or a percentage&lt;br /&gt;
* {{anchor|apply_to-alignment|'''alignment'''}}: {{DevFeature1.13|2}} change a unit's alignment&lt;br /&gt;
** '''set''': the new alignment (one of chaotic, lawful, neutral, liminal)&lt;br /&gt;
* {{anchor|apply_to-new_advancement|'''new_advancement'''}}: {{DevFeature1.13|2}} add new advancement choices to the unit&lt;br /&gt;
** '''replace''': whether to replace existing advancement choices; if this key is set to yes, existing advancement choices are cleared only if you're adding a choice of the same type. (That is, unit type advancements are cleared only if you're adding a new unit advancement choice, and AMLA choices are cleared only if you're adding new AMLA choices.)&lt;br /&gt;
** '''types''': a comma-separated list of additional unit types the unit can advance to. ('''Note:''' If using this, you probably want to include a filter to prevent the unit from being able to advance to this type once it has already done so.)&lt;br /&gt;
** '''[advancement]''': an advancement choice to add, see [[UnitTypeWML#After_max_level_advancement_(AMLA)|AMLAs]]; you can have several of these tags to add multiple advancement choices at the same time.&lt;br /&gt;
* {{anchor|apply_to-remove_advancement|'''remove_advancement'''}}: {{DevFeature1.13|2}} remove existing advancement choices from the unit&lt;br /&gt;
** '''types''': a list of unit type advancements to remove as a possibility&lt;br /&gt;
** '''amlas''': a list of AMLA id attributes; any advancement possibility with the given id will be removed&lt;br /&gt;
* {{anchor|apply_to-level|'''level'''}}: {{DevFeature1.17|15}} change a unit's level. '''Note:''' this key is incompatible with ''times=per level''; if this combination is used, the engine reports a warning and uses ''times=1'' as fallback value&lt;br /&gt;
** '''set''': set level to a specific value; can be positive or negative, but not a percentage&lt;br /&gt;
** '''increase''': alter level relative to original value; can be positive or negative, but not a percentage&lt;br /&gt;
&lt;br /&gt;
== Movement and Vision ==&lt;br /&gt;
&lt;br /&gt;
Wesnoth 1.14 introduced vision points; by default units have the same number of vision points as their max movement points. However, combining effects that change vision with effects that change movement had edge cases which were reworked in 1.16:&lt;br /&gt;
&lt;br /&gt;
Consider a unit with 5 mp, and default vision:&lt;br /&gt;
* It has (effectively) 5 mp and 5 vp.&lt;br /&gt;
* After (mp + 1), it will have 6 mp and 6 vp.&lt;br /&gt;
* After (vp + 2), it will have 5 mp and 7 vp.&lt;br /&gt;
&lt;br /&gt;
In 1.14, using an effect with apply_to=vision breaks the link between vision and movement:&lt;br /&gt;
* After (mp + 1) (vp + 2), it will have 6 mp and 8 vp.&lt;br /&gt;
* After (vp + 2) (mp + 1), it will have 6 mp and 7 vp.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|13}}, [effect]apply_to=movement has another attribute apply_to_vision, which defaults to true. With that change, the order that the effects are applied in doesn't matter:&lt;br /&gt;
* After (mp + 1) (vp + 2), it will have 6 mp and 8 vp.&lt;br /&gt;
* After (vp + 2) (mp + 1), it will have 6 mp and 8 vp.&lt;br /&gt;
&lt;br /&gt;
Increasing movement by 50% increases vision by (50% of movement) not by (50% of vision). For a unit that started with 6 mp and 8 vp, the following effect would give it 9 mp and 11 vp.&lt;br /&gt;
    [effect]&lt;br /&gt;
        apply_to=movement&lt;br /&gt;
        increase=50%&lt;br /&gt;
    [/effect]&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Effect: apply_to = new_animation  ===&lt;br /&gt;
This is the only way to change animations of units after they have been placed on the map.&lt;br /&gt;
In this example, I add very simple idle animation (taken from Goblin Spearman) to the unit, which moves to hex (x=1, y=5). If you want something more complex, you need to check [[AnimationWML]] page.&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
    name=moveto&lt;br /&gt;
    [filter]&lt;br /&gt;
        x,y = 1,5&lt;br /&gt;
    [/filter]&lt;br /&gt;
    [object]&lt;br /&gt;
        [filter]&lt;br /&gt;
            x,y=1,5&lt;br /&gt;
        [/filter]&lt;br /&gt;
        [effect]&lt;br /&gt;
            apply_to=new_animation&lt;br /&gt;
            [idle_anim]&lt;br /&gt;
                {STANDARD_IDLE_FILTER}&lt;br /&gt;
                start_time=0&lt;br /&gt;
                [frame]&lt;br /&gt;
                    image=&amp;quot;units/goblins/spearman-idle-[1~12].png:[150*3,300,150*8]&amp;quot;&lt;br /&gt;
                [/frame]&lt;br /&gt;
            [/idle_anim]&lt;br /&gt;
        [/effect]&lt;br /&gt;
    [/object]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you are going to use '''advanced WML''' and want to add animation to unit, stored in variable, then following example might help you. '''This way is not efficient if you have no additional logic like inventoriy, shops, advanced unit modifications in your add-on.''' Is is preferred to use first variant or define all needed animation in unit_type.&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
    name=moveto&lt;br /&gt;
    [filter]&lt;br /&gt;
        x,y=1,5&lt;br /&gt;
    [/filter]&lt;br /&gt;
    [store_unit]&lt;br /&gt;
        [filter]&lt;br /&gt;
            x,y=1,5&lt;br /&gt;
        [/filter]&lt;br /&gt;
        variable=stored_unit&lt;br /&gt;
    [/store_unit]&lt;br /&gt;
    [set_variables]&lt;br /&gt;
        name=stored_unit.modifications.object&lt;br /&gt;
        [value]&lt;br /&gt;
            [effect]&lt;br /&gt;
                apply_to=new_animation&lt;br /&gt;
                [idle_anim]&lt;br /&gt;
                    {STANDARD_IDLE_FILTER}&lt;br /&gt;
                    start_time=0&lt;br /&gt;
                    [frame]&lt;br /&gt;
                        image=&amp;quot;units/goblins/spearman-idle-[1~12].png:[150*3,300,150*8]&amp;quot;&lt;br /&gt;
                    [/frame]&lt;br /&gt;
                [/idle_anim]&lt;br /&gt;
            [/effect]&lt;br /&gt;
        [/value]&lt;br /&gt;
    [/set_variables]&lt;br /&gt;
    [unstore_unit]&lt;br /&gt;
        variable=stored_unit&lt;br /&gt;
    [/unstore_unit]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Where to Use Effects ==&lt;br /&gt;
&lt;br /&gt;
A collection of effects together makes up a &amp;quot;unit modification&amp;quot;, which is encased in one of the three types of modification tags: '''[trait]''', '''[object]''', or '''[advancement]'''. Which tag to use depends on the goal of the modification.&lt;br /&gt;
&lt;br /&gt;
* [[UnitsWML#.5Btrait.5D|Traits]] are shown in the unit details on the sidebar. They can be placed in a race or unit type to include the trait in the pool of random traits for that race or unit type, or they can be placed in the global [units] tag to add them to the global pool of random traits. (Note that this can cause out-of-sync errors in multiplayer.)&lt;br /&gt;
* [[UnitTypeWML#After_max_level_advancement_.28AMLA.29|Advancements]] are offered when a unit levels up. If a unit type has both modification advancements and regular advancements, the player can choose either each time they level up.&lt;br /&gt;
* [[DirectActionsWML#.5Bobject.5D|Objects]] are usually placed on the map or added by special events. They also have a built-in facility to automatically remove under certain conditions.&lt;br /&gt;
&lt;br /&gt;
An effect can also be placed in '''[modify_unit]''' [[DirectActionsWML#.5Bmodify_unit.5D|ActionWML]] to apply it on-the-fly without keeping a record that it has been applied. This is mainly useful for effects that change transient properties such as current hitpoints or experience. An effect applied in this way is liable to be reverted when the unit is rebuilt in the future, for example when they level up or when an object is removed.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[UnitTypeWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
* [[AnimationWML]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=UnitTypeWML&amp;diff=74597</id>
		<title>UnitTypeWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=UnitTypeWML&amp;diff=74597"/>
		<updated>2025-11-05T01:24:38Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Unit Type ==&lt;br /&gt;
&lt;br /&gt;
Each '''[unit_type]''' tag defines one unit type. (for the use of [unit] to create a unit, see [[SingleUnitWML]])&lt;br /&gt;
&lt;br /&gt;
Unit animation syntax is described in [[AnimationWML]]. In addition to the animation tags described there, the following key/tags are recognized:&lt;br /&gt;
* '''advances_to''': When this unit has ''experience'' greater than or equal to ''experience'', it is replaced by a unit of the type that the value of ''advances_to'' refers to. All modifications that have been done to the unit are applied to the unit it is replaced by. The special value 'null' says that the unit does not advance but gets an AMLA instead. Can be a comma-separated list of units that can be chosen from upon advancing.&lt;br /&gt;
* '''alignment''': one of lawful/neutral/chaotic/liminal (See [[TimeWML]]). Default is &amp;quot;neutral&amp;quot;.&lt;br /&gt;
* '''attacks''': the number of times that this unit can attack each turn. Default is 1.&lt;br /&gt;
* '''cost''': when a player recruits a unit of this type, the player loses ''cost'' gold. If this would cause gold to drop below 0,  the unit cannot be recruited. Default is 1.&lt;br /&gt;
* '''recall_cost''': {{DevFeature1.13|0}} the default recall cost of units of this type, overriding the recall cost set in scenario [[SideWML|[side]]] tags or the global [[GameConfigWML|[game_config]]] value. Individual units may override this value in [[SingleUnitWML|[unit]]]. A value of -1 is equivalent to not specifying this attribute. {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.&lt;br /&gt;
* '''description''': (translatable) the text displayed in the unit descriptor box for this unit. Default 'No description available...'. &lt;br /&gt;
* '''do_not_list''': Not used by the game, but by tools for browsing and listing the unit tree. If this is 'yes', the unit will be ignored by these tools. {{DevFeature1.13|?}} When placing units in debug mode this unit isn't listed (but can still be placed using the :create command). This restriction is lifted in version &amp;lt;b&amp;gt;1.14.3&amp;lt;/b&amp;gt;.&lt;br /&gt;
* '''ellipse''': the ellipse image to display under the unit, which is normally team-colored. Default is &amp;quot;misc/ellipse&amp;quot;. &amp;quot;-nozoc&amp;quot; and &amp;quot;-leader&amp;quot; are automatically appended for units without zone of control and with canrecruit=yes respectively. The [http://www.wesnoth.org/macro-reference.xhtml#IS_HERO IS_HERO]/[http://www.wesnoth.org/macro-reference.xhtml#MAKE_HERO MAKE_HERO]/[http://www.wesnoth.org/macro-reference.xhtml#UNMAKE_HERO UNMAKE_HERO] macros change the ellipse to/back from &amp;quot;misc/ellipse-hero&amp;quot;. Finally, setting this to &amp;quot;none&amp;quot; will cause the unit to not have any ellipses displayed under it regardless of the user's preferences.&amp;lt;br/&amp;gt;WARNING: Be aware that setting this to &amp;quot;misc/ellipse-hero&amp;quot; for a unit with canrecruit=yes will result in the ellipse being &amp;quot;misc/ellipse-hero-leader&amp;quot;, which is not a supported combination (it doesn't have a graphic, and will cause error logs that the graphic is missing). This is tracked as bug [https://github.com/wesnoth/wesnoth/issues/6258 6258] on GitHub.&amp;lt;br/&amp;gt;{{DevFeature1.17|26}} canrecruit=yes is now supported with &amp;quot;misc/ellipse-hero&amp;quot;, since &amp;quot;misc/ellipse-hero-leader&amp;quot; has been added in [https://github.com/wesnoth/wesnoth/pull/8375 8375].&lt;br /&gt;
* '''experience''': When this unit has experience greater than or equal to ''experience'', it is replaced by a unit with 0 experience of the type that the value of ''advances_to'' refers to. All modifications that have been done to the unit are applied to the unit it is replaced by.&lt;br /&gt;
* '''flag_rgb''': usually set by [http://www.wesnoth.org/macro-reference.xhtml#MAGENTA_IS_THE_TEAM_COLOR MAGENTA_IS_THE_TEAM_COLOR]; specifies the colours in the base flag to use for team-colouring the unit, expressed as a colour name (such as magenta) or a comma-separated list of RGB values (in hex format).&lt;br /&gt;
* '''gender''': has a value of either ''male'' or ''female'', and determines which of the keys ''male_names'' and ''female_names''  should be read. When a unit of this type is recruited, it will be randomly assigned a name by the random name generator, which will use these names as a base. If '''gender''' is not specified it defaults to ''male''.&lt;br /&gt;
* '''halo''': an image to place centered on the unit. It is drawn on top of the unit, and on top of surrounding units if the image is larger than one hex. It works similarly to the halo attribute of {{tag|InterfaceActionsWML|item}}, and it can be animated with a comma-separated list of images.&lt;br /&gt;
* '''hide_help''': (yes|no) default=no. Determines if the unit type will appear in the in-game help.&lt;br /&gt;
* '''hitpoints''': the maximum HP that the unit has, and the HP it has when it is created.&lt;br /&gt;
* '''id''': the value of the ''type'' key for units of this type. This is required and must be unique among all [unit_type] tags. An ''id'' must consist only of alphanumerics and spaces (or underscores). ''type'' keys are found in [[SingleUnitWML]] and [[FilterWML]]. For example, id=Drake Flare&lt;br /&gt;
*'''ignore_race_traits''': 'yes' or 'no' (default). Determines whether racial traits (see [[UnitsWML]]) are applied. &lt;br /&gt;
* '''image''': sets the base image of the unit, which is used on the map.&lt;br /&gt;
* '''image_icon''': sets an alternative image to be used to represent the unit in any UI dialogs such as the recruit dialog, attack dialog and the unit image box in the sidebar. This is usually a variant of the image with any transparent padding removed, and is usually needed for images that have extra transparent padding for correct positioning on the game map. The image specified by this key will be scaled to 72x72px in the Unit Recruit/Unit Create dialog's listbox and 144x144px on the unit preview panel (the panel that shows the unit's detailed stats, located on left side on recruit/create dialog and on both sides of the attack dialog). [[ImagePathFunctions#Crop_Function|~CROP]] function can be useful here. Scaling might not be a good idea because it will be internally scaled as mentioned above. You can see Loyalists Paladin or the Fire Dragon/Skeletal Dragon units as an example.&lt;br /&gt;
* '''level''': the amount of upkeep the unit costs.  After this unit fights, its opponent gains ''level'' experience. See also kill_experience ([[GameConfigWML]]), and leadership ([[AbilitiesWML]]).&lt;br /&gt;
* '''upkeep''': the amount of upkeep the unit costs if it differs from its level.&lt;br /&gt;
* '''movement''': the number of move points that this unit receives each turn.&lt;br /&gt;
* '''movement_type''': See [[UnitsWML#.5Bmovetype.5D|movetype]]. Note that the tags '''[movement_costs]''', '''[vision_costs]''', '''[defense]''', and '''[resistance]''' can be used to modify this movetype.&lt;br /&gt;
* '''name''': (translatable) displayed in the Status Table for units of this type.&lt;br /&gt;
* '''num_traits''': the number of traits that units of this type should receive when they are recruited, overriding the value set in the [race] tag.&lt;br /&gt;
* '''profile''': the portrait image to use for this unit type. You can also set a portrait for an individual unit instead of the whole unit type (see [[SingleUnitWML]]). The engine first looks for the image in the transparent subdirectory and if found that image is used. If not found it will use the image as-is. If the image width or height is equal or above 300 the engine will scale the image with a factor between 1/2 and 1. For images which should only be shown on the right side in the dialog append ~RIGHT() to the image.&lt;br /&gt;
** If &amp;quot;unit_image&amp;quot; is given instead of a filename, uses the unit's base image as the portrait (in the same manner that unit types without portraits do by default).&lt;br /&gt;
** If &amp;quot;none&amp;quot; is given instead of a filename, no image will be displayed.&lt;br /&gt;
* '''small_profile''': the image to use when a smaller portrait is needed than the one used for messages (e.g., in the help system). When this attribute is missing, the value of the '''profile''' attribute is used instead. When present, the heuristic for finding a transparent portrait is disabled for the '''profile''' attribute, so the correct '''profile''' should be set too. If '''profile''' is not present, '''small_profile''' is ignored. Note that image modifiers are allowed; they might be useful for cropping and rescaling a portrait:&lt;br /&gt;
 small_profile=&amp;quot;portraits/elves/transparent/marksman+female.png~CROP(0,20,380,380)~SCALE(205,205)&amp;quot;&lt;br /&gt;
 profile=&amp;quot;portraits/elves/transparent/marksman+female.png&amp;quot;&lt;br /&gt;
* '''race''': See {{tag|UnitsWML|race}}.  Also used in standard unit filter (see [[FilterWML]]). Mainline Wesnoth features following values:  bats, drake, dwarf, elf, falcon, goblin, gryphon, human, dunefolk, lizard, mechanical, merman, monster, naga, ogre, orc, troll, undead, wolf, wose. They are defined in /data/core/units.cfg.&lt;br /&gt;
* '''undead_variation''': When a unit of this type is killed by a weapon with the plague special, this variation is applied to the new plague unit that is created, whatever its type. For example, if the plague special creates Walking Corpses and undead_variation is set to &amp;quot;troll&amp;quot;, you'll get a troll Walking Corpse. Defaults to the undead_variation set in this unit type's race.&lt;br /&gt;
* '''usage''': the way that the AI should recruit this unit, as determined by the scenario designer. (See ''recruitment_pattern'', [[AiWML]]).  The following are conventions on usage:&lt;br /&gt;
** ''scout'': Fast, mobile unit meant for exploration and village grabbing.&lt;br /&gt;
** ''fighter'': Melee fighter, melee attack substantially more powerful than ranged.&lt;br /&gt;
** ''archer'': Ranged fighter, ranged attack substantially more powerful than melee.&lt;br /&gt;
** ''mixed fighter'': Melee and ranged fighter, melee and ranged attacks roughly equal.&lt;br /&gt;
** ''healer'': Specialty 'heals' or 'cures'.&lt;br /&gt;
:Note that this field primarily affects recruitment.  It also has a small effect on unit movement (the AI tries to keep scouts away from enemies, to some extent).  It does not affect the AI's behavior in combat; that is always computed from attack power and hitpoints. Non-standard usages may be used as well.&lt;br /&gt;
* '''vision''': the number of vision points to calculate the unit's sight range. Defaults to ''movement'' if not present.&lt;br /&gt;
* '''jamming''': the number of jamming points. Defaults to ''0'' if not present. See [[UnitsWML#.5Bmovetype.5D|[jamming_costs]]]&lt;br /&gt;
* '''zoc''': if &amp;quot;yes&amp;quot; the unit will have a zone of control regardless of level.  If present but set to anything other than &amp;quot;yes,&amp;quot; the unit will have no zone of control.  If the tag is omitted, zone of control is dictated by unit level (level 0 = no zoc, level 1+ = has zoc).&lt;br /&gt;
* '''die_sound''': sets the sound, which is used when the unit dies.&lt;br /&gt;
* '''healed_sound''': sets the sound used when the unit is healed in any way (default: heal.wav).&lt;br /&gt;
* '''hp_bar_scaling''': Overrides the attribute in ([[GameConfigWML]]).&lt;br /&gt;
* '''xp_bar_scaling''': Overrides the attribute in ([[GameConfigWML]]).&lt;br /&gt;
* '''bar_offset_x''', '''bar_offset_y''': The offset of the hp and xp bars from the normal bar position of 72x72 unit sprite.&lt;br /&gt;
&lt;br /&gt;
== After max level advancement (AMLA) ==&lt;br /&gt;
* '''[advancement]''': describes what happens to a unit when it reaches the XP required for advancement.  It is considered as an advancement in the same way as advancement described by '''advances_to'''; however, if the player chooses this advancement, the unit will have one or more effects applied to it instead of advancing.&lt;br /&gt;
** '''id''': unique identifier for this advancement; ''Required'' if there are multiple advancement options, or if ''strict_amla=no''.&lt;br /&gt;
** '''always_display''': if set to true displays the AMLA option even if it is the only available one.&lt;br /&gt;
** '''description''': a description displayed as the option for this advancement if there is another advancement option that the player must choose from; otherwise, the advancement is chosen automatically and this key is irrelevant.&lt;br /&gt;
** '''image''': an image to display next to the description in the advancement menu.&lt;br /&gt;
** '''max_times''': default 1.  The maximum times the unit can be awarded this advancement. Pass -1 for &amp;quot;unlimited&amp;quot;.&lt;br /&gt;
** '''strict_amla''':  (yes|no) default=no. Disable the AMLA if the unit can advance to another unit.&lt;br /&gt;
** '''major_amla''': (yes|no) default=no. Sets whether the unit's XP bar is blue(=yes) or purple(=no). In case of more [advancement] tags, if there is one with major_amla=yes, the XP bar will be blue.&lt;br /&gt;
** '''require_amla''': An optional list of AMLA ''id'' keys that act as prerequisites for this advancement to become available.  Order is not important, and an AMLA id can be repeated any number of times to indicate that another advancement must be chosen several times before this advancement option will become available.&lt;br /&gt;
*** example: &amp;lt;tt&amp;gt;require_amla=tough,tough,incr_damage&amp;lt;/tt&amp;gt; assumes there exist other [advancement] options called ''id=tough'' and ''id=incr_damage''.  Once ''tough'' is chosen twice and ''incr_damage'' is chosen once, then the current [advancement] will become available.&lt;br /&gt;
*** ''require_amla=tough,incr_damage,tough'' is an equivalent way of expressing this.&lt;br /&gt;
** '''exclude_amla''': {{DevFeature1.13|2}} An optional list of AMLA ''id'' keys that represent AMLAs that are mutually exclusive to this one. Order is not important, and an AMLA id can be repeated. If the unit already has any of the AMLAs that appear once in this list, then this AMLA will not be made available. If an AMLA id appears multiple times in the list, then this AMLA will be made available only if the other AMLA has been chosen less than the number of times it appears in the list. Of course, for this to really make two AMLAs mutually exclusive, you need to add ''exclude_amla'' to both AMLA defintions.&lt;br /&gt;
** '''[effect]''': A modification applied to the unit whenever this advancement is chosen.  See [[EffectWML]]&lt;br /&gt;
** '''[filter]''': A  [[StandardUnitFilter]],  the advancement will only be available when the unit passes this filter during the time the advancement dialog is shown.&lt;br /&gt;
&lt;br /&gt;
== Attacks ==&lt;br /&gt;
* '''[attack]''': one of the unit's attacks.&lt;br /&gt;
** '''description''': a translatable text for name of the attack, to be displayed to the user.&lt;br /&gt;
** '''name''': the name of the attack. Used as a default description, if ''description'' is not present, and to determine the default icon, if ''icon'' is not present (see below).  Non-translatable.  Used for the ''has_weapon'' key and animation filters; see [[StandardUnitFilter]] and [[AnimationWML]]&lt;br /&gt;
** '''type''': the damage type of the attack.  Used in determining resistance to this attack (see {{tag|UnitsWML|movetype|resistance}}). Usually this is one of ''blade'', ''pierce'', ''impact'', ''fire'', ''cold'', or ''arcane'', but it can be set to anything (as long as it contains only letters, numbers, and underscores). When using a custom type, you will need to set its user-visible name using [[LanguageWML]]. {{DevFeature1.15|0}} When showing the icon for a custom damage type in the sidebar, the game will look for a file called icons/profiles/''type''.png under your addon's images folder. For example, the icon for a damage type called ''electric'' would be at images/icons/profiles/electric.png.&lt;br /&gt;
** '''[specials]''': contains the specials of the attack. See [[AbilitiesWML#The_.5Bspecials.5D_tag|AbilitiesWML]].&lt;br /&gt;
** '''icon''': the image to use as an icon for the attack in the attack choice menu, as a path relative to the images directory. Defaults to the attack's name in the attacks directory (Ex. if ''name=sword'' then default is ''icon=attacks/sword.png''). &lt;br /&gt;
** '''range''': the range of the attack.  Used to determine the enemy's retaliation, which will be of the same type. The range can be anything (as long as it contains only letters, numbers, and underscores), but the standard values are ''melee'' and ''ranged''. Units can only retaliate against attacks for which they have a corresponding attack of the same range. When using a custom range, you will need to set its user-visible name using [[LanguageWML]]. {{DevFeature1.15|0}} When showing the icon for a custom range in the sidebar the game will look for a file called icons/profiles/''range''_attack.png under your addon's images folder. For example, the icon for a range called ''very_long'' would be at images/icons/profiles/very_long_attack.png.&lt;br /&gt;
** '''max_range''': maximum distance (in number of hexes) to which this attack works. Default is 1.&lt;br /&gt;
*** This currently lacks UI and AI support.&lt;br /&gt;
** '''min_range''': minimum distance (in number of hexes) to which this attack works. Default is 1.&lt;br /&gt;
*** This currently lacks UI and AI support.&lt;br /&gt;
** '''damage''': the damage of this attack&lt;br /&gt;
** '''number''': the number of strikes per attack this weapon has&lt;br /&gt;
** '''accuracy''': a number added to the chance to hit whenever using this weapon offensively (i.e. during a strike with this attack, regardless of who initiated the combat); negative values work too&lt;br /&gt;
** '''parry''': a number deducted from the enemy chance to hit whenever using this weapon defensively (i.e. during the enemy's strike, regardless of who initiated the combat); negative values work too&lt;br /&gt;
** '''movement_used''': determines how many movement points using this attack expends. By default all movement is used up, set this to 0 to make attacking with this attack expend no movement.&lt;br /&gt;
** '''attacks_used''': {{DevFeature1.17|12}} determines how many attacks this attack expends (default 1). This number is deducted from the unit's &amp;lt;tt&amp;gt;attacks_left&amp;lt;/tt&amp;gt; when they use this attack.&lt;br /&gt;
** '''attack_weight''': multiplier for total damage that the AI should use to choose which attack to use when attacking (and offer to player as default). Setting it to 0 disables the attack on attack. Until {{DevFeature1.19|2}} positive attack_weight was ignored.&lt;br /&gt;
** '''defense_weight''': used to determine which attack is used for retaliation. This affects gameplay, as the player is not allowed to determine his unit's retaliation weapon. Setting it to 0 disable the attacks on defense.&lt;br /&gt;
** '''alignment''': {{DevFeature1.19|5}} one of lawful/neutral/chaotic/liminal (See TimeWML). Default is unit alignment.&lt;br /&gt;
&lt;br /&gt;
== Other tags ==&lt;br /&gt;
* {{anchor|base_unit|'''[base_unit]'''}}: Contains one attribute, '''id''', which must be the ID of a unit type.  If specified, the UnitTypeWML for that unit is copied into this one, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Additionally, the unit will be marked as variation of the base unit in its own help page, but not in the help page of the base unit.&lt;br /&gt;
&lt;br /&gt;
* '''[abilities]''': Defines the abilities of a unit. See [[AbilitiesWML]]&lt;br /&gt;
* '''abilities''': {{DevFeature1.19|17}} A comma-separated list of ability [[AbilitiesWML#Common_keys_and_tags_for_every_ability|'''unique_id''']]s. If defined in the registry [[UnitsWML#.5Babilities.5D|[units][abilities]]], these will be added to this unit type as if their full definition was included in '''[abilities]'''. Example: ''abilities=heals_8,regenerates''.&lt;br /&gt;
&lt;br /&gt;
* '''[event]''': Any [event] written inside the [unit_type] tag will get included into any scenario where a unit of this type appears in. Note that such events get included when a unit of this type first appears in the scenario, not automatically when the scenario begins (meaning that ''name=prestart'' events, for example, would usually never trigger). See [[EventWML]] and [[WML_Abilities|WML Abilities]]. {{DevFeature1.19|4}} Abilities support [event].&lt;br /&gt;
&lt;br /&gt;
* {{anchor|variation|'''[variation]'''}}: Defines a variation of a unit. Variations are invoked with an [effect] tag or the variation= attribute in [[SingleUnitWML]]. They are currently used for graphical variations (giving character sprites new weapons) but theoretically you could do anything with it.&lt;br /&gt;
** '''variation_id''': Mandatory. The value of '''variation=''' used in SingleUnitWML to choose this variant.&lt;br /&gt;
** '''variation_name''': Translatable. The name of the variation, which is displayed in the help and in debug mode. Not setting this looks bad unless combined with '''hide_help'''=yes.&lt;br /&gt;
** '''inherit''': if ''yes'', inherits all the properties of the base unit, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Defaults to no.&lt;br /&gt;
*** The '''id''' key is always inherited, regardless of the value of '''inherit'''.&lt;br /&gt;
** All keys and tags of '''[unit_type]''', except ''[advancefrom]'', ''[base_unit]'', ''[female]'', ''[male]'', and ''[variation]''.&lt;br /&gt;
&lt;br /&gt;
* '''[male]''', '''[female]''': These can specify a variation based on gender for a unit. If these are provided, they will automatically apply based upon the gender of a unit.&lt;br /&gt;
** '''inherit''': if ''yes'', inherits all the properties of the base unit, as if by [[InternalActionsWML#.5Bset_variables.5D|[set_variables]mode=merge]]. Defaults to yes.&lt;br /&gt;
*** The '''id''' key is always inherited, regardless of the value of '''inherit'''.&lt;br /&gt;
** All '''[unit_type]''' tags and keys, excluding ''[advancefrom]'', ''[base_unit]'', ''[female]'', and ''[male]''.&lt;br /&gt;
* '''[trait]''': Adds an additional trait to the pool. See [[UnitsWML]] for the syntax.&lt;br /&gt;
* '''[special_note]''' {{DevFeature1.15|2}} see [[UnitTypeWML#Special_Notes|below]].&lt;br /&gt;
&lt;br /&gt;
== Special Notes ==&lt;br /&gt;
&lt;br /&gt;
Use of the '''[special_note]''' tags and attributes results in a bulleted list of special notes in the unit type's help page and in the sidebar tooltip for the unit type's name. Prior to 1.15.2, the old format for special notes was simply text included in the '''[unit_type]description''' attribute.&lt;br /&gt;
&lt;br /&gt;
Note that the sidebar tooltip shows the notes for the current unit, but opening the help-browser by right-clicking on a unit shows the notes for generic units of that type. These can be different if the unit has '''[modifications]'''.&lt;br /&gt;
&lt;br /&gt;
Text given in the following attributes will be collected and shown as the special notes for units and unit types:&lt;br /&gt;
&lt;br /&gt;
* {{DevFeature1.15|2}} [unit_type][special_note]note=&lt;br /&gt;
* {{DevFeature1.15|2}} [unit][special_note]note= (these are used ''instead of'' any defined in the [unit_type])&lt;br /&gt;
* {{DevFeature1.15|14}} [movetype][special_note]note=&lt;br /&gt;
* {{DevFeature1.15|14}} [''ability tag name'']special_note=&lt;br /&gt;
* {{DevFeature1.15|14}} [attack][specials][''special tag name'']special_note=&lt;br /&gt;
* {{DevFeature1.15|14}} [language]special_note_damage_type_''TYPE''=&lt;br /&gt;
    &lt;br /&gt;
It's no longer necessary to put these notes in each unit_type's .cfg file, and the macros for doing so are now deprecated.&lt;br /&gt;
&lt;br /&gt;
== Removed keys ==&lt;br /&gt;
&lt;br /&gt;
These don't work any more, the documentation is left here as an aid to porting old code.&lt;br /&gt;
&lt;br /&gt;
* {{anchor|advancefrom|'''[advancefrom]'''}}: {{DevFeature1.15|4}} replaced by [[ModificationWML|[modify_unit_type]]]. Defines the previous unit type on the advancement tree. Allows a campaign-specific unit to be spliced into an already existing advancement tree.  It should generally be used only inside a campaign ifdef, to prevent changes to other campaigns. Since all multiplayer content shares MULTIPLAYER define, using advancefrom changes unit type even if the addon is not actively used. For that reason multiplayer advancefrom may only be used with unit types defined in the same addon - then everyone who has the unit has it with same advancements.  This tag makes changes to the ''advances_to'' and ''experience'' keys of a base unit to make it advance into this unit.  It takes these keys:&lt;br /&gt;
** ''unit'': the id of the base unit from which this unit advances.  This adds the unit into the list of units which ''unit'' can advance into.&lt;br /&gt;
** ''experience'': (optional) If present the experience needed to advance is set to this value. If there are more than one [advancefrom] tags referencing the same base unit within the same preprocessor scope (e.g. a campaign #ifdef) with experience= keys, the lowest value of these is chosen.  Note: this will also lower the experience required to advance to other units which the base unit can advance into.&lt;br /&gt;
: If the previous unit type makes use of '''[male]''' and/or '''[female]''' tags, then the current (new) unit type is expected to also. That is, the subtypes defined by those tags will only receive this advancement if the new type has a corresponding tag.&lt;br /&gt;
{{DevFeature1.15|4}} '''[advancefrom]''' was effectively removed in 1.15.4. The intention was to deprecate it, but  the compatibility code that was meant to support it in 1.16 was untested and nonfunctional.&lt;br /&gt;
&lt;br /&gt;
== Deprecating units ==&lt;br /&gt;
&lt;br /&gt;
A macro is provided for deprecating a unit, which uses the built-in deprecation system but hard-codes the level to 3 (meaning &amp;quot;for removal&amp;quot;). The syntax is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;{DEPRECATED_UNIT old_id new_id version}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also set the new_id to an empty string if there is no replacement.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[AnimationWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
* [[TerrainWML]]&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=AbilitiesWML&amp;diff=74576</id>
		<title>AbilitiesWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=AbilitiesWML&amp;diff=74576"/>
		<updated>2025-10-26T23:30:26Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Common keys and tags for abilities with a value */ Fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
==  Abilities and their effects ==&lt;br /&gt;
&lt;br /&gt;
There are two types of abilities: ones that apply to units (called ''abilities'') and ones that only apply when using a particular attack (called ''specials'' or ''weapon specials'').  A unit may have multiple abilities and an attack can have multiple specials.&lt;br /&gt;
&lt;br /&gt;
Each ability or special defines an effect based on one to three units. Most abilities apply to a single unit, and '''[filter_self]''' can be used to determine when the ability is active. Weapon specials apply to two units, which can be filtered either as &amp;quot;attacker&amp;quot; and &amp;quot;defender&amp;quot; (with the obvious meaning) or as &amp;quot;self&amp;quot; and &amp;quot;other&amp;quot; – the unit that possesses the special, and that unit's opponent. When filtering on the &amp;quot;other&amp;quot; unit, you use '''[filter_opponent]'''.&lt;br /&gt;
&lt;br /&gt;
Leadership-style abilities are a more complex case, as they involve three units. Like a weapon special, there is an attacker and defender, but there is also a third unit that could be referred to as the &amp;quot;teacher&amp;quot;. The &amp;quot;teacher&amp;quot; is the unit that possesses the ability, so it is referred to as &amp;quot;self&amp;quot; in the ability. A leadership ability works by temporarily granting a weapon special to either the attacker or the defender. The unit that benefits from this is referred to as the &amp;quot;student&amp;quot;, while the unit that does not benefit is simply the &amp;quot;other&amp;quot; unit. When filtering on the &amp;quot;other&amp;quot; unit, you use '''[filter_opponent]''', while the student can be filtered with '''[filter_student]'''.&lt;br /&gt;
&lt;br /&gt;
== The ''[abilities]'' tag ==&lt;br /&gt;
&lt;br /&gt;
The following tags are used to describe an ability in WML:&lt;br /&gt;
&lt;br /&gt;
* '''[heals]''': modifies the hitpoints of a unit at the beginning of the healer's turn&lt;br /&gt;
* '''[regenerate]''': modifies the hitpoints of a unit at the beginning of the unit's turn&lt;br /&gt;
* '''[resistance]''': modifies the resistance of a unit to damage&lt;br /&gt;
* '''[leadership]''': modifies the damage of a unit&lt;br /&gt;
* '''[skirmisher]''': negates enemy zones of control&lt;br /&gt;
* '''[illuminates]''': modifies the time of day adjacent to the affected units&lt;br /&gt;
* '''[teleport]''': allows the unit to teleport&lt;br /&gt;
* '''[hides]''': renders the unit invisible to enemies&lt;br /&gt;
* {{DevFeature1.15|0}} All [[#The_.5Bspecials.5D_tag|weapon specials]] except for '''[plague]''', '''[heal_on_hit]''', and '''[swarm]''' can be placed in the '''[abilities]''' tag. These [[#Extra_tags_and_keys_used_by_weapon_specials_as_abilities|&amp;quot;weapon specials as abilities&amp;quot;]] will give the weapon special to all attacks the unit has.&lt;br /&gt;
* '''[defense]''' {{DevFeature1.19|16}}: modifies the chances of being hit by the opponent's weapon, this value can be modified by the parry attribute, the accuracy attribute of the opponent's weapon, or by their special weapon '''[chance_to_hit]'''. Be careful, the more you increase the value, the less chance the opponent has of hitting you. Using same standard numerical attributes as '''[attacks]''' .&lt;br /&gt;
* Any other tag is valid (for example '''[dummy]'''), but will result in an ability that does nothing but report it's there. '''Note:''' a dummy ability must have an id for the name and description to display.&lt;br /&gt;
* {{DevFeature1.15|3}} All the engine [[#The_.5Bspecials.5D_tag|weapon specials]] can be placed in the [abilities] tag now.&lt;br /&gt;
&lt;br /&gt;
=== Available formula variables in Abilities and Weapon Specials  ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|?}} When using formulas in abilities and weapon specials, the following formula variables are available:&lt;br /&gt;
* '''self''': (unit) the unit that has the ability&lt;br /&gt;
* '''student''': (unit) for leadership-like abilities this is the unit that is adjacent to the unit that has the ability; if affect_self=yes, this is also unit who has ability.&lt;br /&gt;
* '''attacker''': (unit) for attack-related abilities and weapon specials, this is the attacking unit during the attack.&lt;br /&gt;
* '''defender''': (unit) for attack-related abilities and weapon specials, this is the defending unit during the attack.&lt;br /&gt;
* '''other''': (unit) the unit whose stats get modified from the ability. For abilities without 'apply_to=opponent' this is always the same as 'student'.&lt;br /&gt;
&lt;br /&gt;
=== Common keys and tags for every ability ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|?}} All keys inside any ability that expects a numeric value will also accept formulas using &lt;br /&gt;
[[Wesnoth Formula Language]]. In order to use a formula in these keys, you must enclose it in parentheses. However, do '''not''' precede those parentheses with a dollar sign like &amp;lt;code&amp;gt;$(...)&amp;lt;/code&amp;gt;, since that will erase the &amp;lt;tt&amp;gt;self&amp;lt;/tt&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the (translatable) name of the ability. If omitted, the ability will be a hidden ability.&lt;br /&gt;
* '''female_name''': the (translatable) name of the ability when possessed by a female unit. Defaults to ''name'' if not specified.&lt;br /&gt;
* '''name_inactive''': the (translatable) name of the ability when inactive. Defaults to ''name'' if not specified; if the ability is supposed to be not displayed when inactive, you must explicitly set ''name_inactive'' to an empty string (nothing after the equals sign).&lt;br /&gt;
* '''female_name_inactive''': the (translatable) name of the ability when inactive and possessed by a female unit. Defaults to ''name_inactive'' if not specified. You should thus set ''female_name'' as well!&lt;br /&gt;
* '''description''': the (translatable) description of the ability.&lt;br /&gt;
* '''description_inactive''': the (translatable) description of the ability when inactive. Defaults to ''description'' if not specified.&lt;br /&gt;
* '''special_note''' {{DevFeature1.15|14}} Translatable string, which will be displayed in the unit’s help. See also [[UnitTypeWML#Special_Notes]].&lt;br /&gt;
* '''affect_self''': if equal to 'yes' (default), the ability will affect the unit that has it.&lt;br /&gt;
* '''affect_allies''': if equal to 'yes', the ability will affect units from the same and allied sides in the specified adjacent hexes. If set to 'no' it will not affect own or allied sides. If not set (default) it will affect units on the same side but not from allied sides.&lt;br /&gt;
* '''affect_enemies''': if equal to 'yes' (default is 'no'), the ability will affect enemies in the specified adjacent hexes.&lt;br /&gt;
* '''id''': this ability will not be cumulative with other abilities using this id. Must be present if cumulative is anything other than 'yes'.&lt;br /&gt;
* '''halo_image''': {{DevFeature1.17|22}} if used, the halo specified showed on unit affected by ability.&lt;br /&gt;
* '''overlay_image''': {{DevFeature1.17|22}} if used, the overlay specified showed on unit affected by ability.&lt;br /&gt;
* '''halo_image_self''': {{DevFeature1.17|22}} if used, the halo specified showed on unit who has ability when active.&lt;br /&gt;
* '''overlay_image_self''': {{DevFeature1.17|22}} if used, the overlay specified showed on unit who has ability when active.&lt;br /&gt;
* '''[filter]''': [[StandardUnitFilter]] If the unit owning the ability does not match this filter, the ability will be inactive.&lt;br /&gt;
* {{anchor|affect_adjacent|'''[affect_adjacent]'''}}: an adjacent unit that does not match this filter will not receive its effects. There can be multiple [affect_adjacent] tags in a single ability; a unit needs to match any one of these to receive the effects. The side requirement of matching units is defined by the '''affect_allies''' and '''affect_enemies''' keys. If there are no [affect_adjacent] tags, then no adjacent units will receive the effects.&lt;br /&gt;
** '''adjacent''': a comma separated list of any combination of these directions: '''n''','''ne''','''se''','''s''','''sw''','''nw'''. (See [[StandardLocationFilter#Directions|notes]])&lt;br /&gt;
** '''[filter]''': a [[StandardUnitFilter]]. {{DevFeature1.13|2}} The variable $other_unit refers to the unit owning the ability.&lt;br /&gt;
** '''radius''': {{DevFeature1.19|13}} set to 1 by default, it determines the range within which units can be affected beyond immediately adjacent units, if the value is equal to 'full-map', the area is the entire map.&lt;br /&gt;
* '''[filter_self]''': if the owner of the ability does not match this filter, it will not receive the effects of the ability. [filter_self] takes a [[StandardUnitFilter]] as argument.&lt;br /&gt;
* '''[filter_adjacent]''': if an adjacent unit does not match this filter, the ability will not be active and no-one will receive its affects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). In fact, it's really a shorthand for a [filter_adjacent] nested within [filter]. The variables $this_unit and {{DevFeature1.13|2}} $other_unit both work as you'd expect. Multiple [filter_adjacent] can be provided, all of which must pass for the ability to activate.&lt;br /&gt;
* '''[filter_adjacent_location]''': like [filter_adjacent], but filters on locations instead of units. This is a shorthand for [filter][filter_location][filter_adjacent_location].&lt;br /&gt;
* {{anchor|filter_base_value|'''[filter_base_value]'''}}: filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', etc. If several keys are used all have to match.&lt;br /&gt;
* '''[event]''': [[EventWML]]. {{DevFeature1.19|4}} An [event] to be included into any scenario where a unit with this ability appears in. Note that such events get included when a unit with this ability first appears in the scenario, not automatically when the scenario begins (meaning that ''name=prestart'' events, for example, would usually never trigger). See [[WML_Abilities|WML Abilities]]. Shortcut of [unit_type][event].&lt;br /&gt;
&lt;br /&gt;
=== Common keys and tags for abilities with a value ===&lt;br /&gt;
&lt;br /&gt;
The '''[leadership]''', '''[heals]''', '''[regenerate]''',and '''[illuminates]''' abilities take values that specify how those abilities modify their respective base values.&lt;br /&gt;
&lt;br /&gt;
* '''value''': the value to be used. &lt;br /&gt;
* '''add''': the number to add to the base value. Note the interaction with '''sub''' in [[#Common_calculations]].&lt;br /&gt;
* '''sub''': the number to subtract from the base value.&lt;br /&gt;
* '''multiply''': this multiplies the base value.&lt;br /&gt;
* '''divide''': this divides the base value.&lt;br /&gt;
* '''max_value''': {{DevFeature1.19|2}}  maximum special value. Default: no limit.&lt;br /&gt;
* '''min_value''': {{DevFeature1.19|2}}  minimum special value. Default: no limit.&lt;br /&gt;
* '''cumulative''': if set to 'yes', the [leadership] value will be added to another [leadership] value= same if have same id=, for other abilities, the highest value between value= or base_value will be choosen.&lt;br /&gt;
* '''[filter_base_value]''': filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', '''less_than''', '''greater_than''', '''less_than_equal_to''', '''greater_than_equal_to'''.&lt;br /&gt;
&lt;br /&gt;
==== Common calculations ====&lt;br /&gt;
&lt;br /&gt;
Several abilities and weapon specials take the keys '''add''', '''sub''', '''multiply''' and '''divide'''.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}} '''add''' and '''sub''' work independently.&lt;br /&gt;
&lt;br /&gt;
Prior to 1.19.4:&lt;br /&gt;
&lt;br /&gt;
* If '''add''' and '''sub''' are used in the same ability, the '''add''' is ignored&lt;br /&gt;
* If '''add''' and '''sub''' are used in separate abilities with the same id, or with the default id that's used when no id is specified, then the order in which the abilities are encountered controls the calculation, which may change depending on units' positions on the map.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[heals]'' ability ===&lt;br /&gt;
* '''value''': the amount healed.&lt;br /&gt;
* Use common keys and tags for abilities with a value.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[regenerate]'' ability ===&lt;br /&gt;
* '''value''': the amount healed.&lt;br /&gt;
* Use common keys and tags for abilities with a value&lt;br /&gt;
&lt;br /&gt;
=== Extra keys and tags used by the ''[resistance]'' ability ===&lt;br /&gt;
&lt;br /&gt;
* '''value''': set resistance to this value.&lt;br /&gt;
* '''max_value''': maximum resistance value. Default: 0%. {{DevFeature1.17|24}} Default: no limit.&lt;br /&gt;
* '''min_value''': {{DevFeature1.19|0}} minimum resistance value. Default: no limit.&lt;br /&gt;
* Use common keys and tags for abilities with a value&lt;br /&gt;
* '''apply_to''': a list of damage types; if left out, the ability applies to all types.&lt;br /&gt;
* '''active_on''': one of 'defense' or 'offense'; if left out, the ability is active on both.&lt;br /&gt;
These keys affect the actual resistance (e.g. -20%), not the damage modifier normally used in [resistance] (e.g. 120).&lt;br /&gt;
* '''[filter_weapon]''': {{DevFeature1.15|0}} If present, the resistance ability only takes effect when the owner of the ability uses a matching weapon.&lt;br /&gt;
* '''[filter_second_weapon]''': {{DevFeature1.15|0}} If present, the resistance ability only takes effect when the opponent uses a matching weapon.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys and tags used by the ''[defense]'' ability ===&lt;br /&gt;
* '''value''': set defense to this value. Warning, the chance to be hit decrease when value of ability increase.&lt;br /&gt;
* Use common keys and tags for abilities with a value&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[leadership]'' ability ===&lt;br /&gt;
&lt;br /&gt;
* '''value''': the percentage bonus to damage.&lt;br /&gt;
* Use common keys and tags for abilities with a value&lt;br /&gt;
''Note:'' cumulative leadership with '''cumulative=yes''' and '''value=''' doesn't work in 1.16 (but fixed in 1.17.12 and later). To work around use '''add=''' or '''sub=''' key (it doesn't require cumulative) (https://github.com/wesnoth/wesnoth/issues/6466 ). If you want each instance of a ''[leadership]'' with the same id to be added you will be able to reuse '''cumulative=yes''' in 1.17.12 and later, otherwise, if you want to add the value of another ''[leadership]'' only once even with the same id in several copies, use '''add'''.&lt;br /&gt;
* '''[filter_weapon]''': {{DevFeature1.15|0}} If present, the leadership ability only takes effect when the owner of the ability uses a matching weapon.&lt;br /&gt;
* '''[filter_second_weapon]''': {{DevFeature1.15|0}} If present, the leadership ability only takes effect when the opponent uses a matching weapon.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[illuminates]'' ability ===&lt;br /&gt;
&lt;br /&gt;
Because this ability changes the terrain instead of units on it, affect_self, affect_allies, affect_enemies and [filter_adjacent] have no effect. If you use [affect_adjacent] the terrain under and adjacent to adjacent unit will be changed.&lt;br /&gt;
* '''value''': the percentage bonus to lawful units. Units with '''alignment=lawful''' do +''value'' % damage when under the influence of a unit with this ability. Units with '''alignment=chaotic''' do -''value'' % damage. Units with '''alignment=neutral''' are unaffected by this ability. Units with '''alignment=liminal''' do -(abs(''value'')) % damage. ''value'' can be a negative number; this is useful if you want to give Chaotic units an advantage instead of Lawful ones. &lt;br /&gt;
* Use Common keys and tags for abilities with a value&lt;br /&gt;
* '''max_value''': the maximum percentage bonus given. Cannot be less than 0. Defaults to 0 if not present.&lt;br /&gt;
* '''min_value''': the minimum percentage bonus given. Cannot be greater than 0. Defaults to 0 if not present.&lt;br /&gt;
* '''radius''': {{DevFeature1.19|15}} defines the radius of the ability, by default only the terrain the user is on and adjacent hexes are affected, but this can now be extended to a radius defined by '''radius''' ; if '''radius'''=all_map then the whole map will be affected.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[hides]'' ability ===&lt;br /&gt;
&lt;br /&gt;
* '''alert''': the displayed text when the unit is discovered. Default &amp;quot;Ambushed!&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Extra tags used by the ''[teleport]'' ability ===&lt;br /&gt;
&lt;br /&gt;
* '''[tunnel]''' - a [[DirectActionsWML#.5Btunnel.5D|tunnel tag]] (without the remove key) defining the tunneling source and target hexes, and maybe other conditions. (It automatically applies only to the unit with the ability.)  You may use $teleport_unit inside the [tunnel][source] and [tunnel][target] tag for filtering purposes.&lt;br /&gt;
&lt;br /&gt;
=== Extra tags and keys used by weapon specials as abilities ===&lt;br /&gt;
&lt;br /&gt;
* {{anchor|filter_student|'''[filter_student]'''}}: {{DevFeature1.15|0}} If present, only the unit matching this filter, either the possessor of the ability if affect_self=yes, or an adjacent unit matching '''[filter_adjacent]''' will be affected. &lt;br /&gt;
* '''[filter_adjacent_student]''': {{DevFeature1.19|10}} if an adjacent unit to student does not match this filter, the ability will not be active and no-one will receive its affects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). In fact, it's really a shorthand for a [filter_adjacent] nested within [filter_student]. The variables $this_unit and $other_unit both work as you'd expect. Multiple [filter_adjacent_student] can be provided, all of which must pass for the ability to activate.&lt;br /&gt;
** '''radius''': {{DevFeature1.19|13}} determines the distance of units that can be filtered and not just adjacent units, '''radius''' is set to 1 by default.&lt;br /&gt;
* '''[filter_adjacent_student_location]''': {{DevFeature1.19|10}} like [filter_adjacent_student], but filters on locations instead of units. This is a shorthand for [filter_student][filter_location][filter_adjacent_location].&lt;br /&gt;
* '''overwrite_specials''': {{DevFeature1.15|13}} If present, allows a special abilities weapon with a numerical value to impose its value and ignore values of abilities or specials of the same type. If '''overwrite_specials=one_side''', the specials and abilities used by the opponent of the unit affected by the ability with this key and applied to it will not be affected. If '''overwrite_specials=both_sides''', all non-key-carrying abilities and all specials of the same type affecting the recipient unit will be affected, even if used by the opponent (used in the macro FORCE_CHANCE_TO_HIT).&lt;br /&gt;
* {{anchor|overwrite|'''[overwrite]'''}}: {{DevFeature1.17|22}} Part of '''overwrite_specials'''. Allows more flexibility in determining which specials should take priority over other specials of the same type.&lt;br /&gt;
** '''priority''': A numeric value to use when determining which special should be used if multiple specials of the same type have the '''overwrite_specials''' attribute. Default is 0.&lt;br /&gt;
** {{anchor|filter_specials|'''[experimental_filter_specials]'''}}: [[StandardAbilityFilter]] Further attributes to filter specials by to determine if it should take priority over other specials. Accepts the same attributes as [experimental_filter_ability].&lt;br /&gt;
** '''description_affected''': {{DevFeature1.17|13}} becomes the '''description''' of the weapon special, without changing the '''description''' of the ability&lt;br /&gt;
** '''name_affected''': {{DevFeature1.17|13}} becomes the '''name''' of the weapon special, without changing the '''name''' of the ability&lt;br /&gt;
* Other keys and tags appropriate to the specific weapon special.&lt;br /&gt;
&lt;br /&gt;
=== Macros for common abilities ===&lt;br /&gt;
&lt;br /&gt;
[https://www.wesnoth.org/macro-reference.html#file:abilities.cfg macro reference]&lt;br /&gt;
* ABILITY_AMBUSH&lt;br /&gt;
* ABILITY_CURES&lt;br /&gt;
* ABILITY_HEALS&lt;br /&gt;
* ABILITY_ILLUMINATES&lt;br /&gt;
* ABILITY_LEADERSHIP_LEVEL_1 to ABILITY_LEADERSHIP_LEVEL_5&lt;br /&gt;
* {{DevFeature1.13|2}} ABILITY_LEADERSHIP (replaces the above leadership macros, which are now deprecated)&lt;br /&gt;
* ABILITY_NIGHTSTALK&lt;br /&gt;
* ABILITY_REGENERATES&lt;br /&gt;
* ABILITY_SKIRMISHER&lt;br /&gt;
* ABILITY_STEADFAST&lt;br /&gt;
* ABILITY_SUBMERGE&lt;br /&gt;
* ABILITY_TELEPORT&lt;br /&gt;
&lt;br /&gt;
== The ''[specials]'' tag ==&lt;br /&gt;
&lt;br /&gt;
The '''[specials]''' tag goes inside the '''[attack]''' tag. It can contain the following tags:&lt;br /&gt;
&lt;br /&gt;
* '''[attacks]''': modifies the number of attacks of a weapon, in using '''value''', '''add''', '''sub''', '''multiply''' or '''divide''' attributes&lt;br /&gt;
* '''[berserk]''': pushes the attack for more than one combat round, using '''value''' attribute, '''value''' is 1 by default&lt;br /&gt;
* '''[chance_to_hit]''': modifies the chance to hit of a weapon, using same standard numerical attributes as '''[attacks]'''&lt;br /&gt;
* '''[damage]''': modifies the damage of a weapon, using same attributes as '''[attacks]''' and '''[chance_to_hit]'''&lt;br /&gt;
* '''[damage_type]''' {{DevFeature1.17|23}}: changes the damage type of a weapon&lt;br /&gt;
* '''[defense]''' {{DevFeature1.19|15}}: modifies the chances of being hit by the opponent's weapon, this value can be modified by the parry attribute, the accuracy attribute of the opponent's weapon, or by their special weapon '''[chance_to_hit]'''. Be careful, the more you increase the value, the less chance the opponent has of hitting you. Using same standard numerical attributes as '''[attacks]''' {{DevFeature1.19|16}} [defense] is no longer a weapon special but an ability.&lt;br /&gt;
* '''[disable]''': disables the weapon&lt;br /&gt;
* '''[drains]''': heals the attacker '''value''' percentage of the damage dealt, using same attributes as '''[attacks]''' and '''[chance_to_hit]''', '''value''' is 50 by default&lt;br /&gt;
* '''[firststrike]''': forces the weapon to always strike first&lt;br /&gt;
* '''[heal_on_hit]''': heals the attacker when an attack connects, using same attributes as '''[attacks]''' and '''[chance_to_hit]''', '''value''' is 0 by default&lt;br /&gt;
* '''[petrifies]''': turns the target to stone&lt;br /&gt;
* '''[plague]''': when used to kill an enemy, a friendly unit takes its place&lt;br /&gt;
* '''[poison]''': poisons the target&lt;br /&gt;
* '''[slow]''': slows the target&lt;br /&gt;
* '''[swarm]''': number of strikes decreases as the unit loses hitpoints&lt;br /&gt;
Any other tag is valid, but will result in a special that does nothing but report it is there.&lt;br /&gt;
&lt;br /&gt;
=== Common keys and tags for every weapon special ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|?}} All keys inside any weapon special that expects a numeric value will also accept formulas using [[Wesnoth Formula Language]]. In order to use a formula in these keys, you must enclose it in parentheses.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the (translatable) name of the special. If omitted, the special will be hidden from the player.&lt;br /&gt;
* '''name_inactive''': the (translatable) name of the special when inactive. Defaults to ''name'' if not specified; if the special is supposed to be not displayed when inactive, you must explicitly set ''name_inactive'' to an empty string (nothing after the equals sign).&lt;br /&gt;
* '''description''': the (translatable) description of the special.&lt;br /&gt;
* '''description_inactive''': the (translatable) description of the special when inactive. Defaults to ''description'' if not specified.&lt;br /&gt;
* '''special_note''' {{DevFeature1.15|14}} Translatable string, which will be displayed in the unit’s help. See also [[UnitTypeWML#Special_Notes]].&lt;br /&gt;
* '''id''': this ability will not be cumulative with other specials using this id.&lt;br /&gt;
* '''active_on''': one of '''defense''' or '''offense'''; if left out, the special is active on both.&lt;br /&gt;
* '''apply_to''': one of '''self''','''opponent''','''attacker''','''defender''','''both''' (default: ''self''). Determines who the effects of this special are applied to.&lt;br /&gt;
* '''[filter_adjacent]''': if an adjacent unit does not match this filter, the special will not be active and no-one will receive its effects. Takes extra keys ''adjacent'', ''count'', ''is_enemy'', just like in a [[StandardUnitFilter]]. In fact, it's really a shorthand for a [filter_adjacent] nested within [filter_self], with the one difference that, in the absence of a specified ''count'', all listed directions must match (so, with two directiones eg ''adjacent=n,s'', the default is ''count=2''). The variables $this_unit and {{DevFeature1.13|2}} $other_unit both work as you'd expect. Multiple [filter_adjacent] can be provided, all of which must pass for the ability to activate. &lt;br /&gt;
* '''[filter_adjacent_location]''': like [filter_adjacent], but filters on locations instead of units. This is a shorthand for [filter_self][filter_location][filter_adjacent_location].&lt;br /&gt;
* {{anchor|filter_self|'''[filter_self]'''}}: the special will only be active if the owner matches this [[StandardUnitFilter]] (SUF).&lt;br /&gt;
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.&lt;br /&gt;
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the opponent.&lt;br /&gt;
* {{anchor|filter_opponent|'''[filter_opponent]'''}}: the special will only be active if the opponent matches this SUF.&lt;br /&gt;
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.&lt;br /&gt;
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the unit that owns the weapon.&lt;br /&gt;
* {{anchor|filter_attacker|'''[filter_attacker]'''}}: the special will only be active if the attacker matches this SUF.&lt;br /&gt;
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.&lt;br /&gt;
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the defender.&lt;br /&gt;
* {{anchor|filter_defender|'''[filter_defender]'''}} the special will only be active if the defender matches this SUF.&lt;br /&gt;
** '''[filter_weapon]''': a [[FilterWML#Filtering_Weapons|standard weapon filter]], including special=.&lt;br /&gt;
** '''$other_unit''': {{DevFeature1.13|2}} The special variable $other_unit refers to the attacker.&lt;br /&gt;
* '''overwrite_specials''': if equal to 'one_side', then only this unit's specials are evaluated. If equal to 'both_sides', then both this unit's specials and any of the opponent's weapon specials that affect this unit are evaluated. If a special with this attribute is active, it will take precedence over any other specials of the same type that do not have this attribute. Don't applied to boolean weapon special like [poison] ,[slow], [firststrike] or [petrifies].&lt;br /&gt;
* '''[overwrite]''': {{DevFeature1.17|22}} Allows more flexibility in determining which specials should take priority over other specials of the same type.&lt;br /&gt;
** '''priority''': A numeric value to use when determining which special should be used if multiple specials of the same type have the '''overwrite_specials''' attribute. Default is 0.&lt;br /&gt;
** '''[experimental_filter_specials]''': [[StandardAbilityFilter]] Further attributes to filter specials by to determine if it should take priority over other specials. Accepts the same attributes as [experimental_filter_ability], {{DevFeature1.19|5}} [experimental_filter_specials] deprecated, use [filter_specials] instead.&lt;br /&gt;
* '''[event]''': [[EventWML]]. {{DevFeature1.19|4}} An [event] to be included into any scenario where a unit with this weapon special appears in. Note that such events get included when a unit with this weapon special first appears in the scenario, not automatically when the scenario begins (meaning that ''name=prestart'' events, for example, would usually never trigger). See [[WML_Abilities|WML Abilities]]. Shortcut of [unit_type][event].&lt;br /&gt;
&lt;br /&gt;
=== Common keys and tags for specials with a value ===&lt;br /&gt;
&lt;br /&gt;
The '''[damage]''', '''[attacks]''', and '''[chance_to_hit]''' specials take values that specify how those specials modify their respective base values. The '''[drains]''' special takes a value specifying the percentage of damage drained (default 50) and '''[heal_on_hit]''' takes the amount to heal (default 0; negative values will harm the attacker, but not kill). &lt;br /&gt;
&lt;br /&gt;
* '''value''': the value to be used. &lt;br /&gt;
* '''add''': the number to add to the base value. Note the interaction with '''sub''' in [[#Common_calculations]].&lt;br /&gt;
* '''sub''': the number to subtract from the base value.&lt;br /&gt;
* '''multiply''': this multiplies the base value.&lt;br /&gt;
* '''divide''': this divides the base value.&lt;br /&gt;
* '''max_value''': {{DevFeature1.19|2}}  maximum special value. Default: no limit.&lt;br /&gt;
* '''min_value''': {{DevFeature1.19|2}}  minimum special value. Default: no limit.&lt;br /&gt;
* '''cumulative''': if set to 'yes', this special will be cumulative with the base value.&lt;br /&gt;
* '''backstab''': if set to 'yes', this special will only apply to the attacker, and only when there is an enemy on the target's opposite side (i.e. when the standard backstab special applies). {{DevFeature1.13|2}} This is now deprecated. The same functionality can be achieved with a [filter_adjacent] in [filter_opponent]; see the implementation of the default backstab special for details.&lt;br /&gt;
* '''[filter_base_value]''': filters on the value before any modifications; uses the keys '''equals''', '''not_equals''', '''less_than''', '''greater_than''', '''less_than_equal_to''', '''greater_than_equal_to'''.&lt;br /&gt;
&lt;br /&gt;
==== Common calculations ====&lt;br /&gt;
&lt;br /&gt;
Several abilities and weapon specials take the keys '''add''', '''sub''', '''multiply''' and '''divide'''.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.19|4}} '''add''' and '''sub''' work independently.&lt;br /&gt;
&lt;br /&gt;
Prior to 1.19.4:&lt;br /&gt;
&lt;br /&gt;
* If '''add''' and '''sub''' are used in the same ability, the '''add''' is ignored&lt;br /&gt;
* If '''add''' and '''sub''' are used in separate abilities with the same id, or with the default id that's used when no id is specified, then the order in which the abilities are encountered controls the calculation, which may change depending on units' positions on the map.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[damage_type]'' special ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|23}}&lt;br /&gt;
&lt;br /&gt;
* '''replacement_type''': replaces the attack type with the specified type when [damage_type] is active.&lt;br /&gt;
* '''alternative_type''': add a second type of attack to the existing type, it is always the one of the two which will do the most damage to the opponent which will be used.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In 1.18, alternative_type may be stronger than expected, as the damage calculations sometimes ignore [resistance] abilities. This is a known bug, which occurs deterministically and will be left unfixed in 1.18.x to prevent Out Of Sync errors.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' If a [damage_type] special includes a [filter_weapon]type=, that filter is tested against the base type of the weapon, ignoring all [damage_type] specials.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[berserk]'' special ===&lt;br /&gt;
&lt;br /&gt;
* '''value''': the maximum number of combat rounds (default 1).&lt;br /&gt;
* '''cumulative''': if set to 'yes', this special will be cumulative with other active berserk specials (on the current combatant, not with an opponent's berserk).&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[plague]'' special ===&lt;br /&gt;
&lt;br /&gt;
* '''type''': the unit type to be spawned on kill. When not specified, the default is the unit type of the unit doing the plaguing.&lt;br /&gt;
&lt;br /&gt;
=== Extra keys used by the ''[swarm]'' special ===&lt;br /&gt;
&lt;br /&gt;
* '''swarm_attacks_max''': the maximum number of attacks for the swarm. Defaults to the base number of attacks modified by any applicable [attacks] specials. If this is specified, then the base number of attacks is ignored.&lt;br /&gt;
* '''swarm_attacks_min''': the minimum number of attacks for the swarm. Defaults to zero. This can be set higher than swarm_attacks_max to cause a unit to gain attacks as health decreases.&lt;br /&gt;
The ratio of the unit's current to maximum hit points will be used to scale the number of attacks between these two values.&lt;br /&gt;
&lt;br /&gt;
Prior to version 1.11, a [swarm] special will cause [attacks] specials to be ignored. In 1.11 and later, [attacks] specials are applied before [swarm].&lt;br /&gt;
&lt;br /&gt;
=== Macros for common weapon specials ===&lt;br /&gt;
&lt;br /&gt;
[https://www.wesnoth.org/macro-reference.html#file:weapon_specials.cfg macro reference]&lt;br /&gt;
* WEAPON_SPECIAL_BACKSTAB&lt;br /&gt;
* WEAPON_SPECIAL_BERSERK&lt;br /&gt;
* WEAPON_SPECIAL_CHARGE&lt;br /&gt;
* WEAPON_SPECIAL_DRAIN&lt;br /&gt;
* WEAPON_SPECIAL_FIRSTSTRIKE&lt;br /&gt;
* WEAPON_SPECIAL_MAGICAL&lt;br /&gt;
* WEAPON_SPECIAL_MARKSMAN&lt;br /&gt;
* WEAPON_SPECIAL_PLAGUE&lt;br /&gt;
* WEAPON_SPECIAL_PLAGUE_TYPE TYPE&lt;br /&gt;
* WEAPON_SPECIAL_POISON&lt;br /&gt;
* WEAPON_SPECIAL_SLOW&lt;br /&gt;
* WEAPON_SPECIAL_STONE&lt;br /&gt;
* WEAPON_SPECIAL_SWARM&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[UnitTypeWML]]&lt;br /&gt;
* [[SingleUnitWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=ImagePathFunctions&amp;diff=74549</id>
		<title>ImagePathFunctions</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=ImagePathFunctions&amp;diff=74549"/>
		<updated>2025-10-05T19:06:27Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* PAD: Pad function */ That fake offset thing does not work on all images, so make that clear.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Image Path Functions provide a simple method for WML coders to alter the way their specified images will be displayed in the game. All of the function parameters are included at the end of an image path and should not contain any spaces or special characters (other than those specified here).&lt;br /&gt;
&lt;br /&gt;
If you need to practice it without having to reload all WML, you can use an add-on named ''Image loading tester''.  It is available on the 1.9, 1.10, 1.11, 1.12 and 1.14 add-on servers.&lt;br /&gt;
&lt;br /&gt;
All functions are applied in left-to-right order, with the exception of RC(), TC() and PAL() which are applied always before any other functions. Standard team coloring for a unit is applied after all custom RC(), TC() and PAL() functions but before any other functions.&lt;br /&gt;
That is, stuff like&lt;br /&gt;
 &amp;quot;units/elves-wood/fighter.png~CROP(20,20,40,40)~CROP(10,10,10,10)&amp;quot;&lt;br /&gt;
would result in taking a crop to a 40x40 rectangle whose top-left corner is x=20, y=20; and then taking a crop from ''that'' rectangle with x=10, y=10, w=10, h=10. The result is the area x=30, y=30, w=10, h=10 from the original graphic.&lt;br /&gt;
&lt;br /&gt;
== Changing the colors ==&lt;br /&gt;
&lt;br /&gt;
=== BLEND: Color-blend function ===&lt;br /&gt;
Blends the image with the given color to produce a more controlled tinting effect than color-shifting, independently of the image's contents.&lt;br /&gt;
&lt;br /&gt;
'''~BLEND(r,g,b,o)'''&lt;br /&gt;
&lt;br /&gt;
The color is defined by the ''r'', ''g'', and ''b'' parameters (integers ranging from 0 to 255). The ''o'' (opacity) parameter controls the amount by which the given color will be blended into the image, and may be specified either as a factor from 0.0 to 1.0, or percentage up to 100%. Thus, ~BLEND(r,g,b,0.5) and ~BLEND(r,g,b,50%) are equivalent.&lt;br /&gt;
&lt;br /&gt;
=== BW: Black and White function ===&lt;br /&gt;
{{devfeature1.13|1}}&lt;br /&gt;
May be used to convert the image to pure black and white, without grey pixels. &lt;br /&gt;
&lt;br /&gt;
'''~BW(threshold)'''&lt;br /&gt;
* ''threshold'': a value between 0 and 255 (both limits included). All pixels are converted as greyscale first, and if their average value is greater than the threshold they become white, otherwise they become black.&lt;br /&gt;
&lt;br /&gt;
=== CS: Color-shift function ===&lt;br /&gt;
Performs simple per-channel color shifts by adding the arguments to the respective color channels.&lt;br /&gt;
&lt;br /&gt;
''Multi-channel:'' '''~CS(r,g,b)'''&lt;br /&gt;
''Single-channel:'' '''~R(v)''', '''~G(v)''', '''~B(v)'''&lt;br /&gt;
&lt;br /&gt;
The multichannel syntax assumes all arguments are set to zero initially, so one can use, e.g. ~CS(2,4) to add +2 and +4 units to the red and green channels respectively, leaving the blue channel intact. Arguments may be negative to diminish a channel's value; this can be used to change an image's brightness. Checks for out-of-range arguments or results (less than 0 or greater than 255) are made, so the resultant values are truncated if necessary.&lt;br /&gt;
&lt;br /&gt;
The single channel syntax behaves exactly the same, except that only single-channel modifications are made per function. However, one can stack them to produce the same behavior as ~CS(), e.g. ~R(r)~G(g)~B(b), but that tends to be just a performance loss.&lt;br /&gt;
&lt;br /&gt;
=== GS: Greyscale function ===&lt;br /&gt;
May be used to greyscale the image (turn to black and white)&lt;br /&gt;
&lt;br /&gt;
'''~GS( )'''&lt;br /&gt;
&lt;br /&gt;
=== L: Lightmap color-shift function ===&lt;br /&gt;
Performs per-pixel and per-channel color shifts using another image (a &amp;quot;lightmap&amp;quot;) as source, allowing to create textured light effects.&lt;br /&gt;
&lt;br /&gt;
'''~L(lightmap)'''&lt;br /&gt;
&lt;br /&gt;
For each pixel of the original image, it checks the RGB values from the corresponding pixel of the lightmap, slightly transform them, then add these values to the original pixel.&lt;br /&gt;
&lt;br /&gt;
The transformation involved is done to convert the (0,255) spectrum to (-255,255), allowing to add or subtract color. The formula is (x-128)*2, which means that 0 gives -256, 128 gives 0 and 255 gives 254. So, the no-effect lightmap is a fully grey image (RGB = 128,128,128) and any non-grey pixel will shift the colors of the original.&lt;br /&gt;
&lt;br /&gt;
Note that the lightmap will be scaled to the same dimensions as the original image.&lt;br /&gt;
&lt;br /&gt;
=== NEG: Negative function ===&lt;br /&gt;
{{devfeature1.13|0}}&lt;br /&gt;
Also known as ''invert'', it negates all the RGB values of the image, giving it an effect similar to a photographic negative.&lt;br /&gt;
&lt;br /&gt;
'''~NEG( )'''&lt;br /&gt;
&lt;br /&gt;
Inverts the image, giving it an effect like a photographic negative.&lt;br /&gt;
&lt;br /&gt;
{{devfeature1.13|1}} '''~NEG(''' ''threshold'' ''')'''&lt;br /&gt;
&lt;br /&gt;
If a channel has a value greater than the threshold, the channel will be inverted, performing an effect known as ''solarization''.&lt;br /&gt;
Threshold must be between -1 and 255, with -1 equivalent to full inversion and 255 as no-op value.&lt;br /&gt;
&lt;br /&gt;
{{devfeature1.13|1}} '''~NEG(''' ''threshold_red, threshold_green, threshold_blue'' ''')'''&lt;br /&gt;
&lt;br /&gt;
If a channel has a value greater than the corresponding threshold, the channel will be inverted.&lt;br /&gt;
Each threshold must be between -1 and 255, with -1 equivalent to full inversion and 255 as no-op value.&lt;br /&gt;
&lt;br /&gt;
=== PAL: Palette-switch function ===&lt;br /&gt;
May be used to change colors in an image following the specifications of a source and target (new) palette.&lt;br /&gt;
&lt;br /&gt;
'''~PAL(''' ''source color palette'' '''&amp;gt;''' ''target color palette'' ''')'''&lt;br /&gt;
*''source color palette'' - the first parameter is a source color palette, such as magenta. Do not surround this parameter with quotes.&lt;br /&gt;
*''target color palette'' - the new palette to take the place of the source colors in the image.&lt;br /&gt;
&lt;br /&gt;
A color palette can be either the attribute name from '''[[GameConfigWML#Color_Palettes|[color_palette]]]''' (like magenta) or a comma separated list of hex color values.&lt;br /&gt;
&lt;br /&gt;
=== RC: Re-Color function ===&lt;br /&gt;
May be used to change some colors in an image. It is possible to use ''RC'' more than once on the same image, with different source palettes.&lt;br /&gt;
&lt;br /&gt;
'''~RC(''' ''source color palette'' '''&amp;gt;''' ''destination color range'' ''')'''&lt;br /&gt;
&lt;br /&gt;
==== source color palette ====&lt;br /&gt;
The first parameter is a set of colors, usually the magenta palette. Do not surround this parameter with quotes. The three standard palettes are:&lt;br /&gt;
&lt;br /&gt;
* '''magenta''' - the 19 colors described in [[Team_Color_Shifting]]&lt;br /&gt;
* '''ellipse_red''' - all 255 colors with RGB value (n,0,0)&lt;br /&gt;
* '''flag_green''' - all 255 colors with RGB value (0,n,0)&lt;br /&gt;
&lt;br /&gt;
The palette can also be given inline as a set of hexadecimal RGB values.&lt;br /&gt;
&lt;br /&gt;
The named palettes are defined using the '''[[GameConfigWML#Color_Palettes|[color_palette]]]''' tag, and you can also define your own custom color palette using that tag.&lt;br /&gt;
&lt;br /&gt;
Warning: the RC function will also accept (and not give a warning about) '''red''', '''green''' and any other defined '''[color_range]'''; however the set of RGB values for those aren't guaranteed. Using '''red''' instead of '''ellipse_red''' might be equivalent to the palette 030000,060000,0a0000,...,ff0000,ff0a0a,...,fff0f0.&lt;br /&gt;
&lt;br /&gt;
==== destination color range ====&lt;br /&gt;
This is the second parameter, signifying the ID of a color range defined in the file [http://github.com/wesnoth/wesnoth/blob/master/data/core/team-colors.cfg data/core/team-colors.cfg] (or it may be a custom ID for a color range defined locally). You can also define a custom color range inline (the rgb key from [[GameConfigWML#Color_Palettes]]; note that RC does not use the fourth color for anything).&lt;br /&gt;
&lt;br /&gt;
For this destination color range, using '''red''' or '''green''' makes sense.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
In the following example, the magenta regions in an elvish captain's image are turned a healthy shade of green:&lt;br /&gt;
&lt;br /&gt;
  [message]&lt;br /&gt;
      speaker=narrator&lt;br /&gt;
      image=units/elves-wood/captain.png~RC(magenta&amp;gt;green)&lt;br /&gt;
      message=_ &amp;quot;Now I am on the green team.&amp;quot;&lt;br /&gt;
  [/message]&lt;br /&gt;
&lt;br /&gt;
The following example replaces a few of the '''magenta''' pixels with green ones:&lt;br /&gt;
&lt;br /&gt;
  misc/orb.png~RC(690039,c30074,ec008c &amp;gt; 007f00,00ff00,000000,000000)&lt;br /&gt;
&lt;br /&gt;
The IDs of the color ranges may be the lowercased English name of the palette's base color (e.g. 'red', 'brown', etc.). They may also be numeric color indices from the palette WML included with the game, but this is not recommended.&lt;br /&gt;
&lt;br /&gt;
=== SEPIA: Sepia function ===&lt;br /&gt;
{{devfeature1.13|0}}&lt;br /&gt;
May be used to give to the image a sepia tint (like in old pictures).&lt;br /&gt;
&lt;br /&gt;
'''~SEPIA()'''&lt;br /&gt;
&lt;br /&gt;
=== SWAP: Channel Swap function ===&lt;br /&gt;
{{devfeature1.13|1}}&lt;br /&gt;
May be used to swap the RGBA channels of an image.&lt;br /&gt;
&lt;br /&gt;
'''~SWAP(''' ''r, g, b'' ''')'''&lt;br /&gt;
'''~SWAP(''' ''r, g, b, a'' ''')'''&lt;br /&gt;
* ''r'', ''g'', ''b'', ''a'': each of these arguments may have a value equal to ''red'', ''green'', ''blue'' or ''alpha''. The RGBA channels of the original image will be exchanged accordingly (for example, &amp;lt;tt&amp;gt;~SWAP(blue,green,red)&amp;lt;/tt&amp;gt; swaps the blue and red channels).&lt;br /&gt;
&lt;br /&gt;
=== TC: Team-Color function ===&lt;br /&gt;
In Wesnoth version 1.2, the only Image Path Function was '''~TC()''', which took two comma-separated parameters: the team number and the source color palette. The valid values for both of these parameters are defined in the file ''data/team-colors.cfg''&lt;br /&gt;
&lt;br /&gt;
'''~TC(''' ''team number'' ''',''' ''source color palette'' ''')'''&lt;br /&gt;
*''team number'' - this is the first parameter, a number 1-9 signifying the team number of a unit. Number 1 typically means the red team, 2 typically means the blue team, and so on (unless the scenario color settings for any side have been altered).&lt;br /&gt;
*''source color palette'' - the second parameter is a source color palette, usually magenta. Do not surround this parameter with quotes.&lt;br /&gt;
&lt;br /&gt;
== Transformations ==&lt;br /&gt;
&lt;br /&gt;
=== FL: Flip function ===&lt;br /&gt;
May be used to flip an image horizontally and/or vertically.&lt;br /&gt;
&lt;br /&gt;
'''~FL(''' ''optional argument list'' ''')'''&lt;br /&gt;
*''vertical'' - if the string &amp;quot;vert&amp;quot; is found anywhere in the argument list, the image will be flipped vertically.&lt;br /&gt;
*''horizontal'' - if the string &amp;quot;horiz&amp;quot; is found anywhere in the argument list, the image will be flipped horizontally.&lt;br /&gt;
*if the argument list is empty, the image will only be flipped horizontally.&lt;br /&gt;
&lt;br /&gt;
=== ROTATE: Rotate function ===&lt;br /&gt;
May be used to rotate an image.&lt;br /&gt;
&lt;br /&gt;
'''~ROTATE(''' ''degrees'' ''')'''&lt;br /&gt;
* ''degrees'' - The number of degrees by which the image will be rotated. Positive numbers indicate clockwise rotation, while negative numbers indicate counter-clockwise. (Zero indicates no rotation.)&lt;br /&gt;
If the number of degrees is omitted, a quarter turn (90 degrees) clockwise is assumed.&lt;br /&gt;
&lt;br /&gt;
=== SCALE: Image-scaling function ===&lt;br /&gt;
Scales a graphic up or down.&lt;br /&gt;
&lt;br /&gt;
'''~SCALE( ''new_width'', ''new_height'' )&lt;br /&gt;
&lt;br /&gt;
The ''new_width'' and ''new_height'' parameters are taken as the image's original width or height, respectively, if one of them happens to be zero. Negative values are treated in the same way, but an error is printed in stderr. This uses the bilinear interpolation algorithm.&lt;br /&gt;
&lt;br /&gt;
=== SCALE_INTO function ===&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
Similar to SCALE, but preserves aspect aspect ratio, scaling to the minimum extent required to fit into the specified area. The resulting image will have the specified width or the specified height, but not necessarily both.&lt;br /&gt;
&lt;br /&gt;
=== SCALE_SHARP function ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|0}}&lt;br /&gt;
&lt;br /&gt;
Scales functions using a nearest neighbor algorithm. Specify width and height. (It has the same syntax as ~SCALE.)&lt;br /&gt;
&lt;br /&gt;
'''~SCALE_SHARP(200,300)'''&lt;br /&gt;
&lt;br /&gt;
=== SCALE_INTO_SHARP function ===&lt;br /&gt;
{{DevFeature1.13|5}}&lt;br /&gt;
&lt;br /&gt;
Like SCALE_INTO, but uses nearest neighbor algorithm instead of bilinear interpolation.&lt;br /&gt;
&lt;br /&gt;
=== XBRZ function ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|0}}&lt;br /&gt;
&lt;br /&gt;
Scales functions using the XBRZ algorithm. You may scale things up either 2x, 3x, 4x, or 5x. The scaling tries to preserve the pixel art nature.&lt;br /&gt;
&lt;br /&gt;
'''~XBRZ(n)'''&lt;br /&gt;
&lt;br /&gt;
== Cut-paste-extend ==&lt;br /&gt;
&lt;br /&gt;
=== BLIT: Blit function ===&lt;br /&gt;
Blit (superimpose) the parameter image on the main image. Example: peasant.png~BLIT(hat.png,30,10)&lt;br /&gt;
&lt;br /&gt;
'''~BLIT(src,x,y)'''&lt;br /&gt;
* ''src'': an image file used as source for the blit, other image path functions can be used there.&lt;br /&gt;
* ''x'',''y'': top-left corner coordinates where to blit. If missing assume (0,0).&lt;br /&gt;
&lt;br /&gt;
=== CROP: Crop function ===&lt;br /&gt;
Extracts a rectangular section of an image file.&lt;br /&gt;
&lt;br /&gt;
'''~CROP(x,y,width,height)'''&lt;br /&gt;
* ''x'',''y'': top-left corner coordinates for the rectangular section extracted. Must be greater or equal than zero, and inside the image's bounds.&lt;br /&gt;
* ''width'': width of the selected region. Must be less than or equal to the original image's width, and must not be negative.&lt;br /&gt;
* ''height'': height of the selected region. Must be less than or equal to the original image's height, and must not be negative.&lt;br /&gt;
&lt;br /&gt;
=== CROP_TRANSPARENCY ===&lt;br /&gt;
{{devfeature1.17|26}}&lt;br /&gt;
Removes any transparent padding from around an image.&lt;br /&gt;
&lt;br /&gt;
'''~CROP_TRANSPARENCY()'''&lt;br /&gt;
&lt;br /&gt;
=== PAD: Pad function===&lt;br /&gt;
{{devfeature1.19|17}}&lt;br /&gt;
Extends side(s) of an image with transparent pixels.&lt;br /&gt;
&lt;br /&gt;
'''~PAD(..)'''&lt;br /&gt;
*called with a single number like ''~PAD(10)'' and it will add a 10 pixel padding to every side.&lt;br /&gt;
*called with keys (top, t, right, r, bottom, b, left, l) like ''~PAD(bottom=10, t=5)'' and it will pad those sides by that much.&lt;br /&gt;
Can be used to create a fake offset on centered images by padding one side of an image in order to push it in the opposite direction.&lt;br /&gt;
&lt;br /&gt;
=== MASK: Mask function ===&lt;br /&gt;
Remove parts of the main image using the parameter image as a mask. Example: grass.png~MASK(circle.png) will give a circle of grass.&lt;br /&gt;
&lt;br /&gt;
'''~MASK(mask,x,y)'''&lt;br /&gt;
* ''mask'': an image file used as mask, other image path functions can be used there.&lt;br /&gt;
* ''x'',''y'': top-left corner coordinates where to put the mask. Parts ouside of the mask are considered transparent. If missing assume (0,0).&lt;br /&gt;
&lt;br /&gt;
Only the alpha channel of the mask is used and each alpha value will be the maximum alpha of the resulting image. This means that the fully-transparent parts of the mask will erase the corresponding parts of the image, but also that a semi-transparent mask will create a semi-transparent image.&lt;br /&gt;
&lt;br /&gt;
== Opacity ==&lt;br /&gt;
&lt;br /&gt;
=== ADJUST_ALPHA ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|?}}&lt;br /&gt;
&lt;br /&gt;
Alters the alpha of the image according to a WFL formula. The formula must output an integer from 0 to 255 giving the alpha across the canvas. It is evaluated for every pixel and may use the following variables: x, y, red, green, blue, alpha, width, height. {{DevFeature1.15|0}} The variables u and v are also supported now, evaluating to normalized texture coordinates (in the range 0..1); these are equivalent to &amp;lt;tt&amp;gt;x/width&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;y/height&amp;lt;/tt&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
'''~ADJUST_ALPHA(formula)'''.&lt;br /&gt;
&lt;br /&gt;
The context object for the formula is a '''[[#CHAN:_General_function|pixel object]]'''.&lt;br /&gt;
&lt;br /&gt;
=== O: Opacity modifying function ===&lt;br /&gt;
Changes an image's opacity at render time.&lt;br /&gt;
&lt;br /&gt;
'''~O( ''factor or percentage%'' )'''&lt;br /&gt;
&lt;br /&gt;
If the argument includes the percentage symbol (''%''), it will be treated as a percentage of full (real) opacity; an image will be displayed at its native opacity with ~O(100%).&lt;br /&gt;
&lt;br /&gt;
Without the percentage symbol, the argument is assumed to be a factor by which the image's native opacity should be multiplied. Thus, ~O(0.5) and ~O(50%) are equivalent forms of specifying to reduce an image's opacity by half.&lt;br /&gt;
&lt;br /&gt;
=== PLOT_ALPHA ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|0}}&lt;br /&gt;
&lt;br /&gt;
At each pixel, the color is replaced with a grey-tone reflecting the alpha value at that pixel, and the new image is fully opaque. Useful for plotting the alpha to help debug an IPF or inspect a sprite.&lt;br /&gt;
&lt;br /&gt;
'''~PLOT_ALPHA()'''&lt;br /&gt;
&lt;br /&gt;
=== WIPE_ALPHA ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|0}}&lt;br /&gt;
&lt;br /&gt;
At each pixel, the alpha value is discarded and the pixel is made fully opaque. Useful again for diagnostics.&lt;br /&gt;
&lt;br /&gt;
'''~WIPE_ALPHA()'''&lt;br /&gt;
&lt;br /&gt;
=== Background coloring function ===&lt;br /&gt;
Sets the color of all the (semi-)transparent pixels of the image.&lt;br /&gt;
&lt;br /&gt;
'''~BG(r,g,b)'''&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
&lt;br /&gt;
=== BL: Blurring function ===&lt;br /&gt;
&lt;br /&gt;
Blurs a graphic at render time using the same algorithm used for in-game dialogs.&lt;br /&gt;
&lt;br /&gt;
'''~BL( ''radius'' )'''&lt;br /&gt;
&lt;br /&gt;
=== CHAN: General function ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|7}}&lt;br /&gt;
&lt;br /&gt;
This function allows you to do pretty much anything. It takes up to four comma-separated formulas, one each for the red, green, blue, and alpha channels. Each formula functions exactly the same as the formula for '''ADJUST_ALPHA''', but the output integer is used for the corresponding channel rather than always the alpha channel. Do not surround the formula in &amp;lt;code&amp;gt;$(...)&amp;lt;/code&amp;gt;, since that will erase the &amp;lt;tt&amp;gt;self&amp;lt;/tt&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
'''~CHAN(formula, formula, formula)'''&lt;br /&gt;
&lt;br /&gt;
The context object for each of the formulas is a '''pixel object''' with the following properties:&lt;br /&gt;
&lt;br /&gt;
* '''x''', '''y''': coordinates of the pixel, from the top left&lt;br /&gt;
* '''u''', '''v''': {{DevFeature1.15|0}} normalized coordinates in the range [0,1]&lt;br /&gt;
* '''width''', '''height''': size of the image canvas&lt;br /&gt;
* '''red''', '''green''', '''blue''', '''alpha''': components of the pixel colour&lt;br /&gt;
&lt;br /&gt;
=== DARKEN: Removed function ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|7}} This function has been removed. Use a ~BLIT(misc/tod-dark.png) call instead.&lt;br /&gt;
&lt;br /&gt;
Puts a time-of-day schedule overlay (misc/tod-dark.png) on the image, which must be large enough to accommodate it.&lt;br /&gt;
&lt;br /&gt;
'''~DARKEN()'''&lt;br /&gt;
&lt;br /&gt;
=== BRIGHTEN: Removed function ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|7}} This function has been removed. Use a ~BLIT(misc/tod-bright.png) call instead.&lt;br /&gt;
&lt;br /&gt;
Puts a time-of-day schedule overlay (misc/tod-bright.png) on the image, which must be large enough to accommodate it.&lt;br /&gt;
&lt;br /&gt;
'''~BRIGHTEN()'''&lt;br /&gt;
&lt;br /&gt;
=== NOP: Null function ===&lt;br /&gt;
&lt;br /&gt;
Does nothing.&lt;br /&gt;
&lt;br /&gt;
'''~NOP()'''&lt;br /&gt;
&lt;br /&gt;
=== Pseudo IPFs ===&lt;br /&gt;
&lt;br /&gt;
The following functions are ignored by the IPF image modification module, but used by other Wesnoth components. They only work in special areas.&lt;br /&gt;
&lt;br /&gt;
==== NO_TOD_SHIFT: Disabling ToD ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|8}}&lt;br /&gt;
&lt;br /&gt;
This is used by the terrain renderer and prevents terrain and item images from being affected by ToD lighting. This is in particular useful when placing unit images as items, as they will look the same as when placed as unit.&lt;br /&gt;
&lt;br /&gt;
'''~NO_TOD_SHIFT()'''&lt;br /&gt;
&lt;br /&gt;
==== RIGHT: Display portraits on the right ====&lt;br /&gt;
&lt;br /&gt;
'''''([[DevFeature|Version 1.5.8 and later only]])'''''&lt;br /&gt;
&lt;br /&gt;
This is used by the [[InterfaceActionsWML#.5Bmessage.5D|'''[message]''']] interface action and can be used to show a portrait on the right side of the screen.&lt;br /&gt;
&lt;br /&gt;
'''~RIGHT()'''&lt;br /&gt;
&lt;br /&gt;
== Creating an image file from IPFs ==&lt;br /&gt;
&lt;br /&gt;
The big advantage of Image Path Functions is that they allow you to alter an image without needing a new image file. However, you can also save the result into a new image file using Wesnoth's command line option ''--render-image'.&lt;br /&gt;
&lt;br /&gt;
Assuming you find a way to open your computer's terminal:&lt;br /&gt;
 wesnoth --render-image &amp;quot;units/human-peasants/ruffian.png~RC(magenta&amp;gt;green)~BLIT(units/human-peasants/woodsman.png~RC(magenta&amp;gt;lightblue),18,12)&amp;quot; /tmp/new_image_file.png&lt;br /&gt;
&lt;br /&gt;
Or on Windows:&lt;br /&gt;
 &amp;quot;C:\Path\to\Battle for Wesnoth\wesnoth.exe&amp;quot; --render-image &amp;quot;units/human-peasants/ruffian.png~RC(magenta&amp;gt;green)~BLIT(units/human-peasants/woodsman.png~RC(magenta&amp;gt;lightblue),18,12)&amp;quot; new_image_file.png&lt;br /&gt;
&lt;br /&gt;
Use cases include:&lt;br /&gt;
* Experimenting with Image Path Functions. If none of the images are from an add-on, adding ''--noaddons'' will speed this up.&lt;br /&gt;
* If a new Image Path Function is added to the development version of Wesnoth, add-ons for older Wesnoth versions can use a generated image instead.&lt;br /&gt;
* In case you want to use this anywhere out of Wesnoth. On a website, in Project Haldric, …&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[FancyAddonIcons]] - Tips and tricks for advanced Image Path Function manipulation&lt;br /&gt;
* [[DataURI]] - An image path may also contain the image directly, as a Base64 encoded string&lt;br /&gt;
* [https://irydacea.me/projects/wespal Wespal]  - Tool to preview unit recoloring. Covers the effects of the [[#RC:_Re-Color_Function|RC]], [[#TC: Team-Color Function|TC]] and [[#PAL:_Palette-switch_Function|PAL]] functions.&lt;br /&gt;
* [https://github.com/wesnoth/wesnoth/blob/master/src/image_modifications.cpp src/image_modifications.cpp] - file where IPFs are implemented &lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=AddonServers&amp;diff=74518</id>
		<title>AddonServers</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=AddonServers&amp;diff=74518"/>
		<updated>2025-09-17T03:50:40Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: That's supposed to be an external link; also, show the actual URL for both links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;To connect to the default Add-on server from inside Wesnoth, use Add-ons option from the title screen. Alternatively, all web servers can be viewed at this page: [https://addons.wesnoth.org addons.wesnoth.org]. The web page is for reference purposes, archival purposes, and for people who cannot use the game client for technical reasons or otherwise. You may have a look at the list of add-ons available from each one and optionally download their contents from here. The recommended way is to install via the in-game client as mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
Also, from the in-game client, it is possible to connect to another version's Add-on server by using the correct port address like this: &amp;lt;code&amp;gt;addons.wesnoth.org:15018&amp;lt;/code&amp;gt;, where the last two digits of the port specified (&amp;lt;code&amp;gt;15018&amp;lt;/code&amp;gt;) are the same as the last two digits of the Wesnoth version whose add-on server you wish to connect to. In this example, it will connect to [https://addons.wesnoth.org/1.18/ addons.wesnoth.org/1.18/]. Note that this is in general not recommended because Add-ons from another version may not be compatible or refuse to correctly work, and is intended for advanced users or for development purposes only. The port scheme may change at any point in the future and is not recommended to be used as a permanent link.&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=EffectWML&amp;diff=74508</id>
		<title>EffectWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=EffectWML&amp;diff=74508"/>
		<updated>2025-09-07T01:27:51Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
&lt;br /&gt;
== [effect] ==&lt;br /&gt;
&lt;br /&gt;
The tag [effect] is used to describe one modification to a unit. Any number of [effect] tags can be used to describe a complete modification.&lt;br /&gt;
&lt;br /&gt;
Modifications are permanent changes to a unit; however using an [[DirectActionsWML#.5Bobject.5D|[object]]] with a limited ''duration'' to apply an [effect] will cause the unit to be rebuilt without the effect's effects when the duration expires. &lt;br /&gt;
&lt;br /&gt;
The following keys and subtags are always recognized:&lt;br /&gt;
* '''[filter]''': only apply this effect if the affected unit matches. See [[StandardUnitFilter]] for details.&lt;br /&gt;
* '''times''': describes how many times the effect is applied. The default is to apply the effect once. Other possible value : &amp;quot;per level&amp;quot; which means that the effect is applied level times, where level is the unit level. {{DevFeature1.13|5}} Integers are now supported for ''times''.&lt;br /&gt;
* '''apply_to''': describes what the effect actually affects. New effect types can be added with [[LuaAPI/wesnoth#wesnoth.effects]]. Some examples can be seen in [https://github.com/wesnoth/wesnoth/blob/master/data/campaigns/World_Conquest/lua/game_mechanics/effects.lua World Conquest].&lt;br /&gt;
&lt;br /&gt;
[effect] uses different keys depending on the value of '''apply_to'''.  '''apply_to''' can take the following values:&lt;br /&gt;
* {{anchor|apply_to-new_attack|'''new_attack'''}}: will use all other keys and tags as the description of an attack that will be added to the unit. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]].&lt;br /&gt;
* {{anchor|apply_to-remove_attacks|'''remove_attacks'''}}: remove the matching attacks. All tags from the attack filter construct will be used to match the attack; see [[FilterWML#Filtering Weapons|FilterWML]]. Do not use a [filter] tag otherwise it will not work properly.&lt;br /&gt;
* {{anchor|apply_to-attack|'''attack'''}}: find an attack and modify it.  All tags from the attack filter construct will be used to match the attack; see [[FilterWML#Filtering Weapons|FilterWML]].  After that, the following keys and tags can be used to modify the attack.  Note: do not use a [filter] tag.  Just put the keys you want to filter on inside the [effect] tag.&lt;br /&gt;
** '''set_name''': change the attack's name (ie identifier).&lt;br /&gt;
** '''set_description''': change the attack's description (ie displayed name). &lt;br /&gt;
** '''set_type''': change the attack type. The standard values are '''blade''', '''pierce''', '''impact''', '''fire''', '''cold''', and '''arcane'''.&lt;br /&gt;
** '''set_range''': change the attack range. The standard values are '''ranged''' and '''melee'''.&lt;br /&gt;
** '''set_icon''': change the attack's icon.&lt;br /&gt;
** {{anchor|set_specials|'''[set_specials]'''}}: change the attack's specials. The specials to add are given exactly as in the [[AbilitiesWML#The_.5Bspecials.5D_tag|[specials]]] tag.&lt;br /&gt;
*** '''mode''': if '''append''', adds the given specials to the attack. If '''replace''', replaces the existing specials with the given ones. Default '''replace'''.&lt;br /&gt;
**** {{DevFeature1.15|3}} A deprecation warning is triggered unless the '''mode''' attribute is set, although the effect will still be '''replace'''. This is to allow the default to change in the 1.17.x series.&lt;br /&gt;
** '''remove_specials''': remove the listed specials. The value of this key is the comma-separated list of the id of the specials to remove. This key is always evaluated before a [set_specials] tags in the same [effect]&lt;br /&gt;
** '''[remove_specials]''': {{DevFeature1.19|6}} remove the listed specials. Use [[StandardAbilityFilter]], special removed if matches. This tag is always evaluated before a [set_specials] tags in the same [effect]&lt;br /&gt;
** '''increase_damage''': increases the attack's damage.  This can be positive or negative, so you can use it to decrease damage as well.  If it ends in a percent(''''%''''), the change in damage will be a percentage ratio of the attack's original damage.&lt;br /&gt;
** '''increase_attacks''': increases the number of attack strikes. Like '''increase_damage''', it can be positive or negative, or a percentage.&lt;br /&gt;
** '''increase_accuracy''': increases the attack accuracy; can be positive or negative, or a percentage&lt;br /&gt;
** '''increase_parry''': increases the attack parry bonus; can be positive or negative, or a percentage&lt;br /&gt;
** '''increase_movement_used''': {{DevFeature1.13|2}} increases the movement points used by the attack; can be positive or negative, or a percentage&lt;br /&gt;
** '''increase_attacks_used''': {{DevFeature1.17|13}} increases the attack points used by the attack; can be positive or negative, or a percentage&lt;br /&gt;
** '''set_damage''' {{DevFeature1.13|2}} like increase_damage, but sets the damage to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_attacks''' {{DevFeature1.13|2}} like increase_attacks, but sets the attacks to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_accuracy''' {{DevFeature1.13|2}} like increase_accuracy, but sets the accuracy to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_parry''' {{DevFeature1.13|2}} like increase_parry, but sets the parry to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_movement_used''' {{DevFeature1.13|2}} like increase_movement_used, but sets the movement used to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''set_attacks_used''' {{DevFeature1.17|13}} like increase_attacks_used, but sets the attacks used to a specific value instead of setting it relative to its original value&lt;br /&gt;
** '''attack_weight''': change the attack's attack_weight. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]] for explanations about attack_weight.&lt;br /&gt;
** '''defense_weight''': change the attack's defense_weight. See [attack] in [[UnitTypeWML#Attacks|UnitTypeWML]] for explanations about defense_weight.&lt;br /&gt;
** '''set_min_range''' {{DevFeature1.19|4}} modify required distance between units in order to allow using attack&lt;br /&gt;
** '''set_max_range''' {{DevFeature1.19|4}} modify required distance between units in order to allow using attack&lt;br /&gt;
** '''increase_min_range''' {{DevFeature1.19|4}} modify required distance between units in order to allow using attack&lt;br /&gt;
** '''increase_max_range''' {{DevFeature1.19|4}} modify required distance between units in order to allow using attack&lt;br /&gt;
* {{anchor|apply_to-max_attacks|'''max_attacks'''}}: {{DevFeature1.13|2}} change the unit's maximum attacks per turn&lt;br /&gt;
** '''increase''': how much to increase by; can be positive or negative, or a percentage&lt;br /&gt;
* {{anchor|apply_to-hitpoints|'''hitpoints'''}}: modifies the unit's HP and/or max HP.&lt;br /&gt;
** '''increase''': the amount to increase the unit's HP.&lt;br /&gt;
** '''set''': the new amount of the unit's HP.&lt;br /&gt;
** '''heal_full''': if present  and not set to &amp;quot;no&amp;quot; the unit will be put back to full HP.&lt;br /&gt;
** '''increase_total''': will increase the total HP of the unit.  Can be specified either as a negative or a positive value.  It can also be specified as a percentage of the current total; i.e. &amp;quot;-50%&amp;quot; will cut max HP in half.&lt;br /&gt;
** '''set_total''': will set the unit's max HP to the specified value.&lt;br /&gt;
** '''violate_maximum''': if the unit ends up with more than its max HP after these modifications, and this key is present (set to any non-null value, ex. '''yes'''), the unit's HP won't be lowered to its max HP.&lt;br /&gt;
* {{anchor|apply_to-movement|'''movement'''}}: modifies the unit's movement points.&lt;br /&gt;
** '''increase''': maximum movement is increased by this amount. It can be positive, negative, or specified as a percentage.&lt;br /&gt;
** '''set''': maximum movement is set to a specific value.&lt;br /&gt;
** '''apply_to_vision''': {{DevFeature1.15|13}} if set to '''yes''' (which is the default), then the vision points will change by the same amount. See [[#Movement_and_Vision|Movement and Vision]].&lt;br /&gt;
* {{anchor|apply_to-vision|'''vision'''}}: {{DevFeature1.13|2}} modifies the unit's vision points. Note: this has side effects described in [[#Movement_and_Vision|Movement and Vision]].&lt;br /&gt;
** '''increase''': maximum vision is increased by this amount. It can be positive, negative, or specified as a percentage.&lt;br /&gt;
** '''set''': maximum vision is set to a specific value. &lt;br /&gt;
* {{anchor|apply_to-jamming|'''jamming'''}}: {{DevFeature1.13|2}} modifies the unit's jamming points.&lt;br /&gt;
** '''increase''': maximum jamming is increased by this amount. It can be positive, negative, or specified as a percentage.&lt;br /&gt;
** '''set''': maximum jamming is set to a specific value.&lt;br /&gt;
* {{anchor|apply_to-experience|'''experience'''}}: affects the unit's current XP.&lt;br /&gt;
** '''increase''': current XP is increased by this amount. It can be positive, negative, or specified as a percentage.&lt;br /&gt;
** '''set''': current XP is set to a specific value.&lt;br /&gt;
* {{anchor|apply_to-max_experience|'''max_experience'''}}: affects the amount of XP the unit needs for the next level.&lt;br /&gt;
** '''increase''': how to change the xp; again it can be negative, positive or a percentage.&lt;br /&gt;
** '''set''': current max XP is set to a specific value.&lt;br /&gt;
* {{anchor|apply_to-loyal|'''loyal'''}}: no keys associated. The affected unit will be loyal i.e have an upkeep of 0.&lt;br /&gt;
* {{anchor|apply_to-fearless|'''fearless'''}}: Add/Remove fearless attribute.&lt;br /&gt;
** '''set''': new value for fearless (boolean). Defaults to '''yes'''.&lt;br /&gt;
* {{anchor|apply_to-healthy|'''healthy'''}}: Add/Remove healthy attribute.&lt;br /&gt;
** '''set''': new value for healthy (boolean). Defaults to '''yes'''.&lt;br /&gt;
* {{anchor|apply_to_movement_costs|'''movement_costs'''}}: speed through specific terrain is modified&lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed). Defaults to '''no'''.&lt;br /&gt;
** '''[movement_costs]''': a subtag that describes the new movement costs just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-vision_costs|'''vision_costs'''}}: vision through specific terrain is modified&lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed). Defaults to '''no'''.&lt;br /&gt;
** '''[vision_costs]''': a subtag that describes the new vision costs just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-jamming_costs|'''jamming_costs'''}}: jamming through specific terrain is modified&lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values (negative values allowed). Defaults to '''no'''.&lt;br /&gt;
** '''[jamming_costs]''': a subtag that describes the new jamming costs just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-defense|'''defense'''}}: Sets the unit's chance to be hit in specific terrain (100 - the unit's defense as shown in-game). &lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values. In most cases, adding a positive number makes the unit easier to hit, while adding a negative number makes the unit harder to hit. The new value is added to the absolute value of the old, and the sign of the old value is preserved. Defaults to '''no'''.&lt;br /&gt;
** '''[defense]''': a subtag that describes the new defense just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-resistance|'''resistance'''}}: Sets percent damage taken from combat (100 - the unit's resistance as shown in-game)&lt;br /&gt;
** '''replace''': If set to &amp;quot;yes&amp;quot;, any new values replace the old ones. Otherwise, new values are added to old values. Adding a positive number makes the unit take more damage, while adding a negative number makes the unit take less damage. Defaults to '''no'''.&lt;br /&gt;
** '''[resistance]''': a subtag that describes the new resistance just like under [[UnitsWML#.5Bmovetype.5D|[movetype]]] if replace is set to &amp;quot;yes&amp;quot; or the addition if &amp;quot;no&amp;quot;.&lt;br /&gt;
* {{anchor|apply_to-variation|'''variation'''}}: switches the unit into one of its variations. Similar to the '''type''' effect below, this might not behave properly outside of [advancement].&lt;br /&gt;
** '''name''': the id of the variation to invoke. &lt;br /&gt;
* {{anchor|apply_to-type|'''type'''}}: transforms the unit into a new unit_type. This does not work in [trait]; in ActionWML it's recommended to use [transform_unit] instead of an [object] with this effect. This effect cannot be undone with [remove_object].&lt;br /&gt;
** '''name''': the id of the unit_type to invoke.&lt;br /&gt;
* {{anchor|apply_to-status|'''status'''}}: modifies the status affecting the unit.&lt;br /&gt;
** '''add''': a list of status modifications to add. Beware, these may be reapplied later, such as when the unit is recalled or levels up; if in an event, you can use [[InternalActionsWML|[store_unit]]] and [[DirectActionsWML|[unstore_unit]]], modifying unit.status.name directly, to avoid this, or if you are creating the unit, you can just add it to the unit's [status] tag in the [unit] tag.  These are listed in [status], [[SingleUnitWML]].&lt;br /&gt;
** '''remove''': a list of status modifications to remove.&lt;br /&gt;
* {{anchor|apply_to-zoc|'''zoc'''}}: toggle the zone of control.&lt;br /&gt;
** '''value''': new value for zoc (boolean).&lt;br /&gt;
* {{anchor|apply_to-profile|'''profile'''}}: customize the profile of the unit. See [[UnitTypeWML]].&lt;br /&gt;
** '''portrait''': new image to display when the unit speaks.&lt;br /&gt;
** '''small_portrait''': new image to display in unit reports.&lt;br /&gt;
** '''description''': sets the text to display when hovering over the unit's type in the righthand pane.&lt;br /&gt;
** '''[special_note]''': {{DevFeature1.15|2}} Adds or removes a special note in the unit's description.&lt;br /&gt;
*** '''remove''': A boolean value specifying whether to add or remove a note. Defaults to '''no'''.&lt;br /&gt;
*** '''note''' (translatable): The text of the note you want to add or remove. If removing a note, this must be an exact match, character-for-character, for the note you want to remove, and must also be in the same textdomain.&lt;br /&gt;
*** Since the tag name is the same, notes can also be added using the standard special note macros, eg '''{NOTE_HEALS}'''.&lt;br /&gt;
*** To remove a note, you can simply suffix '''{NOTE_REMOVE}''' to the regular note macro, eg '''{NOTE_HEALS}{NOTE_REMOVE}'''.&lt;br /&gt;
* {{anchor|apply_to-new_ability|'''new_ability'''}}: Adds one or more abilities to a unit.&lt;br /&gt;
** '''[abilities]''': A subtag that contains the ability definitions.&lt;br /&gt;
* '''remove_ability''': Removes one or more abilities from a unit. Abilities are not reference counted. Adding twice and removing once still means the ability is gone.&lt;br /&gt;
** '''[abilities]''': A subtag that contains the ability definitions. Strictly speaking, all that is needed is the id= inside some tag. {{DevFeature1.17|17}} This is now deprecated, use [experimental_filter_ability] instead.&lt;br /&gt;
** {{DevFeature1.17|17}} '''[experimental_filter_ability]''': [[StandardAbilityFilter]] to match the abilities to remove.&lt;br /&gt;
* {{anchor|apply_to-new_animation|'''new_animation'''}}: contain animations that will be added to the unit, it can contain multiple animation blocks, and a single &amp;quot;id=&amp;quot; line. That Id should be unique for each effect block and is used by the engine to reuse WML parsing, making the loading faster. See [[AnimationWML]] for further reference.&lt;br /&gt;
* {{anchor|apply_to-image_mod|'''image_mod'''}}: modify the image path function ([[ImagePathFunctions]]) of all the unit's frames. Due to a bug, the effect is permanent even inside [object]duration=turn&lt;br /&gt;
** '''replace''': replaces the image path function(s) to be used, e.g. &amp;quot;RC(magenta&amp;gt;red)&amp;quot;&lt;br /&gt;
** '''add''': adds an image path function without removing any existing ones.&lt;br /&gt;
** If needed, you can also define new [[GameConfigWML#Color_Palettes|color palettes]] here.&lt;br /&gt;
* {{anchor|apply_to-ellipse|'''ellipse'''}}: Change the image used for the unit's ellipse.&lt;br /&gt;
** '''ellipse''' : the new image base path to use. Defaults to '''misc/ellipse'''. Can be set to '''none''' to disable the ellipse. An ellipse consist of a top and bottom part so by default in the simplest case the game will look for image files misc/ellipse-top.png and misc/ellipse-bottom.png. This can get further modified based on if the unit is a leader (can_recruit), does the unit emit a zone of control (ZoC) and/or is the unit selected. For a unit that is a leader, emits no ZoC and is currently selected the used files would then be misc/ellipse-leader-nozoc-selected-top.png and misc/ellipse-leader-nozoc-selected-bottom.png.&lt;br /&gt;
* {{anchor|apply_to-halp|'''halo'''}}: Change the image used for the unit's halo.&lt;br /&gt;
** '''halo''': the new image to use.&lt;br /&gt;
* {{anchor|apply_to-overlay|'''overlay'''}}: Change the unit's overlays.&lt;br /&gt;
**'''add''': the specified overlay will be added to the unit's overlays. It can be a comma separated list with multiple overlays. ''Note: overlays added in this way cannot be removed by [remove_unit_overlay] until the effect's duration is over.''&lt;br /&gt;
**'''replace''': all the unit's overlays will be removed and replaced with the specified one. Again, it can be a comma separated list. ''Note: overlays replaced in this way cannot be modified by [unit_overlay] or [remove_unit_overlay] until the effect's duration is over.''&lt;br /&gt;
**'''remove''': {{DevFeature1.15|0}} the specified overlay will be removed from the unit's overlays. It can be a comma separated list with multiple overlays.&lt;br /&gt;
** {{DevFeature1.15|0}} [unit_overlay] and [remove_unit_overlay] are now equivalent to adding a permanent object with this effect, after checking if the unit already has / already doesn't have the overlay (effects with temporary durations will cause false positives / false negatives in this check).&lt;br /&gt;
* {{anchor|apply_to-recall_cost|'''recall_cost'''}}: {{DevFeature1.13|2}} change a unit's recall cost&lt;br /&gt;
** '''set''': set recall cost to a specific value, or a percentage of original value&lt;br /&gt;
** '''increase''': alter recall cost relative to original value; can be positive or negative, or a percentage&lt;br /&gt;
* {{anchor|apply_to-alignment|'''alignment'''}}: {{DevFeature1.13|2}} change a unit's alignment&lt;br /&gt;
** '''set''': the new alignment (one of chaotic, lawful, neutral, liminal)&lt;br /&gt;
* {{anchor|apply_to-new_advancement|'''new_advancement'''}}: {{DevFeature1.13|2}} add new advancement choices to the unit&lt;br /&gt;
** '''replace''': whether to replace existing advancement choices; if this key is set to yes, existing advancement choices are cleared only if you're adding a choice of the same type. (That is, unit type advancements are cleared only if you're adding a new unit advancement choice, and AMLA choices are cleared only if you're adding new AMLA choices.)&lt;br /&gt;
** '''types''': a comma-separated list of additional unit types the unit can advance to. ('''Note:''' If using this, you probably want to include a filter to prevent the unit from being able to advance to this type once it has already done so.)&lt;br /&gt;
** '''[advancement]''': an advancement choice to add, see [[UnitTypeWML#After_max_level_advancement_(AMLA)|AMLAs]]; you can have several of these tags to add multiple advancement choices at the same time.&lt;br /&gt;
* {{anchor|apply_to-remove_advancement|'''remove_advancement'''}}: {{DevFeature1.13|2}} remove existing advancement choices from the unit&lt;br /&gt;
** '''types''': a list of unit type advancements to remove as a possibility&lt;br /&gt;
** '''amlas''': a list of AMLA id attributes; any advancement possibility with the given id will be removed&lt;br /&gt;
* {{anchor|apply_to-level|'''level'''}}: {{DevFeature1.17|15}} change a unit's level. '''Note:''' this key is incompatible with ''times=per level''; if this combination is used, the engine reports a warning and uses ''times=1'' as fallback value&lt;br /&gt;
** '''set''': set level to a specific value; can be positive or negative, but not a percentage&lt;br /&gt;
** '''increase''': alter level relative to original value; can be positive or negative, but not a percentage&lt;br /&gt;
&lt;br /&gt;
== Movement and Vision ==&lt;br /&gt;
&lt;br /&gt;
Wesnoth 1.14 introduced vision points; by default units have the same number of vision points as their max movement points. However, combining effects that change vision with effects that change movement had edge cases which were reworked in 1.16:&lt;br /&gt;
&lt;br /&gt;
Consider a unit with 5 mp, and default vision:&lt;br /&gt;
* It has (effectively) 5 mp and 5 vp.&lt;br /&gt;
* After (mp + 1), it will have 6 mp and 6 vp.&lt;br /&gt;
* After (vp + 2), it will have 5 mp and 7 vp.&lt;br /&gt;
&lt;br /&gt;
In 1.14, using an effect with apply_to=vision breaks the link between vision and movement:&lt;br /&gt;
* After (mp + 1) (vp + 2), it will have 6 mp and 8 vp.&lt;br /&gt;
* After (vp + 2) (mp + 1), it will have 6 mp and 7 vp.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|13}}, [effect]apply_to=movement has another attribute apply_to_vision, which defaults to true. With that change, the order that the effects are applied in doesn't matter:&lt;br /&gt;
* After (mp + 1) (vp + 2), it will have 6 mp and 8 vp.&lt;br /&gt;
* After (vp + 2) (mp + 1), it will have 6 mp and 8 vp.&lt;br /&gt;
&lt;br /&gt;
Increasing movement by 50% increases vision by (50% of movement) not by (50% of vision). For a unit that started with 6 mp and 8 vp, the following effect would give it 9 mp and 11 vp.&lt;br /&gt;
    [effect]&lt;br /&gt;
        apply_to=movement&lt;br /&gt;
        increase=50%&lt;br /&gt;
    [/effect]&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Effect: apply_to = new_animation  ===&lt;br /&gt;
This is the only way to change animations of units after they have been placed on the map.&lt;br /&gt;
In this example, I add very simple idle animation (taken from Goblin Spearman) to the unit, which moves to hex (x=1, y=5). If you want something more complex, you need to check [[AnimationWML]] page.&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
    name=moveto&lt;br /&gt;
    [filter]&lt;br /&gt;
        x,y = 1,5&lt;br /&gt;
    [/filter]&lt;br /&gt;
    [object]&lt;br /&gt;
        [filter]&lt;br /&gt;
            x,y=1,5&lt;br /&gt;
        [/filter]&lt;br /&gt;
        [effect]&lt;br /&gt;
            apply_to=new_animation&lt;br /&gt;
            [idle_anim]&lt;br /&gt;
                {STANDARD_IDLE_FILTER}&lt;br /&gt;
                start_time=0&lt;br /&gt;
                [frame]&lt;br /&gt;
                    image=&amp;quot;units/goblins/spearman-idle-[1~12].png:[150*3,300,150*8]&amp;quot;&lt;br /&gt;
                [/frame]&lt;br /&gt;
            [/idle_anim]&lt;br /&gt;
        [/effect]&lt;br /&gt;
    [/object]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you are going to use '''advanced WML''' and want to add animation to unit, stored in variable, then following example might help you. '''This way is not efficient if you have no additional logic like inventoriy, shops, advanced unit modifications in your add-on.''' Is is preferred to use first variant or define all needed animation in unit_type.&lt;br /&gt;
&amp;lt;syntaxhighlight lang='wml'&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
    name=moveto&lt;br /&gt;
    [filter]&lt;br /&gt;
        x,y=1,5&lt;br /&gt;
    [/filter]&lt;br /&gt;
    [store_unit]&lt;br /&gt;
        [filter]&lt;br /&gt;
            x,y=1,5&lt;br /&gt;
        [/filter]&lt;br /&gt;
        variable=stored_unit&lt;br /&gt;
    [/store_unit]&lt;br /&gt;
    [set_variables]&lt;br /&gt;
        name=stored_unit.modifications.object&lt;br /&gt;
        [value]&lt;br /&gt;
            [effect]&lt;br /&gt;
                apply_to=new_animation&lt;br /&gt;
                [idle_anim]&lt;br /&gt;
                    {STANDARD_IDLE_FILTER}&lt;br /&gt;
                    start_time=0&lt;br /&gt;
                    [frame]&lt;br /&gt;
                        image=&amp;quot;units/goblins/spearman-idle-[1~12].png:[150*3,300,150*8]&amp;quot;&lt;br /&gt;
                    [/frame]&lt;br /&gt;
                [/idle_anim]&lt;br /&gt;
            [/effect]&lt;br /&gt;
        [/value]&lt;br /&gt;
    [/set_variables]&lt;br /&gt;
    [unstore_unit]&lt;br /&gt;
        variable=stored_unit&lt;br /&gt;
    [/unstore_unit]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Where to Use Effects ==&lt;br /&gt;
&lt;br /&gt;
A collection of effects together makes up a &amp;quot;unit modification&amp;quot;, which is encased in one of the three types of modification tags: '''[trait]''', '''[object]''', or '''[advancement]'''. Which tag to use depends on the goal of the modification.&lt;br /&gt;
&lt;br /&gt;
* [[UnitsWML#.5Btrait.5D|Traits]] are shown in the unit details on the sidebar. They can be placed in a race or unit type to include the trait in the pool of random traits for that race or unit type, or they can be placed in the global [units] tag to add them to the global pool of random traits. (Note that this can cause out-of-sync errors in multiplayer.)&lt;br /&gt;
* [[UnitTypeWML#After_max_level_advancement_.28AMLA.29|Advancements]] are offered when a unit levels up. If a unit type has both modification advancements and regular advancements, the player can choose either each time they level up.&lt;br /&gt;
* [[DirectActionsWML#.5Bobject.5D|Objects]] are usually placed on the map or added by special events. They also have a built-in facility to automatically remove under certain conditions.&lt;br /&gt;
&lt;br /&gt;
An effect can also be placed in '''[modify_unit]''' [[DirectActionsWML#.5Bmodify_unit.5D|ActionWML]] to apply it on-the-fly without keeping a record that it has been applied. This is mainly useful for effects that change transient properties such as current hitpoints or experience. An effect applied in this way is liable to be reverted when the unit is rebuilt in the future, for example when they level up or when an object is removed.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[UnitTypeWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
* [[AnimationWML]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=LuaAPI/wml&amp;diff=74506</id>
		<title>LuaAPI/wml</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=LuaAPI/wml&amp;diff=74506"/>
		<updated>2025-08-31T18:02:02Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* wml.matches_filter */ Linkify&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;tright&amp;quot;&amp;gt; __TOC__ &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;wml&amp;lt;/tt&amp;gt; module contains functions for working with WML tables. This module is available starting in 1.14.0.&lt;br /&gt;
&lt;br /&gt;
A WML table is a specially-formatted Lua table representing WML tags and values. For more detail on the format of WML tables, see [[LuaWML#Encoding_WML_objects_into_Lua_tables|LuaWML]].&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
&lt;br /&gt;
=== wml.attribute_count ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.attribute_count'''(''config'') &amp;amp;rarr; ''count''&lt;br /&gt;
&lt;br /&gt;
Returns the number of attributes in the specified WML table.&lt;br /&gt;
&lt;br /&gt;
=== wml.child_array ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.child_array'''(''config'', ''child_tag_name'') &amp;amp;rarr; ''array''&lt;br /&gt;
&lt;br /&gt;
Like [[#wml.child_range]], but returns an array instead of an iterator. Useful if you need random access to the children.&lt;br /&gt;
&lt;br /&gt;
=== wml.child_count ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.child_count'''(''config'', ''child_tag_name'') &amp;amp;rarr; ''count''&lt;br /&gt;
&lt;br /&gt;
Returns the number of children in the config with the given tag name.&lt;br /&gt;
&lt;br /&gt;
=== wml.child_range ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.child_range'''(''config'', ''child_tag_name'') &amp;amp;rarr; ''iterator'' &amp;amp;rArr; ''wml table''&lt;br /&gt;
&lt;br /&gt;
Returns an iterator over all the sub-tags of a WML object with the given name.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
local u = wesnoth.units.find_on_map{ id = &amp;quot;Delfador&amp;quot; }[1]&lt;br /&gt;
for att in wml.child_range(u.__cfg, &amp;quot;attack&amp;quot;) do&lt;br /&gt;
    wesnoth.message(tostring(att.description))&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.find_child ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.find_child'''(''config'', [''tag_name''], ''filter'') &amp;amp;rarr; ''child or nil'', ''index''&lt;br /&gt;
&lt;br /&gt;
Finds a child of the given config that matches the given filter, and returns the child or nil if not found. The index of the child is also returned. If a tag name is specified, the search is restricted to that tag.&lt;br /&gt;
&lt;br /&gt;
=== wml.get_child ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.get_child'''(''config'', ''child_tag_name'', [''id'']) &amp;amp;rarr; ''child_table''&lt;br /&gt;
&lt;br /&gt;
Returns the first sub-tag of a WML object with the given name.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
local u = wesnoth.units.find_on_map{ id = &amp;quot;Delfador&amp;quot; }[1]&lt;br /&gt;
local costs = wml.get_child(u.__cfg, &amp;quot;movement_costs&amp;quot;)&lt;br /&gt;
wesnoth.message(string.format(&amp;quot;Delfador needs %d points to move through a forest.&amp;quot;, costs.forest))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a third parameter is passed, only children having a ''id'' attribute equal to it are considered.&lt;br /&gt;
&lt;br /&gt;
=== wml.get_nth_child ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.get_nth_child'''(''config'', ''child_tag_name'', ''n'') &amp;amp;rarr; ''child_table''&lt;br /&gt;
&lt;br /&gt;
Returns the ''n''th sub-tag of a WML object with the given name.&lt;br /&gt;
&lt;br /&gt;
=== wml.remove_child ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.remove_child'''(''config'', ''child_tag_name'')&lt;br /&gt;
&lt;br /&gt;
Deletes the first child tag with the given name. This does not work on vconfig objects, however.&lt;br /&gt;
&lt;br /&gt;
=== wml.remove_children ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.17|0}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.remove_children'''(''config'', ''child_tag_name'', ...)&lt;br /&gt;
&lt;br /&gt;
Deletes all child tags with the given names. This does not work on vconfig objects, however. You can pass as many tag names as you want as separate arguments.&lt;br /&gt;
&lt;br /&gt;
=== wml.tag ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.tag'''.''tag_name''(''contents'') &amp;amp;rarr; ''tag_table''&lt;br /&gt;
&lt;br /&gt;
Returns a table representing a tag within a WML table; can be used to create subtags with less brackets. It's common to use direct-table invocation for this, omitting the function parentheses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
wesnoth.wml_actions.event { name = &amp;quot;new turn&amp;quot;, wml.tag.message { speaker = &amp;quot;narrator&amp;quot;, message = &amp;quot;?&amp;quot; } }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.clone ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|0}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.clone'''(''wml_table'') &amp;amp;rarr; ''cloned_table''&lt;br /&gt;
&lt;br /&gt;
Returns a clone (deep copy) of the passed WML table.&lt;br /&gt;
&lt;br /&gt;
=== wml.equal ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.equal'''(''config'', ''config'') &amp;amp;rarr; ''true or false''&lt;br /&gt;
&lt;br /&gt;
Tests whether two WML objects are equal. Equal objects will produce an empty diff, and will be serialized to the same string.&lt;br /&gt;
&lt;br /&gt;
=== wml.valid ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.valid'''(''table'') &amp;amp;rarr; ''is_wml''&lt;br /&gt;
&lt;br /&gt;
Tests whether the passed table represents a valid WML table. It will also return true if passed a vconfig.&lt;br /&gt;
&lt;br /&gt;
=== wml.matches_filter ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.matches_filter'''(''WML table'', ''filter'')''' &amp;amp;rarr; ''boolean''&lt;br /&gt;
&lt;br /&gt;
Test if a config matches a WML filter (as [[FilterWML#Filtering_on_WML_data|&amp;lt;tt&amp;gt;[filter_wml]&amp;lt;/tt&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
=== wml.load ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|0}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.load'''(''file'', [''defines'', [''schema'']]) &amp;amp;rarr; ''config''&lt;br /&gt;
&lt;br /&gt;
Loads WML from a file and optionally validates it against a schema. The file and schema (if present) must both be a valid WML path, and the schema must point to a [[SchemaWML]] file. All built-in schema files can be found directly in the &amp;quot;schema&amp;quot; folder – for example, &amp;quot;schema/game_config.cfg&amp;quot; is the schema for an add-on's (and core's) _main.cfg.&lt;br /&gt;
&lt;br /&gt;
The second parameter can either be a boolean specifying whether or not to preprocess the file (defaults to true), or an array of macros to be defined in the preprocessor (which of course implies the file will be preprocessed). The second form only allows specifying names to be defined. It does not allow setting a value or anything more complex.&lt;br /&gt;
&lt;br /&gt;
=== wml.parse ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|0}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.parse'''(''string'', [''schema'']) &amp;amp;rarr; ''config''&lt;br /&gt;
&lt;br /&gt;
Parses a string containing WML code and optionally validates it against the provided schema. Unlike load, this function does ''not'' run the preprocessor, though &amp;lt;tt&amp;gt;#textdomain&amp;lt;/tt&amp;gt; directives will still be recognized.&lt;br /&gt;
&lt;br /&gt;
=== wml.merge ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.merge'''(''base table'', ''merge data'', [''mode'']) &amp;amp;rarr; ''merged config''&lt;br /&gt;
&lt;br /&gt;
Merges two WML tables recursively, using the specified mode. Possible modes are '''merge''', '''replace''', and '''append'''. The modes work the same as in [[InternalActionsWML#.5Bset_variables.5D|[set_variables]]]. The mode only affects how child tags are merged; merging of attributes is always done the same way. The default mode is '''merge'''.&lt;br /&gt;
&lt;br /&gt;
=== wml.diff ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.diff'''(''left'', ''right'') &amp;amp;rarr; ''diff config''&lt;br /&gt;
&lt;br /&gt;
Compares two WML tables and produces an output table in [[DiffWML]] detailing their differences.&lt;br /&gt;
&lt;br /&gt;
=== wml.patch ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.patch'''(''base'', ''diff'') &amp;amp;rarr; ''patched config''&lt;br /&gt;
&lt;br /&gt;
Takes a WML table and a diff in [[DiffWML]] format and returns a new WML table modified according to the diff's instructions.&lt;br /&gt;
&lt;br /&gt;
=== wml.interpolate ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|3}}&lt;br /&gt;
&lt;br /&gt;
* '''wml.interpolate'''('''template''', '''variables''') &amp;amp;rarr; ''interpolated config''&lt;br /&gt;
&lt;br /&gt;
Interpolates variables into a WML table, including '''[insert_tag]'''. This is the same as what a vconfig does implicitly, but can use any valid WML table as a source of variables.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
local variables = {&lt;br /&gt;
  -- A scalar variable&lt;br /&gt;
  number = 100,&lt;br /&gt;
  -- An array variable with two entries&lt;br /&gt;
  wml.tag.list{value = 42, rank = 3},&lt;br /&gt;
  wml.tag.list{value = 21, rank = 1},&lt;br /&gt;
}&lt;br /&gt;
local subst = {&lt;br /&gt;
  key = &amp;quot;$number&amp;quot;,&lt;br /&gt;
  wml.tag.insert_tag{&lt;br /&gt;
    name = &amp;quot;entry&amp;quot;,&lt;br /&gt;
    variable = &amp;quot;list&amp;quot;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
local result = wml.interpolate(subst, variables)&lt;br /&gt;
print(wml.tostring(result))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code will output the following WML in the Lua console:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
key=100&lt;br /&gt;
[entry]&lt;br /&gt;
  rank=3&lt;br /&gt;
  value=42&lt;br /&gt;
[/entry]&lt;br /&gt;
[entry]&lt;br /&gt;
  rank=1&lt;br /&gt;
  value=21&lt;br /&gt;
[/entry]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.tostring ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.tostring'''(''wml_table'') &amp;amp;rarr; ''string''&lt;br /&gt;
&lt;br /&gt;
Takes a userdata with metatable wml object or a wml table and dumps its content into a pretty string. {{DevFeature1.15|0}} The string output is syntactically valid WML that if parsed would produce the same config.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
wml.variables[&amp;quot;number&amp;quot;] = 100&lt;br /&gt;
local vconfig = wml.tovconfig({ key = &amp;quot;$number&amp;quot;, another_key = true,&lt;br /&gt;
    {&amp;quot;a_subtag&amp;quot;, { a_key_in_the_subtag = &amp;quot;foo&amp;quot; }}&lt;br /&gt;
})&lt;br /&gt;
wesnoth.message(wml.tostring(vconfig))&lt;br /&gt;
wesnoth.message(wml.tostring(vconfig.__literal))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.tovconfig ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.tovconfig'''(''config'') &amp;amp;rarr; ''vconfig''&lt;br /&gt;
&lt;br /&gt;
Converts a WML table into a proxy object which performs variable substitution on the fly. The proxy object can for most intents and purposes be treated as a read-only table - the length operator works as expected, as does the ipairs function. The pairs function also works, but it is a little different than on a plain table - it will return only the attributes of the vconfig and not the tags. See [[LuaWML#Encoding_WML_objects_into_Lua_tables|LuaWML]] for more information about the structure of a vconfig (which is the same as the structure of a WML table). A vconfig has four special keys (''__literal'', ''__parsed'', ''__shallow_literal'', ''__shallow_parsed'') which correspond to the functions in this module by the same name, but in most cases it is better to use the functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
wml.variables[&amp;quot;varname&amp;quot;] = &amp;quot;to_be_deleted&amp;quot;&lt;br /&gt;
&lt;br /&gt;
-- correct&lt;br /&gt;
wesnoth.wml_actions.clear_variable { name = &amp;quot;to_be_deleted&amp;quot; }&lt;br /&gt;
-- error: try to delete a variable literally called &amp;quot;$varname&amp;quot;&lt;br /&gt;
wesnoth.wml_actions.clear_variable { name = &amp;quot;$varname&amp;quot; }&lt;br /&gt;
-- correct: &amp;quot;$varname&amp;quot; is replaced by &amp;quot;to_be_deleted&amp;quot; at the right time&lt;br /&gt;
wesnoth.wml_actions.clear_variable(wml.tovconfig { name = &amp;quot;$varname&amp;quot; })&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.literal ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.literal'''(''config'') &amp;amp;rarr; ''wml_table''&lt;br /&gt;
&lt;br /&gt;
Returns the ''__literal'' field of its argument if it is a userdata, the argument itself otherwise. If the argument is ''nil'', it returns an empty table. This function is meant to be called when a WML action handler can be called indifferently from WML (hence receiving a userdata) or from Lua (hence possibly receiving a table).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
function wml_actions.display_literal_value(cfg)&lt;br /&gt;
   cfg = wml.literal(cfg)&lt;br /&gt;
   wesnoth.message(tostring(cfg.value)) &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: when the argument is a plain table, the function returns it as is. In particular, modifying the fields of the returned table causes the original table to be modified too.&lt;br /&gt;
&lt;br /&gt;
=== wml.parsed ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.parsed'''(''config'') &amp;amp;rarr; ''wml_table''&lt;br /&gt;
&lt;br /&gt;
Returns the ''__parsed'' field of its argument if it is a userdata, the argument itself otherwise. See also [[#wml.literal]].&lt;br /&gt;
&lt;br /&gt;
=== wml.shallow_literal ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.shallow_literal'''(''config'') &amp;amp;rarr; ''wml_table''&lt;br /&gt;
&lt;br /&gt;
Returns the ''__shallow_literal'' field of its argument if it is a userdata, the argument itself otherwise. See also [[#wml.literal]].&lt;br /&gt;
&lt;br /&gt;
=== wml.shallow_parsed ===&lt;br /&gt;
&lt;br /&gt;
* '''wml.shallow_parsed'''(''config'') &amp;amp;rarr; ''wml_table''&lt;br /&gt;
&lt;br /&gt;
Returns the ''__shallow_parsed'' field of its argument if it is a userdata, the argument itself otherwise. See also [[#wml.literal]].&lt;br /&gt;
&lt;br /&gt;
=== wml.all_variables ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.all_variables''' &amp;amp;rarr; ''table''&lt;br /&gt;
&lt;br /&gt;
Returns a copy of all the WML variables currently set in the form of a WML table.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
for key, value in pairs(wml.all_variables) do&lt;br /&gt;
    if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
        print(key, value[1], value[2])&lt;br /&gt;
    else&lt;br /&gt;
        print(key, value)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.variables ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.variables'''.''variable'' &amp;amp;harr; ''variable_contents''&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.variables'''[''variable_path''] &amp;amp;harr; ''variable_contents''&lt;br /&gt;
&lt;br /&gt;
This table grants read-write access to the WML variables by their fully-qualified name. Looking up a non-existent variable yields nil; otherwise, it returns a scalar for a WML attribute and a table for a WML object. The format of the table is described in [[LuaWML#Encoding WML objects into Lua tables]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
wesnoth.fire(&amp;quot;store_unit&amp;quot;, { variable=&amp;quot;my_unit&amp;quot;, { &amp;quot;filter&amp;quot;, { id=&amp;quot;hero&amp;quot; } } })&lt;br /&gt;
local heros_hp = wml.variables[&amp;quot;my_unit[0].hitpoints&amp;quot;]&lt;br /&gt;
wesnoth.message(string.format(&amp;quot;The 'hero' unit has %d hitpoints.&amp;quot;, heros_hp))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that, if the variable name happens to designate a sequence of WML objects, only the first one (index 0) is fetched. If all the WML objects with this name should have been returned, use [[#wml.array_access.get]] instead. If you need a specific one, include the index in the lookup key.&lt;br /&gt;
&lt;br /&gt;
Assigning to a key in this table converts the Lua object to a WML variable if possible. For a table, a WML object is created; otherwise, an attribute is created. Note that you cannot assign a simple array as it will be mistaken for a WML table and give an error. Assigning nil clears the variable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
wml.variables[&amp;quot;my_unit.hitpoints&amp;quot;] = heros_hp + 10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.variables_proxy ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.variables_proxy'''.''variable'' &amp;amp;harr; ''proxy''&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.variables_proxy'''[''variable_path''] &amp;amp;harr; ''proxy''&lt;br /&gt;
&lt;br /&gt;
Similar to &amp;lt;tt&amp;gt;wml.variables&amp;lt;/tt&amp;gt;, but if the variable is a container, then the fields of the returned table are then proxies to the WML objects with the same names; reading/writing to them will directly access the WML sub-variables. Note that this is still somewhat experimental and doesn't allow you to fully treat variables as if they were standard Lua tables.&lt;br /&gt;
&lt;br /&gt;
=== wml.array_access.get ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.array_access.get'''(''var_name'', [''context'']) &amp;amp;rarr; ''array of variable_contents''&lt;br /&gt;
&lt;br /&gt;
Fetches all the WML container variables with given name and returns a table containing them (starting at index 1). The context specifies where to get variables from. You can pass either a unit or a side as the context in order to get an array from the unit variables or side variables, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
function get_recall_list(side)&lt;br /&gt;
    wesnoth.fire(&amp;quot;store_unit&amp;quot;, { x = &amp;quot;recall&amp;quot;, variable = &amp;quot;LUA_recall_list&amp;quot; })&lt;br /&gt;
    local l = wml.array_access.get &amp;quot;LUA_recall_list&amp;quot;&lt;br /&gt;
    wml.variables.LUA_recall_list = nil&lt;br /&gt;
    return l&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.array_access.get_proxy ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.array_access.get_proxy'''(''var_name'') &amp;amp;rarr; ''array of proxies''&lt;br /&gt;
&lt;br /&gt;
Creates proxies for all the WML container variables with given name and returns a table containing them (starting at index 1). This function is similar to [[#wml.array_access.get]], except that the proxies can be used for modifying WML containers. Note that changes to the returned array itself will not be reflected in the variable, however; only changes to the array elements.&lt;br /&gt;
&lt;br /&gt;
=== wml.array_access.set ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.array_access.set'''(''varname'', ''array'', [''context''])&lt;br /&gt;
&lt;br /&gt;
Creates WML container variables with given name from given table. The context specifies where to put the variables. You can pass either a unit or a side as the context in order to set an array in the unit variables or side variables, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
wml.array_access.set(&amp;quot;target&amp;quot;, { {t=t1}, {t=t2}, {t=t3} })&lt;br /&gt;
-- target[0].t &amp;lt;- t1; target[1].t &amp;lt;- t2; target[2].t &amp;lt;- t3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== wml.array_variables ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.array_variables'''.''variable'' &amp;amp;harr; ''array of variable_contents''&lt;br /&gt;
* {{LuaGameOnly}}{{LuaMapOnly}} '''wml.array_variables'''[''variable_path''] &amp;amp;harr; ''array of variable_contents''&lt;br /&gt;
&lt;br /&gt;
Like '''wml.variables''', except that it works on arrays as with '''wml.array_access.get''' and '''wml.array_access.set'''. This is a little more convenient when working with global WML variables rather than unit or side variables.&lt;br /&gt;
&lt;br /&gt;
=== wml.eval_conditional ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}} '''wml.eval_conditional'''(''conditional_tags'') &amp;amp;rarr; ''boolean''&lt;br /&gt;
&lt;br /&gt;
Returns true if the conditional described by the WML table passes. Note: WML variables are substituted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
local result = wml.eval_conditional {&lt;br /&gt;
  wml.tag.have_unit { id = &amp;quot;hero&amp;quot; },&lt;br /&gt;
  wml.tag.variable { name = &amp;quot;counter&amp;quot;, numerical_equals = &amp;quot;$old_counter&amp;quot; }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Prior to 1.15.13, this was available as '''wesnoth.eval_conditional'''.&lt;br /&gt;
&lt;br /&gt;
=== wml.fire ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}} '''wml.fire'''(''tag'', ''parameters'')&lt;br /&gt;
* {{DevFeature1.17|17}} {{LuaGameOnly}} '''wml.fire'''.''tag''(''parameters'')&lt;br /&gt;
&lt;br /&gt;
Fire a WML action tag. Note: WML variables are substituted into the parameters table.&lt;br /&gt;
&lt;br /&gt;
Note: Prior to 1.15.13, this was available as '''wesnoth.fire'''. The second form was available through '''helper.set_wml_action_metatable'''.&lt;br /&gt;
&lt;br /&gt;
=== wml.error ===&lt;br /&gt;
&lt;br /&gt;
* {{LuaGameOnly}} '''wml.error'''(''message'')&lt;br /&gt;
&lt;br /&gt;
Interrupts the current execution and displays a WML error message. This is intended for error messages in the implementaton of custom ActionWML or ConditionalWML tags. For errors in a Lua API, the built-in '''error''' function is a more suitable choice.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=lua&amp;gt;&lt;br /&gt;
local names = cfg.name or wml.error(&amp;quot;[clear_variable] missing required name= attribute.&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Lua Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=FilterWML&amp;diff=74505</id>
		<title>FilterWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=FilterWML&amp;diff=74505"/>
		<updated>2025-08-31T18:00:11Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Filtering on WML data */ Render the substituted parts in italics instead of bold&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
== Filtering in WML ==&lt;br /&gt;
&lt;br /&gt;
A ''filter'' is a special WML block.&lt;br /&gt;
Filters are used to describe a set of units, hexes, weapons or something else.&lt;br /&gt;
Filters are defined as matching something if all the keys in the filter match that thing.&lt;br /&gt;
For example, if a unit filter contains two keys,&lt;br /&gt;
a unit must match both of the keys in order to match the filter.&lt;br /&gt;
&lt;br /&gt;
A StandardUnit(Location, Side, ...)Filter is the place where the set of such keys and tags can appear. A StandardFilter sometimes needs an according surrounding tag but often doesn't. It should be mentioned at the place in the wiki where it's said that you can use at a certain code position a StandardFilter whether you need a surrounding tag or not.&lt;br /&gt;
&lt;br /&gt;
== Filtering Units ==&lt;br /&gt;
&lt;br /&gt;
Filters are often used in action tags (see [[EventWML]]).&lt;br /&gt;
In this case the phrase &amp;quot;standard unit filter&amp;quot; is used in place of the set of standard keys.&lt;br /&gt;
Sometimes a filter is used to find the first unit that matches the filter;&lt;br /&gt;
for example, the '''[recall]''' tag recalls that unit.&lt;br /&gt;
&lt;br /&gt;
Standard unit filters are also used in the tags '''[filter]''' and '''[filter_second]'''.&lt;br /&gt;
These are subtags of '''[event]''' which describe when the event should trigger.&lt;br /&gt;
Most event names (see [[EventWML]]) have units related to them called &amp;quot;primary unit&amp;quot; and &amp;quot;secondary unit&amp;quot;.&lt;br /&gt;
In order for an event to be triggered, ''primary unit'' must match the filter contained in '''[filter]''',&lt;br /&gt;
and ''secondary unit'' must match the filter contained in '''[filter_second]'''.&lt;br /&gt;
&lt;br /&gt;
See [[StandardUnitFilter]] for details.&lt;br /&gt;
&lt;br /&gt;
== Filtering Locations ==&lt;br /&gt;
&lt;br /&gt;
As you have seen, standard unit filter can contain a location filter.&lt;br /&gt;
Several actions, such as '''[terrain]''', also use location filters.&lt;br /&gt;
Location filters are represented on this site by the phrase &amp;quot;standard location filter&amp;quot;.&lt;br /&gt;
A common use for location filters is to check the terrain of a space.&lt;br /&gt;
&lt;br /&gt;
See [[StandardLocationFilter]] for details.&lt;br /&gt;
&lt;br /&gt;
== Filtering Sides ==&lt;br /&gt;
Sometimes, it's needed to get a list of sides which satisfy certain criteria. For this, a side filter can be used.&lt;br /&gt;
Side filters are represented on this site by the phrase &amp;quot;standard side filter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
See [[StandardSideFilter]] for details.&lt;br /&gt;
&lt;br /&gt;
== Filtering Weapons ==&lt;br /&gt;
&lt;br /&gt;
Sometimes weapons/attacks are filtered on in WML.  See also [[EventWML]], [[EffectWML]], [[AnimationWML]].&lt;br /&gt;
&lt;br /&gt;
These keys are used as filter input for attack filters.&lt;br /&gt;
&lt;br /&gt;
* '''range''': a range to filter&lt;br /&gt;
** '''melee''': only melee weapons pass &lt;br /&gt;
** '''ranged''': only ranged weapons pass &lt;br /&gt;
* '''name''': filter on the attack's name. See &amp;lt;code&amp;gt;data/units/&amp;lt;/code&amp;gt; to find the name of a particular unit's attack.&lt;br /&gt;
* '''type''': filter on the attack's type. Values are 'blade', 'pierce', 'impact', 'fire', 'cold', and 'arcane' or customised type. {{DevFeature1.17|23}} [damage_type] can change the type of damage inflicted, and this change can be detected in the filter except when it is applied from a [damage_type] which affects the filtered attack, in this case only the type before any modification by a any [damage_type] will be detectable.&lt;br /&gt;
* '''damage''': filter on damage value. Can be a specific number or a list of ranges like 'damage=0-5,7-99'&lt;br /&gt;
* '''special_id''': {{DevFeature1.15|2}} Filter on a weapon special by id, for example, &amp;lt;code&amp;gt;magical&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;[chance_to_hit] id=magical&amp;lt;/code&amp;gt;. True if the unit has the special, whether or not it's currently active.&lt;br /&gt;
* '''special_type''': {{DevFeature1.15|2}} Filter on a weapon special by tag name for example, &amp;lt;code&amp;gt;chance_to_hit&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;[chance_to_hit] id=magical&amp;lt;/code&amp;gt;. True if the unit has the special, whether or not it's currently active. For values see [[AbilitiesWML]].&lt;br /&gt;
* '''special_id_active''': {{DevFeature1.15|2}} Like '''special_id''', but true if the special is active at the current location. Does not work in 1.16. {{DevFeature1.17|17}} Works again.&lt;br /&gt;
* '''special_type_active''': {{DevFeature1.15|2}} Like '''special_type''', but true if the special is active at the current location.&lt;br /&gt;
* '''special''': filter on the attack's special power, matches both id and tag name. {{DevFeature1.15|2}} Deprecated, see '''special_id''' and '''special_type''' instead.&lt;br /&gt;
* '''special_active''': {{DevFeature1.13|8}} Like '''special''', but true if the special is active at the current location. {{DevFeature1.15|2}} Deprecated, see '''special_id''' and '''special_type''' instead.&lt;br /&gt;
* '''[filter_special]''':   {{DevFeature1.19|6}}  Filter on a weapon special by using[[StandardAbilityFilter]]&lt;br /&gt;
** '''active''': if active=yes, true if the special is active at the current location. If active=no, true whether or not it's currently active, in this case, one special encoded in [attack] can be checked.&lt;br /&gt;
* '''number''': {{DevFeature1.13|5}} filter on number of strikes&lt;br /&gt;
* '''parry''': {{DevFeature1.13|5}} filter on parry value&lt;br /&gt;
* '''accuracy''': {{DevFeature1.13|5}} filter on accuracy value&lt;br /&gt;
* '''movement_used''': {{DevFeature1.13|5}} filter on attack's movement cost&lt;br /&gt;
* '''attacks_used''': {{DevFeature1.17|13}} filter on attack's attack cost&lt;br /&gt;
* '''min_range''': {{DevFeature1.19|4}} filter on attack's range (distance)&lt;br /&gt;
* '''max_range''': {{DevFeature1.19|4}} filter on attack's range (distance)&lt;br /&gt;
* '''formula''': {{DevFeature1.13|5}} filter using [[Wesnoth Formula Language]]. The context object for the formula is a '''weapon object''', which supports the following keys: '''name''', '''description''', '''type''', '''icon''', '''range''', '''damage''', '''number''', '''attack_weight''', '''defense_weight''', '''accuracy''', '''parry''', '''movement_used''', '''specials'''. The '''specials''' key is a list of all the special IDs the unit possesses. Do not surround the formula in &amp;lt;code&amp;gt;$(...)&amp;lt;/code&amp;gt;, since that will erase the &amp;lt;tt&amp;gt;self&amp;lt;/tt&amp;gt; variable. Keys supported after specific version: {{DevFeature1.17|13}} '''attacks_used'''. {{DevFeature1.19|4}} '''min_range''', '''max_range'''.&lt;br /&gt;
&lt;br /&gt;
'''[and]''', '''[or]''', and '''[not]''' subfilters are also supported.&lt;br /&gt;
&lt;br /&gt;
== Filtering Vision ==&lt;br /&gt;
&lt;br /&gt;
The '''[filter_vision]''' tag allows you to filter units or locations based on whether or not the hex is obscured by fog or shroud from the point-of-view of a viewing side, and (in the case of units) whether or not the unit is hidden (via the {{tag|AbilitiesWML|hides}} ability).&lt;br /&gt;
&lt;br /&gt;
* '''visible''':&lt;br /&gt;
** '''yes''' (default): matches when the location is not obscured by fog or shroud for the ''side'' and, when in a SUF, the unit is not hiding.&lt;br /&gt;
** '''no''': matches when the location is obscured by fog or shroud for the ''side'' or, when in a SUF, the unit is hiding.&lt;br /&gt;
* '''respect_fog''': yes or no, default yes. In a location filter (only), setting this to &amp;quot;no&amp;quot; will cause the test to ignore fog; it becomes a test for shrouded or not shrouded. &lt;br /&gt;
** When multiple viewing sides are listed, all of the sides must pass the visibility check in order for the [filter_vision] filter to return a successful match.&lt;br /&gt;
** When no viewing sides are listed, all enemy sides must pass the visibility check.&lt;br /&gt;
*'''[[StandardSideFilter]]''' tags and keys; all matching sides must be able to see the unit/location. If an empty filter, all sides (instead of only all enemy sides) match. If there is *at least one* matching side which can see the unit / location (accounting for fog / hiding / shroud) then the filter matches, and otherwise it fails to match.&lt;br /&gt;
&lt;br /&gt;
'''Example:''' This event will fire when the enemy (side 2) moves to a location within the player's (side 1's) field of vision:&lt;br /&gt;
 [event]&lt;br /&gt;
     name=moveto&lt;br /&gt;
     first_time_only=yes&lt;br /&gt;
     [filter]&lt;br /&gt;
         side=2&lt;br /&gt;
         [filter_vision]&lt;br /&gt;
             side=1 &lt;br /&gt;
         [/filter_vision]&lt;br /&gt;
     [/filter]&lt;br /&gt;
     [message]&lt;br /&gt;
         speaker=unit&lt;br /&gt;
         message=&amp;quot;I am your enemy. I know that you can see me here.&amp;quot;&lt;br /&gt;
     [/message]&lt;br /&gt;
 [/event]&lt;br /&gt;
&lt;br /&gt;
'''Note:''' In a location filter, this tag is only useful when the viewing side is under a fog or shroud. You ''can'' set a shroud over an AI side. This will allow you to use the vision filter from the point-of-view of an AI side. The fog/shroud does not currently affect AI movement patterns, but the AI algorithm may become constrained by fog/shroud in the future.&lt;br /&gt;
&lt;br /&gt;
== Filtering on WML data ==&lt;br /&gt;
&lt;br /&gt;
Some places allow you to filter directly on WML data. WML filters are more free-form than other filters, allowing arbitrary WML data that is to be matched. Anything between '''&amp;lt;&amp;gt;''' needs to be replaced by the actual data to be filtered for. The following conventions are possible:&lt;br /&gt;
&lt;br /&gt;
* ''&amp;lt;key&amp;gt;'''='''&amp;lt;value&amp;gt;'': Means that the key '''key''' must be present with the specified '''value'''.&lt;br /&gt;
* '''glob_on_'''''&amp;lt;key&amp;gt;'''''='''''&amp;lt;glob&amp;gt;'': {{DevFeature1.15|0}} Means that the key '''key''' must be present with a value that matches the specified glob. In a glob, the '''*''' character matches any sequence of characters, while the '''?''' character matches any single character. In addition to the obvious, this is useful for matching the absence of a key - just place '''glob_on_'''''&amp;lt;key&amp;gt;'''''=*''' in a '''[not]''' tag.&lt;br /&gt;
* '''['''''&amp;lt;some_tag&amp;gt;''''']''': In a WML filter, all tags contain further WML filter data as children. The presence of a tag in the filter means that the WML must have at least one tag '''some_tag''' present, and at least one of the '''some_tag''' tags must match the WML filter contained in '''[some_tag]'''.&lt;br /&gt;
* '''[not]''': The WML filter contained in '''[not]''' ''must not'' match the WML.&lt;br /&gt;
* '''[and]''': {{DevFeature1.15|0}} In addition to the main filter, the filter contained in '''[and]''' must also match the WML. In most cases this tag is not necessary (the two filters can simply be merged), but in some unusual cases (particularly when globs are involved) it might be needed to get the desired result.&lt;br /&gt;
* '''[or]''': {{DevFeature1.15|0}} Adds another filter that is allowed to match in place of the main filter. Note that when combining several WML filters with '''[or]''' tags, the first filter must not be wrapped in '''[or]''' tags - doing so would mean that the first filter is actually an empty filter, which matches everything, meaning the other '''[or]''' tags are irrelevant.&lt;br /&gt;
&lt;br /&gt;
== Tutorial ==&lt;br /&gt;
* [[FilterWML/Examples_-_How_to_use_Filter|How To Use Filter (with examples)]]&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[AnimationWML#Animation_Filtering|Animation filtering]]&lt;br /&gt;
* [[UnitTypeWML]]&lt;br /&gt;
* [[EventWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
* [[FilterWML/Examples - How to use Filter]]&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=Android&amp;diff=74474</id>
		<title>Android</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=Android&amp;diff=74474"/>
		<updated>2025-08-05T17:52:22Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* Turning off Developer Mode */ Minor wording change, and code tags are for code, not UI elements&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This pages contains some specific information about the Battle for Wesnoth new Android port (1.19+)&lt;br /&gt;
&lt;br /&gt;
== Playing controls ==&lt;br /&gt;
* Tap a unit to select it&lt;br /&gt;
* Tap a unit, then tap the target hex to show defense stats of that unit and footsteps. (Similar to hover on PC)&lt;br /&gt;
* Tap a unit, then double tap on the target hex to move it. Alternative, you can drag along the path to choose the exact path which the unit is supposed to move by.&lt;br /&gt;
&lt;br /&gt;
== The Settings menu (Splash screen) ==&lt;br /&gt;
&lt;br /&gt;
== Logs and debugging steps ==&lt;br /&gt;
* Install adb (Android Debug Bridge) on your computer. Search internet for information about your OS. Install drivers for your phone/tablet if necessary.&lt;br /&gt;
* Enable Developer Mode on your Android device (phone/tablet). Again, the internet is your friend. On newer devices, you need tap Settings &amp;gt; About Phone &amp;gt; Build Number 7 times until it says &amp;quot;You are now a developer&amp;quot;, then go into the Setting &amp;gt; System &amp;gt; Developer Options (newly appeared), and find &amp;quot;USB Debugging&amp;quot; in the menu and turn that on.&lt;br /&gt;
* Connect phone to PC. Do &amp;lt;code&amp;gt;adb logcat&amp;lt;/code&amp;gt; or similar from a terminal/command prompt to see if your device appears on the list and is authorized. Tap ok on your phone if any permission request appears.&lt;br /&gt;
* Run &amp;lt;code&amp;gt;adb logcat -c&amp;lt;/code&amp;gt; (clears existing logs), then &amp;lt;code&amp;gt;adb logcat &amp;gt; log.txt&amp;lt;/code&amp;gt; (or &amp;lt;code&amp;gt;adb logcat&amp;lt;/code&amp;gt; and copy from terminal). Run Wesnoth on phone. Reproduce the crash.&lt;br /&gt;
* stop &amp;lt;code&amp;gt;adb logcat&amp;lt;/code&amp;gt; on PC, and attach the &amp;lt;code&amp;gt;log.txt&amp;lt;/code&amp;gt; to your issue report on github along with detailed steps of the bug, and use the Android label.&lt;br /&gt;
&lt;br /&gt;
(Note: adb can be &amp;lt;code&amp;gt;./adb.exe&amp;lt;/code&amp;gt; on Windows. Use internet for help on any of the steps if needed, this is supposed to be a preliminary guideline. Steps might slightly differ based on manufacturer or Android version.)&lt;br /&gt;
&lt;br /&gt;
=== Turning off Developer Mode ===&lt;br /&gt;
Go to System &amp;gt; Developer Options and turn off  the '''Use developer options''' toggle.&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=SingleUnitWML&amp;diff=74450</id>
		<title>SingleUnitWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=SingleUnitWML&amp;diff=74450"/>
		<updated>2025-07-24T01:08:31Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: Remove formula AI documentation (but leave a link to the legacy page for posterity)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
The '''[unit]''' tag describes a single unit on the map or in memory, for example Konrad.&lt;br /&gt;
It is different from the '''[unit_type]''' in '''[units]''', which describes a class of units. However it takes many of the same keys and thus can generally override the inherited properties from the associated '''[unit_type]'''.&lt;br /&gt;
&lt;br /&gt;
'''[unit]''' can be used inside '''[side]''' ([[SideWML]]) for units present at start of the scenario, or as [[DirectActionsWML]] for units created during the game. (It is also used in save-files.)&lt;br /&gt;
&lt;br /&gt;
This contains keys and tags which describe the unit's [[#Unit Data|persistent data]], as well as certain [[#Unit State|state variables]] which will also persist with the unit but will change frequently as gameplay progresses. Finally, there are some keys to set certain [[#Creation Options|one-time options]] for how the unit will be initially created, which will ''not'' persist beyond initial creation.&lt;br /&gt;
&lt;br /&gt;
== Unit Data ==&lt;br /&gt;
The following keys and tags describe the unit itself, and will persist with the unit (though some may change automatically when the unit advances):&lt;br /&gt;
* {{anchor|type|'''type'''}}: the ID of the unit's unit type. This key is mandatory. See [[UnitTypeWML]].&lt;br /&gt;
&lt;br /&gt;
* {{anchor|language_name|'''language_name'''}}: the name of the unit's unit type. See [[UnitTypeWML]].&lt;br /&gt;
&lt;br /&gt;
* '''variation''': the [variation] of the [unit_type] as which the unit will appear.&lt;br /&gt;
&lt;br /&gt;
* '''parent_type''': overrides '''type''' if this is present. This is likely of little use to WML authors; it is automatically generated when needed by the game (to keep track of some [unit_type][variation]s).&lt;br /&gt;
&lt;br /&gt;
* '''side''': the side that the unit is on. It has to be an existing side, even if the unit is created in a variable. Defaults to 1, except when the [unit] tag appears inside a [side], in which case the unit always belongs to that side, and this key is ignored.&lt;br /&gt;
&lt;br /&gt;
* '''id''': a unique identifier for the unit. This is (usually) not displayed to the player, but is to be used only for identifying and filtering units. If not specified, a random one will be generated for the unit to ensure that each unit has a unique '''id''' attribute (as will happen when a unit is recruited normally). In older versions, the '''description''' attribute specified a unique ID. (The one instance when an id is displayed to the player is when the leader's id is used as the default for a [[SideWML|side]]'s '''current_player''' attribute.) Note: While it IS technically possible to create multiple units with the same ID, doing so may produce unpredictable results in many cases. WML should therefore be structured in such a way that no two units in existence ever end up with the same ID.&lt;br /&gt;
&lt;br /&gt;
* '''gender''': can be set to male or female to designate the gender of the unit. Default is male (unless [[#random_gender|'''random_gender''']] is set to &amp;quot;yes&amp;quot;), but if the unit has only a female variant it will be female.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the user-visible name of the unit. Note that the player may use the &amp;quot;rename unit&amp;quot; action to change this (unless '''unrenamable''' is also set). Although this is a translated string, see [[GettextForWesnothDevelopers#Proper_nouns_in_strings|proper nouns in strings]] before using it in a translatable string.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;unrenamable&amp;quot;&amp;gt;'''unrenamable'''&amp;lt;/span&amp;gt;: if 'yes', the user-visible name of the unit cannot be changed by the player (which is only possible when the unit is on the player's side anyway).&lt;br /&gt;
&lt;br /&gt;
* '''canrecruit''': a special key for leaders.&lt;br /&gt;
** '''no''': default. Unit cannot recruit.&lt;br /&gt;
** '''yes''': unit can recruit.&lt;br /&gt;
: Normally when a team controls no units with '''canrecruit=yes''', that team loses. However, even if your team has lost you continue to play with whatever units you still have until the scenario is over. Usually scenarios end when only one team is left with a leader that can recruit, but special victory conditions can be set up in campaigns. Normally you want to set the leader of a side with '''canrecruit=yes'''. If you don't want the leader to recruit, it is usually better to just not give him any unit types to recruit, than to make a special victory condition. Units with '''canrecruit=yes''' are exempt from upkeep costs. So that leaders do not need to be given the ''loyal'' trait.&lt;br /&gt;
: More than one unit with '''canrecruit=yes''' for the same side (see [[SideWML]]) are allowed in single player, if the side is human-controlled.&lt;br /&gt;
&lt;br /&gt;
* '''extra_recruit''': a list of unit types which this unit can recruit in addition to the ones given by its [side]recruit= (only relevant for units with '''canrecruit=yes''').&lt;br /&gt;
&lt;br /&gt;
* {{anchor|filter_recall|'''[filter_recall]'''}}: A leader can only recall those units which pass the SUF. (Meaningful only if canrecruit=yes.)&lt;br /&gt;
**'''[[StandardUnitFilter]]''' tags and keys&lt;br /&gt;
&lt;br /&gt;
* '''level''': the unit's current level. Defaults to the level of the [unit_type] described by [[#type|'''type''']]. This is generally not set manually.&lt;br /&gt;
&lt;br /&gt;
* '''upkeep''': the amount of upkeep the unit will require each turn.&lt;br /&gt;
** '''loyal''': no upkeep cost. Can be changed by the effect 'loyal' (see [[EffectWML]])&lt;br /&gt;
** '''free''': synonymous with &amp;quot;loyal&amp;quot;.&lt;br /&gt;
** '''full''': unit costs ''level'' upkeep (see [[UnitTypeWML]]).&lt;br /&gt;
** An integer can be used to set the upkeep cost to that number.&lt;br /&gt;
** The default is &amp;quot;full&amp;quot;.&lt;br /&gt;
** Leaders (units with '''canrecruit=yes''') never pay upkeep no matter what upkeep is set to.&lt;br /&gt;
** Normally you don't want to muck with this value. If you want to give a side units without upkeep costs, give those units the 'loyal' trait.&lt;br /&gt;
&lt;br /&gt;
* {{DevFeature1.13|0}} '''recall_cost''': the recall cost of this unit. Overrides the values specified by the unit's type ([[UnitTypeWML|[unit_type]]]), its side ([[SideWML|[side]]]), and the global [[GameConfigWML|[game_config]]] value. A value of -1 is equivalent to not specifying this attribute. {{DevFeature1.15|0}} Units are now recalled for AI sides even if the recall_cost is larger than the unit's worth (essentially its cost, plus potentially a bonus for experience points). In 1.14 and earlier, units were not recalled by the AI in this case even if this was the only recall/recruit action possible to the AI.&lt;br /&gt;
&lt;br /&gt;
* '''overlays''': a comma-separated list of images that are overlayed on the unit.&lt;br /&gt;
** {{DevFeature1.15|0}} This key is supported when creating a unit from WML, but will be empty when writing the unit back to WML; the overlays will instead be stored as [modifications].&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;max_hitpoints&amp;quot;&amp;gt;'''max_hitpoints'''&amp;lt;/span&amp;gt;: The maximum hitpoints the unit has when at full health. Default is the max HP set for the [unit_type] described by [[#type|'''type''']].&lt;br /&gt;
&lt;br /&gt;
* '''max_experience''': The experience the unit needs to advance. Default is the experience required for the [unit_type] described by [[#type|'''type''']].&lt;br /&gt;
&lt;br /&gt;
* {{anchor|max_moves|'''max_moves'''}}: The maximum number of movement points the unit has. Default is the number of movement specified for the [unit_type] described by [[#type|'''type''']].&lt;br /&gt;
&lt;br /&gt;
* '''vision''': The the number of vision points to calculate the unit's sight range. Default is the number of vision points specified for the [unit_type] described by [[#type|'''type''']].&lt;br /&gt;
&lt;br /&gt;
* '''jamming''': {{DevFeature1.15|0}} The number of jamming points for the unit. Default is the number of jamming points specified for the [unit_type] described by [[#type|'''type''']].&lt;br /&gt;
&lt;br /&gt;
* '''flying''': 'yes' if the unit's [[UnitsWML#.5Bmovetype.5D|movetype]] has flying=yes. For units that don't fly, the '''flying''' attribute is generally omitted rather than being recorded as 'no'. In SingleUnitWML, this attribute has been called '''flying''' since it was added in 1.11.2, it was never called 'flies'.&lt;br /&gt;
&lt;br /&gt;
* {{anchor|max_attacks|'''max_attacks'''}}: The number of attacks the unit can have per turn. Default is the number of attacks specified for the [unit_type] described by [[#type|'''type''']].&lt;br /&gt;
&lt;br /&gt;
* '''profile''': sets a portrait image for this unit. Default is the portrait image set for the [unit_type] described by [[#type|'''type''']]. When the unit advances, if the value of profile is different from the unit-type portrait, that value is preserved. If the profile field is empty or the same as the unit-type portrait, the level-advance changes the unit portrait to the default for the new level and type. See [[UnitTypeWML]] for the rules used for locating files.&lt;br /&gt;
** If &amp;quot;unit_image&amp;quot; is given instead of a filename, uses the unit's base image as the portrait (in the same manner that unit types without portraits do by default).&lt;br /&gt;
** If &amp;quot;none&amp;quot; is given instead of a filename, no image will be displayed.&lt;br /&gt;
&lt;br /&gt;
* '''small_profile''': sets a small portrait image for this unit. See the '''profile''' attribute above for advancement and special values. As with [[UnitTypeWML]], the location heuristic of the '''profile''' attribute is disabled when the '''small_profile''' attribute is provided.&lt;br /&gt;
&lt;br /&gt;
* '''role''': used in standard unit filter ([[FilterWML]]). Can be set using [role] (see [[InternalActionsWML]]).&lt;br /&gt;
&lt;br /&gt;
* '''dismissable''': {{DevFeature1.19|9}} If 'no', unit cannot be dismissed from the recall list using the ''Dismiss'' button in Unit Recall dialog. Default: 'yes'.&lt;br /&gt;
&lt;br /&gt;
* '''block_dismiss_message''': {{DevFeature1.19|9}} Sets the message to be shown when ''dismissable'' is ''no'' and the user presses the  ''Dismiss'' button in Unit Recall dialog. If not set, a default message will be shown instead.&lt;br /&gt;
&lt;br /&gt;
* {{anchor|variables|'''[variables]'''}}: a set of variables that will be stored when this unit is stored (See [store_unit], [[InternalActionsWML]]). The attribute '''variable'''='''value''' means that when the unit is stored in the array ''unit'', the variable '''unit'''.variables.''variable'' will have the value ''value'' (See [[VariablesWML]]). The subnode '''mods''' is special as it is deleted on every unit rebuild (for example when the unit advances or when an [object] is removed). This makes it possible to implement [effect]s that change variables, as those will also be reapplied whenever the unit is reset. (so in particular if your effect changes the variables mods.&amp;lt;whatever&amp;gt; [remove_object] will work properly for those objects.) For example the following code will define a apply_to=moves_on_recruits effect that gives units with that effect full movement when recruited&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang='lua'&amp;gt;&lt;br /&gt;
function wesnoth.effects.move_on_recruit(u, cfg)&lt;br /&gt;
	-- maybe better use a status than a variable ?&lt;br /&gt;
	u.variables[&amp;quot;mods.move_on_recruit&amp;quot;] = true&lt;br /&gt;
end&lt;br /&gt;
on_event(&amp;quot;recruit,recall&amp;quot;, function(ec)&lt;br /&gt;
	local unit = wesnoth.get_unit(ec.x1, ec.y1)&lt;br /&gt;
	if unit and unit.variables[&amp;quot;mods.move_on_recruit&amp;quot;] then&lt;br /&gt;
		unit.attacks_left = 1&lt;br /&gt;
		unit.moves = unit.max_moves&lt;br /&gt;
	end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And since we used the mods subtable, [remove_object] will work properly for objects that give this effect.&lt;br /&gt;
&lt;br /&gt;
* {{anchor|modifications|'''[modifications]'''}}: a collection of tags describing changes that have been made to the unit. Any number and combination of tags of each type may be specified.&lt;br /&gt;
** '''[trait]''': a trait the unit has. Same format as [[UnitsWML#.5Btrait.5D|[trait], UnitsWML]].&lt;br /&gt;
** '''[object]''': an object the unit has. Same format as [[DirectActionsWML#.5Bobject.5D|[object], DirectActionsWML]].&lt;br /&gt;
** '''[advancement]''': an advancement (AMLA) that has been applied to the unit. Same format as [[UnitTypeWML#After max level advancement (AMLA)|[advancement], UnitTypeWML]]. These are automatically added when the player confirms an AMLA in the Advance Unit dialog, but they can also be specified manually to indicate that the unit already has a particular advancement applied; by providing only an advancement ID with no effects, it is even possible to disable a future advancement. {{DevFeature1.13|2}} In versions prior to 1.13.2, this tag was named [advance].&lt;br /&gt;
&lt;br /&gt;
* '''[event]''' The event is copied from this unit's WML description into the scenario. The event is carried along with the unit (even during advancement) and inserted into a scenario whenever this unit is first included. A [unit][event] requires a non-empty id= attribute.&lt;br /&gt;
&lt;br /&gt;
* '''description''': overrides the unit type description for this unit. Note that this will be reset when the unit advances. To avoid this, one can either set up a ''post_advance'' [[EventWML|event]] to override the default description after promotion, or use an [object] with a profile [[EffectWML|effect]] to change the unit description.&lt;br /&gt;
&lt;br /&gt;
* '''[special_note]''' {{DevFeature1.15|2}} see [[UnitTypeWML#Special_Notes]].&lt;br /&gt;
&lt;br /&gt;
* '''ai_special''': causes the unit to act differently&lt;br /&gt;
** &amp;quot;guardian&amp;quot; the unit will not move, except to attack something in the turn it moves (so, it only can move if an enemy unit gets within range of it). Does the same as '''[status] guardian = 'yes''''.&lt;br /&gt;
&lt;br /&gt;
* {{anchor|ai|'''[ai]'''}}: This affects how the computer will control this unit.&lt;br /&gt;
** {{DevFeature1.15|?}} '''[candidate_action]''': Add a candidate action that only applies to this unit; see [[Wesnoth_AI_Framework#The_.5Bcandidate_action.5D_Tag|here]] for details. The [filter_own] tag is not supported.&lt;br /&gt;
*** '''stage''': If specified, the candidate action is added to the stage with the given ID, instead of the default stage (which is main_loop).&lt;br /&gt;
** {{DevFeature1.15|?}} '''[micro_ai]''': Add a micro AI that only applies to this unit; see [[Micro AIs]] for details. This tag does not support side, action, or [filter].&lt;br /&gt;
** Removed in {{DevFeature1.19|14}}: the '''[vars]''' tag and the '''formula''', '''loop_formula''', and '''priority''' keys were part of the legacy [[FormulaAI]] system.&lt;br /&gt;
&lt;br /&gt;
* '''traits_description''': the description of the unit's traits which is displayed. However if it is not specified explicitly, the unit's actual traits' names will be used instead, so it is normally not necessary to set this.&lt;br /&gt;
&lt;br /&gt;
*'''alignment''': one of lawful/neutral/chaotic/liminal (See [[TimeWML]]). Default is the alignment of the [unit_type] described by [[#type|'''type''']]. This is generally not set manually.&lt;br /&gt;
&lt;br /&gt;
*'''advances_to''': comma-separated list of unit types to which this unit can advance. Will override the default provided by the [unit_type]. This is generally not set manually.&lt;br /&gt;
&lt;br /&gt;
*'''race''': See {{tag|UnitsWML|race}}. Will override the default provided by the [unit_type]. This is generally not set manually.&lt;br /&gt;
&lt;br /&gt;
*'''undead_variation''': Will override the default provided by the [unit_type]. This is generally not set manually.&lt;br /&gt;
&lt;br /&gt;
*'''usage''': Will override the default provided by the [unit_type]. This is generally not set manually.&lt;br /&gt;
&lt;br /&gt;
*'''zoc''': whether the unit has a zone of control. Will override the default provided by the [unit_type]. This is generally not set manually.&lt;br /&gt;
&lt;br /&gt;
*'''[movement_costs]''', '''[vision_costs]''', '''[defense]''', and '''[resistance]''': Can be used to modify [[UnitsWML#.5Bmovetype.5D|existing values]].&lt;br /&gt;
&lt;br /&gt;
*'''[attack]''': Takes the same syntax as [[UnitTypeWML#Attacks|[unit_type][attack]]]. By default, the attacks from the [unit_type] will be included. '''Note:''' using this tag will replace ''all'' [attack] tags with the new one.&lt;br /&gt;
&lt;br /&gt;
*'''hidden''': Implementation detail of [[InterfaceActionsWML#%5Bhide_unit%5D|[hide_unit]]]. This should not be set manually.&lt;br /&gt;
&lt;br /&gt;
== Unit State ==&lt;br /&gt;
The following keys and tags describe the current state of the unit, and will change regularly as gameplay progresses:&lt;br /&gt;
* '''x''', '''y''': the location of the unit. By default (unless modified by [[#placement|'''placement''']] below) if a location isn't provided and the side the unit will belong to has a recall list, the unit will be created on the recall list. The recall list can also be explicitly specified as the location with &amp;quot;recall,recall&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* '''location_id''': {{DevFeature1.13|8}} the location of the unit, referencing one of the special locations defined by the map. This overrides '''x''' and '''y''' if present but otherwise has the same effect and can be modified by the placement options.&lt;br /&gt;
&lt;br /&gt;
* '''facing''': which way the unit is facing (this only affects how the unit is displayed).&lt;br /&gt;
** Possible values are '''se''', '''s''', '''sw''', '''nw''', '''n''', '''ne'''. Note that some unit types may not have distinct animations for each direction.&lt;br /&gt;
&lt;br /&gt;
* '''goto_x''':, '''goto_y''': the unit's current movement destination. Default is 0,0 i.e. the unit is not on a course.&lt;br /&gt;
&lt;br /&gt;
* '''hitpoints''': the HP of the unit. Default [[#max_hitpoints|'''max_hitpoints''']].&lt;br /&gt;
&lt;br /&gt;
* '''experience''': the XP of the unit. Default is 0.&lt;br /&gt;
&lt;br /&gt;
* '''moves''': number of movement points the unit has left. Default is [[#max_moves|'''max_moves''']].&lt;br /&gt;
: '''Note:''' Do not assume that moves=max_moves on turns when the unit doesn't move. The wesnoth AIs sometimes manipulate the moves variable during its turn, for internal reasons.&lt;br /&gt;
&lt;br /&gt;
* '''resting''': whether the unit has not moved yet this turn. Used to decide whether to give the unit rest healing. Note that this can be true even if moves is not equal to max_moves.&lt;br /&gt;
&lt;br /&gt;
* '''attacks_left''': number of attacks the unit has left. Default is '''max_attacks'''.&lt;br /&gt;
&lt;br /&gt;
* {{anchor|status|'''[status]'''}}: the status of the unit. This affects different features of the unit, for example whether the unit loses health each turn. Default for all keys is 'no', but this can be changed by the scenario or by special abilities (see [[AbilitiesWML]]). The Status Table displays the status of each unit using the three images '''misc/poisoned.png''', '''misc/slowed.png''' and '''misc/petrified.png'''; other keys do not appear in the Status Table.&lt;br /&gt;
** '''poisoned''': if 'yes', the unit loses 8 HP each turn. See also ''heals'', ''cures'', [[AbilitiesWML]].&lt;br /&gt;
** '''slowed''': if 'yes', the unit has 50% of its normal movement and does half damage. When the controller of the unit's turn is over, '''slowed''' is set to 'no'. &lt;br /&gt;
** '''petrified''': if 'yes', the unit cannot move, attack, or be attacked.&lt;br /&gt;
** '''uncovered''': if 'yes', the unit has performed an action (e.g. attacking) that causes it to no longer be hidden until the next turn. For cutscenes, it may be useful to set this manually.&lt;br /&gt;
** '''guardian''': if 'yes', the unit will not move, except to attack something in the turn it moves (so, it only can move if an enemy unit gets within range of it). Does the same as '''ai_special = &amp;quot;guardian&amp;quot;'''.&lt;br /&gt;
** '''unhealable''': if set to 'yes', the unit cannot be healed through normal game mechanics. This includes the healing by resting. It does ''not'' prevent the unit from being healed by WML or Lua code.&lt;br /&gt;
** '''unpoisonable''':  if set to 'yes', the unit cannot be poisoned.&lt;br /&gt;
** '''undrainable''':  if set to 'yes', the attacker can't gain health with drain ability attacking this unit.&lt;br /&gt;
** '''unplagueable''': if set to 'yes', the unit cannot be affected by plague attack.&lt;br /&gt;
** '''not_living''': Deprecated, this is automatically set when all three above are set and vice versa.&lt;br /&gt;
** '''unslowable''': if set to 'yes', the unit cannot be slowed.&lt;br /&gt;
** '''unpetrifiable''': if set to 'yes', the unit cannot be petrified.&lt;br /&gt;
** '''invulnerable''': {{DevFeature1.13|6}} if 'yes', attacks can't hit the unit. The AI and the attack dialog take it into account.&lt;br /&gt;
** One can add other keys to [status], but they must have boolean values, and they will not do anything meaningful on their own (but can be checked from events and acted upon accordingly). For example, a scenario can set unit.status.''my_custom_key'' to 'yes' or 'no'.&lt;br /&gt;
&lt;br /&gt;
* '''invulnerable''': {{DevFeature1.13|6}} a shorthand to set the ''invulnerable'' status. Useful in [[CommandMode]] for debugging purposes. It's recommended to use [status] in written code instead.&lt;br /&gt;
&lt;br /&gt;
== Creation Options ==&lt;br /&gt;
In addition to the unit's persistent data itself, there are several options for controlling how the unit will be created, as follows:&lt;br /&gt;
* &amp;lt;span id=&amp;quot;placement&amp;quot;&amp;gt;'''placement'''&amp;lt;/span&amp;gt;: How the unit should be placed: can be one value or a comma-separated list of values. Default value is  'map,leader' for a leader given directly in [side], &amp;quot;&amp;quot; otherwise. By default, 'map,recall' is implicitly appended to the end of the list.&lt;br /&gt;
** '''map''': If x,y (or location_id) are explicitly given and point to a valid on-map location - try to place the unit at the nearest free location to there, never overwriting existing units. Successful if x,y (or location_id) are given and a valid on-map vacant location near it can be found.&lt;br /&gt;
** '''leader''': Try to place unit near the leader, if leader is not present or is in recall list - try to place unit near the start location for this side. Successful if a valid on-map vacant location can be found near leader or near start location.&lt;br /&gt;
** '''recall''': Place unit on recall list. Always successful. &lt;br /&gt;
** '''map_overwrite''': If x,y are explicitly given and point to a valid on-map location - try to place unit at this location, if there was a unit there - overwriting it, without firing events. {{DevFeature1.13|8}} Deprecated, use placement=map and overwrite=yes instead.&lt;br /&gt;
** '''map_passable''': If x,y are explicitly given and point to a valid on-map location - try to place unit at this location; if the hex is of an impassable terrain for the unit being placed, or is already occupied by another unit, the new unit will be placed in the nearest vacant hex. {{DevFeature1.13|8}} Deprecated, use placement=map and passable=yes instead.&lt;br /&gt;
** '''leader_passable''': Similar to &amp;quot;leader&amp;quot;, with the additional restriction that the selected location is not impassable for the unit being placed. {{DevFeature1.13|8}} Deprecated, use placement=leader and passable=yes instead.&lt;br /&gt;
* '''passable''': {{DevFeature1.13|8}} (default=no) If yes, and the specified location is of an impassable terrain for the unit being placed, the new unit will be placed in the nearest hex that is of a passable terrain for it.&lt;br /&gt;
* '''overwrite''': {{DevFeature1.13|8}} (default=no) If yes, always place the unit at the exact specified location, overwriting the existing unit if there is one. Generally you don't want to use this together with placement=leader.&lt;br /&gt;
&lt;br /&gt;
* '''generate_name''': (default=yes) will generate a new '''name''' if there isn't one specified for the unit, as if the unit were a freshly-recruited one.&lt;br /&gt;
* '''random_traits''': &amp;quot;no&amp;quot; will prevent random trait generation for units. You should only need to set this for placed nonleaders in multiplayer games or if you want to give the unit fewer traits than it would normally get for its unit type. When generating traits for a unit, first traits the unit has already been given are excluded. Then &amp;quot;musthave&amp;quot; traits (undead, mechanical) for the unit type are given. Then for leaders ('''canrecruit=yes''') traits that are not available to &amp;quot;any&amp;quot; (currently that's all of them to avoid a multiplayer OOS issue, but later will be restricted based on multiplayer play balance issues) are removed from consideration. Then traits are added randomly until the maximum allowed for the unit type is reached or there are no more available traits. Random traits can now be used in MP games but only when spawned in an event, so not for leaders and other units in the [side] definition.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;random_gender&amp;quot;&amp;gt;'''random_gender'''&amp;lt;/span&amp;gt;: &amp;quot;yes&amp;quot; will cause the gender of the unit with male and female variations to be male 50% of the time, female 50% of the time.  If the unit has only one gender variant it will always be given the correct one.&lt;br /&gt;
&lt;br /&gt;
* '''to_variable''': (only for [event][unit]) creates the unit into the given variable instead of placing it on the map.&lt;br /&gt;
&lt;br /&gt;
* '''animate''': whether to display the recruitment animation for this unit as if it were being recruited/recalled. Defaults to &amp;quot;no&amp;quot;. Irrelevant when the [unit] tag appears inside a [side].&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[UnitTypeWML]]&lt;br /&gt;
* [[InternalActionsWMLUnitTags]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
&lt;br /&gt;
[[Category:WML Reference]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.wesnoth.org/index.php?title=InternalActionsWML&amp;diff=74447</id>
		<title>InternalActionsWML</title>
		<link rel="alternate" type="text/html" href="https://wiki.wesnoth.org/index.php?title=InternalActionsWML&amp;diff=74447"/>
		<updated>2025-07-22T12:12:12Z</updated>

		<summary type="html">&lt;p&gt;Celtic Minstrel: /* [remove_event] */  Try to clarify that nested events aren't permanently linked to their parent.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WML Tags}}&lt;br /&gt;
&lt;br /&gt;
Part of [[ActionWML]], Internal actions are actions that WML uses internally that do not directly affect game play (or, at least, are not readily apparent to the player). For example, storing a variable is an internal action.&lt;br /&gt;
&lt;br /&gt;
== Variable Actions ==&lt;br /&gt;
&lt;br /&gt;
These actions are focused, in one way or another, on [[VariablesWML|variables]]. Creating them, modifying them, capturing game data to them, you name it, these actions are all about the variables.&lt;br /&gt;
&lt;br /&gt;
=== [set_variable] ===&lt;br /&gt;
&lt;br /&gt;
The '''[set_variable]''' tag is used to create and manipulate [[VariablesWML|WML variables­­­]]. The [https://www.wesnoth.org/macro-reference.html#VARIABLE VARIABLE] macro is a quick syntactic shortcut for simple variable creation and the [https://www.wesnoth.org/macro-reference.html#VARIABLE_OP VARIABLE_OP] macro is a quick syntactic shortcut for performing simple mathematical operations on variables.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the name of the variable to manipulate&lt;br /&gt;
&lt;br /&gt;
* '''value''': set the variable to the given value (can be numeric or string). Use literal for no substitution. (see [[VariablesWML]])&lt;br /&gt;
&lt;br /&gt;
* '''literal''': set the variable to the given value (can be numeric or string). This does not interpret any dollar signs.&lt;br /&gt;
&lt;br /&gt;
* '''to_variable''': set the variable to the value of the given variable, e.g. 'to_variable=temp' would be equivalent to 'value=$temp'.&lt;br /&gt;
&lt;br /&gt;
* '''add''': add the given amount to the variable.&lt;br /&gt;
&lt;br /&gt;
* '''sub''': subtract the given amount from the variable.&lt;br /&gt;
&lt;br /&gt;
* '''multiply''': multiply the variable by the given number. The result is a float.&amp;lt;br /&amp;gt;To negate a number, multiply by -1. If you negate 0, the result is a floating-point negative zero -0. To display -0 as 0, use a second tag with add=0; it will flip -0 to 0 but not affect other numbers.&lt;br /&gt;
&lt;br /&gt;
* '''divide''': divide the variable by the given number. The result is a float. Wesnoth 1.9 and later no longer uses integer division. Use a second tag with round=floor if you relied on this.&lt;br /&gt;
&lt;br /&gt;
* '''modulo''': returns the remainder of a division.&lt;br /&gt;
&lt;br /&gt;
* '''abs''': Returns the absolute value of the variable.&lt;br /&gt;
&lt;br /&gt;
* '''root''': Use '''root=square''' to calculate the square root. {{DevFeature1.15|0}} Also supports '''root=cube''' and arbitrary integer roots.&lt;br /&gt;
&lt;br /&gt;
* '''power''': Raise the variable to some power.&lt;br /&gt;
&lt;br /&gt;
* '''rand''': the variable will be randomly set.&amp;lt;br&amp;gt;You may provide a comma separated list of possibilities, e.g. 'rand=Bob,Bill,Bella'.&amp;lt;br&amp;gt;You may provide a range of numbers (integers), e.g. 'rand=3..5'.&amp;lt;br&amp;gt;You may combine these, e.g. 'rand=100,1..9', in which case there would be 1/10th chance of getting 100, just like for each of 1 to 9. If a number or item is repeated, it is sampled more frequently as appropriate. See [[MultiplayerContent]] for more info on the MP case.&amp;lt;br&amp;gt;Using rand= will automatically result in the current action being non undoable. Ignoring possible [allow_undo].&lt;br /&gt;
&lt;br /&gt;
* '''time=stamp''': Retrieves a timestamp in milliseconds since wesnoth was started, can be used as timing aid. Don't try to use this as random value in MP since it will cause an OOS.&lt;br /&gt;
&lt;br /&gt;
* '''string_length''': Retrieves the length in characters of the string passed as this attribute's value; such string is parsed and variable substitution applied automatically (see [[VariablesWML]] for details).&lt;br /&gt;
&lt;br /&gt;
* {{anchor|join|'''[join]'''}} joins an array of strings to create a textual list&lt;br /&gt;
** '''variable''': name of the array&lt;br /&gt;
** '''key''': the key of each array element(array[$i].foo) in which the strings are stored&lt;br /&gt;
** '''separator''': separator to connect the elements&lt;br /&gt;
** '''remove_empty''': whether to ignore empty elements&lt;br /&gt;
&lt;br /&gt;
* '''ipart''': Assigns the integer part (the part to the left of the decimal point) of the referenced variable.&lt;br /&gt;
&lt;br /&gt;
* '''fpart''': Assigns the decimal part (the part to the right of the decimal point) of the referenced variable.&lt;br /&gt;
&lt;br /&gt;
* '''round''': Rounds the variable to the specified number of digits of precision. Negative precision works as expected (rounding 19517 to -2 = 19500). Special values:&lt;br /&gt;
**'''round=ceil''': Rounds upward to the nearest integer.&lt;br /&gt;
**'''round=floor''': Rounds down to the nearest integer.&lt;br /&gt;
**'''round=trunc''': {{DevFeature1.15|0}} Rounds towards zero; this is the same operation as '''ipart''', but operating on the value already contained in the variable rather than the value assigned to the key.&lt;br /&gt;
&lt;br /&gt;
* '''min''', '''max''': {{DevFeature1.15|9}} Specify a comma-separated list of numbers; either the smallest or largest number in the list will be assigned to the variable.&lt;br /&gt;
&lt;br /&gt;
* '''reverse=yes''': {{DevFeature1.15|9}} Reverses the string value of the variable. For example, &amp;quot;delfador&amp;quot; becomes &amp;quot;rodafled&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* '''formula''': Calculate the new value of the variable from a [[Wesnoth_Formula_Language|WFL]] formula operating on the old value. This is similar to using the '''$(...)''' syntax but avoids the possibility of WFL syntax errors if a referenced variable is empty.&lt;br /&gt;
&lt;br /&gt;
=== [set_variables] ===&lt;br /&gt;
&lt;br /&gt;
Manipulates a WML array or container&lt;br /&gt;
&lt;br /&gt;
* '''name''': the name of the array or container to manipulate&lt;br /&gt;
&lt;br /&gt;
* '''mode''': one of the following values:&lt;br /&gt;
** ''replace'': will clear the array '''name''' and replace it with given data. This is the default value.&lt;br /&gt;
** ''append'': will append given data to the current array&lt;br /&gt;
** ''merge'': will merge in the given data into '''name'''. Attributes in '''[value]''' will overwrite any existing already in '''name'''. Tags in '''[value]''' modify the corresponding tag of the original value of '''name''', so for example the first '''[attack]''' tag in '''[value]''' would modify the first '''[attack]''' tag of '''name''' rather than appending a new '''[attack]''' tag. A few special syntaxes are supported:&lt;br /&gt;
*** ''__remove=yes'': When used in a subtag, causes the corresponding subtag in '''name''' to be deleted rather than merged. Deletion happens after any other subtags have been merged.&lt;br /&gt;
*** ''add_to_xxx'': Adds its integer value to the integer value of '''xxx''' in '''name''', and sets '''xxx''' in '''name''' to the result. {{DevFeature1.13|8}} Now adds as real numbers rather than integers.&lt;br /&gt;
*** ''concat_to_xxx'': {{DevFeature1.13|8}} Similar to '''add_to_xxx''', but does string concatenation instead of numerical addition.&lt;br /&gt;
** ''insert'': will insert the given data at the index specified in the '''name''' attribute, such as name=my_array[1]. The default index is zero, which will insert to the front of the array. '''Note:''' if an invalid index is used, empty containers will be created before the insertion is performed. In other words, do not attempt to insert at an index greater than (or equal to) the array's current length. This limitation may be removed in future versions.&lt;br /&gt;
&lt;br /&gt;
* '''to_variable''': set the array or container to the value of the given variable&lt;br /&gt;
&lt;br /&gt;
* {{anchor|set_variables-value|'''[value]'''}}: the WML inside the [value] tags will be stored in data, variables will be interpolated directly, use $| in order to escape the $ sign, you can store arrays of WML by supplying multiple [value] tags. ([[#Using_.5Bset_variables.5D_to_Create_Arrays_of_WML|See Example]])&lt;br /&gt;
&lt;br /&gt;
* {{anchor|set_variables-literal|'''[literal]'''}}: same as '''[value]''', but variables will not be substituted, '''[literal]''' and '''[value]''' can not be used in the same [set_variables] tag, i.e. you can not create arrays by piling a mix of '''[value]''' and '''[literal]''' tags&lt;br /&gt;
&lt;br /&gt;
*{{anchor|set_variables-split|'''[split]'''}}: splits a textual list into an array which will then be set to data&lt;br /&gt;
** '''list''': textual list to split&lt;br /&gt;
** '''key''': the key of each array element(array[$i].foo) in which the strings are stored; defaults to ''value'' if omitted.&lt;br /&gt;
** '''separator''': separator to separate the elements; if omitted, each character of the string will become an element in the result array.&lt;br /&gt;
** '''remove_empty''': whether to ignore empty elements; ignored if '''separator''' is omitted&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|4}} You can now mix '''[value]''', '''[literal]''', and '''[split]''' in the same '''[set_variables]''' tag. They will be processed in order of appearance. Multiple instances of [split] are also supported now.&lt;br /&gt;
&lt;br /&gt;
=== Capturing Game Data ===&lt;br /&gt;
&lt;br /&gt;
These actions capture different bits of game data and store them to variables so they can be examined and/or manipulated.&lt;br /&gt;
&lt;br /&gt;
==== [store_gold] ====&lt;br /&gt;
&lt;br /&gt;
Stores a side's gold into a variable.&lt;br /&gt;
&lt;br /&gt;
* '''[[StandardSideFilter]]''': The first matching side's gold will be stored in the variable &amp;quot;variable&amp;quot;.&lt;br /&gt;
* '''variable''': (default='gold') the name of the variable to store the gold in&lt;br /&gt;
&lt;br /&gt;
==== [store_locations] ====&lt;br /&gt;
&lt;br /&gt;
Stores a series of locations that pass certain criteria into an array. Each member of the array has members 'x' and 'y' (the position) and 'terrain' (the terrain type) and 'owner_side' (villages only). The array will include any unreachable border hexes, if applicable.&lt;br /&gt;
&lt;br /&gt;
* [[StandardLocationFilter]]: a location or location range which specifies the locations to store. By default, all locations on the map are stored.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable (array) into which to store the locations. Defaults to '''location'''.&lt;br /&gt;
&lt;br /&gt;
* '''mode''': {{DevFeature1.13|0}} defaults to ''always_clear'', which clears the variable, whether or not a match is found. If mode is set to ''replace'', the variable will not be cleared, and locations which match the filter will overwrite existing elements at the start of the array, leaving any additional elements intact if the original array contained more elements than there are locations matching the filter. If mode is set to ''append'', the variable will not be cleared, and locations which match the filter will be added to the array after the existing elements.&lt;br /&gt;
&lt;br /&gt;
==== [store_reachable_locations] ====&lt;br /&gt;
&lt;br /&gt;
Stores locations reachable by the given units. Can store either the movement, attack or vision ranges.&lt;br /&gt;
&lt;br /&gt;
* '''[filter]''': a [[StandardUnitFilter]]. The locations reachable by any of the matching units will be stored.&lt;br /&gt;
* '''[filter_location]''': (optional) a [[StandardLocationFilter]]. Only locations which also match this filter will be stored.&lt;br /&gt;
* '''range''': possible values ''movement'' (default), ''attack'', ''vision''. If ''movement'', stores the locations within the movement range of the unit, taking Zone of Control into account. If ''attack'', stores the attack range (movement range + 1 hex). See note below for ''vision''.&lt;br /&gt;
* '''moves''':  possible values ''current'' (default), ''max''. For ''movement'' and ''attack'', specifies whether to use the current or maximum movement points when calculating the range. Ignored for ''vision''.&lt;br /&gt;
* '''viewing_side''': If left unset then fog and shroud are ignored, hidden ambushers are not ignored, and the real reach of the units is stored. If set to a non-zero number, then the area stored for each unit matching the SUF is based on the information visible to that unit's side; it doesn't matter which non-zero number is given. Ignored completely for ''vision''.&lt;br /&gt;
* '''variable''': the name of the variable (array) into which to store the locations.&lt;br /&gt;
&lt;br /&gt;
In 1.14 and before, the ''vision'' range is calculated as max movement range ignoring ZoC + 1 hex.&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|12}} ''vision'' uses the same calculations as the fog and shroud, and handles:&lt;br /&gt;
* units with vision costs different to movement costs&lt;br /&gt;
* units whose vision points aren't the same as their max movement points&lt;br /&gt;
* jamming by enemy units&lt;br /&gt;
&lt;br /&gt;
==== [store_map_dimensions] ====&lt;br /&gt;
&lt;br /&gt;
Stores the map dimensions in a variable.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable where the values will be saved into. If it is skipped, a variable 'map_size' is used, and its contents overridden, if they existed already. The result is a container variable, with members ''width'' and ''height''.&lt;br /&gt;
&lt;br /&gt;
==== [store_side] ====&lt;br /&gt;
&lt;br /&gt;
Stores information about a certain side in a variable.&lt;br /&gt;
&lt;br /&gt;
'''Keys:'''&lt;br /&gt;
* '''[[StandardSideFilter]]''': All matching sides are stored. (An array is created if several sides match - access it with side[2].team_name and so on.)&lt;br /&gt;
* '''variable''': the name of the variable to store the information in (default: &amp;quot;side&amp;quot;)&lt;br /&gt;
* '''mode''':{{DevFeature1.13|0}} defaults to ''always_clear'', which clears the variable, whether or not a match is found. If mode is set to ''replace'', the variable will not be cleared, and sides which match the filter will overwrite existing elements at the start of the array, leaving any additional elements intact if the original array contained more elements than there are sides matching the filter. If mode is set to ''append'', the variable will not be cleared, and sides which match the filter will be added to the array after the existing elements.&lt;br /&gt;
'''Result'''&lt;br /&gt;
&lt;br /&gt;
Variable will contain following members:&lt;br /&gt;
* '''color''': Team color used for ellipses, sprites, and flags. Will be one of the id's found in data/core/team-colors.cfg or a custom color defined by [[GameConfigWML#Color_Palettes|[color_range]]].&lt;br /&gt;
* '''controller''': Indicates type of player that control this side. ''Note: In networked multiplayer, the controller attribute may not be the same on all clients. Be very careful or you have OOS errors.''&lt;br /&gt;
** '''human''': Human player&lt;br /&gt;
** '''ai''': If players assigns &amp;quot;Computer Player&amp;quot; to &amp;quot;Player/Type&amp;quot; in game lobby&lt;br /&gt;
** '''null''': If players assigns &amp;quot;Empty&amp;quot; to &amp;quot;Player/Type&amp;quot; in game lobby&lt;br /&gt;
* '''fog''': Indicates whether this side is affected by fog of war.&lt;br /&gt;
* '''gold''': The amount of gold the side has.&lt;br /&gt;
* '''hidden''': (boolean) If 'yes', side is not shown in status table.&lt;br /&gt;
* '''income''': Income for this side (base income + all village income. AKA gross income. Note that this is different from the [side] income key).&lt;br /&gt;
* '''name''': Name of player.&lt;br /&gt;
* '''recruit''': A comma-separated list of unit types that can be recruited by this side.&lt;br /&gt;
* '''shroud''': Whether this side is affected by shroud.&lt;br /&gt;
* '''side''': The $side_number of the side belonging to this container&lt;br /&gt;
* '''side_name''': Translated string representing the side's description.&lt;br /&gt;
* '''team_name''': String representing the team's description. Sides with the same team_name are allied.&lt;br /&gt;
* '''user_team_name''': Translated string representing the team's description.&lt;br /&gt;
* '''village_gold''': The amount of gold given to this side per village it controls per turn.&lt;br /&gt;
* '''scroll_to_leader''': (boolean) Whether the game view scrolls to the side leader at the start of their turn.&lt;br /&gt;
* '''flag''': Flag animation for villages owned by this side (see [[SideWML|[side]]]). Unless previously specified in [side] or changed with WML (see [[DirectActionsWML#.5Bmodify_side.5D|[modify_side]]]), this value may be empty for the default flag animation.&lt;br /&gt;
* '''flag_icon''': Flag icon for the status bar for this side (see [[SideWML|[side]]]). Unless previously specified in [side] or changed with WML (see [[DirectActionsWML#.5Bmodify_side.5D|[modify_side]]]), this value may be empty for the default flag icon.&lt;br /&gt;
* '''village_support''': The number of unit levels this side is able to support (does not pay upkeep on) per village it controls.&lt;br /&gt;
* '''defeat_condition''': {{DevFeature1.13|7}} When the side will be considered defeated. See description at [[SideWML]], [[ScenarioWML#Scenario_End_Conditions]]&lt;br /&gt;
* '''faction''': {{DevFeature1.13|7}} id of the selected faction, string (multiplayer-only)&lt;br /&gt;
* '''faction_name''': {{DevFeature1.13|7}} Name of the selected faction, string (multiplayer-only)&lt;br /&gt;
* '''num_units''' {{DevFeature1.13|7}}: The number of units the side currently has on the map.&lt;br /&gt;
* '''num_villages''' {{DevFeature1.13|7}}: The number of villages the side currently controls.&lt;br /&gt;
* '''total_upkeep''' {{DevFeature1.13|7}}: The number of unit levels the side is currently supporting.&lt;br /&gt;
* '''expenses''' {{DevFeature1.13|7}}: The amount of gold the side is currently spending to support units.&lt;br /&gt;
* '''net_income''' {{DevFeature1.13|7}}: The income the side gains per turn after expenses.&lt;br /&gt;
* '''base_income''' {{DevFeature1.13|8}}: The income the side gains per turn (same as [side] income key)&lt;br /&gt;
&lt;br /&gt;
* {{DevFeature1.13|7}} All other keys and tags of the side that are contained in [[LuaWML:Sides#wesnoth.sides|wesnoth.sides]] .__cfg&lt;br /&gt;
&lt;br /&gt;
==== [store_starting_location] ====&lt;br /&gt;
&lt;br /&gt;
Stores the starting location of a side's leader in a variable. The variable is a composite type which will have members 'x', 'y', 'terrain' and 'owner_side' (villages only)&lt;br /&gt;
&lt;br /&gt;
* [[StandardSideFilter]]: The starting locations of all matching sides will be stored. If multiple sides are matched, a WML array will be created.&lt;br /&gt;
* '''variable''': (default='location'): the name of the variable to store the location in&lt;br /&gt;
* '''mode''':{{DevFeature1.13|0}} defaults to ''always_clear'', which clears the variable, whether or not a match is found. If mode is set to ''replace'', the variable will not be cleared, and the starting locations of the sides which match the filter will overwrite existing elements at the start of the array, leaving any additional elements intact if the original array contained more elements than there are locations matching the filter. If mode is set to ''append'', the variable will not be cleared, and the starting locations of the matching sides will be added to the array after the existing elements.&lt;br /&gt;
&lt;br /&gt;
==== [store_time_of_day] ====&lt;br /&gt;
&lt;br /&gt;
Stores time of day information from the current scenario into a WML variable container.&lt;br /&gt;
&lt;br /&gt;
* '''x, y''': Location to store the time for. [[DirectActionsWML#.5Btime_area.5D|Time areas]] matter; illumination does not. If this is omitted, the global (location-independent) time is stored.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': (default='time_of_day') name of the container on which to store the information. The container will be filled with the same attributes found on [[TimeWML]].&lt;br /&gt;
&lt;br /&gt;
* '''turn''': (defaults to the current turn number) changes the turn number for which time of day information should be retrieved.&lt;br /&gt;
&lt;br /&gt;
==== [store_turns] ====&lt;br /&gt;
&lt;br /&gt;
Stores the turn limit (the maximum number of turns). If there is no limit, this stores ''-1''.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': (default='turns') the name of the variable in which to store the turn limit.&lt;br /&gt;
&lt;br /&gt;
==== [store_unit] ====&lt;br /&gt;
&lt;br /&gt;
Stores details about units into a [[VariablesWML#Container|container]] variable. When a unit is stored, all keys and tags in the unit definition may be manipulated, including some others, with [[InternalActionsWML#.5Bset_variable.5D|[set_variable]]]. A sample '''list of these tags and keys''' can be found at [[InternalActionsWMLUnitTags]].&lt;br /&gt;
&lt;br /&gt;
If you have a doubt about what keys are valid or what the valid value range is for each key, code a [store_unit] event, save the game, and examine what keys are in the file (or just examine the '''[unit]''' tag(s) in any save file). One can also use the [[CommandMode|:inspect]] command or the [[InterfaceActionsWML#.5Binspect.5D|[inspect]]] tag to open a game-state inspector dialog, which can be used to view unit properties.&lt;br /&gt;
&lt;br /&gt;
Common usage is to manipulate a unit by using '''[store_unit]''' to store it into a variable, followed by manipulation of the variable, and then [[DirectActionsWML#.5Bunstore_unit.5D|[unstore_unit]]] to re-create the unit with the modified variables.&lt;br /&gt;
&lt;br /&gt;
''Note: stored units also exist on the field, and modifying the stored variable will not automatically change the stats of the units. You need to use [unstore_unit]. See also [[DirectActionsWML#.5Bunstore_unit.5D|[unstore_unit]]] and [[ConditionalActionsWML#.5Bforeach.5D|[foreach]]].&lt;br /&gt;
&lt;br /&gt;
* '''[filter]''' with a [[StandardUnitFilter]] as argument. All units matching this filter will be stored. If there are multiple units, they will be stored into an array of variables. The units will be stored in order of their internal ''underlying_id'' attribute, which is usually in creation order (but you normally should not depend on the order).&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable into which to store the unit(s)&lt;br /&gt;
&lt;br /&gt;
* '''mode''': defaults to ''always_clear'', which clears the variable, whether or not a match is found. If mode is set to ''replace'', the variable will not be cleared, and units which match the filter will overwrite existing elements at the start of the array, leaving any additional elements intact if the original array contained more elements than there are units matching the filter. If mode is set to ''append'', the variable will not be cleared, and units which match the filter will be added to the array after the existing elements.&lt;br /&gt;
&lt;br /&gt;
* '''kill''': if 'yes' the units that are stored will be removed from play. This is useful for instance to remove access to a player's recall list, with the intent to restore the recall list later.&lt;br /&gt;
&lt;br /&gt;
==== [store_unit_defense] ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|9}}&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|7}} Fixed, was broken in 1.15.3&lt;br /&gt;
&lt;br /&gt;
Stores in a variable the defense of a unit on a particular terrain. If terrain or location is not specified, the terrain on which the unit currently stands is used. (Note: it is a WML defense, so the higher it is, the weaker unit's defense is. A footpad on castle has 70% defense, so this function stores the value 30.)&lt;br /&gt;
&lt;br /&gt;
* StandardUnitFilter&lt;br /&gt;
* '''loc_x''', '''loc_y''': x and y of a valid map location. The terrain on this location will be used for the defense calculation.&lt;br /&gt;
* '''terrain''': The terrain code for which unit defense should be calculated. If '''terrain''' is specified, '''loc_x''' and '''loc_y''' are ignored.&lt;br /&gt;
* '''variable''': the name of the variable into which to store the defense. default: &amp;quot;terrain_defense&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== [store_unit_defense_on] ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.15|7}} Similar to [store_unit_defense], but stores the same number that would be shown in the UI. For example, a footpad on castle has 70% defense, so this stores the value 70.&lt;br /&gt;
&lt;br /&gt;
Takes the same attributes as [store_unit_defense], and defaults to storing the value in &amp;quot;terrain_defense&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== [store_unit_type] ====&lt;br /&gt;
&lt;br /&gt;
Stores a unit type definition into a variable.&lt;br /&gt;
&lt;br /&gt;
* '''type''': (required) the defined ID of the unit type, for example &amp;quot;Goblin Knight&amp;quot;. Do not use a translation mark or it will not work correctly for different languages. A comma-separated list of IDs may also be used to store an array of unit types.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable into which to store the unit type information (default &amp;quot;unit_type&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* '''mode''':{{DevFeature1.13|0}} defaults to ''always_clear'', which clears the variable. If mode is set to ''replace'', the variable will not be cleared, and the unit type will overwrite the existing element at the start of the array, leaving any additional elements intact if the original array contained more elements. If mode is set to ''append'', the variable will not be cleared, and the unit type will be added to the array after the existing elements.&lt;br /&gt;
&lt;br /&gt;
==== [store_unit_type_ids] ====&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable into which to store a comma-separated list of all unit type IDs including all from all loaded addons&lt;br /&gt;
&lt;br /&gt;
==== [store_villages] ====&lt;br /&gt;
&lt;br /&gt;
Stores a series of locations of villages that pass certain criteria into an array. Each member of the result array will have members 'x' and 'y' (the position) and 'terrain' (the terrain type) and 'owner_side'.&lt;br /&gt;
&lt;br /&gt;
Note: This differs from using [store_locations] only in that the hexes considered for match are restricted to those with villages (those whose terrain type has its 'gives_income' flag set to true), in the same way that use of either the 'owner_side' key or the '[filter_owner]' will. In fact, if either of these are present, [store_villages] and [store_locations] will behave identically.&lt;br /&gt;
&lt;br /&gt;
* '''variable''': the name of the variable (array) into which to store the locations (default: &amp;quot;location&amp;quot;)&lt;br /&gt;
* '''[[StandardLocationFilter]]''' tags and keys as arguments&lt;br /&gt;
&lt;br /&gt;
==== [store_items] ====&lt;br /&gt;
&lt;br /&gt;
Stores current items in the scenario into an array. Each entry has at least members x and y and can have all of the other keys listed in the documentation of [[InterfaceActionsWML#.5Bitem.5D|[item]]] (depending on what was set during creating the item).&lt;br /&gt;
&lt;br /&gt;
*'''variable''': name of the wml variable array to use (default &amp;quot;items&amp;quot;)&lt;br /&gt;
*'''[[StandardLocationFilter]]''' keys as arguments: only items on locations matching this [[StandardLocationFilter]] will be stored&lt;br /&gt;
*'''item_name''': {{DevFeature1.15|0}} if given, only items created with a matching '''[item]name=''' will be stored. As of 1.15.0, this does not support comma-separated lists.&lt;br /&gt;
&lt;br /&gt;
==== [store_relative_direction] ====&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|0}}&lt;br /&gt;
&lt;br /&gt;
Gets the relative direction from one hex to another. This is an interface to the function wesnoth uses to decide how a unit will face while it is moving / attacking / defending.&lt;br /&gt;
&lt;br /&gt;
* '''[source]''' x and y must describe a map location&lt;br /&gt;
* '''[destination]''' similar&lt;br /&gt;
* '''variable''' name of the variable to store string result in (one of 'n', 'nw', 'ne', 's', 'sw', 'se')&lt;br /&gt;
* '''mode''' optional. 0 is the default setting corresponding to default wesnoth implementation used in animations. 1 is an alternate &amp;quot;radially symmetric&amp;quot; mode. The default mode breaks ties in the direction of south, since this makes more units face the player directly on screen. The radially symmetric mode breaks ties in the direction of counter-clockwise, and might be more appropriate in some cases.&lt;br /&gt;
&lt;br /&gt;
==== [find_path] ====&lt;br /&gt;
&lt;br /&gt;
A WML interface to the pathfinder. Calculates the path between a unit and a location and returns the result in a WML variable, that contains also an array for every step of the path (including the starting hex).&lt;br /&gt;
&lt;br /&gt;
*'''[traveler]''': [[StandardUnitFilter]], only the first matching unit will be used for calculation&lt;br /&gt;
*'''[destination]''': [[StandardLocationFilter]]&lt;br /&gt;
*'''variable''': the variable name where the result will be stored, if no value is supplied 'path' will be used as default name. Each step will be stored in a [step] array inside that variable.&lt;br /&gt;
*'''allow_multiple_turns''': default no, if yes also moves that require more than one turn will be calculated.&lt;br /&gt;
*'''check_visibility''': default no, if yes the path will not be computed if some hexes are not visible due to shroud.&lt;br /&gt;
*'''check_teleport''': default yes; if no, teleport won't be taken in account while computing path.&lt;br /&gt;
*'''check_zoc''': default yes; if no, unit ZOCs won't be considered while calculating the path.&lt;br /&gt;
*'''nearest_by''': {{DevFeature1.15|2}} possible values &amp;quot;movement_cost&amp;quot; (default), &amp;quot;steps&amp;quot;, &amp;quot;hexes&amp;quot;; if the [destination] SLF matches multiple hexes, the one that would need the least movement points to reach may not be the one that's closest as measured by '''hexes''', or closest as measured by steps, from the starting point. This option chooses which measurement to prefer.&lt;br /&gt;
&lt;br /&gt;
More detail about multiple destinations and the return structure is on [[FindPathExplanation]] (moved out of this page because it has an image in it).&lt;br /&gt;
&lt;br /&gt;
This is the structure of the variable returned by [find_path]:&lt;br /&gt;
 [path]&lt;br /&gt;
 	hexes = non-zero if a path was successfully found.&lt;br /&gt;
 		if the path is calculated to an impassable hex, or the move requires multiple turns&lt;br /&gt;
 		and allow_multiple_turns is no, its value will be 0.&lt;br /&gt;
 	from_x, from_y = location of the unit&lt;br /&gt;
 	to_x, to_y = destination&lt;br /&gt;
 	movement_cost = total movement cost required by unit to reach that hex&lt;br /&gt;
 	required_turns = total turns required by unit to reach that hex&lt;br /&gt;
 	[step]&lt;br /&gt;
 		x, y = location of the step&lt;br /&gt;
 		terrain = terrain of the step&lt;br /&gt;
 		movement_cost = movement cost required by unit to reach that hex&lt;br /&gt;
 		required_turns = turns required by unit to reach that hex&lt;br /&gt;
 	[/step]&lt;br /&gt;
 [/path]&lt;br /&gt;
&lt;br /&gt;
==== [unit_worth] ====&lt;br /&gt;
Takes only an inline [[StandardUnitFilter]] (only the first matching unit will be used for the calculation) and outputs the following variables: &lt;br /&gt;
*'''cost''': the current unit cost&lt;br /&gt;
*'''next_cost''': the cost of the most expensive advancement&lt;br /&gt;
*'''health''': the health of the unit in percentage&lt;br /&gt;
*'''experience''': current experience in percentage&lt;br /&gt;
*'''unit_worth''': how much the unit is worth&lt;br /&gt;
&lt;br /&gt;
Mainly used for internal AI checks, but one could in theory just do anything with it.&lt;br /&gt;
&lt;br /&gt;
 [event]&lt;br /&gt;
     name=moveto&lt;br /&gt;
     [unit_worth]&lt;br /&gt;
        x,y=$x1,$y1&lt;br /&gt;
     [/unit_worth]&lt;br /&gt;
     [message]&lt;br /&gt;
         id=$unit.id&lt;br /&gt;
         message=_&amp;quot;I cost $cost gold, with $health|% of my hitpoints and $experience|% on the way to cost $next_cost|.&lt;br /&gt;
 I am estimated to be worth $unit_worth&amp;quot;&lt;br /&gt;
     [/message]&lt;br /&gt;
     [clear_variable]&lt;br /&gt;
         name=cost,next_cost,health,experience,unit_worth&lt;br /&gt;
     [/clear_variable]&lt;br /&gt;
 [/event]&lt;br /&gt;
&lt;br /&gt;
=== [clear_variable] ===&lt;br /&gt;
&lt;br /&gt;
This will delete the given variable. This tag can delete a scalar or an entire array; it can also delete one container at an array index. The macro [https://www.wesnoth.org/macro-reference.html#CLEAR_VARIABLE CLEAR_VARIABLE] is a shortcut for this tag.&lt;br /&gt;
&lt;br /&gt;
This action is good to use to clean up the set of variables; for example, a well-behaved scenario will delete any variables that should not be kept for the next scenario before the end of the scenario. One can also clear tags and variables of stored units; for example, one can remove [trait]s and [object]s.&lt;br /&gt;
&lt;br /&gt;
* '''name''': the name of the variable to clear. This can also be a comma-separated list of multiple variable names.&lt;br /&gt;
** If a name ends with an array index, then it deletes that one container, and shifts the indexes of all subsequent containers. For example, &amp;lt;code&amp;gt;{CLEAR_VARIABLE my_awesome_array[2]}&amp;lt;/code&amp;gt; deletes &amp;lt;code&amp;gt;my_awesome_array[2]&amp;lt;/code&amp;gt;, but then moves &amp;lt;code&amp;gt;my_awesome_array[3]&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;my_awesome_array[2]&amp;lt;/code&amp;gt;, moves &amp;lt;code&amp;gt;my_awesome_array[4]&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;my_awesome_array[3]&amp;lt;/code&amp;gt;, and so on until the end of the array.&lt;br /&gt;
** Note that &amp;lt;code&amp;gt;{CLEAR_VARIABLE my_awesome_array}&amp;lt;/code&amp;gt; deletes the entire array, but &amp;lt;code&amp;gt;{CLEAR_VARIABLE my_awesome_array[0]}&amp;lt;/code&amp;gt; deletes only the first container.&lt;br /&gt;
&lt;br /&gt;
=== [sync_variable] ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|0}}&lt;br /&gt;
&lt;br /&gt;
Sets one or multiple variables to the same value as on all clients and also on replays, it uses the value from the currently active side.&lt;br /&gt;
* '''name''' the name of the variable to synchonize this can be a comma seperated list.&lt;br /&gt;
&lt;br /&gt;
== Other Internal Actions ==&lt;br /&gt;
&lt;br /&gt;
Believe it or not, there are some internal actions that are not focused primarily on variables. They are all grouped here.&lt;br /&gt;
&lt;br /&gt;
=== [fire_event] ===&lt;br /&gt;
&lt;br /&gt;
Trigger a WML event (used often for [[EventWML#Custom_events|custom events]])&lt;br /&gt;
&lt;br /&gt;
* '''name''': the name of event to trigger&lt;br /&gt;
** ''(Optional)'' {{DevFeature1.13|6}}&lt;br /&gt;
&lt;br /&gt;
* '''id''': ''(Optional)'' the id of a single event to trigger {{DevFeature1.13|6}}&lt;br /&gt;
&lt;br /&gt;
* '''[primary_unit]''': ''(Optional)'' Primary unit for the event. Will never match on a recall list unit. The first unit matching the filter will be chosen.&lt;br /&gt;
**[[StandardUnitFilter]] as argument. Do not use a [filter] tag.&lt;br /&gt;
&lt;br /&gt;
* '''[secondary_unit]''': ''(Optional)'' Same as '''[primary_unit]''' except for the secondary unit.&lt;br /&gt;
**[[StandardUnitFilter]] as argument. Do not use a [filter] tag.&lt;br /&gt;
&lt;br /&gt;
* '''[primary_attack]''': Information passed to the primary attack filter and $weapon variable on the new event.&lt;br /&gt;
&lt;br /&gt;
* '''[secondary_attack]''': Information passed to the second attack filter and $second_weapon variable on the new event.&lt;br /&gt;
&lt;br /&gt;
* {{DevFeature1.17|6}} '''[data]''': Additional arbitrary data to pass to the event. In addition to passing custom data, this can be used to set the '''damage_inflicted''' in an attack event or the '''owner_side''' in a village capture event. Values can be used by Lua. {{DevFeature1.19|9}} Values can be accessed as $data.&lt;br /&gt;
&lt;br /&gt;
=== [remove_event] ===&lt;br /&gt;
{{DevFeature1.13|0}} Removes the event with the specified id.&lt;br /&gt;
&lt;br /&gt;
* '''id''': the id of the event to remove. May be a comma separated list.&lt;br /&gt;
&lt;br /&gt;
'''Note''': Only events whose IDs are explicitly specified will be removed. For example, this will ''not'' automatically remove events nested within the events with those IDs.&lt;br /&gt;
&lt;br /&gt;
=== [role] ===&lt;br /&gt;
&lt;br /&gt;
Tries to find a unit to assign a role to.&amp;lt;br&amp;gt;This is useful if you want to choose a non-major character to say some things during the game. Once a role is assigned, you can use '''role=''' in a unit filter to identify the unit with that role (See [[FilterWML]]).&amp;lt;br&amp;gt;However, there is no guarantee that roles will ever be assigned. You can use '''[have_unit]''' (see [[ConditionalActionsWML#Condition_Tags|Condition Tags]]) to see whether a role was assigned. This tag uses a [[StandardUnitFilter]] (without [filter]) with the modification to order the search by type, mark only the first unit found with the role, and the role attribute is not used in the search. If for some reason you want to search for units that have or don't have existing roles, you can use one or more [not] filters. The will check recall lists in addition to units on the map. In normal use, you will probably want to include a ''side'' attribute to force the unit to be on a particular side.&lt;br /&gt;
&lt;br /&gt;
* '''role''': the value to store as the unit's role. This role is not used in the [[StandardUnitFilter]] when doing the search for the unit to assign this role to.&lt;br /&gt;
&lt;br /&gt;
* '''type''': a comma-separated list of possible types the unit can be. If any types are given, then units will be searched by type in the order listed. If no type is given, then no particular order with respect to type is guaranteed.&lt;br /&gt;
&lt;br /&gt;
* '''reassign''': {{DevFeature1.13|6}} Can be either yes or no, defaults to yes. If set to '''no''' then first search for a unit that already has this role, and if found use that unit.&lt;br /&gt;
&lt;br /&gt;
* '''search_recall_list''': {{DevFeature1.13|5}} whether to consider units on the recall list when assigning the role. Can be either yes or no, defaults to yes. {{DevFeature1.13|6}} If set to 'only', then units on the map are not considered when assigning the role - only units on the recall list can receive it. If '''reassign''' is '''no''', this setting also affects the search for a unit that already has the role.&lt;br /&gt;
&lt;br /&gt;
* '''[else]''' {{DevFeature1.13|5}} ActionWML to execute if the game is unable to find a unit to assign the role to. For example, this could be used to create a new unit satisfying the role.&lt;br /&gt;
&lt;br /&gt;
* {{anchor|auto_recall|'''[auto_recall]'''}}: {{DevFeature1.13|6}} If present, and the role is assigned to a unit on the recall list, then that unit is recalled. Supports all unique keys of [[DirectActionsWML#.5Brecall.5D|&amp;amp;#x5b;recall&amp;amp;#x5d;]], but no [[StandardUnitFilter]].&lt;br /&gt;
&lt;br /&gt;
* [[StandardUnitFilter]], do not use a [filter] sub-tag. SUF's role= and type= keys are not used: if you want to use them, use a nested SUF wrapped inside a [and] tag.&lt;br /&gt;
&lt;br /&gt;
=== [random_placement] ===&lt;br /&gt;
{{DevFeature1.13|2}}&lt;br /&gt;
&lt;br /&gt;
Selects randomly a given number of locations from a given set of locations and exectutes the given code for each of those locations.&lt;br /&gt;
&lt;br /&gt;
* '''[filter_location]''': a [[StandardLocationFilter]].&lt;br /&gt;
* '''[command]''': contains ActionWml that is executed for each of the locations.&lt;br /&gt;
* '''num_items''': the number of locations that should be selected. There are several ways of specifying this:&lt;br /&gt;
** An integer, giving the exact number of locations to use. (Variable substitution is supported too.)&lt;br /&gt;
** {{DevFeature1.15|0}} A percentage, meaning that fraction of the total available spaces.&lt;br /&gt;
** {{DevFeature1.15|0}} A [[Wesnoth_Formula_Language|WFL]] formula. It has access to one variable, ''size'', which is the total number of available spaces. In order to identify it as a WFL formula, the entire expression must be enclosed in parentheses. (Do not use a '''$''', as that will cause it to see ''size'' as zero.)&lt;br /&gt;
** A Lua expression. As with a WFL expression, it can access the ''size'' variable. {{DevFeature1.15|0}} This is now deprecated.&lt;br /&gt;
* '''variable''': The name of the variable that contains the current location during the execution of [command]. This is a container with the attributes x, y, n and terrain.&lt;br /&gt;
* '''min_distance''': The minimum distance of 2 chosen locations, a value less than 0 means that the same locations can be chosen more than one time.&lt;br /&gt;
* '''allow_less''': If yes, the tag will not show an error in case there were less than num_items locations available.&lt;br /&gt;
&lt;br /&gt;
=== Flow control actions ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|2}}&lt;br /&gt;
&lt;br /&gt;
There are three actions that alter the flow of execution. They are '''[break]''', '''[continue]''', and '''[return]'''. All of them take no arguments.&lt;br /&gt;
&lt;br /&gt;
* '''[break]''': The nearest enclosing loop immediately stops executing, and control continues with the next action after the end of that loop. If there is no enclosing loop, this is equivalent to '''[return]'''.&lt;br /&gt;
* '''[continue]''': The nearest enclosing loop immediately stops executing, and control continues at the beginning of that loop, with any iteration variables updated for the next iteration. If there is no enclosing loop, this is an error.&lt;br /&gt;
* '''[return]''': Control immediately returns to the Wesnoth engine. This completely exits the current event, including any nested events, such that the [message] will not be displayed in the below example. No further WML actions are executed in this context. Any separate, subsequent events will be run as usual.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
   name=moveto&lt;br /&gt;
   [fire_event]&lt;br /&gt;
      name=return_please&lt;br /&gt;
   [/fire_event]&lt;br /&gt;
   [message]&lt;br /&gt;
     message=&amp;quot;Made it back&amp;quot;&lt;br /&gt;
   [/message]&lt;br /&gt;
[/event]&lt;br /&gt;
[event]&lt;br /&gt;
   name=return_please&lt;br /&gt;
   [return][/return]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== [unsynced] ===&lt;br /&gt;
&lt;br /&gt;
{{DevFeature1.13|2}}&lt;br /&gt;
&lt;br /&gt;
Runs the contained actionwml in a unsynced context, that means actions performed inside [unsynced] are not synced over the network. for example &lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
   name=moveto&lt;br /&gt;
   {VARIABLE_OP message rand &amp;quot;Hi,Hello,How are you?&amp;quot;}&lt;br /&gt;
   [message]&lt;br /&gt;
      message = $message&lt;br /&gt;
   [/message]&lt;br /&gt;
   {CLEAR_VARIABLE message}&lt;br /&gt;
   [allow_undo]&lt;br /&gt;
   [/allow_undo]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
will print the same message to all clients, but also disallow undoing (regardless of [allow_undo]) for that moveto becasue it requests a synced random seed form the server. However this code&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[event]&lt;br /&gt;
   name=moveto&lt;br /&gt;
   [unsynced]&lt;br /&gt;
      {VARIABLE_OP message rand &amp;quot;Hi,Hello,How are you?&amp;quot;}&lt;br /&gt;
      [message]&lt;br /&gt;
         message = $message&lt;br /&gt;
      [/message]&lt;br /&gt;
      {CLEAR_VARIABLE message}&lt;br /&gt;
   [/unsynced]&lt;br /&gt;
   [allow_undo]&lt;br /&gt;
   [/allow_undo]&lt;br /&gt;
[/event]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
will not prevent undoing, but might print a different message for each client in a multiplayer game (or during a sp replay), so `[unsynced]` should not be used for actions that actually change the gamestate otherwise you'll get OOS&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Using [set_variables] to Create Arrays of WML ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=wml&amp;gt;&lt;br /&gt;
[set_variables]&lt;br /&gt;
    name=arr&lt;br /&gt;
    mode=replace&lt;br /&gt;
    [value]&lt;br /&gt;
        foo=bar&lt;br /&gt;
    [/value]&lt;br /&gt;
    [value]&lt;br /&gt;
       foo=more&lt;br /&gt;
    [/value]&lt;br /&gt;
[/set_variables]&lt;br /&gt;
{DEBUG_MSG $arr[0].foo}&lt;br /&gt;
{DEBUG_MSG $arr[1].foo}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will produce two output messages, first one saying '''bar''' and next one saying '''more'''.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[VariablesWML]]&lt;br /&gt;
* [[ActionWML]]&lt;br /&gt;
** [[ConditionalWML]]&lt;br /&gt;
** [[DirectActionsWML]]&lt;br /&gt;
** [[InterfaceActionsWML]]&lt;br /&gt;
* [[EventWML]]&lt;br /&gt;
* [[ReferenceWML]]&lt;br /&gt;
&lt;br /&gt;
[[Category: WML Reference]]&lt;br /&gt;
[[Category: ActionsWML]]&lt;/div&gt;</summary>
		<author><name>Celtic Minstrel</name></author>
		
	</entry>
</feed>