# Wesnoth Formula Language

## Contents

- 1 Data Types and Operators
- 2 Functions
- 3 Variables
- 4 Comments
- 5 Defining Functions
- 6 Where to Use Formulas
- 7 Files
- 8 Core Functions
- 8.1 Conditional Functions
- 8.2 Numeric Functions
- 8.2.1 abs
- 8.2.2 acos
- 8.2.3 asin
- 8.2.4 atan
- 8.2.5 as_decimal
- 8.2.6 cbrt
- 8.2.7 ceil
- 8.2.8 clamp
- 8.2.9 cos
- 8.2.10 exp
- 8.2.11 floor
- 8.2.12 frac
- 8.2.13 hypot
- 8.2.14 lerp
- 8.2.15 lerp_index
- 8.2.16 log
- 8.2.17 max
- 8.2.18 min
- 8.2.19 pi
- 8.2.20 root
- 8.2.21 round
- 8.2.22 sgn
- 8.2.23 sin
- 8.2.24 sqrt
- 8.2.25 sum
- 8.2.26 tan
- 8.2.27 trunc
- 8.2.28 wave

- 8.3 String Functions
- 8.4 List and Map Functions
- 8.5 List-processing Functions
- 8.6 Location Functions
- 8.7 Miscellaneous Functions
- 8.8 Debugging Functions
- 8.9 Game State Functions

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:

```
[filter]
formula = "(hitpoints < max_hitpoints / 2)"
[/filter]
```

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**.

## Data Types and Operators

Wesnoth Formula Language has seven basic data types – integers, real numbers (usually called "decimals"), strings, lists, maps, objects, and null.

### Numbers

The most common use of WFL is for simple calculations involving numbers. For this, the standard arithmetic operators (`+ - * / %`

) work as you would expect, performing addition, subtraction, multiplication, division, and remainder. * (Version 1.13.5 and later only)* The remainder operator even works on decimal numbers, producing the integer remainder of the division.

The only caveat to watch out for is that `/`

rounds down when used on integers. For example, `5 / 2`

will evaluate to `2`

. To avoid this, make sure at least one of the numbers includes a decimal point - `5.0 / 2`

will evaluate to `2.5`

.

Note that WFL supports only three decimal places of precision for decimal numbers; beyond that it will still be rounded down. (So `1.0 / 16`

will evaluate to `0.062`

instead of `0.0625`

.) The `^`

operator performs exponentiation (raising to a power) - for example, `2 ^ 3`

evaluates to `8`

You can also use the standard comparison operators (`= != < <= > >=`

) on numbers. This is often useful in unit filters - for example, a formula of `hitpoints < max_hitpoints / 2`

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.

One final numeric operator exists - the dice roll. The syntax `3d12`

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. * (Version 1.13.5 and later only)* The dice operator is now synced and should be safe for use in multiplayer contexts.

**Note:** * (Version 1.13.5 and later only)* Some numeric operations will return null instead of a number. This usually involves the exponentiation operator - for example,

`(-2) ^ 0.5`

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 math functions in appropriate circumstances.
### Strings

WFL also supports strings, which must be enclosed in single quotes (`'like this'`

). The comparison operators (`= != < <= > >=`

) also work on strings, performing lexicographical comparison (ie, alphabetical order). The comparison is case sensitive.

**(Version 1.13.5 and later only)**

Strings can be concatenated with the concatenation operator `..`

. They also support interpolations enclosed in square brackets, the contents of which can be any valid formula. For example:

```
'Some text: [a + b]' where a = 12, b = 10
```

results in the string `Some text: 22`

. (The `where`

operator is explained below.)

If you need to include a literal square bracket in a string, write `[(]`

or `[)]`

. For a literal single quote, you can write `[']`

. For example:

```
'[(]It[']s bracketed![)]'
```

results in the string `[It's bracketed!]`

.

You can index the characters or words of a string with the following syntax:

```
'Hello World'.char[4]
'Hello World'.word[1]
```

These return `o`

and `World`

, respectively. A third option is also available, `item`

, which splits the string on commas but allows parentheses to prevent a portion of the string from being split up. For example:

```
'First Item,Second Item,Third Item'.item[1]
'a,b,(c,d,e),f,g'.item[2]
```

These return `Second Item`

and `(c,d,e)`

, respectively.

### Lists

A list is a sequence of values represented as square brackets, [], surrounding a comma-separated list. For instance:

```
[ 1, 5, 'abc' ]
```

The comparison operators work on lists, performing lexicographical comparison. A specific list index can be obtained with the indexing operator, like this: `my_list[index]`

. The first element of a list is numbered 0.

There are four *vector operators* (`.+ .- .* ./`

) that perform entrywise operations on lists. For example, `[1,2,3] .+ [12,2,8]`

produces `[13,4,11]`

. Both lists must be of the same length to use these operators, and of course, they must contain only numbers.

**(Version 1.13.5 and later only)**

A negative list index now counts from the end of the list - `-1`

refers to the last element. You can check if an element exists in a list using the `in`

operator. Lists can also be joined with the concatenation operator `..`

, and sliced using the range operator `~`

. 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:

```
[1, 7, 'abc', 2.5, 'foobar', 127][1~3]
(10~20)[[0,-1]]
[1, 7, 'abc', 2.5, 'foobar', 127][[2,4]]
```

These result in the following lists:

[7, 'abc', 2.5] [10,20] ['abc', 'foobar']

### Maps

A map is a sequence of key-value pairs. For example:

```
[12 -> 'Hello', [1,2] -> 9, 'abc' -> 1.5]
```

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 `self`

):

`self[12] = 'Hello'`

`self[[1,2]] = 9`

`self['abc'] = 1.5`

**(Version 1.13.5 and later only)**

You can now use the `in`

operator to test if a key exists in the map. You can also access string keys using the dot operator `.`

as long as they are valid identifiers. (Valid identifiers contain letters and underscores only; no digits are permitted.)

Note that the selection indexing that lists use is *not* valid for maps - a list can be used as a key, after all.

### Objects

An object is a container containing additional variables (see 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 `u.hitpoints`

will evaluate to the number 30. For a more advanced example, `u . (hitpoints < max_hitpoints - 10)`

will evaluate to true if the unit has taken more than 10 damage, which in this example, it has. (This could also be written `u.hitpoints < u.max_hitpoints - 10`

if you prefer; this enters the scope twice, instead of once, but the result is identical.)

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()`

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*.

#### Documentation of some common objects

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.

- unit objects
- weapon objects
- terrain objects
- side objects
- pixel objects
- WML objects
- game state objects

### Other Types and Operators

There is one other basic type in WFL - the null type, which is used to mean "no value". 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 `null()`

function, which allows you to test if a value is null by writing `value = null()`

.

The logical operators `and`

and `or`

can be used to connect conditional expressions, and the unary operator `not`

negates them. Note that `or`

is inclusive - `A or B`

is false only if both *A* and *B* are false. These operators consider `0`

or null to be false, while all other values count as true. The `if()`

function also follows the same rules to determine whether a value is true or false.

**Note:** Programmers familiar with other languages may occasionally be surprised by the fact that `and`

and `or`

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.

### Operator Precedence

The precedence of various operators is, more or less, what you'd expect - you can write something like `a + b * 2 <= 5 and n - m / 4 > 7`

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 `a ^ b ^ c`

will be evaluated as `(a ^ b) ^ c`

instead of `a ^ (b ^ c)`

like you would expect. * (Version 1.13.5 and later only)* This has been fixed - exponentiation is now right-associative.

The full precedence list is as follows, from lowest to highest; operators on the same line have equal precedence.

`not`

`where`

clauses`or`

`and`

- Comparison operators
`= != < <= > >= in`

- Range-generating operator
`~`

- Additive operators
`+ - ..`

- Multiplicative operators
`* /`

- Modulus
`%`

- Exponentiation
`^`

- Dice operator
`d`

- Dot operator
`.`

## Functions

WFL is a *functional* language, so of course it has functions. There is a large library of built-in functions, and you can also define your own.

Calling a function is simple, and works exactly how you would expect if you've worked with functions in a mathematical context: `clamp(value, 0, 21)`

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 `if` function, as in the following example:

```
if(hitpoints > 37,
max_hitpoints / 2,
hitpoints - 3
)
```

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 `filter`, `choose`, `map`, and `reduce`. See the corresponding function definitions for more information.

## Variables

Formulas may have a variety of variables, depending on the context in which they are evaluated. A string substitution formula like `$(3 + 5)`

has no variables, but a unit filter formula has variables such as `hitpoints`

and `max_hitpoints`

which contain various properties of the unit being tested (the same unit which is also referred to in variable substitution as `$this_unit`

). The special variable `self`

typically refers to the "global context" - in the case of a unit filter formula, the unit itself. This means for example that `self.hitpoints`

and `hitpoints`

are equivalent when used in a unit filter formula. In a string substitution formula (the `$(formula)`

syntax), `self`

is null. Because of this, you should prefer not to use the substitution syntax in places where formulas are specifically supported.

A formula may declare additional variables using a `where`

clause. This assigns a meaning to any unknown variables in the preceding formula. The general syntax is:

<formula> where <variable> = <value> [, <variable> = value ...]

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.)

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:

`d`- dice operator`or`- logical operator`in`- containment operator`def`- defines a function`and`- logical operator`not`- logical operator`fai`- deprecated synonym of`wfl``wfl`- declares filename`where`- declares variables`faiend`- deprecated synonym of`wflend``wflend`- closes file scope`functions`- lists all defined functions

## Comments

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 `#`

characters, like this:

```
#This is a Wesnoth Formula Language comment.#
```

Note the final `#`

- unlike WML, WFL requires this to indicate where the comment ends.

## Defining Functions

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 `functions`

always evaluates to a list of all known function names. This is mainly useful only as a debugging tool, though.

To define a function, you use the `def`

keyword. For example:

```
def sgn(x) if(x < 0, -1, x > 0, 1, 0);
```

This defines a function called `sgn`

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.

Function names have the same limitation as variable names – they can contain only letters and underscores, and cannot contain digits.

You can select one of the function's arguments to be the "default" 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:

```
def is_badly_wounded(u*) hitpoints < max_hitpoints / 2;
```

This function takes a unit and returns 1 if it is at less than half hitpoints. The `*`

indicates the default argument, without which it would instead have to be defined like this:

```
def is_badly_wounded(u) u.hitpoints < u.max_hitpoints / 2;
```

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 an AI context) even though the my_leader variable is defined:

```
def endangers_leader(u) distance_between(u.loc, my_leader.loc) < u.moves;
```

This is because the body of the function can't see the my_leader variable. To make this work, you would need to pass in my_leader as an additional parameter.

**Note: Prior to 1.14, function definitions only work in AI code and GUI2 code.**

## Where to Use Formulas

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 filters, GUI2 dialogs, and unit abilities. Another example is the `$(formula)`

substitution syntax, which allows the use of formulas wherever variables are parsed.

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:

- WML uses the
`+`

operator to represent concatenation of strings, as well as line continuation. Because of this, an unquoted`+`

will be*removed*, likely causing the WFL formula to fail to compile. - Unquoted WML text has the whitespace collapsed. If using WFL strings where whitespace is significant, this can result in surprises. For example, the formula
`length('One Two Three')`

would return 13 instead of the expected 19 if double quotes are not placed around the formula.

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 "formula", it is usually required to be a formula, whereas attributes with optional formulas do *not* contain the word "formula" in the key.

**Note**: Do *not* use a `$`

to introduce a formula. The `$`

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 `$`

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 `$`

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.

## Files

**(Version 1.13.5 and later only)**

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 `wfl`

keyword. The convention is to frame your code, so that any file looks like this:

```
wfl 'filename.wfl'
# Put whatever code you need here, possibly including function definitions. #
wflend
```

The matching `wflend`

is required.

**Note:** This functionality was available prior to 1.13.5 using keywords `fai`

and `faiend`

. These keywords are now deprecated, but still work.

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 filesystem.read_file.

## Core Functions

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.

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:

- Formulas used in FilterWML
- Formulas used in AbilitiesWML
`filter_formula`in EventWML- Formulas evaluated from the formula console (accessed by pressing F)

The following formulas do not have access to the game state and cannot use those functions:

- Formulas used in GUI2
- Substitution formulas using
`$(...)` - IPF formulas used in
`~CHAN()`or`~ALPHA()` - Formulas compiled from Lua

### Conditional Functions

There are two functions which return one of their input values based on some condition - the `if`

function, and the `switch`

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.

#### if

- if(
*condition*,*if true*[,*condition 2*,*if true 2*, ...] [,*otherwise*])

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 `null()`

otherwise.

For instance, an AI that recruits Wolf Riders on the first turn, and Orcish Grunts thereafter might look like this:

```
if(turn = 1, recruit('Wolf Rider'), recruit('Orcish Grunt'))
```

#### switch

- switch(
*formula*,*value 1*,*outcome 1*[, ... ,*value N*,*outcome N*] [,*default outcome*])

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.

### Numeric Functions

Several basic math functions are available. These generally work equally on integer and decimal values.

#### abs

- abs(
*number*)

Returns the absolute value of an input number; for example

```
abs( -5 )
```

will return 5.

* (Version 1.13.5 and later only)* This now works on decimals as well as integers.

#### acos

**(Version 1.13.5 and later only)**

- acos(
*number*)

Returns the arccosine of the input number, in degrees.

#### asin

**(Version 1.13.5 and later only)**

- asin(
*number*)

Returns the arcsine of the input number, in degrees.

#### atan

**(Version 1.13.5 and later only)**

- atan(
*number*)

Returns the arctangent of the input number, in degrees.

#### as_decimal

- as_decimal(
*number*)

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.

#### cbrt

**(Version 1.13.5 and later only)**

- cbrt(
*number*)

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.

#### ceil

- ceil(
*number*)

Returns the ceiling of the specified number, ie rounding it up to the nearest integer.

#### clamp

**(Version 1.17.0 and later only)**

- clamp(
*number*,*min*,*max*)

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*.

#### cos

- cos(
*angle*)

Returns the cosine of the given angle, which is specified in degrees.

#### exp

**(Version 1.13.5 and later only)**

- exp(
*number*)

Returns the exponential of the input number, which is the constant *e* raised to the specified power.

#### floor

- floor(
*number*)

Returns the floor of the specified number, ie rounding it down to the nearest integer.

#### frac

**(Version 1.13.5 and later only)**

- frac(
*number*)

Returns the fractional part of the specified number.

#### hypot

**(Version 1.13.5 and later only)**

- hypot(
*x*,*y*)

Returns the hypoteneuse length of a triangle with sides *x* and *y*.

#### lerp

**(Version 1.17.0 and later only)**

- lerp(
*min*,*max*,*fraction*)

Returns a linear interpolation between *min* and *max* according to the specified *fraction*.

#### lerp_index

**(Version 1.19.4 and later only)**

- lerp_index(
*list*,*ratio*)

Returns the element of the list that is closest to being at the specified ratio of the list's length.

**Example**: `lerp_index([1, 12, 32, 10], 0.26])`

returns 12.

#### log

**(Version 1.13.5 and later only)**

- log(
*number*, [,*base*])

Returns the logarithm of the input number. If *base* is omitted, it returns the natural logarithm; otherwise, the logarithm to the specified base.

#### max

- max(
*list of numbers*)

Returns the largest number from the list. For example:

```
max([2, 8, -10, 3])
```

will return `8`

.

* (Version 1.13.5 and later only)* This now works on decimals as well as integers.

#### min

- min(
*list of numbers*)

Returns the smallest number from the list. For example:

```
min( [ 3, 7, -2, 6] )
```

will return `-2`

.

* (Version 1.13.5 and later only)* This now works on decimals as well as integers.

#### pi

**(Version 1.13.5 and later only)**

- pi()

Returns pi.

#### root

**(Version 1.13.5 and later only)**

- root(
*number*,*base*)

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).

#### round

- round(
*number*)

Returns the specified number rounded to the nearest integer.

#### sgn

**(Version 1.13.5 and later only)**

- sgn(
*number*)

Returns the sign of the number, ie -1 if it is negative, 1 if it is positive, and 0 if it is zero.

#### sin

- sin(
*angle*)

Returns the sine of the given angle, which is specified in degrees.

#### sqrt

**(Version 1.13.5 and later only)**

- sqrt(
*number*)

Returns the square root of the input number.

#### sum

- sum(
*list of numbers*)

This function evaluates to the sum of the numbers in the *list of numbers*. For example:

```
sum([ 2, 5, 8])
```

returns `15`

, and:

```
sum(map(my_units, max_hitpoints - hitpoints))
```

finds the total damage your units have taken.

#### tan

**(Version 1.13.5 and later only)**

- tan(
*number*)

Returns the tangent of the given angle, which is specified in degrees.

#### trunc

**(Version 1.13.5 and later only)**

- trunc(
*number*)

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.

#### wave

- wave(
*number*)

Given a numeric value V, this returns:

sin(2*pi*V)

### String Functions

There are a few useful functions for manipulating strings.

#### concatenate

- concatenate(
*value1*[,*value2*, ...])

Converts each of its arguments to a string, and concatenates the result together into a single string.

#### contains_string

- contains_string(
*string*,*search_string*)

Returns 1 if *search_string* can be found within *string* (as a substring), 0 otherwise. For example:

```
contains_string( 'Testing', 'ing' )
```

returns `1`

.

#### length

- length(
*string*)

Returns the length of the input string.

#### ends_with

**(Version 1.19.4 and later only)**

- ends_with(
*string*,*suffix*)

Determines whether the *string* ends with the specified *suffix*.

#### find_string

**(Version 1.13.5 and later only)**

- find_string(
*string*,*search_string*)

Returns the index at which *search_string* starts within *string* (as a substring), or -1 if it is not found. For example:

```
find_string( 'Testing', 'ing' )
```

returns `4`

.

#### replace

**(Version 1.13.5 and later only)**

- replace(
*string*,*offset*, [*size*,]*replacement*)

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 `substring`

. Examples:

```
replace('The quick brown fox jumps over the lazy dog!', 4, 5, 'dumb')
replace('The quick brown fox jumps over the lazy dog!', -9, 4, 'sleeping')
replace('The quick brown fox jumps over the lazy dog!', -9, 'brook!')
replace('The quick brown fox jumps over the lazy dog!', -6, -4, 'yellow')
```

return the following strings:

'The dumb brown fox jumps over the lazy dog!' 'The quick brown fox jumps over the sleeping dog!' 'The quick brown fox jumps over the brook!' 'The quick brown fox jumps over the yellow dog!'

#### replace_all

**(Version 1.19.4 and later only)**

- replace_all(
*string*,*match*,*replacement*)

Returns a copy of *string* with all occurrences of *match* replaced by *replacement*.

#### starts_with

**(Version 1.19.4 and later only)**

- starts_with(
*string*,*prefix*)

Determines whether the *string* begins with the specified *prefix*.

#### substring

- substring(
*string*,*offset*[,*size*])

Extracts a substring from the given input string. The *offset* specifies the first character to extract; the first character is `0`

, and negative values count from the end, so the last character is `-1`

. 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:

```
substring('The quick brown fox jumps over the lazy dog!', 4, 5)
substring('The quick brown fox jumps over the lazy dog!', -9, 4)
substring('The quick brown fox jumps over the lazy dog!', -9)
```

return `'quick'`

, `'lazy'`

, and `'lazy dog!'`

respectively.

* (Version 1.13.5 and later only)* 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:

```
substring('The quick brown fox jumps over the lazy dog!', -6, -4)
```

returns `'lazy'`

.

### List and Map Functions

This section contains functions that directly manipulate a map or list.

#### head

- head(
*list*[,*count*])

Returns the first item from the *list*; for example

```
head([5, 7, 9])
```

returns `5`

, and

```
head( [ 'Orc', 'Human' ] )
```

returns `'Orc'`

.

* (Version 1.13.5 and later only)* If a second argument is given, it returns a list containing the first

*count*elements from the

*list*. Note that

`head(L)`

is different from `head(L,1)`

- the former returns the first element, while the latter returns a list containing only the first element.
#### index_of

- index_of(
*value*,*list*)

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'.*

#### keys

- keys(
*map*)

Extracts the key values from an input *map* and returns them as a list. For example:

```
keys(['Elvish Fighter' -> 50, 'Elvish Archer' -> 60])
```

returns

['Elvish Fighter', 'Elvish Archer']

#### size

- size(
*list*)

This function returns the number of elements in the *list*.

For example, `size([5, 7, 9])`

returns `3`

and `size(['Archer', 'Fighter'])`

returns `2`

.

#### sort

- sort(
*list*,*formula*)

This function evaluates to a result list sorted according to the comparison *formula* for each item `a`

and its successor `b`

. For instance, sorting units according to hitpoints would be done by:

```
sort(my_units, a.hitpoints > b.hitpoints)
```

To sort them in the reverse order, simply use `<`

instead of `>`

.

#### tail

**(Version 1.13.5 and later only)**

- tail(
*list*[,*count*])

Returns the last item from the *list*; for example

```
tail([5, 7, 9])
```

returns `9`

, and

```
tail( [ 'Orc', 'Human' ] )
```

returns `'Human'`

.

If a second argument is given, it returns a list containing the last *count* elements from the *list*. Note that `tail(L)`

is different from `tail(L,1)`

- the former returns the last element, while the latter returns a list containing only the last element.

#### tolist

- tolist(
*map*)

This function takes a map and return a list of key-value pair objects. For example:

```
tolist(['Elf' -> 10, 'Dwarf' -> 20])
```

will return:

[{key->'Elf',value->10}, {key->'Dwarf',value->20}]

#### tomap

- tomap(
*list A*[,*list B*])

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:

```
tomap(['elf', 'dwarf', 'elf', 'elf', 'human', 'human'])
```

will return:

['elf' -> 3, 'dwarf' -> 1, 'human' -> 2]

* (Version 1.13.5 and later only)* 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.

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:

```
tomap(['elf', 'dwarf' ], [10, 20])
```

will result in:

['elf' -> 10, 'dwarf' -> 20]

#### values

- values(
*map*)

Extracts the values assigned to keys from an input *map* and returns them as a list. For example:

```
values(['Elvish Fighter' -> 50, 'Elvish Archer' -> 60])
```

returns

[50, 60]

### List-processing Functions

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, `reduce`

instead combines all the elements into a single result.

#### choose

- choose(
*input*, [*self_name*,]*formula*)

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:

```
choose(my_units, level)
```

gives back the unit with the highest level.

The implicit input when evaluating a mapping/filtering function's *formula* component will be that specific item under evaluation (in this example one of "my_units"), and it can be explicitly referenced as `self`

when necessary. The optional <self_name> parameter can be used to give a different name to the `self`

variable.

When evaluating a map, we can reference each key by `key`

and each value by `value`

. In this case, the `self`

variable is this key-value pair. For example:

```
choose(['elf' -> 10, 'dwarf' -> 20 ], value)
```

will return a key-value pair

{key->'dwarf', value->20}

The curly braces are used in output to indicate that this is an object, not a map. It is not valid WFL syntax.

#### filter

- filter(
*input*, [*self_name*,]*formula*)

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 <self_name> parameter can be used to give a different name to the `self`

variable.

```
filter(my_units, hitpoints < max_hitpoints)
```

will return all of your units which have less than maximum hitpoints. For instance this could be used if looking for candidates for healing.

#### find

- find(
*input*, [*self_name*,]*formula*)

This function will run <formula> on each item in the <input> (which can be a list or a map) and will return the first item for which <formula> was true. The optional <self_name> parameter can be used to give a different name to the `self`

variable. For example:

```
find(units, type = 'Elvish Archer' )
```

will return the first unit of type 'Elvish Archer'.

#### map

- map(
*input*, [*self_name*,]*formula*)

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 <self_name> parameter can be used to give a different name to the `self`

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:

```
map([10,20], self*self)
```

and

```
map([10,20], 'value', value*value)
```

will both result in [100, 400]. The formula:

```
map(my_units, hitpoints)
```

will give a list back with the number of hitpoints each unit has. This is more useful in conjunction with other functions.

```
map(['elf' -> 10, 'dwarf' -> 20 ], value*2)
```

The above will produce ['elf' -> 20, 'dwarf' -> 40]. Note that in case of a map data type, the `map`

function can only modify the value.

```
map(tomap([3,5,8,8]), value+key*100)
```

The above will produce `[3 -> 301, 5 -> 502, 8 -> 801]`

. This can be used to take a list and make a map containing pairs `[element_from_that_list -> f(element_from_that_list,number_of_repetitions_of_that_element_in_that_list)]`

where `f`

is an arbitrary function.

#### reduce

- reduce(
*list*, [*identity*, ]*formula*)

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'.

For example, `reduce([1,2,3,4], a+b)`

returns `10`

and `reduce([9,4,8,2], 10*a+b)`

returns `9482`

.

* (Version 1.13.5 and later only)* 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:

```
reduce(your_list, 1, a * b)
```

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.

#### take_while

**(Version 1.13.5 and later only)**

- take_while(
*list*,*formula*)

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:

```
take_while([1,5,3,6,3,7,9,5,6,4,12,2,53,2,1], self < 10)
```

returns the list `[1,5,3,6,3,7,9,5,6,4]`

.

#### zip

**(Version 1.13.5 and later only)**

- zip(
*list1*, ... ,*listN*) - zip(
*list of lists*)

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.

```
zip([1,2,3],[4,5,6])
zip([1,4],[2,5],[3,6])
```

return `[[1,4],[2,5],[3,6]]`

and `[[1,2,3],[4,5,6]]`

, respectively.

### Location Functions

Functions for working with locations on a hex map.

#### adjacent_locs

**(Version 1.13.9 and later only)**

- adjacent_locs(
*center*)

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.

#### are_adjacent

**(Version 1.13.9 and later only)**

- are_adjacent(
*loc1*,*loc2*)

Check if two locations are adjacent. Returns 1 (true) or 0 (false).

#### direction_from

**(Version 1.13.9 and later only)**

- direction_from(
*start*,*direction*, [*distance*])

Returns the hex reached by travelling in the specified direction from a starting hex for a certain distance (default 1 hex).

#### distance_between

**(Version 1.13.5 and later only)**

- distance_between(
*start*,*end*)

Returns the distance between the locations *start* and *end*, which must be location objects such as those created by `loc()`

.

**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.

#### loc

- loc(
*x*,*y*)

Creates and returns a location object with the specified coordinates. If assigned to a variable *pos* (eg with a `where`

clause), the individual coordinates can be accessed as `pos.x`

and `pos.y`

.

#### locations_in_radius

**(Version 1.13.9 and later only)**

- locations_in_radius(
*center*,*radius*)

Returns a list of all locations within a given radius of the specified center hex. Only locations on the map will be returned.

#### relative_dir

**(Version 1.13.9 and later only)**

- relative_dir(
*loc1*,*loc2*)

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.

#### rotate_loc_around

* (Version 1.13.9 and later only)* but returns wrong result until

**(Version 1.19.2 and later only)**- rotate_loc_around(
*center*,*loc*,*angle*)

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.

### Miscellaneous Functions

Some functions really don't fit into any category. They are all listed here.

#### null

- null([
*arguments*])

Evaluates each of its arguments (if any) in order, then returns null. Since formulas generally do not have side-effects, there is little point in specifying any arguments unless you are writing AI code (where several functions do have side-effects).

#### pair

**(Version 1.13.5 and later only)**

- pair(
*key*,*value*)

Creates a key-value pair object, the same as those created by the *tolist* function.

#### reverse

**(Version 1.13.5 and later only)**

- reverse(
*string or list*)

Returns the input string or list backwards.

#### type

**(Version 1.13.5 and later only)**

- type(
*anything*)

Returns the type of its input as a string. Possible results are:

`'integer'`

`'decimal'`

`'string'`

`'list'`

`'map'`

`'null'`

`'object'`

#### get_palette

**(Version 1.19.4 and later only)**

- get_palette(
*name*)

Returns a list of colours that make up the named palette. Palettes are defined by a **[color_palette]** tag, usually in the 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.

### Debugging Functions

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.

#### debug

- debug([
*formula*])

Starts a GUI formula AI 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.

* (Version 1.13.5 and later only)* 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 debug mode to use the debugger; otherwise, it will simply be skipped.

#### debug_print

**you need to enable formula log (--log-info='scripting/formula') to see the result of this call**

- debug_print([
*explanation*,]*formula*)

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:

```
debug_print([1, 2, 3])
```

will result in printing to the console

[1, 2, 3]

and returning the same.

We can specify an optional parameter *explanation* that helps to distinguish between multiple *debug_print* calls in the same formula:

```
debug_print('My array: ', [1, 2, 3])
```

will write in the console:

My array: [1, 2, 3]

and return

[1, 2, 3]

#### debug_profile

- debug_profile(
*formula*[,*explanation*])

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.

#### debug_float

- debug_float(
*location*, [*explanation*,]*formula*)

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 `loc()`

function. For example:

```
debug_float(me.loc, me.id)
```

will make a label containing the id of the unit *me* float over the unit.

Return value is also the unit id.

We can specify an optional parameter *explanation* that helps to distinguish between multiple *debug_float* calls in the same formula:

```
debug_float( me.loc, 'id: ', me.id )
```

will float the following label

id: unit_id

and return the unit id.

#### dir

- dir(
*object*)

This function return a list of all attributes in *object*. For example:

```
dir(my_leader)
```

will result in the following output:

[ 'x', 'y', 'loc', 'id', 'type', 'name', 'leader', 'undead', 'traits', 'attacks', 'abilities', 'hitpoints', 'max_hitpoints', 'experience', 'max_experience', 'level', 'total_movement', 'movement_left', 'attacks_left', 'side', 'states', 'cost', 'usage', 'vars']

This command is useful in the formula command line, to get information about the attributes of different types of data.

### Game State Functions

These are functions that access the game state. Therefore, they are not available in all formulas, as described above.

#### base_tod_bonus

- base_tod_bonus([
*loc*, [*turn*]])

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.

#### chance_to_hit

- chance_to_hit(
*unit*,*location or terrain*)

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.

#### defense_on

- defense_on(
*unit*,*location or terrain*)

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.

#### enemy_of

- enemy_of(
*self*,*other*)

Determines whether two units are enemies. Returns 1 (true) or 0 (false).

#### get_unit_type

- get_unit_type(
*id*)

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 `hitpoints` or `name`.

#### jamming_cost

- jamming_cost(
*unit or unit type*,*location or terrain*)

Calculates the jamming cost for the unit to block vision on the given location terrain.

#### movement_cost

- movement_cost(
*unit or unit type*,*location or terrain*)

Calculates the movement cost for the unit to enter the given location or terrain.

#### resistance_on

- resistance_on(
*unit*,*location*,*type*, [*attacker*])

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.

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.

#### tod_bonus

- tod_bonus([
*loc*, [*turn*]])

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.

#### unit_at

- unit_at(
*location*)

Returns the unit on the given location, or null if there is no unit there.

#### vision_cost

- vision_cost(
*unit or unit type*,*location or terrain*)

Calculates the vision cost for the unit to see through the given location or terrain.